diff --git a/p4-fusion/CMakeLists.txt b/p4-fusion/CMakeLists.txt index 7fc861e5..8bef5b97 100644 --- a/p4-fusion/CMakeLists.txt +++ b/p4-fusion/CMakeLists.txt @@ -48,6 +48,6 @@ target_link_libraries(p4-fusion PUBLIC p4script_cstub ${OPENSSL_SSL_LIBRARIES} ${OPENSSL_CRYPTO_LIBRARIES} - git2 + libgit2package minitrace ) diff --git a/vendor/libgit2/.clang-format b/vendor/libgit2/.clang-format new file mode 100644 index 00000000..d6e9cfce --- /dev/null +++ b/vendor/libgit2/.clang-format @@ -0,0 +1,92 @@ +# This file is an example configuration for clang-format 5.0. +# +# Note that this style definition should only be understood as a hint +# for writing new code. The rules are still work-in-progress and does +# not yet exactly match the style we have in the existing code. + +# C Language specifics +Language: Cpp + +# Use tabs whenever we need to fill whitespace that spans at least from one tab +# stop to the next one. +# +# These settings are mirrored in .editorconfig. Keep them in sync. +UseTab: ForIndentation +TabWidth: 8 +IndentWidth: 8 +ContinuationIndentWidth: 8 +ColumnLimit: 80 + +AlignAfterOpenBracket: AlwaysBreak +AlignEscapedNewlines: Left +AlignTrailingComments: false + +# Allow putting parameters onto the next line +AllowAllArgumentsOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false + +# Don't allow short braced statements to be on a single line +# if (a) not if (a) return; +# return; +AllowShortBlocksOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortLoopsOnASingleLine: false +AllowShortLambdasOnASingleLine: None + +# Pack as many parameters or arguments onto the same line as possible +# int myFunction(int aaaaaaaaaaaa, int bbbbbbbb, +# int cccc); +BinPackArguments: true +BinPackParameters: false + +BreakBeforeBraces: Linux +BreakBeforeBinaryOperators: None +BreakBeforeTernaryOperators: false +BreakStringLiterals: false + +# The number of spaces before trailing line comments (// - comments). +# This does not affect trailing block comments (/* - comments). +SpacesBeforeTrailingComments: 1 + +# Don't insert spaces in casts +# x = (int32) y; not x = ( int32 ) y; +SpacesInCStyleCastParentheses: false + +# Don't insert spaces inside container literals +# var arr = [1, 2, 3]; not var arr = [ 1, 2, 3 ]; +SpacesInContainerLiterals: false + +# Don't insert spaces after '(' or before ')' +# f(arg); not f( arg ); +SpacesInParentheses: false + +# Don't insert spaces after '[' or before ']' +# int a[5]; not int a[ 5 ]; +SpacesInSquareBrackets: false + +# Insert a space after '{' and before '}' in struct initializers +Cpp11BracedListStyle: false + +# A list of macros that should be interpreted as foreach loops instead of as +# function calls. +ForEachMacros: + - 'git_array_foreach' + - 'git_vector_foreach' + +# The maximum number of consecutive empty lines to keep. +MaxEmptyLinesToKeep: 1 + +# No empty line at the start of a block. +KeepEmptyLinesAtTheStartOfBlocks: false + +# Penalties +# This decides what order things should be done if a line is too long +PenaltyBreakAssignment: 10 +PenaltyBreakBeforeFirstCallParameter: 30 +PenaltyBreakComment: 10 +PenaltyBreakFirstLessLess: 0 +PenaltyBreakString: 10 +PenaltyExcessCharacter: 100 +PenaltyReturnTypeOnItsOwnLine: 60 + +SortIncludes: false diff --git a/vendor/libgit2/.gitattributes b/vendor/libgit2/.gitattributes index 3d90b7d6..3788dc98 100644 --- a/vendor/libgit2/.gitattributes +++ b/vendor/libgit2/.gitattributes @@ -1,2 +1,4 @@ * text=auto +ci/**/*.sh text eol=lf +script/**/*.sh text eol=lf tests/resources/** linguist-vendored diff --git a/vendor/libgit2/.github/actions/download-or-build-container/action.yml b/vendor/libgit2/.github/actions/download-or-build-container/action.yml new file mode 100644 index 00000000..9c83a983 --- /dev/null +++ b/vendor/libgit2/.github/actions/download-or-build-container/action.yml @@ -0,0 +1,109 @@ +# Run a build step in a container or directly on the Actions runner +name: Download or Build Container +description: Download a container from the package registry, or build it if it's not found + +inputs: + container: + description: Container name + type: string + required: true + dockerfile: + description: Dockerfile + type: string + base: + description: Container base + type: string + registry: + description: Docker registry to read and publish to + type: string + default: ghcr.io + config-path: + description: Path to Dockerfiles + type: string + github_token: + description: GitHub Token + type: string + +runs: + using: 'composite' + steps: + - name: Download container + run: | + IMAGE_NAME="${{ inputs.container }}" + DOCKERFILE_PATH="${{ inputs.dockerfile }}" + DOCKER_REGISTRY="${{ inputs.registry }}" + DOCKERFILE_ROOT="${{ inputs.config-path }}" + + if [ "${DOCKERFILE_PATH}" = "" ]; then + DOCKERFILE_PATH="${DOCKERFILE_ROOT}/${IMAGE_NAME}" + else + DOCKERFILE_PATH="${DOCKERFILE_ROOT}/${DOCKERFILE_PATH}" + fi + + GIT_WORKTREE=$(cd "${GITHUB_ACTION_PATH}" && git rev-parse --show-toplevel) + echo "::: git worktree is ${GIT_WORKTREE}" + cd "${GIT_WORKTREE}" + + DOCKER_CONTAINER="${GITHUB_REPOSITORY}/${IMAGE_NAME}" + DOCKER_REGISTRY_CONTAINER="${DOCKER_REGISTRY}/${DOCKER_CONTAINER}" + + echo "dockerfile=${DOCKERFILE_PATH}" >> $GITHUB_ENV + echo "docker-container=${DOCKER_CONTAINER}" >> $GITHUB_ENV + echo "docker-registry-container=${DOCKER_REGISTRY_CONTAINER}" >> $GITHUB_ENV + + # Identify the last git commit that touched the Dockerfiles + # Use this as a hash to identify the resulting docker containers + echo "::: dockerfile path is ${DOCKERFILE_PATH}" + + DOCKER_SHA=$(git log -1 --pretty=format:"%h" -- "${DOCKERFILE_PATH}") + echo "docker-sha=${DOCKER_SHA}" >> $GITHUB_ENV + + echo "::: docker sha is ${DOCKER_SHA}" + + DOCKER_REGISTRY_CONTAINER_SHA="${DOCKER_REGISTRY_CONTAINER}:${DOCKER_SHA}" + + echo "docker-registry-container-sha=${DOCKER_REGISTRY_CONTAINER_SHA}" >> $GITHUB_ENV + echo "docker-registry-container-latest=${DOCKER_REGISTRY_CONTAINER}:latest" >> $GITHUB_ENV + + echo "::: logging in to ${DOCKER_REGISTRY} as ${GITHUB_ACTOR}" + + exists="true" + docker login https://${DOCKER_REGISTRY} -u ${GITHUB_ACTOR} -p ${GITHUB_TOKEN} || exists="false" + + echo "::: pulling ${DOCKER_REGISTRY_CONTAINER_SHA}" + + if [ "${exists}" != "false" ]; then + docker pull ${DOCKER_REGISTRY_CONTAINER_SHA} || exists="false" + fi + + if [ "${exists}" = "true" ]; then + echo "::: docker container exists in registry" + echo "docker-container-exists=true" >> $GITHUB_ENV + else + echo "::: docker container does not exist in registry" + echo "docker-container-exists=false" >> $GITHUB_ENV + fi + shell: bash + env: + GITHUB_TOKEN: ${{ inputs.github_token }} + - name: Create container + run: | + if [ "${{ inputs.base }}" != "" ]; then + BASE_ARG="--build-arg BASE=${{ inputs.base }}" + fi + + GIT_WORKTREE=$(cd "${GITHUB_ACTION_PATH}" && git rev-parse --show-toplevel) + echo "::: git worktree is ${GIT_WORKTREE}" + cd "${GIT_WORKTREE}" + + docker build -t ${{ env.docker-registry-container-sha }} --build-arg UID=$(id -u) --build-arg GID=$(id -g) ${BASE_ARG} -f ${{ env.dockerfile }} . + docker tag ${{ env.docker-registry-container-sha }} ${{ env.docker-registry-container-latest }} + shell: bash + working-directory: source/${{ inputs.config-path }} + if: env.docker-container-exists != 'true' + - name: Publish container + run: | + docker push ${{ env.docker-registry-container-sha }} + docker push ${{ env.docker-registry-container-latest }} + shell: bash + if: env.docker-container-exists != 'true' && github.event_name != 'pull_request' diff --git a/vendor/libgit2/.github/actions/run-build/action.yml b/vendor/libgit2/.github/actions/run-build/action.yml new file mode 100644 index 00000000..9afcfb11 --- /dev/null +++ b/vendor/libgit2/.github/actions/run-build/action.yml @@ -0,0 +1,51 @@ +# Run a build step in a container or directly on the Actions runner +name: Run Build Step +description: Run a build step in a container or directly on the Actions runner + +inputs: + command: + description: Command to run + type: string + required: true + container: + description: Optional container to run in + type: string + container-version: + description: Version of the container to run + type: string + shell: + description: Shell to use + type: string + required: true + default: 'bash' + +runs: + using: 'composite' + steps: + - run: | + if [ -n "${{ inputs.container }}" ]; then + docker run \ + --rm \ + --user "$(id -u):$(id -g)" \ + -v "$(pwd)/source:/home/libgit2/source" \ + -v "$(pwd)/build:/home/libgit2/build" \ + -w /home/libgit2 \ + -e ASAN_SYMBOLIZER_PATH \ + -e CC \ + -e CFLAGS \ + -e CMAKE_GENERATOR \ + -e CMAKE_OPTIONS \ + -e GITTEST_NEGOTIATE_PASSWORD \ + -e GITTEST_FLAKY_STAT \ + -e PKG_CONFIG_PATH \ + -e SKIP_NEGOTIATE_TESTS \ + -e SKIP_SSH_TESTS \ + -e SKIP_PUSHOPTIONS_TESTS \ + -e TSAN_OPTIONS \ + -e UBSAN_OPTIONS \ + ${{ inputs.container-version }} \ + /bin/bash -c "${{ inputs.command }}" + else + ${{ inputs.command }} + fi + shell: ${{ inputs.shell != '' && inputs.shell || 'bash' }} diff --git a/vendor/libgit2/.github/release.yml b/vendor/libgit2/.github/release.yml index c3c8da29..4d4e3186 100644 --- a/vendor/libgit2/.github/release.yml +++ b/vendor/libgit2/.github/release.yml @@ -3,18 +3,33 @@ changelog: - title: New features labels: - feature + - title: Performance improvements + labels: + - performance - title: Bug fixes labels: - bug + - title: Security fixes + labels: + - security - title: Code cleanups labels: - cleanup - - title: CI improvements + - title: Build and CI improvements labels: - build - title: Documentation improvements labels: - documentation + - title: Platform compatibility fixes + labels: + - compatibility + - title: Git compatibility fixes + labels: + - git compatibility + - title: Dependency updates + labels: + - dependency - title: Other changes labels: - '*' diff --git a/vendor/libgit2/.github/workflows/benchmark.yml b/vendor/libgit2/.github/workflows/benchmark.yml new file mode 100644 index 00000000..6ee492ac --- /dev/null +++ b/vendor/libgit2/.github/workflows/benchmark.yml @@ -0,0 +1,140 @@ +# Benchmark libgit2 against the git reference implementation. +name: Benchmark + +on: + workflow_dispatch: + schedule: + - cron: '15 4 * * *' + +permissions: + contents: read + +jobs: + # Run our benchmarks. We build a matrix with the various build + # targets and their details. Unlike our CI builds, we run these + # directly on the VM instead of in containers since we do not + # need the breadth of platform diversity. + build: + # Only run scheduled workflows on the main repository; prevents people + # from using build minutes on their forks. + if: github.repository == 'libgit2/libgit2' + + strategy: + matrix: + platform: + - name: "Linux (clang, OpenSSL)" + env: + CC: clang + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_GSSAPI=ON -DBUILD_TESTS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_CLI=ON -DCMAKE_BUILD_TYPE=Release + CMAKE_BUILD_OPTIONS: --config Release + id: linux + os: ubuntu-latest + setup-script: ubuntu + - name: "macOS" + os: macos-12 + env: + CC: clang + CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_GSSAPI=ON -DBUILD_TESTS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_CLI=ON -DCMAKE_BUILD_TYPE=Release + CMAKE_BUILD_OPTIONS: --config Release + PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig + id: macos + setup-script: osx + - name: "Windows (amd64, Visual Studio)" + os: windows-2019 + env: + ARCH: amd64 + CMAKE_GENERATOR: Visual Studio 16 2019 + CMAKE_OPTIONS: -A x64 -DDEPRECATE_HARD=ON -DBUILD_TESTS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_CLI=ON -DCMAKE_BUILD_TYPE=Release + CMAKE_BUILD_OPTIONS: --config Release + id: windows + setup-script: win32 + fail-fast: false + name: "Benchmark ${{ matrix.platform.name }}" + env: ${{ matrix.platform.env }} + runs-on: ${{ matrix.platform.os }} + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + path: source + fetch-depth: 0 + - name: Set up benchmark environment + run: source/ci/setup-${{ matrix.platform.setup-script }}-benchmark.sh + shell: bash + if: matrix.platform.setup-script != '' + - name: Build + run: | + mkdir build && cd build + ../source/ci/build.sh + shell: bash + - name: Benchmark + run: | + if [[ "$(uname -s)" == MINGW* ]]; then + GIT2_CLI="$(cygpath -w $(pwd))\\build\\Release\\git2" + else + GIT2_CLI="$(pwd)/build/git2" + fi + + mkdir benchmark && cd benchmark + ../source/tests/benchmarks/benchmark.sh --baseline-cli "git" --cli "${GIT2_CLI}" --name libgit2 --json benchmarks.json --zip benchmarks.zip + shell: bash + - name: Upload results + uses: actions/upload-artifact@v4 + with: + name: benchmark-${{ matrix.platform.id }} + path: benchmark + if: always() + + # Publish the results + publish: + name: Publish results + needs: [ build ] + if: ${{ always() && github.repository == 'libgit2/libgit2' }} + runs-on: ubuntu-latest + steps: + - name: Check out benchmark repository + uses: actions/checkout@v4 + with: + repository: libgit2/benchmarks + path: site + fetch-depth: 0 + ssh-key: ${{ secrets.BENCHMARKS_PUBLISH_KEY }} + - name: Download test results + uses: actions/download-artifact@v4 + - name: Publish API + run: | + # Move today's benchmark run into the right place + for platform in linux macos windows; do + TIMESTAMP=$(jq .time.start < "benchmark-${platform}/benchmarks.json") + TIMESTAMP_LEN=$(echo -n ${TIMESTAMP} | wc -c | xargs) + DENOMINATOR=1 + if [ "${TIMESTAMP_LEN}" = "19" ]; then + DENOMINATOR="1000000000" + elif [ "${TIMESTAMP_LEN}" = "13" ]; then + DENOMINATOR="1000" + else + echo "unknown timestamp" + exit 1 + fi + + if [[ "$(uname -s)" == "Darwin" ]]; then + DATE=$(date -R -r $(("${TIMESTAMP}/${DENOMINATOR}")) +"%Y-%m-%d") + else + DATE=$(date -d @$(("${TIMESTAMP}/${DENOMINATOR}")) +"%Y-%m-%d") + fi + + mkdir -p "site/public/api/runs/${DATE}" + cp "benchmark-${platform}/benchmarks.json" "site/public/api/runs/${DATE}/${platform}.json" + done + + (cd site && node scripts/aggregate.js) + + ( + cd site && + git config user.name 'Benchmark Site Generation' && + git config user.email 'libgit2@users.noreply.github.com' && + git add . && + git commit --allow-empty -m"benchmark update ${DATE}" && + git push origin main + ) + shell: bash diff --git a/vendor/libgit2/.github/workflows/build-containers.yml b/vendor/libgit2/.github/workflows/build-containers.yml new file mode 100644 index 00000000..b52571c1 --- /dev/null +++ b/vendor/libgit2/.github/workflows/build-containers.yml @@ -0,0 +1,74 @@ +# Generate the containers that we use for builds. +name: Build Containers + +on: + workflow_call: + +env: + docker-registry: ghcr.io + docker-config-path: source/ci/docker + +jobs: + # Build the docker container images that we will use for our Linux + # builds. This will identify the last commit to the repository that + # updated the docker images, and try to download the image tagged with + # that sha. If it does not exist, we'll do a docker build and push + # the image up to GitHub Packages for the actual CI/CD runs. We tag + # with both the sha and "latest" so that the subsequent runs need not + # know the sha. Only do this on CI builds (when the event is a "push") + # because PR builds from forks lack permission to write packages. + containers: + strategy: + matrix: + container: + - name: xenial + - name: bionic + - name: focal + - name: noble + - name: docurium + - name: bionic-x86 + dockerfile: bionic + base: multiarch/ubuntu-core:x86-bionic + qemu: true + - name: bionic-arm32 + dockerfile: bionic + base: multiarch/ubuntu-core:armhf-bionic + qemu: true + - name: bionic-arm64 + dockerfile: bionic + base: multiarch/ubuntu-core:arm64-bionic + qemu: true + - name: centos7 + - name: centos8 + - name: fedora + runs-on: ubuntu-latest + name: "Create container: ${{ matrix.container.name }}" + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + path: source + fetch-depth: 0 + if: github.event_name != 'pull_request' + - name: Setup QEMU + run: docker run --rm --privileged multiarch/qemu-user-static:register --reset + if: matrix.container.qemu == true + - name: Download existing container + run: | + "${{ github.workspace }}/source/ci/getcontainer.sh" "${{ matrix.container.name }}" "${{ matrix.container.dockerfile }}" + env: + DOCKER_REGISTRY: ${{ env.docker-registry }} + GITHUB_TOKEN: ${{ secrets.github_token }} + working-directory: ${{ env.docker-config-path }} + if: github.event_name != 'pull_request' + - name: Build and publish image + run: | + if [ "${{ matrix.container.base }}" != "" ]; then + BASE_ARG="--build-arg BASE=${{ matrix.container.base }}" + fi + docker build -t ${{ env.docker-registry-container-sha }} --build-arg UID=$(id -u) --build-arg GID=$(id -g) ${BASE_ARG} -f ${{ env.dockerfile }} . + docker tag ${{ env.docker-registry-container-sha }} ${{ env.docker-registry-container-latest }} + docker push ${{ env.docker-registry-container-sha }} + docker push ${{ env.docker-registry-container-latest }} + working-directory: ${{ env.docker-config-path }} + if: github.event_name != 'pull_request' && env.docker-container-exists != 'true' diff --git a/vendor/libgit2/.github/workflows/codeql.yml b/vendor/libgit2/.github/workflows/codeql.yml deleted file mode 100644 index 38b4a044..00000000 --- a/vendor/libgit2/.github/workflows/codeql.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: "CodeQL" - -on: - workflow_dispatch: - schedule: - - cron: '21 3 * * 1' - -env: - docker-registry: docker.pkg.github.com - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - - steps: - - name: Check out repository - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: 'cpp' - - - name: Build - run: | - mkdir build - cd build - cmake .. -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON - cmake --build . - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 diff --git a/vendor/libgit2/.github/workflows/experimental.yml b/vendor/libgit2/.github/workflows/experimental.yml new file mode 100644 index 00000000..7df77911 --- /dev/null +++ b/vendor/libgit2/.github/workflows/experimental.yml @@ -0,0 +1,118 @@ +# Validation builds for experimental features; these shouldn't be +# required for pull request approval. +name: Experimental Features + +on: + push: + branches: [ main, maint/* ] + pull_request: + branches: [ main, maint/* ] + workflow_dispatch: + +env: + docker-registry: ghcr.io + docker-config-path: ci/docker + +permissions: + contents: write + packages: write + +jobs: + # Run our CI/CD builds. We build a matrix with the various build targets + # and their details. Then we build either in a docker container (Linux) + # or on the actual hosts (macOS, Windows). + build: + strategy: + matrix: + platform: + # All builds: experimental SHA256 support + - name: "Linux (SHA256, Xenial, Clang, OpenSSL)" + id: linux-sha256 + os: ubuntu-latest + container: + name: xenial + env: + CC: clang + CMAKE_GENERATOR: Ninja + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON -DEXPERIMENTAL_SHA256=ON + - name: "macOS (SHA256)" + id: macos-sha256 + os: macos-13 + setup-script: osx + env: + CC: clang + CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DEXPERIMENTAL_SHA256=ON + CMAKE_GENERATOR: Ninja + PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + - name: "Windows (SHA256, amd64, Visual Studio)" + id: windows-sha256 + os: windows-2019 + env: + ARCH: amd64 + CMAKE_GENERATOR: Visual Studio 16 2019 + CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DEXPERIMENTAL_SHA256=ON + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + fail-fast: false + env: ${{ matrix.platform.env }} + runs-on: ${{ matrix.platform.os }} + name: "Build: ${{ matrix.platform.name }}" + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + path: source + fetch-depth: 0 + - name: Set up build environment + run: source/ci/setup-${{ matrix.platform.setup-script }}-build.sh + shell: bash + if: matrix.platform.setup-script != '' + - name: Setup QEMU + run: docker run --rm --privileged multiarch/qemu-user-static:register --reset + if: matrix.platform.container.qemu == true + - name: Set up container + uses: ./source/.github/actions/download-or-build-container + with: + registry: ${{ env.docker-registry }} + config-path: ${{ env.docker-config-path }} + container: ${{ matrix.platform.container.name }} + github_token: ${{ secrets.github_token }} + dockerfile: ${{ matrix.platform.container.dockerfile }} + if: matrix.platform.container.name != '' + - name: Prepare build + run: mkdir build + - name: Build + uses: ./source/.github/actions/run-build + with: + command: cd ${BUILD_WORKSPACE:-.}/build && ../source/ci/build.sh + container: ${{ matrix.platform.container.name }} + container-version: ${{ env.docker-registry-container-sha }} + shell: ${{ matrix.platform.shell }} + - name: Test + uses: ./source/.github/actions/run-build + with: + command: cd ${BUILD_WORKSPACE:-.}/build && ../source/ci/test.sh + container: ${{ matrix.platform.container.name }} + container-version: ${{ env.docker-registry-container-sha }} + shell: ${{ matrix.platform.shell }} + - name: Upload test results + uses: actions/upload-artifact@v4 + if: success() || failure() + with: + name: test-results-${{ matrix.platform.id }} + path: build/results_*.xml + + test_results: + name: Test results + needs: [ build ] + if: always() + runs-on: ubuntu-latest + steps: + - name: Download test results + uses: actions/download-artifact@v4 + - name: Generate test summary + uses: test-summary/action@v2 + with: + paths: 'test-results-*/*.xml' diff --git a/vendor/libgit2/.github/workflows/main.yml b/vendor/libgit2/.github/workflows/main.yml index 74bab53f..207ce9ba 100644 --- a/vendor/libgit2/.github/workflows/main.yml +++ b/vendor/libgit2/.github/workflows/main.yml @@ -10,178 +10,95 @@ on: workflow_dispatch: env: - docker-registry: docker.pkg.github.com - docker-config-path: source/ci/docker + docker-registry: ghcr.io + docker-config-path: ci/docker -jobs: - # Build the docker container images that we will use for our Linux - # builds. This will identify the last commit to the repository that - # updated the docker images, and try to download the image tagged with - # that sha. If it does not exist, we'll do a docker build and push - # the image up to GitHub Packages for the actual CI/CD runs. We tag - # with both the sha and "latest" so that the subsequent runs need not - # know the sha. Only do this on CI builds (when the event is a "push") - # because PR builds from forks lack permission to write packages. - containers: - strategy: - matrix: - container: - - name: xenial - - name: bionic - - name: focal - - name: docurium - - name: bionic-x86 - dockerfile: bionic - base: multiarch/ubuntu-core:x86-bionic - qemu: true - - name: bionic-arm32 - dockerfile: bionic - base: multiarch/ubuntu-core:armhf-bionic - qemu: true - - name: bionic-arm64 - dockerfile: bionic - base: multiarch/ubuntu-core:arm64-bionic - qemu: true - - name: centos7 - - name: centos8 - runs-on: ubuntu-latest - name: "Create container: ${{ matrix.container.name }}" - steps: - - name: Check out repository - uses: actions/checkout@v2 - with: - path: source - fetch-depth: 0 - if: github.event_name != 'pull_request' - - name: Setup QEMU - run: docker run --rm --privileged multiarch/qemu-user-static:register --reset - if: matrix.container.qemu == true - - name: Download existing container - run: | - "${{ github.workspace }}/source/ci/getcontainer.sh" "${{ matrix.container.name }}" "${{ matrix.container.dockerfile }}" - env: - DOCKER_REGISTRY: ${{ env.docker-registry }} - GITHUB_TOKEN: ${{ secrets.github_token }} - working-directory: ${{ env.docker-config-path }} - if: github.event_name != 'pull_request' - - name: Build and publish image - run: | - if [ "${{ matrix.container.base }}" != "" ]; then - BASE_ARG="--build-arg BASE=${{ matrix.container.base }}" - fi - docker build -t ${{ env.docker-registry-container-sha }} ${BASE_ARG} -f ${{ env.dockerfile }} . - docker tag ${{ env.docker-registry-container-sha }} ${{ env.docker-registry-container-latest }} - docker push ${{ env.docker-registry-container-sha }} - docker push ${{ env.docker-registry-container-latest }} - working-directory: ${{ env.docker-config-path }} - if: github.event_name != 'pull_request' && env.docker-container-exists != 'true' +permissions: + contents: write + packages: write +jobs: # Run our CI/CD builds. We build a matrix with the various build targets # and their details. Then we build either in a docker container (Linux) # or on the actual hosts (macOS, Windows). build: - needs: [ containers ] strategy: matrix: platform: - - name: "Linux (Xenial, GCC, OpenSSL)" - container: - name: xenial - env: - CC: gcc - CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON + # All builds: core platforms + - name: "Linux (Noble, GCC, OpenSSL, libssh2)" + id: noble-gcc-openssl os: ubuntu-latest - - name: Linux (Xenial, GCC, mbedTLS) container: - name: xenial + name: noble env: CC: gcc CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON + - name: "Linux (Noble, Clang, mbedTLS, OpenSSH)" + id: noble-clang-mbedtls os: ubuntu-latest - - name: "Linux (Xenial, Clang, OpenSSL)" container: - name: xenial + name: noble env: CC: clang + CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + - name: "Linux (Xenial, GCC, OpenSSL, OpenSSH)" + id: xenial-gcc-openssl os: ubuntu-latest - - name: "Linux (Xenial, Clang, mbedTLS)" container: name: xenial env: - CC: clang - CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON - CMAKE_GENERATOR: Ninja - os: ubuntu-latest - - name: "Linux (MemorySanitizer)" - container: - name: focal - env: - CC: clang-10 - CFLAGS: -fsanitize=memory -fsanitize-memory-track-origins=2 -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer - CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local/msan -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON - CMAKE_GENERATOR: Ninja - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true - ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 - UBSAN_OPTIONS: print_stacktrace=1 - os: ubuntu-latest - - name: "Linux (UndefinedBehaviorSanitizer)" - container: - name: focal - env: - CC: clang-10 - CFLAGS: -fsanitize=undefined,nullability -fno-sanitize-recover=undefined,nullability -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer - CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON + CC: gcc CMAKE_GENERATOR: Ninja - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true - ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 - UBSAN_OPTIONS: print_stacktrace=1 + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON + - name: "Linux (Xenial, Clang, mbedTLS, libssh2)" + id: xenial-gcc-mbedtls os: ubuntu-latest - - name: "Linux (ThreadSanitizer)" container: - name: focal + name: xenial env: - CC: clang-10 - CFLAGS: -fsanitize=thread -fno-optimize-sibling-calls -fno-omit-frame-pointer - CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON + CC: clang CMAKE_GENERATOR: Ninja - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true - ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 - UBSAN_OPTIONS: print_stacktrace=1 - TSAN_OPTIONS: suppressions=/home/libgit2/source/script/thread-sanitizer.supp second_deadlock_stack=1 - os: ubuntu-latest + CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 - name: "macOS" - os: macos-10.15 + id: macos + os: macos-13 + setup-script: osx env: CC: clang CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON + CMAKE_GENERATOR: Ninja PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - setup-script: osx - - name: "Windows (amd64, Visual Studio)" + - name: "Windows (amd64, Visual Studio, Schannel)" + id: windows-amd64-vs os: windows-2019 + setup-script: win32 env: ARCH: amd64 CMAKE_GENERATOR: Visual Studio 16 2019 - CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON + CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_HTTPS=Schannel -DUSE_SSH=ON -DCMAKE_PREFIX_PATH=D:\Temp\libssh2 + BUILD_PATH: C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin;D:\Temp\libssh2\bin + BUILD_TEMP: D:\Temp SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - - name: "Windows (x86, Visual Studio)" + - name: "Windows (x86, Visual Studio, WinHTTP)" + id: windows-x86-vs os: windows-2019 + setup-script: win32 env: ARCH: x86 CMAKE_GENERATOR: Visual Studio 16 2019 - CMAKE_OPTIONS: -A Win32 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS -DUSE_BUNDLED_ZLIB=ON + CMAKE_OPTIONS: -A Win32 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON -DCMAKE_PREFIX_PATH=D:\Temp\libssh2 + BUILD_PATH: C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin;D:\Temp\libssh2\bin + BUILD_TEMP: D:\Temp SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - - name: "Windows (amd64, mingw)" + - name: "Windows (amd64, mingw, WinHTTP)" + id: windows-amd64-mingw os: windows-2019 setup-script: mingw env: @@ -192,75 +109,143 @@ jobs: BUILD_PATH: D:\Temp\mingw64\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - - name: "Windows (x86, mingw)" + - name: "Windows (x86, mingw, Schannel)" + id: windows-x86-mingw os: windows-2019 setup-script: mingw env: ARCH: x86 CMAKE_GENERATOR: MinGW Makefiles - CMAKE_OPTIONS: -DDEPRECATE_HARD=ON + CMAKE_OPTIONS: -DDEPRECATE_HARD=ON -DUSE_HTTPS=Schannel BUILD_TEMP: D:\Temp BUILD_PATH: D:\Temp\mingw32\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true + + # All builds: sanitizers + - name: "Sanitizer (Memory)" + id: sanitizer-memory + os: ubuntu-latest + setup-script: sanitizer + container: + name: noble + env: + CC: clang + CFLAGS: -fsanitize=memory -fsanitize-memory-track-origins=2 -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer + CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local/msan -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON + CMAKE_GENERATOR: Ninja + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 + UBSAN_OPTIONS: print_stacktrace=1 + - name: "Sanitizer (Address)" + id: sanitizer-address + os: ubuntu-latest + setup-script: sanitizer + container: + name: noble + env: + CC: clang + CFLAGS: -fsanitize=address -ggdb -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer + CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON + CMAKE_GENERATOR: Ninja + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 + UBSAN_OPTIONS: print_stacktrace=1 + - name: "Sanitizer (UndefinedBehavior)" + id: sanitizer-ub + os: ubuntu-latest + setup-script: sanitizer + container: + name: noble + env: + CC: clang + CFLAGS: -fsanitize=undefined,nullability -fno-sanitize-recover=undefined,nullability -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer + CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON + CMAKE_GENERATOR: Ninja + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 + UBSAN_OPTIONS: print_stacktrace=1 + - name: "Sanitizer (Thread)" + id: sanitizer-thread + os: ubuntu-latest + setup-script: sanitizer + container: + name: noble + env: + CC: clang + CFLAGS: -fsanitize=thread -fno-optimize-sibling-calls -fno-omit-frame-pointer + CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON + CMAKE_GENERATOR: Ninja + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 + UBSAN_OPTIONS: print_stacktrace=1 + TSAN_OPTIONS: suppressions=/home/libgit2/source/script/thread-sanitizer.supp second_deadlock_stack=1 fail-fast: false env: ${{ matrix.platform.env }} runs-on: ${{ matrix.platform.os }} name: "Build: ${{ matrix.platform.name }}" steps: - name: Check out repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: path: source fetch-depth: 0 - name: Set up build environment - run: source/ci/setup-${{ matrix.platform.setup-script }}.sh + run: source/ci/setup-${{ matrix.platform.setup-script }}-build.sh shell: bash if: matrix.platform.setup-script != '' - name: Setup QEMU run: docker run --rm --privileged multiarch/qemu-user-static:register --reset if: matrix.platform.container.qemu == true - - name: Download container - run: | - "${{ github.workspace }}/source/ci/getcontainer.sh" "${{ matrix.platform.container.name }}" "${{ matrix.platform.container.dockerfile }}" - env: - DOCKER_REGISTRY: ${{ env.docker-registry }} - GITHUB_TOKEN: ${{ secrets.github_token }} - working-directory: ${{ env.docker-config-path }} + - name: Set up container + uses: ./source/.github/actions/download-or-build-container + with: + registry: ${{ env.docker-registry }} + config-path: ${{ env.docker-config-path }} + container: ${{ matrix.platform.container.name }} + github_token: ${{ secrets.github_token }} + dockerfile: ${{ matrix.platform.container.dockerfile }} if: matrix.platform.container.name != '' - - name: Create container - run: docker build -t ${{ env.docker-registry-container-sha }} -f ${{ env.dockerfile }} . - working-directory: ${{ env.docker-config-path }} - if: matrix.platform.container.name != '' && env.docker-container-exists != 'true' - - name: Build and test - run: | - export GITTEST_NEGOTIATE_PASSWORD="${{ secrets.GITTEST_NEGOTIATE_PASSWORD }}" + - name: Prepare build + run: mkdir build + - name: Build + uses: ./source/.github/actions/run-build + with: + command: cd ${BUILD_WORKSPACE:-.}/build && ../source/ci/build.sh + container: ${{ matrix.platform.container.name }} + container-version: ${{ env.docker-registry-container-sha }} + shell: ${{ matrix.platform.shell }} + - name: Test + uses: ./source/.github/actions/run-build + with: + command: cd ${BUILD_WORKSPACE:-.}/build && ../source/ci/test.sh + container: ${{ matrix.platform.container.name }} + container-version: ${{ env.docker-registry-container-sha }} + shell: ${{ matrix.platform.shell }} + - name: Upload test results + uses: actions/upload-artifact@v4 + if: success() || failure() + with: + name: test-results-${{ matrix.platform.id }} + path: build/results_*.xml + + test_results: + name: Test results + needs: [ build ] + if: always() + runs-on: ubuntu-latest + steps: + - name: Download test results + uses: actions/download-artifact@v4 + - name: Generate test summary + uses: test-summary/action@v2 + with: + paths: 'test-results-*/*.xml' - if [ -n "${{ matrix.platform.container.name }}" ]; then - docker run \ - --rm \ - --user libgit2:libgit2 \ - -v "$(pwd)/source:/home/libgit2/source" \ - -w /home/libgit2 \ - -e ASAN_SYMBOLIZER_PATH \ - -e CC \ - -e CFLAGS \ - -e CMAKE_GENERATOR \ - -e CMAKE_OPTIONS \ - -e GITTEST_NEGOTIATE_PASSWORD \ - -e PKG_CONFIG_PATH \ - -e SKIP_NEGOTIATE_TESTS \ - -e SKIP_SSH_TESTS \ - -e TSAN_OPTIONS \ - -e UBSAN_OPTIONS \ - ${{ env.docker-registry-container-sha }} \ - /bin/bash -c "mkdir build && cd build && ../source/ci/build.sh && ../source/ci/test.sh" - else - mkdir build && cd build - ../source/ci/build.sh - ../source/ci/test.sh - fi - shell: bash # Generate documentation using docurium. We'll upload the documentation # as a build artifact so that it can be reviewed as part of a pull @@ -269,14 +254,22 @@ jobs: # published to our documentation site. documentation: name: Generate documentation - needs: [ containers ] + if: success() || failure() runs-on: ubuntu-latest steps: - name: Check out repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: path: source fetch-depth: 0 + - name: Set up container + uses: ./source/.github/actions/download-or-build-container + with: + registry: ${{ env.docker-registry }} + config-path: ${{ env.docker-config-path }} + container: docurium + github_token: ${{ secrets.github_token }} + dockerfile: ${{ matrix.platform.container.dockerfile }} - name: Generate documentation working-directory: source run: | @@ -292,7 +285,7 @@ jobs: cm doc api.docurium git checkout gh-pages zip --exclude .git/\* --exclude .gitignore --exclude .gitattributes -r api-documentation.zip . - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 name: Upload artifact with: name: api-documentation diff --git a/vendor/libgit2/.github/workflows/nightly.yml b/vendor/libgit2/.github/workflows/nightly.yml index 5513d5b4..28a06189 100644 --- a/vendor/libgit2/.github/workflows/nightly.yml +++ b/vendor/libgit2/.github/workflows/nightly.yml @@ -7,70 +7,131 @@ on: - cron: '15 1 * * *' env: - docker-registry: docker.pkg.github.com - docker-config-path: source/ci/docker + docker-registry: ghcr.io + docker-config-path: ci/docker + +permissions: + contents: read + packages: write jobs: # Run our nightly builds. We build a matrix with the various build # targets and their details. Then we build either in a docker container # (Linux) or on the actual hosts (macOS, Windows). build: + # Only run scheduled workflows on the main repository; prevents people + # from using build minutes on their forks. + if: github.repository == 'libgit2/libgit2' + strategy: matrix: platform: - - name: Linux (Xenial, GCC, OpenSSL) - container: - name: xenial - env: - CC: gcc - CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + # All builds: core platforms + - name: "Linux (Noble, GCC, OpenSSL, libssh2)" + id: noble-gcc-openssl os: ubuntu-latest - - name: "Linux (Xenial, GCC, mbedTLS)" container: - name: xenial + name: noble env: CC: gcc CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON + - name: "Linux (Noble, Clang, mbedTLS, OpenSSH)" + id: noble-clang-mbedtls os: ubuntu-latest - - name: "Linux (Xenial, Clang, OpenSSL)" container: - name: xenial + name: noble env: CC: clang + CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + - name: "Linux (Xenial, GCC, OpenSSL, OpenSSH)" + id: xenial-gcc-openssl os: ubuntu-latest - - name: "Linux (Xenial, Clang, mbedTLS)" container: name: xenial env: - CC: clang - CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CC: gcc CMAKE_GENERATOR: Ninja + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=exec -DDEBUG_STRICT_ALLOC=ON -DDEBUG_STRICT_OPEN=ON + - name: "Linux (Xenial, Clang, mbedTLS, libssh2)" + id: xenial-gcc-mbedtls os: ubuntu-latest - - name: "Linux (no threads)" container: name: xenial env: - CC: gcc - CMAKE_OPTIONS: -DTHREADSAFE=OFF -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CC: clang CMAKE_GENERATOR: Ninja - os: ubuntu-latest - - name: "Linux (dynamically-loaded OpenSSL)" - container: - name: xenial + CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 + - name: "macOS" + id: macos + os: macos-12 + setup-script: osx env: CC: clang - CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON CMAKE_GENERATOR: Ninja + PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + - name: "Windows (amd64, Visual Studio, Schannel)" + id: windows-amd64-vs + os: windows-2019 + setup-script: win32 + env: + ARCH: amd64 + CMAKE_GENERATOR: Visual Studio 16 2019 + CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_HTTPS=Schannel -DUSE_SSH=ON -DCMAKE_PREFIX_PATH=D:\Temp\libssh2 + BUILD_PATH: C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin;D:\Temp\libssh2\bin + BUILD_TEMP: D:\Temp + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + - name: "Windows (x86, Visual Studio, WinHTTP)" + id: windows-x86-vs + os: windows-2019 + setup-script: win32 + env: + ARCH: x86 + CMAKE_GENERATOR: Visual Studio 16 2019 + CMAKE_OPTIONS: -A Win32 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON -DCMAKE_PREFIX_PATH=D:\Temp\libssh2 + BUILD_PATH: C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin;D:\Temp\libssh2\bin + BUILD_TEMP: D:\Temp + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + - name: "Windows (amd64, mingw, WinHTTP)" + id: windows-amd64-mingw + os: windows-2019 + setup-script: mingw + env: + ARCH: amd64 + CMAKE_GENERATOR: MinGW Makefiles + CMAKE_OPTIONS: -DDEPRECATE_HARD=ON + BUILD_TEMP: D:\Temp + BUILD_PATH: D:\Temp\mingw64\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + - name: "Windows (x86, mingw, Schannel)" + id: windows-x86-mingw + os: windows-2019 + setup-script: mingw + env: + ARCH: x86 + CMAKE_GENERATOR: MinGW Makefiles + CMAKE_OPTIONS: -DDEPRECATE_HARD=ON -DUSE_HTTPS=Schannel + BUILD_TEMP: D:\Temp + BUILD_PATH: D:\Temp\mingw32\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + + # All builds: sanitizers + - name: "Sanitizer (Memory)" + id: memorysanitizer os: ubuntu-latest - - name: "Linux (MemorySanitizer)" + setup-script: sanitizer container: - name: focal + name: noble env: - CC: clang-10 + CC: clang-17 CFLAGS: -fsanitize=memory -fsanitize-memory-track-origins=2 -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local/msan -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON CMAKE_GENERATOR: Ninja @@ -78,60 +139,62 @@ jobs: SKIP_NEGOTIATE_TESTS: true ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 UBSAN_OPTIONS: print_stacktrace=1 + - name: "Sanitizer (UndefinedBehavior)" + id: ubsanitizer os: ubuntu-latest - - name: "Linux (UndefinedBehaviorSanitizer)" + setup-script: sanitizer container: - name: focal + name: noble env: - CC: clang-10 + CC: clang-17 CFLAGS: -fsanitize=undefined,nullability -fno-sanitize-recover=undefined,nullability -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer - CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON + CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON CMAKE_GENERATOR: Ninja SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 + UBSAN_OPTIONS: print_stacktrace=1 + - name: "Sanitizer (Thread)" + id: threadsanitizer os: ubuntu-latest - - name: "Linux (ThreadSanitizer)" + setup-script: sanitizer container: - name: focal + name: noble env: - CC: clang-10 + CC: clang-17 CFLAGS: -fsanitize=thread -fno-optimize-sibling-calls -fno-omit-frame-pointer - CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON + CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON CMAKE_GENERATOR: Ninja SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10 + UBSAN_OPTIONS: print_stacktrace=1 TSAN_OPTIONS: suppressions=/home/libgit2/source/script/thread-sanitizer.supp second_deadlock_stack=1 + + # Nightly builds: extended platforms + - name: "Linux (CentOS 7, OpenSSL)" + id: centos7-openssl os: ubuntu-latest - - name: "Linux (no mmap)" - container: - name: focal - env: - CC: clang-10 - CFLAGS: -DNO_MMAP - CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local - CMAKE_GENERATOR: Ninja - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true - os: ubuntu-latest - - name: "Linux (CentOS 7)" container: name: centos7 env: CMAKE_OPTIONS: -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON PKG_CONFIG_PATH: /usr/local/lib/pkgconfig SKIP_NEGOTIATE_TESTS: true - os: ubuntu-latest + SKIP_PUSHOPTIONS_TESTS: true - name: "Linux (CentOS 7, dynamically-loaded OpenSSL)" + id: centos7-dynamicopenssl + os: ubuntu-latest container: name: centos7 env: CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON PKG_CONFIG_PATH: /usr/local/lib/pkgconfig SKIP_NEGOTIATE_TESTS: true + SKIP_PUSHOPTIONS_TESTS: true + - name: "Linux (CentOS 8, OpenSSL)" + id: centos8-openssl os: ubuntu-latest - - name: "Linux (CentOS 8)" container: name: centos8 env: @@ -139,8 +202,9 @@ jobs: PKG_CONFIG_PATH: /usr/local/lib/pkgconfig SKIP_NEGOTIATE_TESTS: true SKIP_SSH_TESTS: true - os: ubuntu-latest - name: "Linux (CentOS 8, dynamically-loaded OpenSSL)" + id: centos8-dynamicopenssl + os: ubuntu-latest container: name: centos8 env: @@ -148,64 +212,18 @@ jobs: PKG_CONFIG_PATH: /usr/local/lib/pkgconfig SKIP_NEGOTIATE_TESTS: true SKIP_SSH_TESTS: true - os: ubuntu-latest - - name: "macOS" - os: macos-10.15 - env: - CC: clang - CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON - PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true - setup-script: osx - - name: "Windows (amd64, Visual Studio)" - os: windows-2019 - env: - ARCH: amd64 - CMAKE_GENERATOR: Visual Studio 16 2019 - CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true - - name: "Windows (no mmap)" - os: windows-2019 - env: - ARCH: amd64 - CMAKE_GENERATOR: Visual Studio 16 2019 - CFLAGS: -DNO_MMAP - CMAKE_OPTIONS: -A x64 -DDEPRECATE_HARD=ON - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true - - name: "Windows (x86, Visual Studio)" - os: windows-2019 - env: ARCH: x86 - CMAKE_GENERATOR: Visual Studio 16 2019 - CMAKE_OPTIONS: -A Win32 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS -DUSE_BUNDLED_ZLIB=ON - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true - - name: "Windows (amd64, mingw)" - os: windows-2019 - setup-script: mingw - env: - ARCH: amd64 - CMAKE_GENERATOR: MinGW Makefiles - CMAKE_OPTIONS: -DDEPRECATE_HARD=ON - BUILD_TEMP: D:\Temp - BUILD_PATH: D:\Temp\mingw64\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true - - name: "Windows (x86, mingw)" - os: windows-2019 - setup-script: mingw + - name: "Linux (Fedora, llhttp)" + id: fedora + os: ubuntu-latest + container: + name: fedora env: - ARCH: x86 - CMAKE_GENERATOR: MinGW Makefiles - CMAKE_OPTIONS: -DDEPRECATE_HARD=ON - BUILD_TEMP: D:\Temp - BUILD_PATH: D:\Temp\mingw32\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin - SKIP_SSH_TESTS: true - SKIP_NEGOTIATE_TESTS: true + CC: gcc + CMAKE_GENERATOR: Ninja + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=pcre2 -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=libssh2 -DUSE_HTTP_PARSER=llhttp - name: "Linux (Bionic, GCC, dynamically-loaded OpenSSL)" + id: bionic-gcc-dynamicopenssl container: name: bionic dockerfile: bionic @@ -214,8 +232,10 @@ jobs: CMAKE_GENERATOR: Ninja CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON RUN_INVASIVE_TESTS: true + SKIP_PUSHOPTIONS_TESTS: true os: ubuntu-latest - name: "Linux (x86, Bionic, Clang, OpenSSL)" + id: bionic-x86-clang-openssl container: name: bionic-x86 dockerfile: bionic @@ -225,8 +245,10 @@ jobs: CMAKE_GENERATOR: Ninja CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON RUN_INVASIVE_TESTS: true + SKIP_PUSHOPTIONS_TESTS: true os: ubuntu-latest - name: "Linux (x86, Bionic, GCC, OpenSSL)" + id: bionic-x86-gcc-openssl container: name: bionic-x86 dockerfile: bionic @@ -235,8 +257,10 @@ jobs: CMAKE_GENERATOR: Ninja CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON RUN_INVASIVE_TESTS: true + SKIP_PUSHOPTIONS_TESTS: true os: ubuntu-latest - name: "Linux (arm32, Bionic, GCC, OpenSSL)" + id: bionic-arm32-gcc-openssl container: name: bionic-arm32 dockerfile: bionic @@ -247,8 +271,11 @@ jobs: CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_GSSAPI=ON -DUSE_SSH=ON RUN_INVASIVE_TESTS: true SKIP_PROXY_TESTS: true + SKIP_PUSHOPTIONS_TESTS: true + GITTEST_FLAKY_STAT: true os: ubuntu-latest - name: "Linux (arm64, Bionic, GCC, OpenSSL)" + id: bionic-arm64-gcc-openssl container: name: bionic-arm64 dockerfile: bionic @@ -259,82 +286,201 @@ jobs: CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_GSSAPI=ON -DUSE_SSH=ON RUN_INVASIVE_TESTS: true SKIP_PROXY_TESTS: true + SKIP_PUSHOPTIONS_TESTS: true + os: ubuntu-latest + + # Nightly builds: ensure we fallback when missing core functionality + - name: "Linux (no threads)" + id: xenial-nothreads + os: ubuntu-latest + container: + name: xenial + env: + CC: gcc + CMAKE_OPTIONS: -DTHREADSAFE=OFF -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_GENERATOR: Ninja + SKIP_PUSHOPTIONS_TESTS: true + - name: "Linux (no mmap)" + id: noble-nommap + os: ubuntu-latest + container: + name: noble + env: + CC: gcc + CFLAGS: -DNO_MMAP + CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local + CMAKE_GENERATOR: Ninja + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + - name: "Windows (no mmap)" + id: windows-nommap + os: windows-2019 + env: + ARCH: amd64 + CMAKE_GENERATOR: Visual Studio 16 2019 + CFLAGS: -DNO_MMAP + CMAKE_OPTIONS: -A x64 -DDEPRECATE_HARD=ON + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + + # Nightly builds: extended SSL support + - name: "Linux (dynamically-loaded OpenSSL)" + id: xenial-dynamicopenssl + os: ubuntu-latest + container: + name: xenial + env: + CC: clang + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + CMAKE_GENERATOR: Ninja + + # All builds: experimental SHA256 support + - name: "Linux (SHA256, Xenial, Clang, OpenSSL)" + id: linux-sha256 + container: + name: xenial + env: + CC: clang + CMAKE_GENERATOR: Ninja + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON os: ubuntu-latest + - name: "macOS (SHA256)" + id: macos-sha256 + os: macos-12 + setup-script: osx + env: + CC: clang + CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DEXPERIMENTAL_SHA256=ON + PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + - name: "Windows (SHA256, amd64, Visual Studio)" + id: windows-sha256 + os: windows-2019 + env: + ARCH: amd64 + CMAKE_GENERATOR: Visual Studio 16 2019 + CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DEXPERIMENTAL_SHA256=ON + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true fail-fast: false - name: "Build ${{ matrix.platform.name }}" env: ${{ matrix.platform.env }} runs-on: ${{ matrix.platform.os }} + name: "Build ${{ matrix.platform.name }}" steps: - name: Check out repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: path: source fetch-depth: 0 - name: Set up build environment - run: source/ci/setup-${{ matrix.platform.setup-script }}.sh + run: source/ci/setup-${{ matrix.platform.setup-script }}-build.sh shell: bash if: matrix.platform.setup-script != '' - name: Setup QEMU run: docker run --rm --privileged multiarch/qemu-user-static:register --reset if: matrix.platform.container.qemu == true - - name: Download container - run: | - "${{ github.workspace }}/source/ci/getcontainer.sh" "${{ matrix.platform.container.name }}" "${{ matrix.platform.container.dockerfile }}" - env: - DOCKER_REGISTRY: ${{ env.docker-registry }} - GITHUB_TOKEN: ${{ secrets.github_token }} - working-directory: ${{ env.docker-config-path }} + - name: Set up container + uses: ./source/.github/actions/download-or-build-container + with: + registry: ${{ env.docker-registry }} + config-path: ${{ env.docker-config-path }} + container: ${{ matrix.platform.container.name }} + github_token: ${{ secrets.github_token }} + dockerfile: ${{ matrix.platform.container.dockerfile }} if: matrix.platform.container.name != '' - - name: Create container - run: docker build -t ${{ env.docker-registry-container-sha }} -f ${{ env.dockerfile }} . - working-directory: ${{ env.docker-config-path }} - if: matrix.platform.container.name != '' && env.docker-container-exists != 'true' - - name: Build and test - run: | - export GITTEST_NEGOTIATE_PASSWORD="${{ secrets.GITTEST_NEGOTIATE_PASSWORD }}" + - name: Prepare build + run: mkdir build + - name: Build + uses: ./source/.github/actions/run-build + with: + command: cd ${BUILD_WORKSPACE:-.}/build && ../source/ci/build.sh + container: ${{ matrix.platform.container.name }} + container-version: ${{ env.docker-registry-container-sha }} + shell: ${{ matrix.platform.shell }} + - name: Test + uses: ./source/.github/actions/run-build + with: + command: cd ${BUILD_WORKSPACE:-.}/build && ../source/ci/test.sh + container: ${{ matrix.platform.container.name }} + container-version: ${{ env.docker-registry-container-sha }} + shell: ${{ matrix.platform.shell }} + - name: Upload test results + uses: actions/upload-artifact@v4 + if: success() || failure() + with: + name: test-results-${{ matrix.platform.id }} + path: build/results_*.xml - if [ -n "${{ matrix.platform.container.name }}" ]; then - docker run \ - --rm \ - --user libgit2:libgit2 \ - -v "$(pwd)/source:/home/libgit2/source" \ - -w /home/libgit2 \ - -e ASAN_SYMBOLIZER_PATH \ - -e CC \ - -e CFLAGS \ - -e CMAKE_GENERATOR \ - -e CMAKE_OPTIONS \ - -e GITTEST_NEGOTIATE_PASSWORD \ - -e PKG_CONFIG_PATH \ - -e SKIP_NEGOTIATE_TESTS \ - -e SKIP_SSH_TESTS \ - -e TSAN_OPTIONS \ - ${{ env.docker-registry-container-sha }} \ - /bin/bash -c "mkdir build && cd build && ../source/ci/build.sh && ../source/ci/test.sh" - else - mkdir build && cd build - ../source/ci/build.sh - ../source/ci/test.sh - fi - shell: bash + test_results: + name: Test results + needs: [ build ] + if: ${{ always() && github.repository == 'libgit2/libgit2' }} + runs-on: ubuntu-latest + steps: + - name: Download test results + uses: actions/download-artifact@v3 + - name: Generate test summary + uses: test-summary/action@v2 + with: + paths: 'test-results-*/*.xml' coverity: + # Only run scheduled workflows on the main repository; prevents people + # from using build minutes on their forks. + if: github.repository == 'libgit2/libgit2' + name: Coverity runs-on: ubuntu-latest steps: - name: Check out repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: path: source fetch-depth: 0 - - name: Download container - run: | - "${{ github.workspace }}/source/ci/getcontainer.sh" xenial - env: - DOCKER_REGISTRY: ${{ env.docker-registry }} - GITHUB_TOKEN: ${{ secrets.github_token }} - working-directory: ${{ env.docker-config-path }} + - name: Set up container + uses: ./source/.github/actions/download-or-build-container + with: + registry: ${{ env.docker-registry }} + config-path: ${{ env.docker-config-path }} + container: xenial + github_token: ${{ secrets.github_token }} + if: matrix.platform.container.name != '' - name: Run Coverity run: source/ci/coverity.sh env: COVERITY_TOKEN: ${{ secrets.coverity_token }} + + codeql: + # Only run scheduled workflows on the main repository; prevents people + # from using build minutes on their forks. + if: github.repository == 'libgit2/libgit2' + + permissions: + actions: read + contents: read + security-events: write + + name: CodeQL + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: 'cpp' + + - name: Build + run: | + mkdir build + cd build + cmake .. -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON + cmake --build . + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/vendor/libgit2/CMakeLists.txt b/vendor/libgit2/CMakeLists.txt index 9ff6748e..22eaea06 100644 --- a/vendor/libgit2/CMakeLists.txt +++ b/vendor/libgit2/CMakeLists.txt @@ -1,9 +1,12 @@ -# CMake build script for the libgit2 project +# libgit2: the cross-platform, linkable library implementation of git. # See `README.md` for build instructions. +# +# This top-level CMakeLists.txt sets up configuration options and +# determines which subprojects to build. cmake_minimum_required(VERSION 3.5.1) -project(libgit2 VERSION "1.4.3" LANGUAGES C) +project(libgit2 VERSION "1.8.5" LANGUAGES C) # Add find modules to the path set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake") @@ -12,9 +15,13 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake") # Build options # +# Experimental features +option(EXPERIMENTAL_SHA256 "Enable experimental SHA256 support (for R&D/testing)" OFF) + # Optional subsystems option(BUILD_SHARED_LIBS "Build Shared Library (OFF for Static)" ON) option(BUILD_TESTS "Build Tests using the Clar suite" ON) +option(BUILD_CLI "Build the command-line interface" ON) option(BUILD_EXAMPLES "Build library usage example apps" OFF) option(BUILD_FUZZERS "Build the fuzz targets" OFF) @@ -23,11 +30,13 @@ option(USE_THREADS "Use threads for parallel processing when possibl option(USE_NSEC "Support nanosecond precision file mtimes and ctimes" ON) # Backend selection -option(USE_SSH "Link with libssh2 to enable SSH support" OFF) +option(USE_SSH "Enable SSH support. Can be set to a specific backend" OFF) option(USE_HTTPS "Enable HTTPS support. Can be set to a specific backend" ON) -option(USE_SHA1 "Enable SHA1. Can be set to CollisionDetection(ON)/HTTPS/Generic" ON) +option(USE_SHA1 "Enable SHA1. Can be set to CollisionDetection(ON)/HTTPS" ON) +option(USE_SHA256 "Enable SHA256. Can be set to HTTPS/Builtin" ON) option(USE_GSSAPI "Link with libgssapi for SPNEGO auth" OFF) set(USE_HTTP_PARSER "" CACHE STRING "Specifies the HTTP Parser implementation; either system or builtin.") +# set(USE_XDIFF "" CACHE STRING "Specifies the xdiff implementation; either system or builtin.") set(REGEX_BACKEND "" CACHE STRING "Regular expression implementation. One of regcomp_l, pcre2, pcre, regcomp, or builtin.") option(USE_BUNDLED_ZLIB "Use the bundled version of zlib. Can be set to one of Bundled(ON)/Chromium. The Chromium option requires a x86_64 processor with SSE4.2 and CLMUL" OFF) @@ -74,12 +83,6 @@ if(MSVC) option(WIN32_LEAKCHECK "Enable leak reporting via crtdbg" OFF) endif() -if(WIN32) - # By default, libgit2 is built with WinHTTP. To use the built-in - # HTTP transport, invoke CMake with the "-DUSE_WINHTTP=OFF" argument. - option(USE_WINHTTP "Use Win32 WinHTTP routines" ON) -endif() - if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) endif() @@ -91,7 +94,7 @@ include(CheckLibraryExists) include(CheckFunctionExists) include(CheckSymbolExists) include(CheckStructHasMember) -include(CheckPrototypeDefinition) +include(CheckPrototypeDefinitionSafe) include(AddCFlagIfSupported) include(FindPkgLibraries) include(FindThreads) @@ -102,6 +105,7 @@ include(IdeSplitSources) include(FeatureSummary) include(EnableWarnings) include(DefaultCFlags) +include(ExperimentalFeatures) # @@ -127,6 +131,14 @@ if(BUILD_FUZZERS) endif() +# Export for people who use us as a dependency + +if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}") + set(LIBGIT2_DEPENDENCY_OBJECTS ${LIBGIT2_DEPENDENCY_OBJECTS} PARENT_SCOPE) + set(LIBGIT2_SYSTEM_LIBS ${LIBGIT2_SYSTEM_LIBS} PARENT_SCOPE) +endif() + + # Summary feature_summary(WHAT ENABLED_FEATURES DESCRIPTION "Enabled features:") diff --git a/vendor/libgit2/COPYING b/vendor/libgit2/COPYING index ccfb7dbf..701792e9 100644 --- a/vendor/libgit2/COPYING +++ b/vendor/libgit2/COPYING @@ -365,7 +365,7 @@ Public License instead of this License. The bundled ZLib code is licensed under the ZLib license: -Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler + (C) 1995-2022 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -1144,3 +1144,267 @@ worldwide. This software is distributed without any warranty. See . +---------------------------------------------------------------------- + +The built-in SHA256 support (src/hash/rfc6234) is taken from RFC 6234 +under the following license: + +Copyright (c) 2011 IETF Trust and the persons identified as +authors of the code. All rights reserved. + +Redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following +conditions are met: + +- Redistributions of source code must retain the above + copyright notice, this list of conditions and + the following disclaimer. + +- Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +- Neither the name of Internet Society, IETF or IETF Trust, nor + the names of specific contributors, may be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- + +The built-in git_fs_path_basename_r() function is based on the +Android implementation, BSD licensed: + +Copyright (C) 2008 The Android Open Source Project +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +---------------------------------------------------------------------- + +The bundled ntlmclient code is licensed under the MIT license: + +Copyright (c) Edward Thomson. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +---------------------------------------------------------------------- + +Portions of this software derived from Team Explorer Everywhere: + +Copyright (c) Microsoft Corporation + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +--------------------------------------------------------------------------- + +Portions of this software derived from the LLVM Compiler Infrastructure: + +Copyright (c) 2003-2016 University of Illinois at Urbana-Champaign. +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +--------------------------------------------------------------------------- + +Portions of this software derived from Unicode, Inc: + +Copyright 2001-2004 Unicode, Inc. + +Disclaimer + +This source code is provided as is by Unicode, Inc. No claims are +made as to fitness for any particular purpose. No warranties of any +kind are expressed or implied. The recipient agrees to determine +applicability of information provided. If this file has been +purchased on magnetic or optical media from Unicode, Inc., the +sole remedy for any claim will be exchange of defective media +within 90 days of receipt. + +Limitations on Rights to Redistribute This Code + +Unicode, Inc. hereby grants the right to freely use the information +supplied in this file in the creation of products supporting the +Unicode Standard, and to make copies of this file in any form +for internal or external distribution as long as this notice +remains attached. + +--------------------------------------------------------------------------- + +Portions of this software derived from sheredom/utf8.h: + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to + +--------------------------------------------------------------------------- + +Portions of this software derived from RFC 1320: + +Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD4 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD4 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + +---------------------------------------------------------------------- + +The bundled llhttp dependency is licensed under the MIT license: + +Copyright Fedor Indutny, 2018. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/libgit2/README.md b/vendor/libgit2/README.md index c73b5070..77efdd4a 100644 --- a/vendor/libgit2/README.md +++ b/vendor/libgit2/README.md @@ -4,8 +4,8 @@ libgit2 - the Git linkable library | Build Status | | | ------------ | - | | **main** branch CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush) | -| **v1.4 branch** CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?branch=maint%2Fv1.4&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush+branch%3Amaint%2Fv1.4) | -| **v1.3 branch** CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?branch=maint%2Fv1.3&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush+branch%3Amaint%2Fv1.3) | +| **v1.8 branch** CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?branch=maint%2Fv1.8&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush+branch%3Amaint%2Fv1.8) | +| **v1.7 branch** CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?branch=maint%2Fv1.7&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush+branch%3Amaint%2Fv1.7) | | **Nightly** builds | [![Nightly Build](https://github.com/libgit2/libgit2/workflows/Nightly%20Build/badge.svg)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22Nightly+Build%22) [![Coverity Scan Status](https://scan.coverity.com/projects/639/badge.svg)](https://scan.coverity.com/projects/639) | `libgit2` is a portable, pure C implementation of the Git core methods @@ -18,15 +18,16 @@ functionality into your application. Language bindings like in your favorite language. `libgit2` is used to power Git GUI clients like -[GitKraken](https://gitkraken.com/) and [gmaster](https://gmaster.io/) +[GitKraken](https://gitkraken.com/) and [GitButler](https://gitbutler.com/) and on Git hosting providers like [GitHub](https://github.com/), [GitLab](https://gitlab.com/) and [Azure DevOps](https://azure.com/devops). We perform the merge every time you click "merge pull request". `libgit2` is licensed under a **very permissive license** (GPLv2 with a special -Linking Exception). This basically means that you can link it (unmodified) -with any kind of software without having to release its source code. +Linking Exception). This means that you can link against the library with any +kind of software without making that software fall under the GPL. +Changes to libgit2 would still be covered under its GPL license. Additionally, the example code has been released to the public domain (see the [separate license](examples/COPYING) for more information). @@ -67,7 +68,7 @@ But if you _do_ want to use libgit2 directly - because you're building an application in C - then you may be able use an existing binary. There are packages for the [vcpkg](https://github.com/Microsoft/vcpkg) and -[conan](https://conan.io/center/libgit2) +[conan](https://conan.io/center/recipes/libgit2) package managers. And libgit2 is available in [Homebrew](https://formulae.brew.sh/formula/libgit2) and most Linux distributions. @@ -112,7 +113,7 @@ Getting Help **Getting Help** If you have questions about the library, please be sure to check out the -[API documentation](http://libgit2.github.com/libgit2/). If you still have +[API documentation](https://libgit2.org/libgit2/). If you still have questions, reach out to us on Slack or post a question on [StackOverflow](http://stackoverflow.com/questions/tagged/libgit2) (with the `libgit2` tag). @@ -392,8 +393,10 @@ Here are the bindings to libgit2 that are currently available: * parrot-libgit2 * Perl * Git-Raw +* Pharo Smalltalk + * libgit2-pharo-bindings * PHP - * php-git + * php-git2 * Python * pygit2 * R @@ -405,6 +408,8 @@ Here are the bindings to libgit2 that are currently available: * git2-rs * Swift * SwiftGit2 +* Tcl + * lg2 * Vala * libgit2.vapi diff --git a/vendor/libgit2/ci/build.sh b/vendor/libgit2/ci/build.sh index 5a51f925..a9b66f66 100755 --- a/vendor/libgit2/ci/build.sh +++ b/vendor/libgit2/ci/build.sh @@ -13,16 +13,30 @@ BUILD_PATH=${BUILD_PATH:=$PATH} CMAKE=$(which cmake) CMAKE_GENERATOR=${CMAKE_GENERATOR:-Unix Makefiles} +indent() { sed "s/^/ /"; } + +cygfullpath() { + result=$(echo "${1}" | tr \; \\n | while read -r element; do + if [ "${last}" != "" ]; then echo -n ":"; fi + echo -n $(cygpath "${element}") + last="${element}" + done) + if [ "${result}" = "" ]; then exit 1; fi + echo "${result}" +} + if [[ "$(uname -s)" == MINGW* ]]; then - BUILD_PATH=$(cygpath "$BUILD_PATH") + BUILD_PATH=$(cygfullpath "${BUILD_PATH}") fi -indent() { sed "s/^/ /"; } echo "Source directory: ${SOURCE_DIR}" echo "Build directory: ${BUILD_DIR}" echo "" +echo "Platform:" +uname -s | indent + if [ "$(uname -s)" = "Darwin" ]; then echo "macOS version:" sw_vers | indent @@ -40,13 +54,15 @@ echo "Kernel version:" uname -a 2>&1 | indent echo "CMake version:" -env PATH="${BUILD_PATH}" "${CMAKE}" --version 2>&1 | indent +env PATH="${BUILD_PATH}" "${CMAKE}" --version | head -1 2>&1 | indent if test -n "${CC}"; then echo "Compiler version:" "${CC}" --version 2>&1 | indent fi echo "Environment:" +echo "PATH=${BUILD_PATH}" | indent + if test -n "${CC}"; then echo "CC=${CC}" | indent fi @@ -59,7 +75,7 @@ echo "########################################################################## echo "## Configuring build environment" echo "##############################################################################" -echo cmake -DENABLE_WERROR=ON -DBUILD_EXAMPLES=ON -DBUILD_FUZZERS=ON -DUSE_STANDALONE_FUZZERS=ON -G \"${CMAKE_GENERATOR}\" ${CMAKE_OPTIONS} -S \"${SOURCE_DIR}\" +echo "${CMAKE}" -DENABLE_WERROR=ON -DBUILD_EXAMPLES=ON -DBUILD_FUZZERS=ON -DUSE_STANDALONE_FUZZERS=ON -G \"${CMAKE_GENERATOR}\" ${CMAKE_OPTIONS} -S \"${SOURCE_DIR}\" env PATH="${BUILD_PATH}" "${CMAKE}" -DENABLE_WERROR=ON -DBUILD_EXAMPLES=ON -DBUILD_FUZZERS=ON -DUSE_STANDALONE_FUZZERS=ON -G "${CMAKE_GENERATOR}" ${CMAKE_OPTIONS} -S "${SOURCE_DIR}" echo "" @@ -69,10 +85,11 @@ echo "########################################################################## # Determine parallelism; newer cmake supports `--build --parallel` but # we cannot yet rely on that. -if [ "${CMAKE_GENERATOR}" = "Unix Makefiles" -a "${CORES}" != "" ]; then +if [ "${CMAKE_GENERATOR}" = "Unix Makefiles" -a "${CORES}" != "" -a "${CMAKE_BUILD_OPTIONS}" = "" ]; then BUILDER=(make -j ${CORES}) else - BUILDER=("${CMAKE}" --build .) + BUILDER=("${CMAKE}" --build . ${CMAKE_BUILD_OPTIONS}) fi +echo "${BUILDER[@]}" env PATH="${BUILD_PATH}" "${BUILDER[@]}" diff --git a/vendor/libgit2/ci/docker/bionic b/vendor/libgit2/ci/docker/bionic index 51af5c01..f42c6d2a 100644 --- a/vendor/libgit2/ci/docker/bionic +++ b/vendor/libgit2/ci/docker/bionic @@ -12,7 +12,6 @@ RUN apt-get update && \ libcurl4-openssl-dev \ libkrb5-dev \ libpcre3-dev \ - libssh2-1-dev \ libssl-dev \ libz-dev \ ninja-build \ @@ -28,17 +27,31 @@ RUN apt-get update && \ FROM apt AS mbedtls RUN cd /tmp && \ - curl --location --silent --show-error https://tls.mbed.org/download/mbedtls-2.16.2-apache.tgz | \ - tar -xz && \ - cd mbedtls-2.16.2 && \ + curl --location --silent --show-error https://github.com/Mbed-TLS/mbedtls/archive/refs/tags/mbedtls-2.16.2.tar.gz | \ + tar -xz && \ + cd mbedtls-mbedtls-2.16.2 && \ scripts/config.pl set MBEDTLS_MD4_C 1 && \ CFLAGS=-fPIC cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=OFF -DUSE_STATIC_MBEDTLS_LIBRARY=ON . && \ ninja install && \ cd .. && \ - rm -rf mbedtls-2.16.2 + rm -rf mbedtls-mbedtls-2.16.2 -FROM mbedtls AS adduser -RUN useradd --shell /bin/bash libgit2 --create-home +FROM mbedtls AS libssh2 +RUN cd /tmp && \ + curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.11.0.tar.gz | tar -xz && \ + cd libssh2-1.11.0 && \ + CFLAGS=-fPIC cmake -G Ninja -DBUILD_SHARED_LIBS=ON . && \ + ninja install && \ + cd .. && \ + rm -rf libssh2-1.11.0 + +FROM libssh2 AS adduser +ARG UID="" +ARG GID="" +RUN if [ "${UID}" != "" ]; then USER_ARG="--uid ${UID}"; fi && \ + if [ "${GID}" != "" ]; then GROUP_ARG="--gid ${GID}"; fi && \ + groupadd ${GROUP_ARG} libgit2 && \ + useradd ${USER_ARG} --gid libgit2 --shell /bin/bash --create-home libgit2 FROM adduser AS configure RUN mkdir /var/run/sshd diff --git a/vendor/libgit2/ci/docker/centos7 b/vendor/libgit2/ci/docker/centos7 index 8105f144..45c299d1 100644 --- a/vendor/libgit2/ci/docker/centos7 +++ b/vendor/libgit2/ci/docker/centos7 @@ -18,13 +18,13 @@ RUN yum install -y \ FROM yum AS libssh2 RUN cd /tmp && \ - curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.8.0.tar.gz | tar -xz && \ - cd libssh2-1.8.0 && \ + curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.11.0.tar.gz | tar -xz && \ + cd libssh2-1.11.0 && \ ./configure && \ make && \ make install && \ cd .. && \ - rm -rf libssh-1.8.0 + rm -rf libssh-1.11.0 FROM libssh2 AS valgrind RUN cd /tmp && \ @@ -48,7 +48,12 @@ RUN cd /tmp && \ rm -rf cmake-3.21.1 FROM cmake AS adduser -RUN useradd --shell /bin/bash libgit2 --create-home +ARG UID="" +ARG GID="" +RUN if [ "${UID}" != "" ]; then USER_ARG="--uid ${UID}"; fi && \ + if [ "${GID}" != "" ]; then GROUP_ARG="--gid ${GID}"; fi && \ + groupadd ${GROUP_ARG} libgit2 && \ + useradd ${USER_ARG} --gid libgit2 --shell /bin/bash --create-home libgit2 FROM adduser AS configure ENV PKG_CONFIG_PATH /usr/local/lib/pkgconfig diff --git a/vendor/libgit2/ci/docker/centos8 b/vendor/libgit2/ci/docker/centos8 index cca08810..c2ac5f07 100644 --- a/vendor/libgit2/ci/docker/centos8 +++ b/vendor/libgit2/ci/docker/centos8 @@ -1,6 +1,10 @@ ARG BASE=centos:8 -FROM ${BASE} AS yum +FROM ${BASE} AS stream +RUN dnf -y --disablerepo '*' --enablerepo=extras swap centos-linux-repos centos-stream-repos && \ + dnf -y distro-sync + +FROM stream AS yum RUN yum install -y \ which \ bzip2 \ @@ -20,13 +24,13 @@ RUN yum install -y \ FROM yum AS libssh2 RUN cd /tmp && \ - curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.8.0.tar.gz | tar -xz && \ - cd libssh2-1.8.0 && \ + curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.11.0.tar.gz | tar -xz && \ + cd libssh2-1.11.0 && \ ./configure && \ make && \ make install && \ cd .. && \ - rm -rf libssh2-1.8.0 + rm -rf libssh2-1.11.0 FROM libssh2 AS valgrind RUN cd /tmp && \ @@ -40,7 +44,12 @@ RUN cd /tmp && \ rm -rf valgrind-3.15.0 FROM valgrind AS adduser -RUN useradd --shell /bin/bash libgit2 --create-home +ARG UID="" +ARG GID="" +RUN if [ "${UID}" != "" ]; then USER_ARG="--uid ${UID}"; fi && \ + if [ "${GID}" != "" ]; then GROUP_ARG="--gid ${GID}"; fi && \ + groupadd ${GROUP_ARG} libgit2 && \ + useradd ${USER_ARG} --gid libgit2 --shell /bin/bash --create-home libgit2 FROM adduser AS configure ENV PKG_CONFIG_PATH /usr/local/lib/pkgconfig diff --git a/vendor/libgit2/ci/docker/fedora b/vendor/libgit2/ci/docker/fedora new file mode 100644 index 00000000..1db3ceb7 --- /dev/null +++ b/vendor/libgit2/ci/docker/fedora @@ -0,0 +1,52 @@ +ARG BASE=fedora:rawhide + +FROM ${BASE} AS stream +RUN dnf -y distro-sync + +FROM stream AS yum +RUN yum install -y \ + which \ + bzip2 \ + git \ + libarchive \ + cmake \ + gcc \ + make \ + openssl-devel \ + openssh-server \ + git-daemon \ + java-1.8.0-openjdk-headless \ + sudo \ + python3 \ + valgrind \ + krb5-workstation \ + krb5-libs \ + krb5-devel \ + pcre2-devel \ + zlib-devel \ + ninja-build \ + llhttp-devel + +FROM yum AS libssh2 +RUN cd /tmp && \ + curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.11.0.tar.gz | tar -xz && \ + cd libssh2-1.11.0 && \ + ./configure && \ + make && \ + make install && \ + cd .. && \ + rm -rf libssh2-1.11.0 + +FROM libssh2 AS adduser +ARG UID="" +ARG GID="" +RUN if [ "${UID}" != "" ]; then USER_ARG="--uid ${UID}"; fi && \ + if [ "${GID}" != "" ]; then GROUP_ARG="--gid ${GID}"; fi && \ + groupadd ${GROUP_ARG} libgit2 && \ + useradd ${USER_ARG} --gid libgit2 --shell /bin/bash --create-home libgit2 + +FROM adduser AS configure +ENV PKG_CONFIG_PATH /usr/local/lib/pkgconfig +RUN mkdir /var/run/sshd +RUN echo "/usr/local/lib" > /etc/ld.so.conf.d/local && \ + ldconfig diff --git a/vendor/libgit2/ci/docker/focal b/vendor/libgit2/ci/docker/focal index 37d7d635..62f5b630 100644 --- a/vendor/libgit2/ci/docker/focal +++ b/vendor/libgit2/ci/docker/focal @@ -32,9 +32,9 @@ RUN apt-get update && \ FROM apt AS mbedtls RUN cd /tmp && \ - curl --location --silent --show-error https://tls.mbed.org/download/mbedtls-2.16.2-apache.tgz | \ + curl --location --silent --show-error https://github.com/Mbed-TLS/mbedtls/archive/refs/tags/mbedtls-2.16.2.tar.gz | \ tar -xz && \ - cd mbedtls-2.16.2 && \ + cd mbedtls-mbedtls-2.16.2 && \ scripts/config.pl unset MBEDTLS_AESNI_C && \ scripts/config.pl set MBEDTLS_MD4_C 1 && \ mkdir build build-msan && \ @@ -45,7 +45,7 @@ RUN cd /tmp && \ CC=clang-10 CFLAGS="-fPIC" cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=ON -DUSE_STATIC_MBEDTLS_LIBRARY=OFF -DCMAKE_BUILD_TYPE=MemSanDbg -DCMAKE_INSTALL_PREFIX=/usr/local/msan .. && \ ninja install && \ cd .. && \ - rm -rf mbedtls-2.16.2 + rm -rf mbedtls-mbedtls-2.16.2 FROM mbedtls AS libssh2 RUN cd /tmp && \ @@ -53,7 +53,7 @@ RUN cd /tmp && \ cd libssh2-1.9.0 && \ mkdir build build-msan && \ cd build && \ - CC=clang-10 CFLAGS="-fPIC" cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCRYPTO_BACKEND=Libgcrypt -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_PREFIX=/usr/local .. && \ + CC=clang-10 CFLAGS="-fPIC" cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_PREFIX=/usr/local .. && \ ninja install && \ cd ../build-msan && \ CC=clang-10 CFLAGS="-fPIC -fsanitize=memory -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer" LDFLAGS="-fsanitize=memory" cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCRYPTO_BACKEND=mbedTLS -DCMAKE_PREFIX_PATH=/usr/local/msan -DCMAKE_INSTALL_PREFIX=/usr/local/msan .. && \ @@ -73,7 +73,13 @@ RUN cd /tmp && \ rm -rf valgrind-3.15.0 FROM valgrind AS adduser -RUN useradd --shell /bin/bash libgit2 --create-home +ARG UID="" +ARG GID="" +RUN if [ "${UID}" != "" ]; then USER_ARG="--uid ${UID}"; fi && \ + if [ "${GID}" != "" ]; then GROUP_ARG="--gid ${GID}"; fi && \ + groupadd ${GROUP_ARG} libgit2 && \ + useradd ${USER_ARG} --gid libgit2 --shell /bin/bash --create-home libgit2 + FROM adduser AS configure RUN mkdir /var/run/sshd diff --git a/vendor/libgit2/ci/docker/noble b/vendor/libgit2/ci/docker/noble new file mode 100644 index 00000000..05cd2768 --- /dev/null +++ b/vendor/libgit2/ci/docker/noble @@ -0,0 +1,88 @@ +ARG BASE=ubuntu:noble + +FROM ${BASE} AS apt +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + bzip2 \ + clang \ + cmake \ + curl \ + gcc \ + git \ + krb5-user \ + libclang-rt-17-dev \ + libcurl4-gnutls-dev \ + libgcrypt20-dev \ + libkrb5-dev \ + libpcre3-dev \ + libssl-dev \ + libz-dev \ + llvm-17 \ + make \ + ninja-build \ + openjdk-8-jre-headless \ + openssh-server \ + openssl \ + pkgconf \ + python3 \ + sudo \ + valgrind \ + && \ + rm -rf /var/lib/apt/lists/* && \ + mkdir /usr/local/msan + +FROM apt AS mbedtls +RUN cd /tmp && \ + curl --location --silent --show-error https://github.com/Mbed-TLS/mbedtls/archive/refs/tags/mbedtls-2.28.6.tar.gz | \ + tar -xz && \ + cd mbedtls-mbedtls-2.28.6 && \ + scripts/config.pl unset MBEDTLS_AESNI_C && \ + scripts/config.pl set MBEDTLS_MD4_C 1 && \ + mkdir build build-msan && \ + cd build && \ + CC=clang-17 CFLAGS="-fPIC" cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=ON -DUSE_STATIC_MBEDTLS_LIBRARY=OFF -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_PREFIX=/usr/local .. && \ + ninja install && \ + cd ../build-msan && \ + CC=clang-17 CFLAGS="-fPIC" cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=ON -DUSE_STATIC_MBEDTLS_LIBRARY=OFF -DCMAKE_BUILD_TYPE=MemSanDbg -DCMAKE_INSTALL_PREFIX=/usr/local/msan .. && \ + ninja install && \ + cd .. && \ + rm -rf mbedtls-mbedtls-2.28.6 + +FROM mbedtls AS libssh2 +RUN cd /tmp && \ + curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.11.0.tar.gz | tar -xz && \ + cd libssh2-1.11.0 && \ + mkdir build build-msan && \ + cd build && \ + CC=clang-17 CFLAGS="-fPIC" cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_PREFIX=/usr/local .. && \ + ninja install && \ + cd ../build-msan && \ + CC=clang-17 CFLAGS="-fPIC -fsanitize=memory -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer" LDFLAGS="-fsanitize=memory" cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCRYPTO_BACKEND=mbedTLS -DCMAKE_PREFIX_PATH=/usr/local/msan -DCMAKE_INSTALL_PREFIX=/usr/local/msan .. && \ + ninja install && \ + cd .. && \ + rm -rf libssh2-1.11.0 + +FROM libssh2 AS valgrind +RUN cd /tmp && \ + curl --insecure --location --silent --show-error https://sourceware.org/pub/valgrind/valgrind-3.22.0.tar.bz2 | \ + tar -xj && \ + cd valgrind-3.22.0 && \ + CC=clang-17 ./configure && \ + make MAKEFLAGS="-j -l$(grep -c ^processor /proc/cpuinfo)" && \ + make install && \ + cd .. && \ + rm -rf valgrind-3.22.0 + +FROM valgrind AS adduser +ARG UID="" +ARG GID="" +RUN if [ "${UID}" != "" ]; then USER_ARG="--uid ${UID}"; fi && \ + if [ "${GID}" != "" ]; then GROUP_ARG="--gid ${GID}"; fi && \ + groupadd ${GROUP_ARG} libgit2 && \ + useradd ${USER_ARG} --gid libgit2 --shell /bin/bash --create-home libgit2 + +FROM adduser AS ldconfig +RUN ldconfig + +FROM ldconfig AS configure +RUN mkdir /var/run/sshd diff --git a/vendor/libgit2/ci/docker/xenial b/vendor/libgit2/ci/docker/xenial index c19fe421..793df4bd 100644 --- a/vendor/libgit2/ci/docker/xenial +++ b/vendor/libgit2/ci/docker/xenial @@ -7,11 +7,13 @@ RUN apt-get update && \ clang \ cmake \ curl \ + gettext \ gcc \ - git \ krb5-user \ libcurl4-gnutls-dev \ + libexpat1-dev \ libgcrypt20-dev \ + libintl-perl \ libkrb5-dev \ libpcre3-dev \ libssl-dev \ @@ -28,25 +30,35 @@ RUN apt-get update && \ && \ rm -rf /var/lib/apt/lists/* -FROM apt AS mbedtls +FROM apt AS git RUN cd /tmp && \ - curl --location --silent --show-error https://tls.mbed.org/download/mbedtls-2.16.2-apache.tgz | \ - tar -xz && \ - cd mbedtls-2.16.2 && \ + curl --location --silent --show-error https://github.com/git/git/archive/refs/tags/v2.39.1.tar.gz | \ + tar -xz && \ + cd git-2.39.1 && \ + make && \ + make prefix=/usr install && \ + cd .. && \ + rm -rf git-2.39.1 + +FROM git AS mbedtls +RUN cd /tmp && \ + curl --location --silent --show-error https://github.com/Mbed-TLS/mbedtls/archive/refs/tags/mbedtls-2.16.2.tar.gz | \ + tar -xz && \ + cd mbedtls-mbedtls-2.16.2 && \ scripts/config.pl set MBEDTLS_MD4_C 1 && \ CFLAGS=-fPIC cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=OFF -DUSE_STATIC_MBEDTLS_LIBRARY=ON . && \ ninja install && \ cd .. && \ - rm -rf mbedtls-2.16.2 + rm -rf mbedtls-mbedtls-2.16.2 FROM mbedtls AS libssh2 RUN cd /tmp && \ - curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.8.2.tar.gz | tar -xz && \ - cd libssh2-1.8.2 && \ - CFLAGS=-fPIC cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCRYPTO_BACKEND=Libgcrypt . && \ + curl --location --silent --show-error https://www.libssh2.org/download/libssh2-1.11.0.tar.gz | tar -xz && \ + cd libssh2-1.11.0 && \ + CFLAGS=-fPIC cmake -G Ninja -DBUILD_SHARED_LIBS=ON . && \ ninja install && \ cd .. && \ - rm -rf libssh2-1.8.2 + rm -rf libssh2-1.11.0 FROM libssh2 AS valgrind RUN cd /tmp && \ @@ -60,7 +72,13 @@ RUN cd /tmp && \ rm -rf valgrind-3.15.0 FROM valgrind AS adduser -RUN useradd --shell /bin/bash libgit2 --create-home +ARG UID="" +ARG GID="" +RUN if [ "${UID}" != "" ]; then USER_ARG="--uid ${UID}"; fi && \ + if [ "${GID}" != "" ]; then GROUP_ARG="--gid ${GID}"; fi && \ + groupadd ${GROUP_ARG} libgit2 && \ + useradd ${USER_ARG} --gid libgit2 --shell /bin/bash --create-home libgit2 + FROM adduser AS configure RUN mkdir /var/run/sshd diff --git a/vendor/libgit2/ci/getcontainer.sh b/vendor/libgit2/ci/getcontainer.sh deleted file mode 100755 index 07ef7b8e..00000000 --- a/vendor/libgit2/ci/getcontainer.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/bash - -set -e - -IMAGE_NAME=$1 -DOCKERFILE_PATH=$2 - -if [ "${IMAGE_NAME}" = "" ]; then - echo "usage: $0 image_name [dockerfile]" - exit 1 -fi - -if [ "${DOCKERFILE_PATH}" = "" ]; then - DOCKERFILE_PATH="${IMAGE_NAME}" -fi - -if [ "${DOCKER_REGISTRY}" = "" ]; then - echo "DOCKER_REGISTRY environment variable is unset." - echo "Not running inside GitHub Actions or misconfigured?" - exit 1 -fi - -DOCKER_CONTAINER="${GITHUB_REPOSITORY}/${IMAGE_NAME}" -DOCKER_REGISTRY_CONTAINER="${DOCKER_REGISTRY}/${DOCKER_CONTAINER}" - -echo "dockerfile=${DOCKERFILE_PATH}" >> $GITHUB_ENV -echo "docker-container=${DOCKER_CONTAINER}" >> $GITHUB_ENV -echo "docker-registry-container=${DOCKER_REGISTRY_CONTAINER}" >> $GITHUB_ENV - -# Identify the last git commit that touched the Dockerfiles -# Use this as a hash to identify the resulting docker containers -DOCKER_SHA=$(git log -1 --pretty=format:"%h" -- "${DOCKERFILE_PATH}") -echo "docker-sha=${DOCKER_SHA}" >> $GITHUB_ENV - -DOCKER_REGISTRY_CONTAINER_SHA="${DOCKER_REGISTRY_CONTAINER}:${DOCKER_SHA}" - -echo "docker-registry-container-sha=${DOCKER_REGISTRY_CONTAINER_SHA}" >> $GITHUB_ENV -echo "docker-registry-container-latest=${DOCKER_REGISTRY_CONTAINER}:latest" >> $GITHUB_ENV - -exists="true" -docker login https://${DOCKER_REGISTRY} -u ${GITHUB_ACTOR} -p ${GITHUB_TOKEN} || exists="false" - -if [ "${exists}" != "false" ]; then - docker pull ${DOCKER_REGISTRY_CONTAINER_SHA} || exists="false" -fi - -if [ "${exists}" = "true" ]; then - echo "docker-container-exists=true" >> $GITHUB_ENV -else - echo "docker-container-exists=false" >> $GITHUB_ENV -fi diff --git a/vendor/libgit2/ci/setup-mingw-build.sh b/vendor/libgit2/ci/setup-mingw-build.sh new file mode 100755 index 00000000..6c444f58 --- /dev/null +++ b/vendor/libgit2/ci/setup-mingw-build.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +set -ex + +echo "##############################################################################" +echo "## Downloading mingw" +echo "##############################################################################" + +BUILD_TEMP=${BUILD_TEMP:=$TEMP} +BUILD_TEMP=$(cygpath $BUILD_TEMP) + +case "$ARCH" in + amd64) + MINGW_URI="https://github.com/libgit2/ci-dependencies/releases/download/2023-01-23/mingw-x86_64-8.1.0-release-win32-sjlj-rt_v6-rev0.zip";; + x86) + MINGW_URI="https://github.com/libgit2/ci-dependencies/releases/download/2023-01-23/mingw-i686-8.1.0-release-win32-sjlj-rt_v6-rev0.zip";; +esac + +if [ -z "$MINGW_URI" ]; then + echo "No URL" + exit 1 +fi + +mkdir -p "$BUILD_TEMP" + +curl -s -L "$MINGW_URI" -o "$BUILD_TEMP"/mingw-"$ARCH".zip +unzip -q "$BUILD_TEMP"/mingw-"$ARCH".zip -d "$BUILD_TEMP" diff --git a/vendor/libgit2/ci/setup-mingw.sh b/vendor/libgit2/ci/setup-mingw.sh deleted file mode 100755 index f5a882d2..00000000 --- a/vendor/libgit2/ci/setup-mingw.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -e - -echo "##############################################################################" -echo "## Downloading mingw" -echo "##############################################################################" - -BUILD_TEMP=${BUILD_TEMP:=$TEMP} -BUILD_TEMP=$(cygpath $BUILD_TEMP) - -case "$ARCH" in - amd64) - MINGW_URI="https://github.com/libgit2/ci-dependencies/releases/download/2021-05-04/mingw-x86_64-8.1.0-release-win32-sjlj-rt_v6-rev0.zip";; - x86) - MINGW_URI="https://github.com/libgit2/ci-dependencies/releases/download/2021-05-04/mingw-i686-8.1.0-release-win32-sjlj-rt_v6-rev0.zip";; -esac - -if [ -z "$MINGW_URI" ]; then - echo "No URL" - exit 1 -fi - -mkdir -p "$BUILD_TEMP" - -curl -s -L "$MINGW_URI" -o "$BUILD_TEMP"/mingw-"$ARCH".zip -unzip -q "$BUILD_TEMP"/mingw-"$ARCH".zip -d "$BUILD_TEMP" diff --git a/vendor/libgit2/ci/setup-osx-benchmark.sh b/vendor/libgit2/ci/setup-osx-benchmark.sh new file mode 100755 index 00000000..80d87682 --- /dev/null +++ b/vendor/libgit2/ci/setup-osx-benchmark.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +set -ex + +brew update +brew install hyperfine diff --git a/vendor/libgit2/ci/setup-osx-build.sh b/vendor/libgit2/ci/setup-osx-build.sh new file mode 100755 index 00000000..511d886c --- /dev/null +++ b/vendor/libgit2/ci/setup-osx-build.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +set -ex + +brew update +brew install pkgconfig libssh2 ninja + +ln -s /Applications/Xcode.app/Contents/Developer/usr/lib/libLeaksAtExit.dylib /usr/local/lib diff --git a/vendor/libgit2/ci/setup-osx.sh b/vendor/libgit2/ci/setup-osx.sh deleted file mode 100755 index 2e630eed..00000000 --- a/vendor/libgit2/ci/setup-osx.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -set -x - -brew update -brew install pkgconfig zlib curl openssl libssh2 ninja - -ln -s /Applications/Xcode.app/Contents/Developer/usr/lib/libLeaksAtExit.dylib /usr/local/lib diff --git a/vendor/libgit2/ci/setup-sanitizer-build.sh b/vendor/libgit2/ci/setup-sanitizer-build.sh new file mode 100755 index 00000000..e4591f85 --- /dev/null +++ b/vendor/libgit2/ci/setup-sanitizer-build.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +set -ex + +# Linux updated its ASLR randomization in a way that is incompatible with +# TSAN. See https://github.com/google/sanitizers/issues/1716 +sudo sysctl vm.mmap_rnd_bits=28 diff --git a/vendor/libgit2/ci/setup-ubuntu-benchmark.sh b/vendor/libgit2/ci/setup-ubuntu-benchmark.sh new file mode 100755 index 00000000..561a18fd --- /dev/null +++ b/vendor/libgit2/ci/setup-ubuntu-benchmark.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +set -ex + +sudo apt-get update +sudo apt-get install -y --no-install-recommends \ + cargo \ + cmake \ + gcc \ + git \ + krb5-user \ + libkrb5-dev \ + libssl-dev \ + libz-dev \ + make \ + ninja-build \ + pkgconf + +wget https://github.com/sharkdp/hyperfine/releases/download/v1.12.0/hyperfine_1.12.0_amd64.deb +sudo dpkg -i hyperfine_1.12.0_amd64.deb diff --git a/vendor/libgit2/ci/setup-win32-benchmark.sh b/vendor/libgit2/ci/setup-win32-benchmark.sh new file mode 100755 index 00000000..0eac2f66 --- /dev/null +++ b/vendor/libgit2/ci/setup-win32-benchmark.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +set -ex + +choco install hyperfine zip + +CHOCO_PATH=$(mktemp -d) +curl -L https://github.com/ethomson/PurgeStandbyList/releases/download/v1.0/purgestandbylist.1.0.0.nupkg -o "${CHOCO_PATH}/purgestandbylist.1.0.0.nupkg" +choco install purgestandbylist -s $(cygpath -w "${CHOCO_PATH}") diff --git a/vendor/libgit2/ci/setup-win32-build.sh b/vendor/libgit2/ci/setup-win32-build.sh new file mode 100755 index 00000000..a8b81e5e --- /dev/null +++ b/vendor/libgit2/ci/setup-win32-build.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +set -ex + +echo "##############################################################################" +echo "## Downloading libssh2" +echo "##############################################################################" + +BUILD_TEMP=${BUILD_TEMP:=$TEMP} +BUILD_TEMP=$(cygpath $BUILD_TEMP) + +case "$ARCH" in + amd64) + LIBSSH2_URI="https://github.com/libgit2/ci-dependencies/releases/download/2023-02-01/libssh2-20230201-amd64.zip";; + x86) + LIBSSH2_URI="https://github.com/libgit2/ci-dependencies/releases/download/2023-02-01-v2/libssh2-20230201-x86.zip";; +esac + +if [ -z "$LIBSSH2_URI" ]; then + echo "No URL" + exit 1 +fi + +mkdir -p "$BUILD_TEMP" + +curl -s -L "$LIBSSH2_URI" -o "$BUILD_TEMP"/libssh2-"$ARCH".zip +unzip -q "$BUILD_TEMP"/libssh2-"$ARCH".zip -d "$BUILD_TEMP" diff --git a/vendor/libgit2/ci/test.sh b/vendor/libgit2/ci/test.sh index a9483977..98093c6e 100755 --- a/vendor/libgit2/ci/test.sh +++ b/vendor/libgit2/ci/test.sh @@ -3,7 +3,14 @@ set -e if [ -n "$SKIP_TESTS" ]; then - exit 0 + if [ -z "$SKIP_OFFLINE_TESTS" ]; then SKIP_OFFLINE_TESTS=1; fi + if [ -z "$SKIP_ONLINE_TESTS" ]; then SKIP_ONLINE_TESTS=1; fi + if [ -z "$SKIP_GITDAEMON_TESTS" ]; then SKIP_GITDAEMON_TESTS=1; fi + if [ -z "$SKIP_PROXY_TESTS" ]; then SKIP_PROXY_TESTS=1; fi + if [ -z "$SKIP_NTLM_TESTS" ]; then SKIP_NTLM_TESTS=1; fi + if [ -z "$SKIP_NEGOTIATE_TESTS" ]; then SKIP_NEGOTIATE_TESTS=1; fi + if [ -z "$SKIP_SSH_TESTS" ]; then SKIP_SSH_TESTS=1; fi + if [ -z "$SKIP_FUZZERS" ]; then SKIP_FUZZERS=1; fi fi # Windows doesn't run the NTLM tests properly (yet) @@ -11,24 +18,71 @@ if [[ "$(uname -s)" == MINGW* ]]; then SKIP_NTLM_TESTS=1 fi +# older versions of git don't support push options +if [ -z "$SKIP_PUSHOPTIONS_TESTS" ]; then + export GITTEST_PUSH_OPTIONS=true +fi + SOURCE_DIR=${SOURCE_DIR:-$( cd "$( dirname "${BASH_SOURCE[0]}" )" && dirname $( pwd ) )} BUILD_DIR=$(pwd) +BUILD_PATH=${BUILD_PATH:=$PATH} +CTEST=$(which ctest) TMPDIR=${TMPDIR:-/tmp} USER=${USER:-$(whoami)} +GITTEST_SSH_KEYTYPE=${GITTEST_SSH_KEYTYPE:="ecdsa"} + +HOME=`mktemp -d ${TMPDIR}/home.XXXXXXXX` +export CLAR_HOMEDIR=${HOME} + SUCCESS=1 CONTINUE_ON_FAILURE=0 +should_run() { + eval "skip=\${SKIP_${1}}" + [ -z "$skip" \ + -o "$skip" == "no" -o "$skip" == "NO" \ + -o "$skip" == "n" -o "$skip" == "N" \ + -o "$skip" == "false" -o "$skip" == "FALSE" \ + -o "$skip" == "f" -o "$skip" == "F" \ + -o "$skip" == "0" ] +} + cleanup() { echo "Cleaning up..." - if [ ! -z "$GITDAEMON_PID" ]; then - echo "Stopping git daemon..." - kill $GITDAEMON_PID + if [ ! -z "$GIT_STANDARD_PID" ]; then + echo "Stopping git daemon (standard)..." + kill $GIT_STANDARD_PID + fi + + if [ ! -z "$GIT_NAMESPACE_PID" ]; then + echo "Stopping git daemon (namespace)..." + kill $GIT_NAMESPACE_PID + fi + + if [ ! -z "$GIT_SHA256_PID" ]; then + echo "Stopping git daemon (sha256)..." + kill $GIT_SHA256_PID + fi + + if [ ! -z "$PROXY_BASIC_PID" ]; then + echo "Stopping proxy (Basic)..." + kill $PROXY_BASIC_PID + fi + + if [ ! -z "$PROXY_NTLM_PID" ]; then + echo "Stopping proxy (NTLM)..." + kill $PROXY_NTLM_PID + fi + + if [ ! -z "$HTTP_PID" ]; then + echo "Stopping HTTP server..." + kill $HTTP_PID fi if [ ! -z "$SSHD_DIR" -a -f "${SSHD_DIR}/pid" ]; then - echo "Stopping SSH..." + echo "Stopping SSH server..." kill $(cat "${SSHD_DIR}/pid") fi @@ -48,11 +102,17 @@ run_test() { echo "" echo "Re-running flaky ${1} tests..." echo "" + + sleep 2 fi RETURN_CODE=0 - CLAR_SUMMARY="${BUILD_DIR}/results_${1}.xml" ctest -V -R "^${1}$" || RETURN_CODE=$? && true + ( + export PATH="${BUILD_PATH}" + export CLAR_SUMMARY="${BUILD_DIR}/results_${1}.xml" + "${CTEST}" -V -R "^${1}$" + ) || RETURN_CODE=$? && true if [ "$RETURN_CODE" -eq 0 ]; then FAILED=0 @@ -73,55 +133,91 @@ run_test() { fi } +indent() { sed "s/^/ /"; } + +cygfullpath() { + result=$(echo "${1}" | tr \; \\n | while read -r element; do + if [ "${last}" != "" ]; then echo -n ":"; fi + echo -n $(cygpath "${element}") + last="${element}" + done) + if [ "${result}" = "" ]; then exit 1; fi + echo "${result}" +} + +if [[ "$(uname -s)" == MINGW* ]]; then + BUILD_PATH=$(cygfullpath "$BUILD_PATH") +fi + + # Configure the test environment; run them early so that we're certain # that they're started by the time we need them. +echo "CTest version:" +env PATH="${BUILD_PATH}" "${CTEST}" --version | head -1 2>&1 | indent + +echo "" + echo "##############################################################################" echo "## Configuring test environment" echo "##############################################################################" -if [ -z "$SKIP_GITDAEMON_TESTS" ]; then - echo "Starting git daemon..." - GITDAEMON_DIR=`mktemp -d ${TMPDIR}/gitdaemon.XXXXXXXX` - git init --bare "${GITDAEMON_DIR}/test.git" >/dev/null - git daemon --listen=localhost --export-all --enable=receive-pack --base-path="${GITDAEMON_DIR}" "${GITDAEMON_DIR}" 2>/dev/null & - GITDAEMON_PID=$! - disown $GITDAEMON_PID +echo "" + +if should_run "GITDAEMON_TESTS"; then + echo "Starting git daemon (standard)..." + GIT_STANDARD_DIR=`mktemp -d ${TMPDIR}/git_standard.XXXXXXXX` + cp -R "${SOURCE_DIR}/tests/resources/pushoptions.git" "${GIT_STANDARD_DIR}/test.git" + git daemon --listen=localhost --export-all --enable=receive-pack --base-path="${GIT_STANDARD_DIR}" "${GIT_STANDARD_DIR}" 2>/dev/null & + + GIT_STANDARD_PID=$! + + echo "Starting git daemon (namespace)..." + GIT_NAMESPACE_DIR=`mktemp -d ${TMPDIR}/git_namespace.XXXXXXXX` + cp -R "${SOURCE_DIR}/tests/resources/namespace.git" "${GIT_NAMESPACE_DIR}/namespace.git" + GIT_NAMESPACE="name1" git daemon --listen=localhost --port=9419 --export-all --enable=receive-pack --base-path="${GIT_NAMESPACE_DIR}" "${GIT_NAMESPACE_DIR}" & + GIT_NAMESPACE_PID=$! + + echo "Starting git daemon (sha256)..." + GIT_SHA256_DIR=`mktemp -d ${TMPDIR}/git_sha256.XXXXXXXX` + cp -R "${SOURCE_DIR}/tests/resources/testrepo_256.git" "${GIT_SHA256_DIR}/testrepo_256.git" + git daemon --listen=localhost --port=9420 --export-all --enable=receive-pack --base-path="${GIT_SHA256_DIR}" "${GIT_SHA256_DIR}" & + GIT_SHA256_PID=$! fi -if [ -z "$SKIP_PROXY_TESTS" ]; then +if should_run "PROXY_TESTS"; then curl --location --silent --show-error https://github.com/ethomson/poxyproxy/releases/download/v0.7.0/poxyproxy-0.7.0.jar >poxyproxy.jar - echo "" echo "Starting HTTP proxy (Basic)..." java -jar poxyproxy.jar --address 127.0.0.1 --port 8080 --credentials foo:bar --auth-type basic --quiet & + PROXY_BASIC_PID=$! - echo "" echo "Starting HTTP proxy (NTLM)..." java -jar poxyproxy.jar --address 127.0.0.1 --port 8090 --credentials foo:bar --auth-type ntlm --quiet & + PROXY_NTLM_PID=$! fi -if [ -z "$SKIP_NTLM_TESTS" -o -z "$SKIP_ONLINE_TESTS" ]; then - curl --location --silent --show-error https://github.com/ethomson/poxygit/releases/download/v0.5.1/poxygit-0.5.1.jar >poxygit.jar +if should_run "NTLM_TESTS" || should_run "ONLINE_TESTS"; then + curl --location --silent --show-error https://github.com/ethomson/poxygit/releases/download/v0.6.0/poxygit-0.6.0.jar >poxygit.jar - echo "" echo "Starting HTTP server..." - NTLM_DIR=`mktemp -d ${TMPDIR}/ntlm.XXXXXXXX` - git init --bare "${NTLM_DIR}/test.git" - java -jar poxygit.jar --address 127.0.0.1 --port 9000 --credentials foo:baz --quiet "${NTLM_DIR}" & + HTTP_DIR=`mktemp -d ${TMPDIR}/http.XXXXXXXX` + cp -R "${SOURCE_DIR}/tests/resources/pushoptions.git" "${HTTP_DIR}/test.git" + + java -jar poxygit.jar --address 127.0.0.1 --port 9000 --credentials foo:baz --quiet "${HTTP_DIR}" & + HTTP_PID=$! fi -if [ -z "$SKIP_SSH_TESTS" ]; then - echo "" - echo "Starting ssh daemon..." - HOME=`mktemp -d ${TMPDIR}/home.XXXXXXXX` +if should_run "SSH_TESTS"; then + echo "Starting SSH server..." SSHD_DIR=`mktemp -d ${TMPDIR}/sshd.XXXXXXXX` - git init --bare "${SSHD_DIR}/test.git" >/dev/null + cp -R "${SOURCE_DIR}/tests/resources/pushoptions.git" "${SSHD_DIR}/test.git" + cat >"${SSHD_DIR}/sshd_config" <<-EOF Port 2222 ListenAddress 0.0.0.0 Protocol 2 - HostKey ${SSHD_DIR}/id_rsa + HostKey ${SSHD_DIR}/id_${GITTEST_SSH_KEYTYPE} PidFile ${SSHD_DIR}/pid AuthorizedKeysFile ${HOME}/.ssh/authorized_keys LogLevel DEBUG @@ -130,19 +226,26 @@ if [ -z "$SKIP_SSH_TESTS" ]; then PubkeyAuthentication yes ChallengeResponseAuthentication no StrictModes no + HostCertificate ${SSHD_DIR}/id_${GITTEST_SSH_KEYTYPE}.pub + HostKey ${SSHD_DIR}/id_${GITTEST_SSH_KEYTYPE} # Required here as sshd will simply close connection otherwise UsePAM no EOF - ssh-keygen -t rsa -f "${SSHD_DIR}/id_rsa" -N "" -q + ssh-keygen -t "${GITTEST_SSH_KEYTYPE}" -f "${SSHD_DIR}/id_${GITTEST_SSH_KEYTYPE}" -N "" -q /usr/sbin/sshd -f "${SSHD_DIR}/sshd_config" -E "${SSHD_DIR}/log" # Set up keys mkdir "${HOME}/.ssh" - ssh-keygen -t rsa -f "${HOME}/.ssh/id_rsa" -N "" -q - cat "${HOME}/.ssh/id_rsa.pub" >>"${HOME}/.ssh/authorized_keys" + ssh-keygen -t "${GITTEST_SSH_KEYTYPE}" -f "${HOME}/.ssh/id_${GITTEST_SSH_KEYTYPE}" -N "" -q + cat "${HOME}/.ssh/id_${GITTEST_SSH_KEYTYPE}.pub" >>"${HOME}/.ssh/authorized_keys" while read algorithm key comment; do echo "[localhost]:2222 $algorithm $key" >>"${HOME}/.ssh/known_hosts" - done <"${SSHD_DIR}/id_rsa.pub" + done <"${SSHD_DIR}/id_${GITTEST_SSH_KEYTYPE}.pub" + + # Append the github.com keys for the tests that don't override checks. + # We ask for ssh-rsa to test that the selection based off of known_hosts + # is working. + ssh-keyscan -t ssh-rsa github.com >>"${HOME}/.ssh/known_hosts" # Get the fingerprint for localhost and remove the colons so we can # parse it as a hex number. Older versions have a different output @@ -156,13 +259,21 @@ fi # Run the tests that do not require network connectivity. -if [ -z "$SKIP_OFFLINE_TESTS" ]; then +if should_run "OFFLINE_TESTS"; then echo "" echo "##############################################################################" - echo "## Running (offline) tests" + echo "## Running core tests" echo "##############################################################################" + echo "" + echo "Running libgit2 integration (offline) tests" + echo "" run_test offline + + echo "" + echo "Running utility tests" + echo "" + run_test util fi if [ -n "$RUN_INVASIVE_TESTS" ]; then @@ -179,42 +290,68 @@ if [ -n "$RUN_INVASIVE_TESTS" ]; then unset GITTEST_INVASIVE_SPEED fi -if [ -z "$SKIP_ONLINE_TESTS" ]; then +# the various network tests can fail due to network connectivity problems; +# allow them to retry up to 5 times +export GITTEST_FLAKY_RETRY=5 + +if should_run "ONLINE_TESTS"; then # Run the online tests. The "online" test suite only includes the # default online tests that do not require additional configuration. # The "proxy" and "ssh" test suites require further setup. echo "" echo "##############################################################################" - echo "## Running (online) tests" + echo "## Running networking (online) tests" echo "##############################################################################" export GITTEST_REMOTE_REDIRECT_INITIAL="http://localhost:9000/initial-redirect/libgit2/TestGitRepository" export GITTEST_REMOTE_REDIRECT_SUBSEQUENT="http://localhost:9000/subsequent-redirect/libgit2/TestGitRepository" + export GITTEST_REMOTE_SPEED_SLOW="http://localhost:9000/speed-9600/test.git" + export GITTEST_REMOTE_SPEED_TIMESOUT="http://localhost:9000/speed-0.5/test.git" run_test online unset GITTEST_REMOTE_REDIRECT_INITIAL unset GITTEST_REMOTE_REDIRECT_SUBSEQUENT + unset GITTEST_REMOTE_SPEED_SLOW + unset GITTEST_REMOTE_SPEED_TIMESOUT # Run the online tests that immutably change global state separately # to avoid polluting the test environment. echo "" - echo "##############################################################################" - echo "## Running (online_customcert) tests" - echo "##############################################################################" + echo "Running custom certificate (online_customcert) tests" + echo "" + run_test online_customcert fi -if [ -z "$SKIP_GITDAEMON_TESTS" ]; then +if should_run "GITDAEMON_TESTS"; then echo "" - echo "Running gitdaemon tests" + echo "Running gitdaemon (standard) tests" echo "" export GITTEST_REMOTE_URL="git://localhost/test.git" run_test gitdaemon unset GITTEST_REMOTE_URL + + echo "" + echo "Running gitdaemon (namespace) tests" + echo "" + + export GITTEST_REMOTE_URL="git://localhost:9419/namespace.git" + export GITTEST_REMOTE_BRANCH="four" + run_test gitdaemon_namespace + unset GITTEST_REMOTE_URL + unset GITTEST_REMOTE_BRANCH + + echo "" + echo "Running gitdaemon (sha256) tests" + echo "" + + export GITTEST_REMOTE_URL="git://localhost:9420/testrepo_256.git" + run_test gitdaemon_sha256 + unset GITTEST_REMOTE_URL fi -if [ -z "$SKIP_PROXY_TESTS" ]; then +if should_run "PROXY_TESTS"; then echo "" echo "Running proxy tests (Basic authentication)" echo "" @@ -240,7 +377,7 @@ if [ -z "$SKIP_PROXY_TESTS" ]; then unset GITTEST_REMOTE_PROXY_PASS fi -if [ -z "$SKIP_NTLM_TESTS" ]; then +if should_run "NTLM_TESTS"; then echo "" echo "Running NTLM tests (IIS emulation)" echo "" @@ -266,7 +403,7 @@ if [ -z "$SKIP_NTLM_TESTS" ]; then unset GITTEST_REMOTE_PASS fi -if [ -z "$SKIP_NEGOTIATE_TESTS" -a -n "$GITTEST_NEGOTIATE_PASSWORD" ]; then +if should_run "NEGOTIATE_TESTS" && -n "$GITTEST_NEGOTIATE_PASSWORD" ; then echo "" echo "Running SPNEGO tests" echo "" @@ -299,13 +436,15 @@ if [ -z "$SKIP_NEGOTIATE_TESTS" -a -n "$GITTEST_NEGOTIATE_PASSWORD" ]; then kdestroy -A fi -if [ -z "$SKIP_SSH_TESTS" ]; then +if should_run "SSH_TESTS"; then export GITTEST_REMOTE_USER=$USER - export GITTEST_REMOTE_SSH_KEY="${HOME}/.ssh/id_rsa" - export GITTEST_REMOTE_SSH_PUBKEY="${HOME}/.ssh/id_rsa.pub" + export GITTEST_REMOTE_SSH_KEY="${HOME}/.ssh/id_${GITTEST_SSH_KEYTYPE}" + export GITTEST_REMOTE_SSH_PUBKEY="${HOME}/.ssh/id_${GITTEST_SSH_KEYTYPE}.pub" export GITTEST_REMOTE_SSH_PASSPHRASE="" export GITTEST_REMOTE_SSH_FINGERPRINT="${SSH_FINGERPRINT}" + export GITTEST_SSH_CMD="ssh -i ${HOME}/.ssh/id_${GITTEST_SSH_KEYTYPE} -o UserKnownHostsFile=${HOME}/.ssh/known_hosts" + echo "" echo "Running ssh tests" echo "" @@ -322,6 +461,8 @@ if [ -z "$SKIP_SSH_TESTS" ]; then run_test ssh unset GITTEST_REMOTE_URL + unset GITTEST_SSH_CMD + unset GITTEST_REMOTE_USER unset GITTEST_REMOTE_SSH_KEY unset GITTEST_REMOTE_SSH_PUBKEY @@ -329,13 +470,15 @@ if [ -z "$SKIP_SSH_TESTS" ]; then unset GITTEST_REMOTE_SSH_FINGERPRINT fi -if [ -z "$SKIP_FUZZERS" ]; then +unset GITTEST_FLAKY_RETRY + +if should_run "FUZZERS"; then echo "" echo "##############################################################################" echo "## Running fuzzers" echo "##############################################################################" - ctest -V -R 'fuzzer' + env PATH="${BUILD_PATH}" "${CTEST}" -V -R 'fuzzer' fi cleanup diff --git a/vendor/libgit2/cmake/AddClarTest.cmake b/vendor/libgit2/cmake/AddClarTest.cmake new file mode 100644 index 00000000..74394163 --- /dev/null +++ b/vendor/libgit2/cmake/AddClarTest.cmake @@ -0,0 +1,7 @@ +function(ADD_CLAR_TEST project name) + if(NOT USE_LEAK_CHECKER STREQUAL "OFF") + add_test(${name} "${PROJECT_SOURCE_DIR}/script/${USE_LEAK_CHECKER}.sh" "${PROJECT_BINARY_DIR}/${project}" ${ARGN}) + else() + add_test(${name} "${PROJECT_BINARY_DIR}/${project}" ${ARGN}) + endif() +endfunction(ADD_CLAR_TEST) diff --git a/vendor/libgit2/cmake/CheckPrototypeDefinitionSafe.cmake b/vendor/libgit2/cmake/CheckPrototypeDefinitionSafe.cmake new file mode 100644 index 00000000..f82603d3 --- /dev/null +++ b/vendor/libgit2/cmake/CheckPrototypeDefinitionSafe.cmake @@ -0,0 +1,16 @@ +include(CheckPrototypeDefinition) + +function(check_prototype_definition_safe function prototype return header variable) + # temporarily save CMAKE_C_FLAGS and disable warnings about unused + # unused functions and parameters, otherwise they will always fail + # if ENABLE_WERROR is on + set(SAVED_CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") + + disable_warnings(unused-function) + disable_warnings(unused-parameter) + + check_prototype_definition("${function}" "${prototype}" "${return}" "${header}" "${variable}") + + # restore CMAKE_C_FLAGS + set(CMAKE_C_FLAGS "${SAVED_CMAKE_C_FLAGS}") +endfunction() diff --git a/vendor/libgit2/cmake/DefaultCFlags.cmake b/vendor/libgit2/cmake/DefaultCFlags.cmake index a9c9ab97..6dad185e 100644 --- a/vendor/libgit2/cmake/DefaultCFlags.cmake +++ b/vendor/libgit2/cmake/DefaultCFlags.cmake @@ -13,6 +13,9 @@ if(MSVC) # /Gd - explicitly set cdecl calling convention set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Gd") + # Remove warnings about operands that use different enum types. + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd5287") + if(NOT (MSVC_VERSION LESS 1900)) # /guard:cf - Enable Control Flow Guard set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /guard:cf") diff --git a/vendor/libgit2/cmake/ExperimentalFeatures.cmake b/vendor/libgit2/cmake/ExperimentalFeatures.cmake new file mode 100644 index 00000000..7eff40bd --- /dev/null +++ b/vendor/libgit2/cmake/ExperimentalFeatures.cmake @@ -0,0 +1,23 @@ +# Experimental feature support for libgit2 - developers can opt in to +# experimental functionality, like sha256 support. When experimental +# functionality is enabled, we set both a cmake flag *and* a compile +# definition. The cmake flag is used to generate `experimental.h`, +# which will be installed by a `make install`. But the compile definition +# is used by the libgit2 sources to detect the functionality at library +# build time. This allows us to have an in-tree `experimental.h` with +# *no* experiments enabled. This lets us support users who build without +# cmake and cannot generate the `experimental.h` file. + +if(EXPERIMENTAL_SHA256) + add_feature_info("SHA256 API" ON "experimental SHA256 APIs") + + set(EXPERIMENTAL 1) + set(GIT_EXPERIMENTAL_SHA256 1) + add_definitions(-DGIT_EXPERIMENTAL_SHA256=1) +else() + add_feature_info("SHA256 API" OFF "experimental SHA256 APIs") +endif() + +if(EXPERIMENTAL) + set(LIBGIT2_FILENAME "${LIBGIT2_FILENAME}-experimental") +endif() diff --git a/vendor/libgit2/cmake/FindIconv.cmake b/vendor/libgit2/cmake/FindIntlIconv.cmake similarity index 100% rename from vendor/libgit2/cmake/FindIconv.cmake rename to vendor/libgit2/cmake/FindIntlIconv.cmake diff --git a/vendor/libgit2/cmake/FindLLHTTP.cmake b/vendor/libgit2/cmake/FindLLHTTP.cmake new file mode 100644 index 00000000..a87d335d --- /dev/null +++ b/vendor/libgit2/cmake/FindLLHTTP.cmake @@ -0,0 +1,39 @@ +# - Try to find llhttp +# +# Defines the following variables: +# +# LLHTTP_FOUND - system has llhttp +# LLHTTP_INCLUDE_DIR - the llhttp include directory +# LLHTTP_LIBRARIES - Link these to use llhttp +# LLHTTP_VERSION_MAJOR - major version +# LLHTTP_VERSION_MINOR - minor version +# LLHTTP_VERSION_STRING - the version of llhttp found + +# Find the header and library +find_path(LLHTTP_INCLUDE_DIR NAMES llhttp.h) +find_library(LLHTTP_LIBRARY NAMES llhttp libllhttp) + +# Found the header, read version +if(LLHTTP_INCLUDE_DIR AND EXISTS "${LLHTTP_INCLUDE_DIR}/llhttp.h") + file(READ "${LLHTTP_INCLUDE_DIR}/llhttp.h" LLHTTP_H) + if(LLHTTP_H) + string(REGEX REPLACE ".*#define[\t ]+LLHTTP_VERSION_MAJOR[\t ]+([0-9]+).*" "\\1" LLHTTP_VERSION_MAJOR "${LLHTTP_H}") + string(REGEX REPLACE ".*#define[\t ]+LLHTTP_VERSION_MINOR[\t ]+([0-9]+).*" "\\1" LLHTTP_VERSION_MINOR "${LLHTTP_H}") + set(LLHTTP_VERSION_STRING "${LLHTTP_VERSION_MAJOR}.${LLHTTP_VERSION_MINOR}") + endif() + unset(LLHTTP_H) +endif() + +# Handle the QUIETLY and REQUIRED arguments and set LLHTTP_FOUND +# to TRUE if all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LLHTTP REQUIRED_VARS LLHTTP_INCLUDE_DIR LLHTTP_LIBRARY) + +# Hide advanced variables +mark_as_advanced(LLHTTP_INCLUDE_DIR LLHTTP_LIBRARY) + +# Set standard variables +if(LLHTTP_FOUND) + set(LLHTTP_LIBRARIES ${LLHTTP_LIBRARY}) + set(LLHTTP_INCLUDE_DIRS ${LLHTTP_INCLUDE_DIR}) +endif() diff --git a/vendor/libgit2/cmake/FindPCRE.cmake b/vendor/libgit2/cmake/FindPCRE.cmake index 3a7cfad9..02e7edce 100644 --- a/vendor/libgit2/cmake/FindPCRE.cmake +++ b/vendor/libgit2/cmake/FindPCRE.cmake @@ -16,19 +16,18 @@ # PCRE_FOUND - True if pcre found. # Look for the header file. -find_path(PCRE_INCLUDE_DIR NAMES pcreposix.h) +find_path(PCRE_INCLUDE_DIR NAMES pcre.h) # Look for the library. find_library(PCRE_LIBRARY NAMES pcre) -find_library(PCRE_POSIX_LIBRARY NAMES pcreposix) # Handle the QUIETLY and REQUIRED arguments and set PCRE_FOUND to TRUE if all listed variables are TRUE. include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(PCRE DEFAULT_MSG PCRE_LIBRARY PCRE_POSIX_LIBRARY PCRE_INCLUDE_DIR) +find_package_handle_standard_args(PCRE DEFAULT_MSG PCRE_LIBRARY PCRE_INCLUDE_DIR) # Copy the results to the output variables. if(PCRE_FOUND) - set(PCRE_LIBRARIES ${PCRE_LIBRARY} ${PCRE_POSIX_LIBRARY}) + set(PCRE_LIBRARIES ${PCRE_LIBRARY}) set(PCRE_INCLUDE_DIRS ${PCRE_INCLUDE_DIR}) else(PCRE_FOUND) set(PCRE_LIBRARIES) diff --git a/vendor/libgit2/cmake/FindPCRE2.cmake b/vendor/libgit2/cmake/FindPCRE2.cmake index d4b8e676..41c165b6 100644 --- a/vendor/libgit2/cmake/FindPCRE2.cmake +++ b/vendor/libgit2/cmake/FindPCRE2.cmake @@ -16,7 +16,7 @@ # PCRE2_FOUND - True if pcre found. # Look for the header file. -find_path(PCRE2_INCLUDE_DIR NAMES pcre2posix.h) +find_path(PCRE2_INCLUDE_DIR NAMES pcre2.h) # Look for the library. find_library(PCRE2_LIBRARY NAMES pcre2-8) diff --git a/vendor/libgit2/cmake/SelectGSSAPI.cmake b/vendor/libgit2/cmake/SelectGSSAPI.cmake index 24e2d68b..5bde1169 100644 --- a/vendor/libgit2/cmake/SelectGSSAPI.cmake +++ b/vendor/libgit2/cmake/SelectGSSAPI.cmake @@ -29,7 +29,7 @@ if(USE_GSSAPI) list(APPEND LIBGIT2_SYSTEM_LIBS ${GSSFRAMEWORK_LIBRARIES}) set(GIT_GSSFRAMEWORK 1) - add_feature_info(SPNEGO GIT_GSSFRAMEWORK "SPNEGO authentication support (${USE_GSSAPI})") + add_feature_info(GSSAPI GIT_GSSFRAMEWORK "GSSAPI support for SPNEGO authentication (${USE_GSSAPI})") elseif(USE_GSSAPI STREQUAL "gssapi") if(NOT GSSAPI_FOUND) message(FATAL_ERROR "Asked for gssapi GSS backend, but it wasn't found") @@ -38,11 +38,11 @@ if(USE_GSSAPI) list(APPEND LIBGIT2_SYSTEM_LIBS ${GSSAPI_LIBRARIES}) set(GIT_GSSAPI 1) - add_feature_info(SPNEGO GIT_GSSAPI "SPNEGO authentication support (${USE_GSSAPI})") + add_feature_info(GSSAPI GIT_GSSAPI "GSSAPI support for SPNEGO authentication (${USE_GSSAPI})") else() message(FATAL_ERROR "Asked for backend ${USE_GSSAPI} but it wasn't found") endif() else() set(GIT_GSSAPI 0) - add_feature_info(SPNEGO NO "SPNEGO authentication support") + add_feature_info(GSSAPI NO "GSSAPI support for SPNEGO authentication") endif() diff --git a/vendor/libgit2/cmake/SelectHTTPParser.cmake b/vendor/libgit2/cmake/SelectHTTPParser.cmake index 955aea33..4fc1f696 100644 --- a/vendor/libgit2/cmake/SelectHTTPParser.cmake +++ b/vendor/libgit2/cmake/SelectHTTPParser.cmake @@ -1,19 +1,32 @@ # Optional external dependency: http-parser -if(USE_HTTP_PARSER STREQUAL "system") +if(USE_HTTP_PARSER STREQUAL "http-parser") find_package(HTTPParser) if(HTTP_PARSER_FOUND AND HTTP_PARSER_VERSION_MAJOR EQUAL 2) list(APPEND LIBGIT2_SYSTEM_INCLUDES ${HTTP_PARSER_INCLUDE_DIRS}) list(APPEND LIBGIT2_SYSTEM_LIBS ${HTTP_PARSER_LIBRARIES}) list(APPEND LIBGIT2_PC_LIBS "-lhttp_parser") - add_feature_info(http-parser ON "http-parser support (system)") + set(GIT_HTTPPARSER_HTTPPARSER 1) + add_feature_info(http-parser ON "using http-parser (system)") else() message(FATAL_ERROR "http-parser support was requested but not found") endif() +elseif(USE_HTTP_PARSER STREQUAL "llhttp") + find_package(LLHTTP) + + if(LLHTTP_FOUND AND LLHTTP_VERSION_MAJOR EQUAL 9) + list(APPEND LIBGIT2_SYSTEM_INCLUDES ${LLHTTP_INCLUDE_DIRS}) + list(APPEND LIBGIT2_SYSTEM_LIBS ${LLHTTP_LIBRARIES}) + list(APPEND LIBGIT2_PC_LIBS "-lllhttp") + set(GIT_HTTPPARSER_LLHTTP 1) + add_feature_info(http-parser ON "using llhttp (system)") + else() + message(FATAL_ERROR "llhttp support was requested but not found") + endif() else() - message(STATUS "http-parser version 2 was not found or disabled; using bundled 3rd-party sources.") - add_subdirectory("${PROJECT_SOURCE_DIR}/deps/http-parser" "${PROJECT_BINARY_DIR}/deps/http-parser") - list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/http-parser") - list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$") - add_feature_info(http-parser ON "http-parser support (bundled)") + add_subdirectory("${PROJECT_SOURCE_DIR}/deps/llhttp" "${PROJECT_BINARY_DIR}/deps/llhttp") + list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/llhttp") + list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$") + set(GIT_HTTPPARSER_BUILTIN 1) + add_feature_info(http-parser ON "using bundled parser") endif() diff --git a/vendor/libgit2/cmake/SelectHTTPSBackend.cmake b/vendor/libgit2/cmake/SelectHTTPSBackend.cmake index 79319502..d293001f 100644 --- a/vendor/libgit2/cmake/SelectHTTPSBackend.cmake +++ b/vendor/libgit2/cmake/SelectHTTPSBackend.cmake @@ -19,7 +19,7 @@ if(USE_HTTPS) message(STATUS "Security framework is too old, falling back to OpenSSL") set(USE_HTTPS "OpenSSL") endif() - elseif(USE_WINHTTP) + elseif(WIN32) set(USE_HTTPS "WinHTTP") elseif(OPENSSL_FOUND) set(USE_HTTPS "OpenSSL") @@ -55,6 +55,10 @@ if(USE_HTTPS) set(GIT_OPENSSL 1) list(APPEND LIBGIT2_SYSTEM_INCLUDES ${OPENSSL_INCLUDE_DIR}) list(APPEND LIBGIT2_SYSTEM_LIBS ${OPENSSL_LIBRARIES}) + # Static OpenSSL (lib crypto.a) requires libdl, include it explicitly + if(LINK_WITH_STATIC_LIBRARIES STREQUAL ON) + list(APPEND LIBGIT2_SYSTEM_LIBS ${CMAKE_DL_LIBS}) + endif() list(APPEND LIBGIT2_PC_LIBS ${OPENSSL_LDFLAGS}) list(APPEND LIBGIT2_PC_REQUIRES "openssl") elseif(USE_HTTPS STREQUAL "mbedTLS") @@ -64,7 +68,7 @@ if(USE_HTTPS) if(NOT CERT_LOCATION) message(STATUS "Auto-detecting default certificates location") - if(CMAKE_SYSTEM_NAME MATCHES Darwin) + if(EXISTS "/usr/local/opt/openssl/bin/openssl") # Check for an Homebrew installation set(OPENSSL_CMD "/usr/local/opt/openssl/bin/openssl") else() @@ -106,8 +110,27 @@ if(USE_HTTPS) # https://github.com/ARMmbed/mbedtls/issues/228 # For now, pass its link flags as our own list(APPEND LIBGIT2_PC_LIBS ${MBEDTLS_LIBRARIES}) + elseif(USE_HTTPS STREQUAL "Schannel") + set(GIT_SCHANNEL 1) + + list(APPEND LIBGIT2_SYSTEM_LIBS "rpcrt4" "crypt32" "ole32") + list(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32") elseif(USE_HTTPS STREQUAL "WinHTTP") - # WinHTTP setup was handled in the WinHTTP-specific block above + set(GIT_WINHTTP 1) + + # Since MinGW does not come with headers or an import library for winhttp, + # we have to include a private header and generate our own import library + if(MINGW) + add_subdirectory("${PROJECT_SOURCE_DIR}/deps/winhttp" "${PROJECT_BINARY_DIR}/deps/winhttp") + list(APPEND LIBGIT2_SYSTEM_LIBS winhttp) + list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/winhttp") + else() + list(APPEND LIBGIT2_SYSTEM_LIBS "winhttp") + list(APPEND LIBGIT2_PC_LIBS "-lwinhttp") + endif() + + list(APPEND LIBGIT2_SYSTEM_LIBS "rpcrt4" "crypt32" "ole32") + list(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32") elseif(USE_HTTPS STREQUAL "OpenSSL-Dynamic") set(GIT_OPENSSL 1) set(GIT_OPENSSL_DYNAMIC 1) diff --git a/vendor/libgit2/cmake/SelectHashes.cmake b/vendor/libgit2/cmake/SelectHashes.cmake index bedd8c4e..5c007e58 100644 --- a/vendor/libgit2/cmake/SelectHashes.cmake +++ b/vendor/libgit2/cmake/SelectHashes.cmake @@ -4,12 +4,17 @@ include(SanitizeBool) # USE_SHA1=CollisionDetection(ON)/HTTPS/Generic/OFF sanitizebool(USE_SHA1) +sanitizebool(USE_SHA256) + +# sha1 if(USE_SHA1 STREQUAL ON) SET(USE_SHA1 "CollisionDetection") elseif(USE_SHA1 STREQUAL "HTTPS") if(USE_HTTPS STREQUAL "SecureTransport") set(USE_SHA1 "CommonCrypto") + elseif(USE_HTTPS STREQUAL "Schannel") + set(USE_SHA1 "Win32") elseif(USE_HTTPS STREQUAL "WinHTTP") set(USE_SHA1 "Win32") elseif(USE_HTTPS) @@ -21,32 +26,79 @@ endif() if(USE_SHA1 STREQUAL "CollisionDetection") set(GIT_SHA1_COLLISIONDETECT 1) - add_definitions(-DSHA1DC_NO_STANDARD_INCLUDES=1) - add_definitions(-DSHA1DC_CUSTOM_INCLUDE_SHA1_C=\"common.h\") - add_definitions(-DSHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C=\"common.h\") elseif(USE_SHA1 STREQUAL "OpenSSL") - # OPENSSL_FOUND should already be set, we're checking USE_HTTPS - set(GIT_SHA1_OPENSSL 1) +elseif(USE_SHA1 STREQUAL "OpenSSL-Dynamic") + set(GIT_SHA1_OPENSSL 1) + set(GIT_SHA1_OPENSSL_DYNAMIC 1) + list(APPEND LIBGIT2_SYSTEM_LIBS dl) +elseif(USE_SHA1 STREQUAL "CommonCrypto") + set(GIT_SHA1_COMMON_CRYPTO 1) +elseif(USE_SHA1 STREQUAL "mbedTLS") + set(GIT_SHA1_MBEDTLS 1) +elseif(USE_SHA1 STREQUAL "Win32") + set(GIT_SHA1_WIN32 1) +else() + message(FATAL_ERROR "Asked for unknown SHA1 backend: ${USE_SHA1}") +endif() + +# sha256 + +if(USE_SHA256 STREQUAL ON AND USE_HTTPS) + SET(USE_SHA256 "HTTPS") +elseif(USE_SHA256 STREQUAL ON) + SET(USE_SHA256 "Builtin") +endif() + +if(USE_SHA256 STREQUAL "HTTPS") + if(USE_HTTPS STREQUAL "SecureTransport") + set(USE_SHA256 "CommonCrypto") + elseif(USE_HTTPS STREQUAL "Schannel") + set(USE_SHA256 "Win32") + elseif(USE_HTTPS STREQUAL "WinHTTP") + set(USE_SHA256 "Win32") + elseif(USE_HTTPS) + set(USE_SHA256 ${USE_HTTPS}) + endif() +endif() + +if(USE_SHA256 STREQUAL "Builtin") + set(GIT_SHA256_BUILTIN 1) +elseif(USE_SHA256 STREQUAL "OpenSSL") + set(GIT_SHA256_OPENSSL 1) +elseif(USE_SHA256 STREQUAL "OpenSSL-Dynamic") + set(GIT_SHA256_OPENSSL 1) + set(GIT_SHA256_OPENSSL_DYNAMIC 1) + list(APPEND LIBGIT2_SYSTEM_LIBS dl) +elseif(USE_SHA256 STREQUAL "CommonCrypto") + set(GIT_SHA256_COMMON_CRYPTO 1) +elseif(USE_SHA256 STREQUAL "mbedTLS") + set(GIT_SHA256_MBEDTLS 1) +elseif(USE_SHA256 STREQUAL "Win32") + set(GIT_SHA256_WIN32 1) +else() + message(FATAL_ERROR "Asked for unknown SHA256 backend: ${USE_SHA256}") +endif() + +# add library requirements +if(USE_SHA1 STREQUAL "OpenSSL" OR USE_SHA256 STREQUAL "OpenSSL") if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") list(APPEND LIBGIT2_PC_LIBS "-lssl") else() list(APPEND LIBGIT2_PC_REQUIRES "openssl") endif() -elseif(USE_SHA1 STREQUAL "CommonCrypto") - set(GIT_SHA1_COMMON_CRYPTO 1) -elseif(USE_SHA1 STREQUAL "mbedTLS") - set(GIT_SHA1_MBEDTLS 1) +endif() + +if(USE_SHA1 STREQUAL "mbedTLS" OR USE_SHA256 STREQUAL "mbedTLS") list(APPEND LIBGIT2_SYSTEM_INCLUDES ${MBEDTLS_INCLUDE_DIR}) list(APPEND LIBGIT2_SYSTEM_LIBS ${MBEDTLS_LIBRARIES}) # mbedTLS has no pkgconfig file, hence we can't require it # https://github.com/ARMmbed/mbedtls/issues/228 # For now, pass its link flags as our own list(APPEND LIBGIT2_PC_LIBS ${MBEDTLS_LIBRARIES}) -elseif(USE_SHA1 STREQUAL "Win32") - set(GIT_SHA1_WIN32 1) -elseif(NOT (USE_SHA1 STREQUAL "Generic")) - message(FATAL_ERROR "Asked for unknown SHA1 backend: ${USE_SHA1}") endif() -add_feature_info(SHA ON "using ${USE_SHA1}") +# notify feature enablement + +add_feature_info(SHA1 ON "using ${USE_SHA1}") +add_feature_info(SHA256 ON "using ${USE_SHA256}") diff --git a/vendor/libgit2/cmake/SelectSSH.cmake b/vendor/libgit2/cmake/SelectSSH.cmake index 23dfc978..079857f5 100644 --- a/vendor/libgit2/cmake/SelectSSH.cmake +++ b/vendor/libgit2/cmake/SelectSSH.cmake @@ -1,6 +1,11 @@ -# Optional external dependency: libssh2 -if(USE_SSH) +if(USE_SSH STREQUAL "exec") + set(GIT_SSH 1) + set(GIT_SSH_EXEC 1) + + add_feature_info(SSH ON "using OpenSSH exec support") +elseif(USE_SSH STREQUAL ON OR USE_SSH STREQUAL "libssh2") find_pkglibraries(LIBSSH2 libssh2) + if(NOT LIBSSH2_FOUND) find_package(LibSSH2) set(LIBSSH2_INCLUDE_DIRS ${LIBSSH2_INCLUDE_DIR}) @@ -12,30 +17,28 @@ if(USE_SSH) if(NOT LIBSSH2_FOUND) message(FATAL_ERROR "LIBSSH2 not found. Set CMAKE_PREFIX_PATH if it is installed outside of the default search path.") endif() -endif() -if(LIBSSH2_FOUND) - set(GIT_SSH 1) list(APPEND LIBGIT2_SYSTEM_INCLUDES ${LIBSSH2_INCLUDE_DIRS}) list(APPEND LIBGIT2_SYSTEM_LIBS ${LIBSSH2_LIBRARIES}) list(APPEND LIBGIT2_PC_LIBS ${LIBSSH2_LDFLAGS}) check_library_exists("${LIBSSH2_LIBRARIES}" libssh2_userauth_publickey_frommemory "${LIBSSH2_LIBRARY_DIRS}" HAVE_LIBSSH2_MEMORY_CREDENTIALS) if(HAVE_LIBSSH2_MEMORY_CREDENTIALS) - set(GIT_SSH_MEMORY_CREDENTIALS 1) + set(GIT_SSH_LIBSSH2_MEMORY_CREDENTIALS 1) endif() -else() - message(STATUS "LIBSSH2 not found. Set CMAKE_PREFIX_PATH if it is installed outside of the default search path.") -endif() -if(WIN32 AND EMBED_SSH_PATH) - file(GLOB SSH_SRC "${EMBED_SSH_PATH}/src/*.c") - list(SORT SSH_SRC) - list(APPEND LIBGIT2_DEPENDENCY_OBJECTS ${SSH_SRC}) + if(WIN32 AND EMBED_SSH_PATH) + file(GLOB SSH_SRC "${EMBED_SSH_PATH}/src/*.c") + list(SORT SSH_SRC) + list(APPEND LIBGIT2_DEPENDENCY_OBJECTS ${SSH_SRC}) + + list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${EMBED_SSH_PATH}/include") + file(WRITE "${EMBED_SSH_PATH}/src/libssh2_config.h" "#define HAVE_WINCNG\n#define LIBSSH2_WINCNG\n#include \"../win32/libssh2_config.h\"") + endif() - list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${EMBED_SSH_PATH}/include") - file(WRITE "${EMBED_SSH_PATH}/src/libssh2_config.h" "#define HAVE_WINCNG\n#define LIBSSH2_WINCNG\n#include \"../win32/libssh2_config.h\"") set(GIT_SSH 1) + set(GIT_SSH_LIBSSH2 1) + add_feature_info(SSH ON "using libssh2") +else() + add_feature_info(SSH OFF "SSH transport support") endif() - -add_feature_info(SSH GIT_SSH "SSH transport support") diff --git a/vendor/libgit2/cmake/SelectWinHTTP.cmake b/vendor/libgit2/cmake/SelectWinHTTP.cmake deleted file mode 100644 index 96e0bdba..00000000 --- a/vendor/libgit2/cmake/SelectWinHTTP.cmake +++ /dev/null @@ -1,17 +0,0 @@ -if(WIN32 AND USE_WINHTTP) - set(GIT_WINHTTP 1) - - # Since MinGW does not come with headers or an import library for winhttp, - # we have to include a private header and generate our own import library - if(MINGW) - add_subdirectory("${PROJECT_SOURCE_DIR}/deps/winhttp" "${PROJECT_BINARY_DIR}/deps/winhttp") - list(APPEND LIBGIT2_SYSTEM_LIBS winhttp) - list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/winhttp") - else() - list(APPEND LIBGIT2_SYSTEM_LIBS "winhttp") - list(APPEND LIBGIT2_PC_LIBS "-lwinhttp") - endif() - - list(APPEND LIBGIT2_SYSTEM_LIBS "rpcrt4" "crypt32" "ole32") - list(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32") -endif() diff --git a/vendor/libgit2/cmake/SelectXdiff.cmake b/vendor/libgit2/cmake/SelectXdiff.cmake new file mode 100644 index 00000000..9ab9f3f4 --- /dev/null +++ b/vendor/libgit2/cmake/SelectXdiff.cmake @@ -0,0 +1,9 @@ +# Optional external dependency: xdiff +if(USE_XDIFF STREQUAL "system") + message(FATAL_ERROR "external/system xdiff is not yet supported") +else() + add_subdirectory("${PROJECT_SOURCE_DIR}/deps/xdiff" "${PROJECT_BINARY_DIR}/deps/xdiff") + list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/xdiff") + list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$") + add_feature_info(xdiff ON "xdiff support (bundled)") +endif() diff --git a/vendor/libgit2/deps/http-parser/CMakeLists.txt b/vendor/libgit2/deps/http-parser/CMakeLists.txt deleted file mode 100644 index b9da2496..00000000 --- a/vendor/libgit2/deps/http-parser/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -file(GLOB SRC_HTTP "*.c" "*.h") -list(SORT SRC_HTTP) - -add_library(http-parser OBJECT ${SRC_HTTP}) - -enable_warnings(implicit-fallthrough=1) diff --git a/vendor/libgit2/deps/http-parser/COPYING b/vendor/libgit2/deps/http-parser/COPYING deleted file mode 100644 index 58010b38..00000000 --- a/vendor/libgit2/deps/http-parser/COPYING +++ /dev/null @@ -1,23 +0,0 @@ -http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright -Igor Sysoev. - -Additional changes are licensed under the same terms as NGINX and -copyright Joyent, Inc. and other Node contributors. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. diff --git a/vendor/libgit2/deps/http-parser/http_parser.c b/vendor/libgit2/deps/http-parser/http_parser.c deleted file mode 100644 index 1bcd330e..00000000 --- a/vendor/libgit2/deps/http-parser/http_parser.c +++ /dev/null @@ -1,2182 +0,0 @@ -/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev - * - * Additional changes are licensed under the same terms as NGINX and - * copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#include "http_parser.h" -#include -#include -#include -#include -#include -#include - -#ifndef ULLONG_MAX -# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */ -#endif - -#ifndef MIN -# define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -#ifndef ARRAY_SIZE -# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#endif - -#ifndef BIT_AT -# define BIT_AT(a, i) \ - (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \ - (1 << ((unsigned int) (i) & 7)))) -#endif - -#ifndef ELEM_AT -# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v)) -#endif - -#define SET_ERRNO(e) \ -do { \ - parser->http_errno = (e); \ -} while(0) - - -/* Run the notify callback FOR, returning ER if it fails */ -#define CALLBACK_NOTIFY_(FOR, ER) \ -do { \ - assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ - \ - if (settings->on_##FOR) { \ - if (0 != settings->on_##FOR(parser)) { \ - SET_ERRNO(HPE_CB_##FOR); \ - } \ - \ - /* We either errored above or got paused; get out */ \ - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \ - return (ER); \ - } \ - } \ -} while (0) - -/* Run the notify callback FOR and consume the current byte */ -#define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1) - -/* Run the notify callback FOR and don't consume the current byte */ -#define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data) - -/* Run data callback FOR with LEN bytes, returning ER if it fails */ -#define CALLBACK_DATA_(FOR, LEN, ER) \ -do { \ - assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ - \ - if (FOR##_mark) { \ - if (settings->on_##FOR) { \ - if (0 != settings->on_##FOR(parser, FOR##_mark, (LEN))) { \ - SET_ERRNO(HPE_CB_##FOR); \ - } \ - \ - /* We either errored above or got paused; get out */ \ - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \ - return (ER); \ - } \ - } \ - FOR##_mark = NULL; \ - } \ -} while (0) - -/* Run the data callback FOR and consume the current byte */ -#define CALLBACK_DATA(FOR) \ - CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1) - -/* Run the data callback FOR and don't consume the current byte */ -#define CALLBACK_DATA_NOADVANCE(FOR) \ - CALLBACK_DATA_(FOR, p - FOR##_mark, p - data) - -/* Set the mark FOR; non-destructive if mark is already set */ -#define MARK(FOR) \ -do { \ - if (!FOR##_mark) { \ - FOR##_mark = p; \ - } \ -} while (0) - - -#define PROXY_CONNECTION "proxy-connection" -#define CONNECTION "connection" -#define CONTENT_LENGTH "content-length" -#define TRANSFER_ENCODING "transfer-encoding" -#define UPGRADE "upgrade" -#define CHUNKED "chunked" -#define KEEP_ALIVE "keep-alive" -#define CLOSE "close" - - -static const char *method_strings[] = - { -#define XX(num, name, string) #string, - HTTP_METHOD_MAP(XX) -#undef XX - }; - - -/* Tokens as defined by rfc 2616. Also lowercases them. - * token = 1* - * separators = "(" | ")" | "<" | ">" | "@" - * | "," | ";" | ":" | "\" | <"> - * | "/" | "[" | "]" | "?" | "=" - * | "{" | "}" | SP | HT - */ -static const char tokens[256] = { -/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ - 0, '!', 0, '#', '$', '%', '&', '\'', -/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ - 0, 0, '*', '+', 0, '-', '.', 0, -/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ - '0', '1', '2', '3', '4', '5', '6', '7', -/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ - '8', '9', 0, 0, 0, 0, 0, 0, -/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ - 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', -/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', -/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', -/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ - 'x', 'y', 'z', 0, 0, 0, '^', '_', -/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ - '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', -/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', -/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', -/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 'x', 'y', 'z', 0, '|', 0, '~', 0 }; - - -static const int8_t unhex[256] = - {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - }; - - -#if HTTP_PARSER_STRICT -# define T(v) 0 -#else -# define T(v) v -#endif - - -static const uint8_t normal_url_char[32] = { -/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0, -/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ - 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128, -/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, -/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, }; - -#undef T - -enum state - { s_dead = 1 /* important that this is > 0 */ - - , s_start_req_or_res - , s_res_or_resp_H - , s_start_res - , s_res_H - , s_res_HT - , s_res_HTT - , s_res_HTTP - , s_res_first_http_major - , s_res_http_major - , s_res_first_http_minor - , s_res_http_minor - , s_res_first_status_code - , s_res_status_code - , s_res_status - , s_res_line_almost_done - - , s_start_req - - , s_req_method - , s_req_spaces_before_url - , s_req_schema - , s_req_schema_slash - , s_req_schema_slash_slash - , s_req_server_start - , s_req_server - , s_req_server_with_at - , s_req_path - , s_req_query_string_start - , s_req_query_string - , s_req_fragment_start - , s_req_fragment - , s_req_http_start - , s_req_http_H - , s_req_http_HT - , s_req_http_HTT - , s_req_http_HTTP - , s_req_first_http_major - , s_req_http_major - , s_req_first_http_minor - , s_req_http_minor - , s_req_line_almost_done - - , s_header_field_start - , s_header_field - , s_header_value_start - , s_header_value - , s_header_value_lws - - , s_header_almost_done - - , s_chunk_size_start - , s_chunk_size - , s_chunk_parameters - , s_chunk_size_almost_done - - , s_headers_almost_done - , s_headers_done - - /* Important: 's_headers_done' must be the last 'header' state. All - * states beyond this must be 'body' states. It is used for overflow - * checking. See the PARSING_HEADER() macro. - */ - - , s_chunk_data - , s_chunk_data_almost_done - , s_chunk_data_done - - , s_body_identity - , s_body_identity_eof - - , s_message_done - }; - - -#define PARSING_HEADER(state) (state <= s_headers_done) - - -enum header_states - { h_general = 0 - , h_C - , h_CO - , h_CON - - , h_matching_connection - , h_matching_proxy_connection - , h_matching_content_length - , h_matching_transfer_encoding - , h_matching_upgrade - - , h_connection - , h_content_length - , h_transfer_encoding - , h_upgrade - - , h_matching_transfer_encoding_chunked - , h_matching_connection_keep_alive - , h_matching_connection_close - - , h_transfer_encoding_chunked - , h_connection_keep_alive - , h_connection_close - }; - -enum http_host_state - { - s_http_host_dead = 1 - , s_http_userinfo_start - , s_http_userinfo - , s_http_host_start - , s_http_host_v6_start - , s_http_host - , s_http_host_v6 - , s_http_host_v6_end - , s_http_host_port_start - , s_http_host_port -}; - -/* Macros for character classes; depends on strict-mode */ -#define CR '\r' -#define LF '\n' -#define LOWER(c) (unsigned char)(c | 0x20) -#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z') -#define IS_NUM(c) ((c) >= '0' && (c) <= '9') -#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c)) -#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f')) -#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \ - (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \ - (c) == ')') -#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \ - (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \ - (c) == '$' || (c) == ',') - -#if HTTP_PARSER_STRICT -#define TOKEN(c) (tokens[(unsigned char)c]) -#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c)) -#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-') -#else -#define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c]) -#define IS_URL_CHAR(c) \ - (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80)) -#define IS_HOST_CHAR(c) \ - (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') -#endif - - -#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res) - - -#if HTTP_PARSER_STRICT -# define STRICT_CHECK(cond) \ -do { \ - if (cond) { \ - SET_ERRNO(HPE_STRICT); \ - goto error; \ - } \ -} while (0) -# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead) -#else -# define STRICT_CHECK(cond) -# define NEW_MESSAGE() start_state -#endif - - -/* Map errno values to strings for human-readable output */ -#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s }, -static struct { - const char *name; - const char *description; -} http_strerror_tab[] = { - HTTP_ERRNO_MAP(HTTP_STRERROR_GEN) -}; -#undef HTTP_STRERROR_GEN - -int http_message_needs_eof(const http_parser *parser); - -/* Our URL parser. - * - * This is designed to be shared by http_parser_execute() for URL validation, - * hence it has a state transition + byte-for-byte interface. In addition, it - * is meant to be embedded in http_parser_parse_url(), which does the dirty - * work of turning state transitions URL components for its API. - * - * This function should only be invoked with non-space characters. It is - * assumed that the caller cares about (and can detect) the transition between - * URL and non-URL states by looking for these. - */ -static enum state -parse_url_char(enum state s, const char ch) -{ - if (ch == ' ' || ch == '\r' || ch == '\n') { - return s_dead; - } - -#if HTTP_PARSER_STRICT - if (ch == '\t' || ch == '\f') { - return s_dead; - } -#endif - - switch (s) { - case s_req_spaces_before_url: - /* Proxied requests are followed by scheme of an absolute URI (alpha). - * All methods except CONNECT are followed by '/' or '*'. - */ - - if (ch == '/' || ch == '*') { - return s_req_path; - } - - /* The schema must start with an alpha character. After that, it may - * consist of digits, '+', '-' or '.', followed by a ':'. - */ - if (IS_ALPHA(ch)) { - return s_req_schema; - } - - break; - - case s_req_schema: - if (IS_ALPHANUM(ch) || ch == '+' || ch == '-' || ch == '.') { - return s; - } - - if (ch == ':') { - return s_req_schema_slash; - } - - break; - - case s_req_schema_slash: - if (ch == '/') { - return s_req_schema_slash_slash; - } - - break; - - case s_req_schema_slash_slash: - if (ch == '/') { - return s_req_server_start; - } - - break; - - case s_req_server_with_at: - if (ch == '@') { - return s_dead; - } - - /* FALLTHROUGH */ - case s_req_server_start: - case s_req_server: - if (ch == '/') { - return s_req_path; - } - - if (ch == '?') { - return s_req_query_string_start; - } - - if (ch == '@') { - return s_req_server_with_at; - } - - if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') { - return s_req_server; - } - - break; - - case s_req_path: - if (IS_URL_CHAR(ch)) { - return s; - } - - switch (ch) { - case '?': - return s_req_query_string_start; - - case '#': - return s_req_fragment_start; - } - - break; - - case s_req_query_string_start: - case s_req_query_string: - if (IS_URL_CHAR(ch)) { - return s_req_query_string; - } - - switch (ch) { - case '?': - /* allow extra '?' in query string */ - return s_req_query_string; - - case '#': - return s_req_fragment_start; - } - - break; - - case s_req_fragment_start: - if (IS_URL_CHAR(ch)) { - return s_req_fragment; - } - - switch (ch) { - case '?': - return s_req_fragment; - - case '#': - return s; - } - - break; - - case s_req_fragment: - if (IS_URL_CHAR(ch)) { - return s; - } - - switch (ch) { - case '?': - case '#': - return s; - } - - break; - - default: - break; - } - - /* We should never fall out of the switch above unless there's an error */ - return s_dead; -} - -size_t http_parser_execute (http_parser *parser, - const http_parser_settings *settings, - const char *data, - size_t len) -{ - char c, ch; - int8_t unhex_val; - const char *p = data; - const char *header_field_mark = 0; - const char *header_value_mark = 0; - const char *url_mark = 0; - const char *body_mark = 0; - - /* We're in an error state. Don't bother doing anything. */ - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { - return 0; - } - - if (len == 0) { - switch (parser->state) { - case s_body_identity_eof: - /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if - * we got paused. - */ - CALLBACK_NOTIFY_NOADVANCE(message_complete); - return 0; - - case s_dead: - case s_start_req_or_res: - case s_start_res: - case s_start_req: - return 0; - - default: - SET_ERRNO(HPE_INVALID_EOF_STATE); - return 1; - } - } - - - if (parser->state == s_header_field) - header_field_mark = data; - if (parser->state == s_header_value) - header_value_mark = data; - switch (parser->state) { - case s_req_path: - case s_req_schema: - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - case s_req_server: - case s_req_server_with_at: - case s_req_query_string_start: - case s_req_query_string: - case s_req_fragment_start: - case s_req_fragment: - url_mark = data; - break; - } - - for (p=data; p != data + len; p++) { - ch = *p; - - if (PARSING_HEADER(parser->state)) { - ++parser->nread; - /* Buffer overflow attack */ - if (parser->nread > HTTP_MAX_HEADER_SIZE) { - SET_ERRNO(HPE_HEADER_OVERFLOW); - goto error; - } - } - - reexecute_byte: - switch (parser->state) { - - case s_dead: - /* this state is used after a 'Connection: close' message - * the parser will error out if it reads another message - */ - if (ch == CR || ch == LF) - break; - - SET_ERRNO(HPE_CLOSED_CONNECTION); - goto error; - - case s_start_req_or_res: - { - if (ch == CR || ch == LF) - break; - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - if (ch == 'H') { - parser->state = s_res_or_resp_H; - - CALLBACK_NOTIFY(message_begin); - } else { - parser->type = HTTP_REQUEST; - parser->state = s_start_req; - goto reexecute_byte; - } - - break; - } - - case s_res_or_resp_H: - if (ch == 'T') { - parser->type = HTTP_RESPONSE; - parser->state = s_res_HT; - } else { - if (ch != 'E') { - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - - parser->type = HTTP_REQUEST; - parser->method = HTTP_HEAD; - parser->index = 2; - parser->state = s_req_method; - } - break; - - case s_start_res: - { - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - switch (ch) { - case 'H': - parser->state = s_res_H; - break; - - case CR: - case LF: - break; - - default: - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - - CALLBACK_NOTIFY(message_begin); - break; - } - - case s_res_H: - STRICT_CHECK(ch != 'T'); - parser->state = s_res_HT; - break; - - case s_res_HT: - STRICT_CHECK(ch != 'T'); - parser->state = s_res_HTT; - break; - - case s_res_HTT: - STRICT_CHECK(ch != 'P'); - parser->state = s_res_HTTP; - break; - - case s_res_HTTP: - STRICT_CHECK(ch != '/'); - parser->state = s_res_first_http_major; - break; - - case s_res_first_http_major: - if (ch < '0' || ch > '9') { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major = ch - '0'; - parser->state = s_res_http_major; - break; - - /* major HTTP version or dot */ - case s_res_http_major: - { - if (ch == '.') { - parser->state = s_res_first_http_minor; - break; - } - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major *= 10; - parser->http_major += ch - '0'; - - if (parser->http_major > 999) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* first digit of minor HTTP version */ - case s_res_first_http_minor: - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor = ch - '0'; - parser->state = s_res_http_minor; - break; - - /* minor HTTP version or end of request line */ - case s_res_http_minor: - { - if (ch == ' ') { - parser->state = s_res_first_status_code; - break; - } - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor *= 10; - parser->http_minor += ch - '0'; - - if (parser->http_minor > 999) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - case s_res_first_status_code: - { - if (!IS_NUM(ch)) { - if (ch == ' ') { - break; - } - - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - parser->status_code = ch - '0'; - parser->state = s_res_status_code; - break; - } - - case s_res_status_code: - { - if (!IS_NUM(ch)) { - switch (ch) { - case ' ': - parser->state = s_res_status; - break; - case CR: - parser->state = s_res_line_almost_done; - break; - case LF: - parser->state = s_header_field_start; - break; - default: - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - break; - } - - parser->status_code *= 10; - parser->status_code += ch - '0'; - - if (parser->status_code > 999) { - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - - break; - } - - case s_res_status: - /* the human readable status. e.g. "NOT FOUND" - * we are not humans so just ignore this */ - if (ch == CR) { - parser->state = s_res_line_almost_done; - break; - } - - if (ch == LF) { - parser->state = s_header_field_start; - break; - } - break; - - case s_res_line_almost_done: - STRICT_CHECK(ch != LF); - parser->state = s_header_field_start; - break; - - case s_start_req: - { - if (ch == CR || ch == LF) - break; - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - if (!IS_ALPHA(ch)) { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - parser->method = (enum http_method) 0; - parser->index = 1; - switch (ch) { - case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break; - case 'D': parser->method = HTTP_DELETE; break; - case 'G': parser->method = HTTP_GET; break; - case 'H': parser->method = HTTP_HEAD; break; - case 'L': parser->method = HTTP_LOCK; break; - case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break; - case 'N': parser->method = HTTP_NOTIFY; break; - case 'O': parser->method = HTTP_OPTIONS; break; - case 'P': parser->method = HTTP_POST; - /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ - break; - case 'R': parser->method = HTTP_REPORT; break; - case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break; - case 'T': parser->method = HTTP_TRACE; break; - case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break; - default: - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - parser->state = s_req_method; - - CALLBACK_NOTIFY(message_begin); - - break; - } - - case s_req_method: - { - const char *matcher; - if (ch == '\0') { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - matcher = method_strings[parser->method]; - if (ch == ' ' && matcher[parser->index] == '\0') { - parser->state = s_req_spaces_before_url; - } else if (ch == matcher[parser->index]) { - ; /* nada */ - } else if (parser->method == HTTP_CONNECT) { - if (parser->index == 1 && ch == 'H') { - parser->method = HTTP_CHECKOUT; - } else if (parser->index == 2 && ch == 'P') { - parser->method = HTTP_COPY; - } else { - goto error; - } - } else if (parser->method == HTTP_MKCOL) { - if (parser->index == 1 && ch == 'O') { - parser->method = HTTP_MOVE; - } else if (parser->index == 1 && ch == 'E') { - parser->method = HTTP_MERGE; - } else if (parser->index == 1 && ch == '-') { - parser->method = HTTP_MSEARCH; - } else if (parser->index == 2 && ch == 'A') { - parser->method = HTTP_MKACTIVITY; - } else { - goto error; - } - } else if (parser->method == HTTP_SUBSCRIBE) { - if (parser->index == 1 && ch == 'E') { - parser->method = HTTP_SEARCH; - } else { - goto error; - } - } else if (parser->index == 1 && parser->method == HTTP_POST) { - if (ch == 'R') { - parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */ - } else if (ch == 'U') { - parser->method = HTTP_PUT; /* or HTTP_PURGE */ - } else if (ch == 'A') { - parser->method = HTTP_PATCH; - } else { - goto error; - } - } else if (parser->index == 2) { - if (parser->method == HTTP_PUT) { - if (ch == 'R') parser->method = HTTP_PURGE; - } else if (parser->method == HTTP_UNLOCK) { - if (ch == 'S') parser->method = HTTP_UNSUBSCRIBE; - } - } else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') { - parser->method = HTTP_PROPPATCH; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - ++parser->index; - break; - } - - case s_req_spaces_before_url: - { - if (ch == ' ') break; - - MARK(url); - if (parser->method == HTTP_CONNECT) { - parser->state = s_req_server_start; - } - - parser->state = parse_url_char((enum state)parser->state, ch); - if (parser->state == s_dead) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - - break; - } - - case s_req_schema: - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - { - switch (ch) { - /* No whitespace allowed here */ - case ' ': - case CR: - case LF: - SET_ERRNO(HPE_INVALID_URL); - goto error; - default: - parser->state = parse_url_char((enum state)parser->state, ch); - if (parser->state == s_dead) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - } - - break; - } - - case s_req_server: - case s_req_server_with_at: - case s_req_path: - case s_req_query_string_start: - case s_req_query_string: - case s_req_fragment_start: - case s_req_fragment: - { - switch (ch) { - case ' ': - parser->state = s_req_http_start; - CALLBACK_DATA(url); - break; - case CR: - case LF: - parser->http_major = 0; - parser->http_minor = 9; - parser->state = (ch == CR) ? - s_req_line_almost_done : - s_header_field_start; - CALLBACK_DATA(url); - break; - default: - parser->state = parse_url_char((enum state)parser->state, ch); - if (parser->state == s_dead) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - } - break; - } - - case s_req_http_start: - switch (ch) { - case 'H': - parser->state = s_req_http_H; - break; - case ' ': - break; - default: - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - break; - - case s_req_http_H: - STRICT_CHECK(ch != 'T'); - parser->state = s_req_http_HT; - break; - - case s_req_http_HT: - STRICT_CHECK(ch != 'T'); - parser->state = s_req_http_HTT; - break; - - case s_req_http_HTT: - STRICT_CHECK(ch != 'P'); - parser->state = s_req_http_HTTP; - break; - - case s_req_http_HTTP: - STRICT_CHECK(ch != '/'); - parser->state = s_req_first_http_major; - break; - - /* first digit of major HTTP version */ - case s_req_first_http_major: - if (ch < '1' || ch > '9') { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major = ch - '0'; - parser->state = s_req_http_major; - break; - - /* major HTTP version or dot */ - case s_req_http_major: - { - if (ch == '.') { - parser->state = s_req_first_http_minor; - break; - } - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major *= 10; - parser->http_major += ch - '0'; - - if (parser->http_major > 999) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* first digit of minor HTTP version */ - case s_req_first_http_minor: - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor = ch - '0'; - parser->state = s_req_http_minor; - break; - - /* minor HTTP version or end of request line */ - case s_req_http_minor: - { - if (ch == CR) { - parser->state = s_req_line_almost_done; - break; - } - - if (ch == LF) { - parser->state = s_header_field_start; - break; - } - - /* XXX allow spaces after digit? */ - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor *= 10; - parser->http_minor += ch - '0'; - - if (parser->http_minor > 999) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* end of request line */ - case s_req_line_almost_done: - { - if (ch != LF) { - SET_ERRNO(HPE_LF_EXPECTED); - goto error; - } - - parser->state = s_header_field_start; - break; - } - - case s_header_field_start: - { - if (ch == CR) { - parser->state = s_headers_almost_done; - break; - } - - if (ch == LF) { - /* they might be just sending \n instead of \r\n so this would be - * the second \n to denote the end of headers*/ - parser->state = s_headers_almost_done; - goto reexecute_byte; - } - - c = TOKEN(ch); - - if (!c) { - SET_ERRNO(HPE_INVALID_HEADER_TOKEN); - goto error; - } - - MARK(header_field); - - parser->index = 0; - parser->state = s_header_field; - - switch (c) { - case 'c': - parser->header_state = h_C; - break; - - case 'p': - parser->header_state = h_matching_proxy_connection; - break; - - case 't': - parser->header_state = h_matching_transfer_encoding; - break; - - case 'u': - parser->header_state = h_matching_upgrade; - break; - - default: - parser->header_state = h_general; - break; - } - break; - } - - case s_header_field: - { - c = TOKEN(ch); - - if (c) { - switch (parser->header_state) { - case h_general: - break; - - case h_C: - parser->index++; - parser->header_state = (c == 'o' ? h_CO : h_general); - break; - - case h_CO: - parser->index++; - parser->header_state = (c == 'n' ? h_CON : h_general); - break; - - case h_CON: - parser->index++; - switch (c) { - case 'n': - parser->header_state = h_matching_connection; - break; - case 't': - parser->header_state = h_matching_content_length; - break; - default: - parser->header_state = h_general; - break; - } - break; - - /* connection */ - - case h_matching_connection: - parser->index++; - if (parser->index > sizeof(CONNECTION)-1 - || c != CONNECTION[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CONNECTION)-2) { - parser->header_state = h_connection; - } - break; - - /* proxy-connection */ - - case h_matching_proxy_connection: - parser->index++; - if (parser->index > sizeof(PROXY_CONNECTION)-1 - || c != PROXY_CONNECTION[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(PROXY_CONNECTION)-2) { - parser->header_state = h_connection; - } - break; - - /* content-length */ - - case h_matching_content_length: - parser->index++; - if (parser->index > sizeof(CONTENT_LENGTH)-1 - || c != CONTENT_LENGTH[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CONTENT_LENGTH)-2) { - parser->header_state = h_content_length; - } - break; - - /* transfer-encoding */ - - case h_matching_transfer_encoding: - parser->index++; - if (parser->index > sizeof(TRANSFER_ENCODING)-1 - || c != TRANSFER_ENCODING[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) { - parser->header_state = h_transfer_encoding; - } - break; - - /* upgrade */ - - case h_matching_upgrade: - parser->index++; - if (parser->index > sizeof(UPGRADE)-1 - || c != UPGRADE[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(UPGRADE)-2) { - parser->header_state = h_upgrade; - } - break; - - case h_connection: - case h_content_length: - case h_transfer_encoding: - case h_upgrade: - if (ch != ' ') parser->header_state = h_general; - break; - - default: - assert(0 && "Unknown header_state"); - break; - } - break; - } - - if (ch == ':') { - parser->state = s_header_value_start; - CALLBACK_DATA(header_field); - break; - } - - if (ch == CR) { - parser->state = s_header_almost_done; - CALLBACK_DATA(header_field); - break; - } - - if (ch == LF) { - parser->state = s_header_field_start; - CALLBACK_DATA(header_field); - break; - } - - SET_ERRNO(HPE_INVALID_HEADER_TOKEN); - goto error; - } - - case s_header_value_start: - { - if (ch == ' ' || ch == '\t') break; - - MARK(header_value); - - parser->state = s_header_value; - parser->index = 0; - - if (ch == CR) { - parser->header_state = h_general; - parser->state = s_header_almost_done; - CALLBACK_DATA(header_value); - break; - } - - if (ch == LF) { - parser->state = s_header_field_start; - CALLBACK_DATA(header_value); - break; - } - - c = LOWER(ch); - - switch (parser->header_state) { - case h_upgrade: - parser->flags |= F_UPGRADE; - parser->header_state = h_general; - break; - - case h_transfer_encoding: - /* looking for 'Transfer-Encoding: chunked' */ - if ('c' == c) { - parser->header_state = h_matching_transfer_encoding_chunked; - } else { - parser->header_state = h_general; - } - break; - - case h_content_length: - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - parser->content_length = ch - '0'; - break; - - case h_connection: - /* looking for 'Connection: keep-alive' */ - if (c == 'k') { - parser->header_state = h_matching_connection_keep_alive; - /* looking for 'Connection: close' */ - } else if (c == 'c') { - parser->header_state = h_matching_connection_close; - } else { - parser->header_state = h_general; - } - break; - - default: - parser->header_state = h_general; - break; - } - break; - } - - case s_header_value: - { - - if (ch == CR) { - parser->state = s_header_almost_done; - CALLBACK_DATA(header_value); - break; - } - - if (ch == LF) { - parser->state = s_header_almost_done; - CALLBACK_DATA_NOADVANCE(header_value); - goto reexecute_byte; - } - - c = LOWER(ch); - - switch (parser->header_state) { - case h_general: - break; - - case h_connection: - case h_transfer_encoding: - assert(0 && "Shouldn't get here."); - break; - - case h_content_length: - { - uint64_t t; - - if (ch == ' ') break; - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - t = parser->content_length; - t *= 10; - t += ch - '0'; - - /* Overflow? */ - if (t < parser->content_length || t == ULLONG_MAX) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - parser->content_length = t; - break; - } - - /* Transfer-Encoding: chunked */ - case h_matching_transfer_encoding_chunked: - parser->index++; - if (parser->index > sizeof(CHUNKED)-1 - || c != CHUNKED[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CHUNKED)-2) { - parser->header_state = h_transfer_encoding_chunked; - } - break; - - /* looking for 'Connection: keep-alive' */ - case h_matching_connection_keep_alive: - parser->index++; - if (parser->index > sizeof(KEEP_ALIVE)-1 - || c != KEEP_ALIVE[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(KEEP_ALIVE)-2) { - parser->header_state = h_connection_keep_alive; - } - break; - - /* looking for 'Connection: close' */ - case h_matching_connection_close: - parser->index++; - if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CLOSE)-2) { - parser->header_state = h_connection_close; - } - break; - - case h_transfer_encoding_chunked: - case h_connection_keep_alive: - case h_connection_close: - if (ch != ' ') parser->header_state = h_general; - break; - - default: - parser->state = s_header_value; - parser->header_state = h_general; - break; - } - break; - } - - case s_header_almost_done: - { - STRICT_CHECK(ch != LF); - - parser->state = s_header_value_lws; - - switch (parser->header_state) { - case h_connection_keep_alive: - parser->flags |= F_CONNECTION_KEEP_ALIVE; - break; - case h_connection_close: - parser->flags |= F_CONNECTION_CLOSE; - break; - case h_transfer_encoding_chunked: - parser->flags |= F_CHUNKED; - break; - default: - break; - } - - break; - } - - case s_header_value_lws: - { - if (ch == ' ' || ch == '\t') - parser->state = s_header_value_start; - else - { - parser->state = s_header_field_start; - goto reexecute_byte; - } - break; - } - - case s_headers_almost_done: - { - STRICT_CHECK(ch != LF); - - if (parser->flags & F_TRAILING) { - /* End of a chunked request */ - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - break; - } - - parser->state = s_headers_done; - - /* Set this here so that on_headers_complete() callbacks can see it */ - parser->upgrade = - (parser->flags & F_UPGRADE || parser->method == HTTP_CONNECT); - - /* Here we call the headers_complete callback. This is somewhat - * different than other callbacks because if the user returns 1, we - * will interpret that as saying that this message has no body. This - * is needed for the annoying case of recieving a response to a HEAD - * request. - * - * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so - * we have to simulate it by handling a change in errno below. - */ - if (settings->on_headers_complete) { - switch (settings->on_headers_complete(parser)) { - case 0: - break; - - case 1: - parser->flags |= F_SKIPBODY; - break; - - default: - SET_ERRNO(HPE_CB_headers_complete); - return p - data; /* Error */ - } - } - - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { - return p - data; - } - - goto reexecute_byte; - } - - case s_headers_done: - { - STRICT_CHECK(ch != LF); - - parser->nread = 0; - - /* Exit, the rest of the connect is in a different protocol. */ - if (parser->upgrade) { - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - return (p - data) + 1; - } - - if (parser->flags & F_SKIPBODY) { - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - } else if (parser->flags & F_CHUNKED) { - /* chunked encoding - ignore Content-Length header */ - parser->state = s_chunk_size_start; - } else { - if (parser->content_length == 0) { - /* Content-Length header given but zero: Content-Length: 0\r\n */ - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - } else if (parser->content_length != ULLONG_MAX) { - /* Content-Length header given and non-zero */ - parser->state = s_body_identity; - } else { - if (parser->type == HTTP_REQUEST || - !http_message_needs_eof(parser)) { - /* Assume content-length 0 - read the next */ - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - } else { - /* Read body until EOF */ - parser->state = s_body_identity_eof; - } - } - } - - break; - } - - case s_body_identity: - { - uint64_t to_read = MIN(parser->content_length, - (uint64_t) ((data + len) - p)); - - assert(parser->content_length != 0 - && parser->content_length != ULLONG_MAX); - - /* The difference between advancing content_length and p is because - * the latter will automaticaly advance on the next loop iteration. - * Further, if content_length ends up at 0, we want to see the last - * byte again for our message complete callback. - */ - MARK(body); - parser->content_length -= to_read; - p += to_read - 1; - - if (parser->content_length == 0) { - parser->state = s_message_done; - - /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte. - * - * The alternative to doing this is to wait for the next byte to - * trigger the data callback, just as in every other case. The - * problem with this is that this makes it difficult for the test - * harness to distinguish between complete-on-EOF and - * complete-on-length. It's not clear that this distinction is - * important for applications, but let's keep it for now. - */ - CALLBACK_DATA_(body, p - body_mark + 1, p - data); - goto reexecute_byte; - } - - break; - } - - /* read until EOF */ - case s_body_identity_eof: - MARK(body); - p = data + len - 1; - - break; - - case s_message_done: - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - break; - - case s_chunk_size_start: - { - assert(parser->nread == 1); - assert(parser->flags & F_CHUNKED); - - unhex_val = unhex[(unsigned char)ch]; - if (unhex_val == -1) { - SET_ERRNO(HPE_INVALID_CHUNK_SIZE); - goto error; - } - - parser->content_length = unhex_val; - parser->state = s_chunk_size; - break; - } - - case s_chunk_size: - { - uint64_t t; - - assert(parser->flags & F_CHUNKED); - - if (ch == CR) { - parser->state = s_chunk_size_almost_done; - break; - } - - unhex_val = unhex[(unsigned char)ch]; - - if (unhex_val == -1) { - if (ch == ';' || ch == ' ') { - parser->state = s_chunk_parameters; - break; - } - - SET_ERRNO(HPE_INVALID_CHUNK_SIZE); - goto error; - } - - t = parser->content_length; - t *= 16; - t += unhex_val; - - /* Overflow? */ - if (t < parser->content_length || t == ULLONG_MAX) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - parser->content_length = t; - break; - } - - case s_chunk_parameters: - { - assert(parser->flags & F_CHUNKED); - /* just ignore this. TODO check for overflow */ - if (ch == CR) { - parser->state = s_chunk_size_almost_done; - break; - } - break; - } - - case s_chunk_size_almost_done: - { - assert(parser->flags & F_CHUNKED); - STRICT_CHECK(ch != LF); - - parser->nread = 0; - - if (parser->content_length == 0) { - parser->flags |= F_TRAILING; - parser->state = s_header_field_start; - } else { - parser->state = s_chunk_data; - } - break; - } - - case s_chunk_data: - { - uint64_t to_read = MIN(parser->content_length, - (uint64_t) ((data + len) - p)); - - assert(parser->flags & F_CHUNKED); - assert(parser->content_length != 0 - && parser->content_length != ULLONG_MAX); - - /* See the explanation in s_body_identity for why the content - * length and data pointers are managed this way. - */ - MARK(body); - parser->content_length -= to_read; - p += to_read - 1; - - if (parser->content_length == 0) { - parser->state = s_chunk_data_almost_done; - } - - break; - } - - case s_chunk_data_almost_done: - assert(parser->flags & F_CHUNKED); - assert(parser->content_length == 0); - STRICT_CHECK(ch != CR); - parser->state = s_chunk_data_done; - CALLBACK_DATA(body); - break; - - case s_chunk_data_done: - assert(parser->flags & F_CHUNKED); - STRICT_CHECK(ch != LF); - parser->nread = 0; - parser->state = s_chunk_size_start; - break; - - default: - assert(0 && "unhandled state"); - SET_ERRNO(HPE_INVALID_INTERNAL_STATE); - goto error; - } - } - - /* Run callbacks for any marks that we have leftover after we ran our of - * bytes. There should be at most one of these set, so it's OK to invoke - * them in series (unset marks will not result in callbacks). - * - * We use the NOADVANCE() variety of callbacks here because 'p' has already - * overflowed 'data' and this allows us to correct for the off-by-one that - * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p' - * value that's in-bounds). - */ - - assert(((header_field_mark ? 1 : 0) + - (header_value_mark ? 1 : 0) + - (url_mark ? 1 : 0) + - (body_mark ? 1 : 0)) <= 1); - - CALLBACK_DATA_NOADVANCE(header_field); - CALLBACK_DATA_NOADVANCE(header_value); - CALLBACK_DATA_NOADVANCE(url); - CALLBACK_DATA_NOADVANCE(body); - - return len; - -error: - if (HTTP_PARSER_ERRNO(parser) == HPE_OK) { - SET_ERRNO(HPE_UNKNOWN); - } - - return (p - data); -} - - -/* Does the parser need to see an EOF to find the end of the message? */ -int -http_message_needs_eof (const http_parser *parser) -{ - if (parser->type == HTTP_REQUEST) { - return 0; - } - - /* See RFC 2616 section 4.4 */ - if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ - parser->status_code == 204 || /* No Content */ - parser->status_code == 304 || /* Not Modified */ - parser->flags & F_SKIPBODY) { /* response to a HEAD request */ - return 0; - } - - if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) { - return 0; - } - - return 1; -} - - -int -http_should_keep_alive (const http_parser *parser) -{ - if (parser->http_major > 0 && parser->http_minor > 0) { - /* HTTP/1.1 */ - if (parser->flags & F_CONNECTION_CLOSE) { - return 0; - } - } else { - /* HTTP/1.0 or earlier */ - if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) { - return 0; - } - } - - return !http_message_needs_eof(parser); -} - - -const char * -http_method_str (enum http_method m) -{ - return ELEM_AT(method_strings, m, ""); -} - - -void -http_parser_init (http_parser *parser, enum http_parser_type t) -{ - void *data = parser->data; /* preserve application data */ - memset(parser, 0, sizeof(*parser)); - parser->data = data; - parser->type = t; - parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res)); - parser->http_errno = HPE_OK; -} - -const char * -http_errno_name(enum http_errno err) { - assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0]))); - return http_strerror_tab[err].name; -} - -const char * -http_errno_description(enum http_errno err) { - assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0]))); - return http_strerror_tab[err].description; -} - -static enum http_host_state -http_parse_host_char(enum http_host_state s, const char ch) { - switch(s) { - case s_http_userinfo: - case s_http_userinfo_start: - if (ch == '@') { - return s_http_host_start; - } - - if (IS_USERINFO_CHAR(ch)) { - return s_http_userinfo; - } - break; - - case s_http_host_start: - if (ch == '[') { - return s_http_host_v6_start; - } - - if (IS_HOST_CHAR(ch)) { - return s_http_host; - } - - break; - - case s_http_host: - if (IS_HOST_CHAR(ch)) { - return s_http_host; - } - - /* FALLTHROUGH */ - case s_http_host_v6_end: - if (ch == ':') { - return s_http_host_port_start; - } - - break; - - case s_http_host_v6: - if (ch == ']') { - return s_http_host_v6_end; - } - - /* FALLTHROUGH */ - case s_http_host_v6_start: - if (IS_HEX(ch) || ch == ':') { - return s_http_host_v6; - } - - break; - - case s_http_host_port: - case s_http_host_port_start: - if (IS_NUM(ch)) { - return s_http_host_port; - } - - break; - - default: - break; - } - return s_http_host_dead; -} - -static int -http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { - enum http_host_state s; - - const char *p; - size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len; - - if (buflen > UINT16_MAX) - return 1; - - u->field_data[UF_HOST].len = 0; - - s = found_at ? s_http_userinfo_start : s_http_host_start; - - for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) { - enum http_host_state new_s = http_parse_host_char(s, *p); - - if (new_s == s_http_host_dead) { - return 1; - } - - switch(new_s) { - case s_http_host: - if (s != s_http_host) { - u->field_data[UF_HOST].off = (uint16_t)(p - buf); - } - u->field_data[UF_HOST].len++; - break; - - case s_http_host_v6: - if (s != s_http_host_v6) { - u->field_data[UF_HOST].off = (uint16_t)(p - buf); - } - u->field_data[UF_HOST].len++; - break; - - case s_http_host_port: - if (s != s_http_host_port) { - u->field_data[UF_PORT].off = (uint16_t)(p - buf); - u->field_data[UF_PORT].len = 0; - u->field_set |= (1 << UF_PORT); - } - u->field_data[UF_PORT].len++; - break; - - case s_http_userinfo: - if (s != s_http_userinfo) { - u->field_data[UF_USERINFO].off = (uint16_t)(p - buf); - u->field_data[UF_USERINFO].len = 0; - u->field_set |= (1 << UF_USERINFO); - } - u->field_data[UF_USERINFO].len++; - break; - - default: - break; - } - s = new_s; - } - - /* Make sure we don't end somewhere unexpected */ - switch (s) { - case s_http_host_start: - case s_http_host_v6_start: - case s_http_host_v6: - case s_http_userinfo: - case s_http_userinfo_start: - return 1; - default: - break; - } - - return 0; -} - -int -http_parser_parse_url(const char *buf, size_t buflen, int is_connect, - struct http_parser_url *u) -{ - enum state s; - const char *p; - enum http_parser_url_fields uf, old_uf; - int found_at = 0; - - if (buflen > UINT16_MAX) - return 1; - - u->port = u->field_set = 0; - s = is_connect ? s_req_server_start : s_req_spaces_before_url; - uf = old_uf = UF_MAX; - - for (p = buf; p < buf + buflen; p++) { - s = parse_url_char(s, *p); - - /* Figure out the next field that we're operating on */ - switch (s) { - case s_dead: - return 1; - - /* Skip delimeters */ - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - case s_req_query_string_start: - case s_req_fragment_start: - continue; - - case s_req_schema: - uf = UF_SCHEMA; - break; - - case s_req_server_with_at: - found_at = 1; - - /* FALLTROUGH */ - case s_req_server: - uf = UF_HOST; - break; - - case s_req_path: - uf = UF_PATH; - break; - - case s_req_query_string: - uf = UF_QUERY; - break; - - case s_req_fragment: - uf = UF_FRAGMENT; - break; - - default: - assert(!"Unexpected state"); - return 1; - } - - /* Nothing's changed; soldier on */ - if (uf == old_uf) { - u->field_data[uf].len++; - continue; - } - - u->field_data[uf].off = (uint16_t)(p - buf); - u->field_data[uf].len = 1; - - u->field_set |= (1 << uf); - old_uf = uf; - } - - /* host must be present if there is a schema */ - /* parsing http:///toto will fail */ - if ((u->field_set & ((1 << UF_SCHEMA) | (1 << UF_HOST))) != 0) { - if (http_parse_host(buf, u, found_at) != 0) { - return 1; - } - } - - /* CONNECT requests can only contain "hostname:port" */ - if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) { - return 1; - } - - if (u->field_set & (1 << UF_PORT)) { - /* Don't bother with endp; we've already validated the string */ - unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10); - - /* Ports have a max value of 2^16 */ - if (v > 0xffff) { - return 1; - } - - u->port = (uint16_t) v; - } - - return 0; -} - -void -http_parser_pause(http_parser *parser, int paused) { - /* Users should only be pausing/unpausing a parser that is not in an error - * state. In non-debug builds, there's not much that we can do about this - * other than ignore it. - */ - if (HTTP_PARSER_ERRNO(parser) == HPE_OK || - HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) { - SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK); - } else { - assert(0 && "Attempting to pause parser in error state"); - } -} - -int -http_body_is_final(const struct http_parser *parser) { - return parser->state == s_message_done; -} diff --git a/vendor/libgit2/deps/http-parser/http_parser.h b/vendor/libgit2/deps/http-parser/http_parser.h deleted file mode 100644 index 67e1d95d..00000000 --- a/vendor/libgit2/deps/http-parser/http_parser.h +++ /dev/null @@ -1,305 +0,0 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#ifndef http_parser_h -#define http_parser_h -#ifdef __cplusplus -extern "C" { -#endif - -#define HTTP_PARSER_VERSION_MAJOR 2 -#define HTTP_PARSER_VERSION_MINOR 0 - -#include -#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) -#include -typedef __int8 int8_t; -typedef unsigned __int8 uint8_t; -typedef __int16 int16_t; -typedef unsigned __int16 uint16_t; -typedef __int32 int32_t; -typedef unsigned __int32 uint32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -typedef SIZE_T size_t; -typedef SSIZE_T ssize_t; -#elif defined(__sun) || defined(__sun__) -#include -#else -#include -#endif - -/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run - * faster - */ -#ifndef HTTP_PARSER_STRICT -# define HTTP_PARSER_STRICT 1 -#endif - -/* Maximium header size allowed */ -#define HTTP_MAX_HEADER_SIZE (80*1024) - - -typedef struct http_parser http_parser; -typedef struct http_parser_settings http_parser_settings; - - -/* Callbacks should return non-zero to indicate an error. The parser will - * then halt execution. - * - * The one exception is on_headers_complete. In a HTTP_RESPONSE parser - * returning '1' from on_headers_complete will tell the parser that it - * should not expect a body. This is used when receiving a response to a - * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: - * chunked' headers that indicate the presence of a body. - * - * http_data_cb does not return data chunks. It will be call arbitrarally - * many times for each string. E.G. you might get 10 callbacks for "on_url" - * each providing just a few characters more data. - */ -typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); -typedef int (*http_cb) (http_parser*); - - -/* Request Methods */ -#define HTTP_METHOD_MAP(XX) \ - XX(0, DELETE, DELETE) \ - XX(1, GET, GET) \ - XX(2, HEAD, HEAD) \ - XX(3, POST, POST) \ - XX(4, PUT, PUT) \ - /* pathological */ \ - XX(5, CONNECT, CONNECT) \ - XX(6, OPTIONS, OPTIONS) \ - XX(7, TRACE, TRACE) \ - /* webdav */ \ - XX(8, COPY, COPY) \ - XX(9, LOCK, LOCK) \ - XX(10, MKCOL, MKCOL) \ - XX(11, MOVE, MOVE) \ - XX(12, PROPFIND, PROPFIND) \ - XX(13, PROPPATCH, PROPPATCH) \ - XX(14, SEARCH, SEARCH) \ - XX(15, UNLOCK, UNLOCK) \ - /* subversion */ \ - XX(16, REPORT, REPORT) \ - XX(17, MKACTIVITY, MKACTIVITY) \ - XX(18, CHECKOUT, CHECKOUT) \ - XX(19, MERGE, MERGE) \ - /* upnp */ \ - XX(20, MSEARCH, M-SEARCH) \ - XX(21, NOTIFY, NOTIFY) \ - XX(22, SUBSCRIBE, SUBSCRIBE) \ - XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \ - /* RFC-5789 */ \ - XX(24, PATCH, PATCH) \ - XX(25, PURGE, PURGE) \ - -enum http_method - { -#define XX(num, name, string) HTTP_##name = num, - HTTP_METHOD_MAP(XX) -#undef XX - }; - - -enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; - - -/* Flag values for http_parser.flags field */ -enum flags - { F_CHUNKED = 1 << 0 - , F_CONNECTION_KEEP_ALIVE = 1 << 1 - , F_CONNECTION_CLOSE = 1 << 2 - , F_TRAILING = 1 << 3 - , F_UPGRADE = 1 << 4 - , F_SKIPBODY = 1 << 5 - }; - - -/* Map for errno-related constants - * - * The provided argument should be a macro that takes 2 arguments. - */ -#define HTTP_ERRNO_MAP(XX) \ - /* No error */ \ - XX(OK, "success") \ - \ - /* Callback-related errors */ \ - XX(CB_message_begin, "the on_message_begin callback failed") \ - XX(CB_url, "the on_url callback failed") \ - XX(CB_header_field, "the on_header_field callback failed") \ - XX(CB_header_value, "the on_header_value callback failed") \ - XX(CB_headers_complete, "the on_headers_complete callback failed") \ - XX(CB_body, "the on_body callback failed") \ - XX(CB_message_complete, "the on_message_complete callback failed") \ - \ - /* Parsing-related errors */ \ - XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ - XX(HEADER_OVERFLOW, \ - "too many header bytes seen; overflow detected") \ - XX(CLOSED_CONNECTION, \ - "data received after completed connection: close message") \ - XX(INVALID_VERSION, "invalid HTTP version") \ - XX(INVALID_STATUS, "invalid HTTP status code") \ - XX(INVALID_METHOD, "invalid HTTP method") \ - XX(INVALID_URL, "invalid URL") \ - XX(INVALID_HOST, "invalid host") \ - XX(INVALID_PORT, "invalid port") \ - XX(INVALID_PATH, "invalid path") \ - XX(INVALID_QUERY_STRING, "invalid query string") \ - XX(INVALID_FRAGMENT, "invalid fragment") \ - XX(LF_EXPECTED, "LF character expected") \ - XX(INVALID_HEADER_TOKEN, "invalid character in header") \ - XX(INVALID_CONTENT_LENGTH, \ - "invalid character in content-length header") \ - XX(INVALID_CHUNK_SIZE, \ - "invalid character in chunk size header") \ - XX(INVALID_CONSTANT, "invalid constant string") \ - XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ - XX(STRICT, "strict mode assertion failed") \ - XX(PAUSED, "parser is paused") \ - XX(UNKNOWN, "an unknown error occurred") - - -/* Define HPE_* values for each errno value above */ -#define HTTP_ERRNO_GEN(n, s) HPE_##n, -enum http_errno { - HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) -}; -#undef HTTP_ERRNO_GEN - - -/* Get an http_errno value from an http_parser */ -#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) - - -struct http_parser { - /** PRIVATE **/ - unsigned char type : 2; /* enum http_parser_type */ - unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */ - unsigned char state; /* enum state from http_parser.c */ - unsigned char header_state; /* enum header_state from http_parser.c */ - unsigned char index; /* index into current matcher */ - - uint32_t nread; /* # bytes read in various scenarios */ - uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ - - /** READ-ONLY **/ - unsigned short http_major; - unsigned short http_minor; - unsigned short status_code; /* responses only */ - unsigned char method; /* requests only */ - unsigned char http_errno : 7; - - /* 1 = Upgrade header was present and the parser has exited because of that. - * 0 = No upgrade header present. - * Should be checked when http_parser_execute() returns in addition to - * error checking. - */ - unsigned char upgrade : 1; - - /** PUBLIC **/ - void *data; /* A pointer to get hook to the "connection" or "socket" object */ -}; - - -struct http_parser_settings { - http_cb on_message_begin; - http_data_cb on_url; - http_data_cb on_header_field; - http_data_cb on_header_value; - http_cb on_headers_complete; - http_data_cb on_body; - http_cb on_message_complete; -}; - - -enum http_parser_url_fields - { UF_SCHEMA = 0 - , UF_HOST = 1 - , UF_PORT = 2 - , UF_PATH = 3 - , UF_QUERY = 4 - , UF_FRAGMENT = 5 - , UF_USERINFO = 6 - , UF_MAX = 7 - }; - - -/* Result structure for http_parser_parse_url(). - * - * Callers should index into field_data[] with UF_* values iff field_set - * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and - * because we probably have padding left over), we convert any port to - * a uint16_t. - */ -struct http_parser_url { - uint16_t field_set; /* Bitmask of (1 << UF_*) values */ - uint16_t port; /* Converted UF_PORT string */ - - struct { - uint16_t off; /* Offset into buffer in which field starts */ - uint16_t len; /* Length of run in buffer */ - } field_data[UF_MAX]; -}; - - -void http_parser_init(http_parser *parser, enum http_parser_type type); - - -size_t http_parser_execute(http_parser *parser, - const http_parser_settings *settings, - const char *data, - size_t len); - - -/* If http_should_keep_alive() in the on_headers_complete or - * on_message_complete callback returns 0, then this should be - * the last message on the connection. - * If you are the server, respond with the "Connection: close" header. - * If you are the client, close the connection. - */ -int http_should_keep_alive(const http_parser *parser); - -/* Returns a string version of the HTTP method. */ -const char *http_method_str(enum http_method m); - -/* Return a string name of the given error */ -const char *http_errno_name(enum http_errno err); - -/* Return a string description of the given error */ -const char *http_errno_description(enum http_errno err); - -/* Parse a URL; return nonzero on failure */ -int http_parser_parse_url(const char *buf, size_t buflen, - int is_connect, - struct http_parser_url *u); - -/* Pause or un-pause the parser; a nonzero value pauses */ -void http_parser_pause(http_parser *parser, int paused); - -/* Checks if this is the final chunk of the body. */ -int http_body_is_final(const http_parser *parser); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/vendor/libgit2/deps/llhttp/CMakeLists.txt b/vendor/libgit2/deps/llhttp/CMakeLists.txt new file mode 100644 index 00000000..6965335a --- /dev/null +++ b/vendor/libgit2/deps/llhttp/CMakeLists.txt @@ -0,0 +1,8 @@ +file(GLOB SRC_LLHTTP "*.c" "*.h") +list(SORT SRC_LLHTTP) + +add_library(llhttp OBJECT ${SRC_LLHTTP}) + +if(NOT MSVC) + set_source_files_properties(api.c http.c llhttp.c PROPERTIES COMPILE_FLAGS "-Wno-unused-parameter -Wno-missing-declarations") +endif() diff --git a/vendor/libgit2/deps/llhttp/LICENSE-MIT b/vendor/libgit2/deps/llhttp/LICENSE-MIT new file mode 100644 index 00000000..6c1512dd --- /dev/null +++ b/vendor/libgit2/deps/llhttp/LICENSE-MIT @@ -0,0 +1,22 @@ +This software is licensed under the MIT License. + +Copyright Fedor Indutny, 2018. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/libgit2/deps/llhttp/api.c b/vendor/libgit2/deps/llhttp/api.c new file mode 100644 index 00000000..8c2ce3dc --- /dev/null +++ b/vendor/libgit2/deps/llhttp/api.c @@ -0,0 +1,510 @@ +#include +#include +#include + +#include "llhttp.h" + +#define CALLBACK_MAYBE(PARSER, NAME) \ + do { \ + const llhttp_settings_t* settings; \ + settings = (const llhttp_settings_t*) (PARSER)->settings; \ + if (settings == NULL || settings->NAME == NULL) { \ + err = 0; \ + break; \ + } \ + err = settings->NAME((PARSER)); \ + } while (0) + +#define SPAN_CALLBACK_MAYBE(PARSER, NAME, START, LEN) \ + do { \ + const llhttp_settings_t* settings; \ + settings = (const llhttp_settings_t*) (PARSER)->settings; \ + if (settings == NULL || settings->NAME == NULL) { \ + err = 0; \ + break; \ + } \ + err = settings->NAME((PARSER), (START), (LEN)); \ + if (err == -1) { \ + err = HPE_USER; \ + llhttp_set_error_reason((PARSER), "Span callback error in " #NAME); \ + } \ + } while (0) + +void llhttp_init(llhttp_t* parser, llhttp_type_t type, + const llhttp_settings_t* settings) { + llhttp__internal_init(parser); + + parser->type = type; + parser->settings = (void*) settings; +} + + +#if defined(__wasm__) + +extern int wasm_on_message_begin(llhttp_t * p); +extern int wasm_on_url(llhttp_t* p, const char* at, size_t length); +extern int wasm_on_status(llhttp_t* p, const char* at, size_t length); +extern int wasm_on_header_field(llhttp_t* p, const char* at, size_t length); +extern int wasm_on_header_value(llhttp_t* p, const char* at, size_t length); +extern int wasm_on_headers_complete(llhttp_t * p, int status_code, + uint8_t upgrade, int should_keep_alive); +extern int wasm_on_body(llhttp_t* p, const char* at, size_t length); +extern int wasm_on_message_complete(llhttp_t * p); + +static int wasm_on_headers_complete_wrap(llhttp_t* p) { + return wasm_on_headers_complete(p, p->status_code, p->upgrade, + llhttp_should_keep_alive(p)); +} + +const llhttp_settings_t wasm_settings = { + wasm_on_message_begin, + wasm_on_url, + wasm_on_status, + NULL, + NULL, + wasm_on_header_field, + wasm_on_header_value, + NULL, + NULL, + wasm_on_headers_complete_wrap, + wasm_on_body, + wasm_on_message_complete, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +}; + + +llhttp_t* llhttp_alloc(llhttp_type_t type) { + llhttp_t* parser = malloc(sizeof(llhttp_t)); + llhttp_init(parser, type, &wasm_settings); + return parser; +} + +void llhttp_free(llhttp_t* parser) { + free(parser); +} + +#endif // defined(__wasm__) + +/* Some getters required to get stuff from the parser */ + +uint8_t llhttp_get_type(llhttp_t* parser) { + return parser->type; +} + +uint8_t llhttp_get_http_major(llhttp_t* parser) { + return parser->http_major; +} + +uint8_t llhttp_get_http_minor(llhttp_t* parser) { + return parser->http_minor; +} + +uint8_t llhttp_get_method(llhttp_t* parser) { + return parser->method; +} + +int llhttp_get_status_code(llhttp_t* parser) { + return parser->status_code; +} + +uint8_t llhttp_get_upgrade(llhttp_t* parser) { + return parser->upgrade; +} + + +void llhttp_reset(llhttp_t* parser) { + llhttp_type_t type = parser->type; + const llhttp_settings_t* settings = parser->settings; + void* data = parser->data; + uint16_t lenient_flags = parser->lenient_flags; + + llhttp__internal_init(parser); + + parser->type = type; + parser->settings = (void*) settings; + parser->data = data; + parser->lenient_flags = lenient_flags; +} + + +llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len) { + return llhttp__internal_execute(parser, data, data + len); +} + + +void llhttp_settings_init(llhttp_settings_t* settings) { + memset(settings, 0, sizeof(*settings)); +} + + +llhttp_errno_t llhttp_finish(llhttp_t* parser) { + int err; + + /* We're in an error state. Don't bother doing anything. */ + if (parser->error != 0) { + return 0; + } + + switch (parser->finish) { + case HTTP_FINISH_SAFE_WITH_CB: + CALLBACK_MAYBE(parser, on_message_complete); + if (err != HPE_OK) return err; + + /* FALLTHROUGH */ + case HTTP_FINISH_SAFE: + return HPE_OK; + case HTTP_FINISH_UNSAFE: + parser->reason = "Invalid EOF state"; + return HPE_INVALID_EOF_STATE; + default: + abort(); + } +} + + +void llhttp_pause(llhttp_t* parser) { + if (parser->error != HPE_OK) { + return; + } + + parser->error = HPE_PAUSED; + parser->reason = "Paused"; +} + + +void llhttp_resume(llhttp_t* parser) { + if (parser->error != HPE_PAUSED) { + return; + } + + parser->error = 0; +} + + +void llhttp_resume_after_upgrade(llhttp_t* parser) { + if (parser->error != HPE_PAUSED_UPGRADE) { + return; + } + + parser->error = 0; +} + + +llhttp_errno_t llhttp_get_errno(const llhttp_t* parser) { + return parser->error; +} + + +const char* llhttp_get_error_reason(const llhttp_t* parser) { + return parser->reason; +} + + +void llhttp_set_error_reason(llhttp_t* parser, const char* reason) { + parser->reason = reason; +} + + +const char* llhttp_get_error_pos(const llhttp_t* parser) { + return parser->error_pos; +} + + +const char* llhttp_errno_name(llhttp_errno_t err) { +#define HTTP_ERRNO_GEN(CODE, NAME, _) case HPE_##NAME: return "HPE_" #NAME; + switch (err) { + HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) + default: abort(); + } +#undef HTTP_ERRNO_GEN +} + + +const char* llhttp_method_name(llhttp_method_t method) { +#define HTTP_METHOD_GEN(NUM, NAME, STRING) case HTTP_##NAME: return #STRING; + switch (method) { + HTTP_ALL_METHOD_MAP(HTTP_METHOD_GEN) + default: abort(); + } +#undef HTTP_METHOD_GEN +} + +const char* llhttp_status_name(llhttp_status_t status) { +#define HTTP_STATUS_GEN(NUM, NAME, STRING) case HTTP_STATUS_##NAME: return #STRING; + switch (status) { + HTTP_STATUS_MAP(HTTP_STATUS_GEN) + default: abort(); + } +#undef HTTP_STATUS_GEN +} + + +void llhttp_set_lenient_headers(llhttp_t* parser, int enabled) { + if (enabled) { + parser->lenient_flags |= LENIENT_HEADERS; + } else { + parser->lenient_flags &= ~LENIENT_HEADERS; + } +} + + +void llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled) { + if (enabled) { + parser->lenient_flags |= LENIENT_CHUNKED_LENGTH; + } else { + parser->lenient_flags &= ~LENIENT_CHUNKED_LENGTH; + } +} + + +void llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled) { + if (enabled) { + parser->lenient_flags |= LENIENT_KEEP_ALIVE; + } else { + parser->lenient_flags &= ~LENIENT_KEEP_ALIVE; + } +} + +void llhttp_set_lenient_transfer_encoding(llhttp_t* parser, int enabled) { + if (enabled) { + parser->lenient_flags |= LENIENT_TRANSFER_ENCODING; + } else { + parser->lenient_flags &= ~LENIENT_TRANSFER_ENCODING; + } +} + +void llhttp_set_lenient_version(llhttp_t* parser, int enabled) { + if (enabled) { + parser->lenient_flags |= LENIENT_VERSION; + } else { + parser->lenient_flags &= ~LENIENT_VERSION; + } +} + +void llhttp_set_lenient_data_after_close(llhttp_t* parser, int enabled) { + if (enabled) { + parser->lenient_flags |= LENIENT_DATA_AFTER_CLOSE; + } else { + parser->lenient_flags &= ~LENIENT_DATA_AFTER_CLOSE; + } +} + +void llhttp_set_lenient_optional_lf_after_cr(llhttp_t* parser, int enabled) { + if (enabled) { + parser->lenient_flags |= LENIENT_OPTIONAL_LF_AFTER_CR; + } else { + parser->lenient_flags &= ~LENIENT_OPTIONAL_LF_AFTER_CR; + } +} + +void llhttp_set_lenient_optional_crlf_after_chunk(llhttp_t* parser, int enabled) { + if (enabled) { + parser->lenient_flags |= LENIENT_OPTIONAL_CRLF_AFTER_CHUNK; + } else { + parser->lenient_flags &= ~LENIENT_OPTIONAL_CRLF_AFTER_CHUNK; + } +} + +void llhttp_set_lenient_optional_cr_before_lf(llhttp_t* parser, int enabled) { + if (enabled) { + parser->lenient_flags |= LENIENT_OPTIONAL_CR_BEFORE_LF; + } else { + parser->lenient_flags &= ~LENIENT_OPTIONAL_CR_BEFORE_LF; + } +} + +void llhttp_set_lenient_spaces_after_chunk_size(llhttp_t* parser, int enabled) { + if (enabled) { + parser->lenient_flags |= LENIENT_SPACES_AFTER_CHUNK_SIZE; + } else { + parser->lenient_flags &= ~LENIENT_SPACES_AFTER_CHUNK_SIZE; + } +} + +/* Callbacks */ + + +int llhttp__on_message_begin(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_message_begin); + return err; +} + + +int llhttp__on_url(llhttp_t* s, const char* p, const char* endp) { + int err; + SPAN_CALLBACK_MAYBE(s, on_url, p, endp - p); + return err; +} + + +int llhttp__on_url_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_url_complete); + return err; +} + + +int llhttp__on_status(llhttp_t* s, const char* p, const char* endp) { + int err; + SPAN_CALLBACK_MAYBE(s, on_status, p, endp - p); + return err; +} + + +int llhttp__on_status_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_status_complete); + return err; +} + + +int llhttp__on_method(llhttp_t* s, const char* p, const char* endp) { + int err; + SPAN_CALLBACK_MAYBE(s, on_method, p, endp - p); + return err; +} + + +int llhttp__on_method_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_method_complete); + return err; +} + + +int llhttp__on_version(llhttp_t* s, const char* p, const char* endp) { + int err; + SPAN_CALLBACK_MAYBE(s, on_version, p, endp - p); + return err; +} + + +int llhttp__on_version_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_version_complete); + return err; +} + + +int llhttp__on_header_field(llhttp_t* s, const char* p, const char* endp) { + int err; + SPAN_CALLBACK_MAYBE(s, on_header_field, p, endp - p); + return err; +} + + +int llhttp__on_header_field_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_header_field_complete); + return err; +} + + +int llhttp__on_header_value(llhttp_t* s, const char* p, const char* endp) { + int err; + SPAN_CALLBACK_MAYBE(s, on_header_value, p, endp - p); + return err; +} + + +int llhttp__on_header_value_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_header_value_complete); + return err; +} + + +int llhttp__on_headers_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_headers_complete); + return err; +} + + +int llhttp__on_message_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_message_complete); + return err; +} + + +int llhttp__on_body(llhttp_t* s, const char* p, const char* endp) { + int err; + SPAN_CALLBACK_MAYBE(s, on_body, p, endp - p); + return err; +} + + +int llhttp__on_chunk_header(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_chunk_header); + return err; +} + + +int llhttp__on_chunk_extension_name(llhttp_t* s, const char* p, const char* endp) { + int err; + SPAN_CALLBACK_MAYBE(s, on_chunk_extension_name, p, endp - p); + return err; +} + + +int llhttp__on_chunk_extension_name_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_chunk_extension_name_complete); + return err; +} + + +int llhttp__on_chunk_extension_value(llhttp_t* s, const char* p, const char* endp) { + int err; + SPAN_CALLBACK_MAYBE(s, on_chunk_extension_value, p, endp - p); + return err; +} + + +int llhttp__on_chunk_extension_value_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_chunk_extension_value_complete); + return err; +} + + +int llhttp__on_chunk_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_chunk_complete); + return err; +} + + +int llhttp__on_reset(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_reset); + return err; +} + + +/* Private */ + + +void llhttp__debug(llhttp_t* s, const char* p, const char* endp, + const char* msg) { + if (p == endp) { + fprintf(stderr, "p=%p type=%d flags=%02x next=null debug=%s\n", s, s->type, + s->flags, msg); + } else { + fprintf(stderr, "p=%p type=%d flags=%02x next=%02x debug=%s\n", s, + s->type, s->flags, *p, msg); + } +} diff --git a/vendor/libgit2/deps/llhttp/http.c b/vendor/libgit2/deps/llhttp/http.c new file mode 100644 index 00000000..1ab91a55 --- /dev/null +++ b/vendor/libgit2/deps/llhttp/http.c @@ -0,0 +1,170 @@ +#include +#ifndef LLHTTP__TEST +# include "llhttp.h" +#else +# define llhttp_t llparse_t +#endif /* */ + +int llhttp_message_needs_eof(const llhttp_t* parser); +int llhttp_should_keep_alive(const llhttp_t* parser); + +int llhttp__before_headers_complete(llhttp_t* parser, const char* p, + const char* endp) { + /* Set this here so that on_headers_complete() callbacks can see it */ + if ((parser->flags & F_UPGRADE) && + (parser->flags & F_CONNECTION_UPGRADE)) { + /* For responses, "Upgrade: foo" and "Connection: upgrade" are + * mandatory only when it is a 101 Switching Protocols response, + * otherwise it is purely informational, to announce support. + */ + parser->upgrade = + (parser->type == HTTP_REQUEST || parser->status_code == 101); + } else { + parser->upgrade = (parser->method == HTTP_CONNECT); + } + return 0; +} + + +/* Return values: + * 0 - No body, `restart`, message_complete + * 1 - CONNECT request, `restart`, message_complete, and pause + * 2 - chunk_size_start + * 3 - body_identity + * 4 - body_identity_eof + * 5 - invalid transfer-encoding for request + */ +int llhttp__after_headers_complete(llhttp_t* parser, const char* p, + const char* endp) { + int hasBody; + + hasBody = parser->flags & F_CHUNKED || parser->content_length > 0; + if ( + (parser->upgrade && (parser->method == HTTP_CONNECT || + (parser->flags & F_SKIPBODY) || !hasBody)) || + /* See RFC 2616 section 4.4 - 1xx e.g. Continue */ + (parser->type == HTTP_RESPONSE && parser->status_code == 101) + ) { + /* Exit, the rest of the message is in a different protocol. */ + return 1; + } + + if (parser->type == HTTP_RESPONSE && parser->status_code == 100) { + /* No body, restart as the message is complete */ + return 0; + } + + /* See RFC 2616 section 4.4 */ + if ( + parser->flags & F_SKIPBODY || /* response to a HEAD request */ + ( + parser->type == HTTP_RESPONSE && ( + parser->status_code == 102 || /* Processing */ + parser->status_code == 103 || /* Early Hints */ + parser->status_code == 204 || /* No Content */ + parser->status_code == 304 /* Not Modified */ + ) + ) + ) { + return 0; + } else if (parser->flags & F_CHUNKED) { + /* chunked encoding - ignore Content-Length header, prepare for a chunk */ + return 2; + } else if (parser->flags & F_TRANSFER_ENCODING) { + if (parser->type == HTTP_REQUEST && + (parser->lenient_flags & LENIENT_CHUNKED_LENGTH) == 0 && + (parser->lenient_flags & LENIENT_TRANSFER_ENCODING) == 0) { + /* RFC 7230 3.3.3 */ + + /* If a Transfer-Encoding header field + * is present in a request and the chunked transfer coding is not + * the final encoding, the message body length cannot be determined + * reliably; the server MUST respond with the 400 (Bad Request) + * status code and then close the connection. + */ + return 5; + } else { + /* RFC 7230 3.3.3 */ + + /* If a Transfer-Encoding header field is present in a response and + * the chunked transfer coding is not the final encoding, the + * message body length is determined by reading the connection until + * it is closed by the server. + */ + return 4; + } + } else { + if (!(parser->flags & F_CONTENT_LENGTH)) { + if (!llhttp_message_needs_eof(parser)) { + /* Assume content-length 0 - read the next */ + return 0; + } else { + /* Read body until EOF */ + return 4; + } + } else if (parser->content_length == 0) { + /* Content-Length header given but zero: Content-Length: 0\r\n */ + return 0; + } else { + /* Content-Length header given and non-zero */ + return 3; + } + } +} + + +int llhttp__after_message_complete(llhttp_t* parser, const char* p, + const char* endp) { + int should_keep_alive; + + should_keep_alive = llhttp_should_keep_alive(parser); + parser->finish = HTTP_FINISH_SAFE; + parser->flags = 0; + + /* NOTE: this is ignored in loose parsing mode */ + return should_keep_alive; +} + + +int llhttp_message_needs_eof(const llhttp_t* parser) { + if (parser->type == HTTP_REQUEST) { + return 0; + } + + /* See RFC 2616 section 4.4 */ + if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ + parser->status_code == 204 || /* No Content */ + parser->status_code == 304 || /* Not Modified */ + (parser->flags & F_SKIPBODY)) { /* response to a HEAD request */ + return 0; + } + + /* RFC 7230 3.3.3, see `llhttp__after_headers_complete` */ + if ((parser->flags & F_TRANSFER_ENCODING) && + (parser->flags & F_CHUNKED) == 0) { + return 1; + } + + if (parser->flags & (F_CHUNKED | F_CONTENT_LENGTH)) { + return 0; + } + + return 1; +} + + +int llhttp_should_keep_alive(const llhttp_t* parser) { + if (parser->http_major > 0 && parser->http_minor > 0) { + /* HTTP/1.1 */ + if (parser->flags & F_CONNECTION_CLOSE) { + return 0; + } + } else { + /* HTTP/1.0 or earlier */ + if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) { + return 0; + } + } + + return !llhttp_message_needs_eof(parser); +} diff --git a/vendor/libgit2/deps/llhttp/llhttp.c b/vendor/libgit2/deps/llhttp/llhttp.c new file mode 100644 index 00000000..3ef3b817 --- /dev/null +++ b/vendor/libgit2/deps/llhttp/llhttp.c @@ -0,0 +1,10168 @@ +#include +#include +#include + +#ifdef __SSE4_2__ + #ifdef _MSC_VER + #include + #else /* !_MSC_VER */ + #include + #endif /* _MSC_VER */ +#endif /* __SSE4_2__ */ + +#ifdef _MSC_VER + #define ALIGN(n) _declspec(align(n)) +#else /* !_MSC_VER */ + #define ALIGN(n) __attribute__((aligned(n))) +#endif /* _MSC_VER */ + +#include "llhttp.h" + +typedef int (*llhttp__internal__span_cb)( + llhttp__internal_t*, const char*, const char*); + +static const unsigned char llparse_blob0[] = { + 'o', 'n' +}; +static const unsigned char llparse_blob1[] = { + 'e', 'c', 't', 'i', 'o', 'n' +}; +static const unsigned char llparse_blob2[] = { + 'l', 'o', 's', 'e' +}; +static const unsigned char llparse_blob3[] = { + 'e', 'e', 'p', '-', 'a', 'l', 'i', 'v', 'e' +}; +static const unsigned char llparse_blob4[] = { + 'p', 'g', 'r', 'a', 'd', 'e' +}; +static const unsigned char llparse_blob5[] = { + 'c', 'h', 'u', 'n', 'k', 'e', 'd' +}; +#ifdef __SSE4_2__ +static const unsigned char ALIGN(16) llparse_blob6[] = { + 0x9, 0x9, ' ', '~', 0x80, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0 +}; +#endif /* __SSE4_2__ */ +#ifdef __SSE4_2__ +static const unsigned char ALIGN(16) llparse_blob7[] = { + '!', '!', '#', '\'', '*', '+', '-', '.', '0', '9', 'A', + 'Z', '^', 'z', '|', '|' +}; +#endif /* __SSE4_2__ */ +#ifdef __SSE4_2__ +static const unsigned char ALIGN(16) llparse_blob8[] = { + '~', '~', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0 +}; +#endif /* __SSE4_2__ */ +static const unsigned char llparse_blob9[] = { + 'e', 'n', 't', '-', 'l', 'e', 'n', 'g', 't', 'h' +}; +static const unsigned char llparse_blob10[] = { + 'r', 'o', 'x', 'y', '-', 'c', 'o', 'n', 'n', 'e', 'c', + 't', 'i', 'o', 'n' +}; +static const unsigned char llparse_blob11[] = { + 'r', 'a', 'n', 's', 'f', 'e', 'r', '-', 'e', 'n', 'c', + 'o', 'd', 'i', 'n', 'g' +}; +static const unsigned char llparse_blob12[] = { + 'p', 'g', 'r', 'a', 'd', 'e' +}; +static const unsigned char llparse_blob13[] = { + 'T', 'T', 'P', '/' +}; +static const unsigned char llparse_blob14[] = { + 0xd, 0xa, 0xd, 0xa, 'S', 'M', 0xd, 0xa, 0xd, 0xa +}; +static const unsigned char llparse_blob15[] = { + 'C', 'E', '/' +}; +static const unsigned char llparse_blob16[] = { + 'T', 'S', 'P', '/' +}; +static const unsigned char llparse_blob17[] = { + 'N', 'O', 'U', 'N', 'C', 'E' +}; +static const unsigned char llparse_blob18[] = { + 'I', 'N', 'D' +}; +static const unsigned char llparse_blob19[] = { + 'E', 'C', 'K', 'O', 'U', 'T' +}; +static const unsigned char llparse_blob20[] = { + 'N', 'E', 'C', 'T' +}; +static const unsigned char llparse_blob21[] = { + 'E', 'T', 'E' +}; +static const unsigned char llparse_blob22[] = { + 'C', 'R', 'I', 'B', 'E' +}; +static const unsigned char llparse_blob23[] = { + 'L', 'U', 'S', 'H' +}; +static const unsigned char llparse_blob24[] = { + 'E', 'T' +}; +static const unsigned char llparse_blob25[] = { + 'P', 'A', 'R', 'A', 'M', 'E', 'T', 'E', 'R' +}; +static const unsigned char llparse_blob26[] = { + 'E', 'A', 'D' +}; +static const unsigned char llparse_blob27[] = { + 'N', 'K' +}; +static const unsigned char llparse_blob28[] = { + 'C', 'K' +}; +static const unsigned char llparse_blob29[] = { + 'S', 'E', 'A', 'R', 'C', 'H' +}; +static const unsigned char llparse_blob30[] = { + 'R', 'G', 'E' +}; +static const unsigned char llparse_blob31[] = { + 'C', 'T', 'I', 'V', 'I', 'T', 'Y' +}; +static const unsigned char llparse_blob32[] = { + 'L', 'E', 'N', 'D', 'A', 'R' +}; +static const unsigned char llparse_blob33[] = { + 'V', 'E' +}; +static const unsigned char llparse_blob34[] = { + 'O', 'T', 'I', 'F', 'Y' +}; +static const unsigned char llparse_blob35[] = { + 'P', 'T', 'I', 'O', 'N', 'S' +}; +static const unsigned char llparse_blob36[] = { + 'C', 'H' +}; +static const unsigned char llparse_blob37[] = { + 'S', 'E' +}; +static const unsigned char llparse_blob38[] = { + 'A', 'Y' +}; +static const unsigned char llparse_blob39[] = { + 'S', 'T' +}; +static const unsigned char llparse_blob40[] = { + 'I', 'N', 'D' +}; +static const unsigned char llparse_blob41[] = { + 'A', 'T', 'C', 'H' +}; +static const unsigned char llparse_blob42[] = { + 'G', 'E' +}; +static const unsigned char llparse_blob43[] = { + 'U', 'E', 'R', 'Y' +}; +static const unsigned char llparse_blob44[] = { + 'I', 'N', 'D' +}; +static const unsigned char llparse_blob45[] = { + 'O', 'R', 'D' +}; +static const unsigned char llparse_blob46[] = { + 'I', 'R', 'E', 'C', 'T' +}; +static const unsigned char llparse_blob47[] = { + 'O', 'R', 'T' +}; +static const unsigned char llparse_blob48[] = { + 'R', 'C', 'H' +}; +static const unsigned char llparse_blob49[] = { + 'P', 'A', 'R', 'A', 'M', 'E', 'T', 'E', 'R' +}; +static const unsigned char llparse_blob50[] = { + 'U', 'R', 'C', 'E' +}; +static const unsigned char llparse_blob51[] = { + 'B', 'S', 'C', 'R', 'I', 'B', 'E' +}; +static const unsigned char llparse_blob52[] = { + 'A', 'R', 'D', 'O', 'W', 'N' +}; +static const unsigned char llparse_blob53[] = { + 'A', 'C', 'E' +}; +static const unsigned char llparse_blob54[] = { + 'I', 'N', 'D' +}; +static const unsigned char llparse_blob55[] = { + 'N', 'K' +}; +static const unsigned char llparse_blob56[] = { + 'C', 'K' +}; +static const unsigned char llparse_blob57[] = { + 'U', 'B', 'S', 'C', 'R', 'I', 'B', 'E' +}; +static const unsigned char llparse_blob58[] = { + 'H', 'T', 'T', 'P', '/' +}; +static const unsigned char llparse_blob59[] = { + 'A', 'D' +}; +static const unsigned char llparse_blob60[] = { + 'T', 'P', '/' +}; + +enum llparse_match_status_e { + kMatchComplete, + kMatchPause, + kMatchMismatch +}; +typedef enum llparse_match_status_e llparse_match_status_t; + +struct llparse_match_s { + llparse_match_status_t status; + const unsigned char* current; +}; +typedef struct llparse_match_s llparse_match_t; + +static llparse_match_t llparse__match_sequence_to_lower( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp, + const unsigned char* seq, uint32_t seq_len) { + uint32_t index; + llparse_match_t res; + + index = s->_index; + for (; p != endp; p++) { + unsigned char current; + + current = ((*p) >= 'A' && (*p) <= 'Z' ? (*p | 0x20) : (*p)); + if (current == seq[index]) { + if (++index == seq_len) { + res.status = kMatchComplete; + goto reset; + } + } else { + res.status = kMatchMismatch; + goto reset; + } + } + s->_index = index; + res.status = kMatchPause; + res.current = p; + return res; +reset: + s->_index = 0; + res.current = p; + return res; +} + +static llparse_match_t llparse__match_sequence_to_lower_unsafe( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp, + const unsigned char* seq, uint32_t seq_len) { + uint32_t index; + llparse_match_t res; + + index = s->_index; + for (; p != endp; p++) { + unsigned char current; + + current = ((*p) | 0x20); + if (current == seq[index]) { + if (++index == seq_len) { + res.status = kMatchComplete; + goto reset; + } + } else { + res.status = kMatchMismatch; + goto reset; + } + } + s->_index = index; + res.status = kMatchPause; + res.current = p; + return res; +reset: + s->_index = 0; + res.current = p; + return res; +} + +static llparse_match_t llparse__match_sequence_id( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp, + const unsigned char* seq, uint32_t seq_len) { + uint32_t index; + llparse_match_t res; + + index = s->_index; + for (; p != endp; p++) { + unsigned char current; + + current = *p; + if (current == seq[index]) { + if (++index == seq_len) { + res.status = kMatchComplete; + goto reset; + } + } else { + res.status = kMatchMismatch; + goto reset; + } + } + s->_index = index; + res.status = kMatchPause; + res.current = p; + return res; +reset: + s->_index = 0; + res.current = p; + return res; +} + +enum llparse_state_e { + s_error, + s_n_llhttp__internal__n_closed, + s_n_llhttp__internal__n_invoke_llhttp__after_message_complete, + s_n_llhttp__internal__n_pause_1, + s_n_llhttp__internal__n_invoke_is_equal_upgrade, + s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2, + s_n_llhttp__internal__n_chunk_data_almost_done_1, + s_n_llhttp__internal__n_chunk_data_almost_done, + s_n_llhttp__internal__n_consume_content_length, + s_n_llhttp__internal__n_span_start_llhttp__on_body, + s_n_llhttp__internal__n_invoke_is_equal_content_length, + s_n_llhttp__internal__n_chunk_size_almost_done, + s_n_llhttp__internal__n_invoke_test_lenient_flags_9, + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete, + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1, + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2, + s_n_llhttp__internal__n_invoke_test_lenient_flags_10, + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete, + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1, + s_n_llhttp__internal__n_chunk_extension_quoted_value_done, + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2, + s_n_llhttp__internal__n_error_30, + s_n_llhttp__internal__n_chunk_extension_quoted_value_quoted_pair, + s_n_llhttp__internal__n_error_31, + s_n_llhttp__internal__n_chunk_extension_quoted_value, + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3, + s_n_llhttp__internal__n_error_33, + s_n_llhttp__internal__n_chunk_extension_value, + s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value, + s_n_llhttp__internal__n_error_34, + s_n_llhttp__internal__n_chunk_extension_name, + s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name, + s_n_llhttp__internal__n_chunk_extensions, + s_n_llhttp__internal__n_chunk_size_otherwise, + s_n_llhttp__internal__n_chunk_size, + s_n_llhttp__internal__n_chunk_size_digit, + s_n_llhttp__internal__n_invoke_update_content_length_1, + s_n_llhttp__internal__n_consume_content_length_1, + s_n_llhttp__internal__n_span_start_llhttp__on_body_1, + s_n_llhttp__internal__n_eof, + s_n_llhttp__internal__n_span_start_llhttp__on_body_2, + s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete, + s_n_llhttp__internal__n_error_5, + s_n_llhttp__internal__n_headers_almost_done, + s_n_llhttp__internal__n_header_field_colon_discard_ws, + s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete, + s_n_llhttp__internal__n_span_start_llhttp__on_header_value, + s_n_llhttp__internal__n_header_value_discard_lws, + s_n_llhttp__internal__n_header_value_discard_ws_almost_done, + s_n_llhttp__internal__n_header_value_lws, + s_n_llhttp__internal__n_header_value_almost_done, + s_n_llhttp__internal__n_invoke_test_lenient_flags_17, + s_n_llhttp__internal__n_header_value_lenient, + s_n_llhttp__internal__n_error_54, + s_n_llhttp__internal__n_header_value_otherwise, + s_n_llhttp__internal__n_header_value_connection_token, + s_n_llhttp__internal__n_header_value_connection_ws, + s_n_llhttp__internal__n_header_value_connection_1, + s_n_llhttp__internal__n_header_value_connection_2, + s_n_llhttp__internal__n_header_value_connection_3, + s_n_llhttp__internal__n_header_value_connection, + s_n_llhttp__internal__n_error_56, + s_n_llhttp__internal__n_error_57, + s_n_llhttp__internal__n_header_value_content_length_ws, + s_n_llhttp__internal__n_header_value_content_length, + s_n_llhttp__internal__n_error_59, + s_n_llhttp__internal__n_error_58, + s_n_llhttp__internal__n_header_value_te_token_ows, + s_n_llhttp__internal__n_header_value, + s_n_llhttp__internal__n_header_value_te_token, + s_n_llhttp__internal__n_header_value_te_chunked_last, + s_n_llhttp__internal__n_header_value_te_chunked, + s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1, + s_n_llhttp__internal__n_header_value_discard_ws, + s_n_llhttp__internal__n_invoke_load_header_state, + s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete, + s_n_llhttp__internal__n_header_field_general_otherwise, + s_n_llhttp__internal__n_header_field_general, + s_n_llhttp__internal__n_header_field_colon, + s_n_llhttp__internal__n_header_field_3, + s_n_llhttp__internal__n_header_field_4, + s_n_llhttp__internal__n_header_field_2, + s_n_llhttp__internal__n_header_field_1, + s_n_llhttp__internal__n_header_field_5, + s_n_llhttp__internal__n_header_field_6, + s_n_llhttp__internal__n_header_field_7, + s_n_llhttp__internal__n_header_field, + s_n_llhttp__internal__n_span_start_llhttp__on_header_field, + s_n_llhttp__internal__n_header_field_start, + s_n_llhttp__internal__n_headers_start, + s_n_llhttp__internal__n_url_to_http_09, + s_n_llhttp__internal__n_url_skip_to_http09, + s_n_llhttp__internal__n_url_skip_lf_to_http09_1, + s_n_llhttp__internal__n_url_skip_lf_to_http09, + s_n_llhttp__internal__n_req_pri_upgrade, + s_n_llhttp__internal__n_req_http_complete_crlf, + s_n_llhttp__internal__n_req_http_complete, + s_n_llhttp__internal__n_invoke_load_method_1, + s_n_llhttp__internal__n_invoke_llhttp__on_version_complete, + s_n_llhttp__internal__n_error_66, + s_n_llhttp__internal__n_error_73, + s_n_llhttp__internal__n_req_http_minor, + s_n_llhttp__internal__n_error_74, + s_n_llhttp__internal__n_req_http_dot, + s_n_llhttp__internal__n_error_75, + s_n_llhttp__internal__n_req_http_major, + s_n_llhttp__internal__n_span_start_llhttp__on_version, + s_n_llhttp__internal__n_req_http_start_1, + s_n_llhttp__internal__n_req_http_start_2, + s_n_llhttp__internal__n_req_http_start_3, + s_n_llhttp__internal__n_req_http_start, + s_n_llhttp__internal__n_url_to_http, + s_n_llhttp__internal__n_url_skip_to_http, + s_n_llhttp__internal__n_url_fragment, + s_n_llhttp__internal__n_span_end_stub_query_3, + s_n_llhttp__internal__n_url_query, + s_n_llhttp__internal__n_url_query_or_fragment, + s_n_llhttp__internal__n_url_path, + s_n_llhttp__internal__n_span_start_stub_path_2, + s_n_llhttp__internal__n_span_start_stub_path, + s_n_llhttp__internal__n_span_start_stub_path_1, + s_n_llhttp__internal__n_url_server_with_at, + s_n_llhttp__internal__n_url_server, + s_n_llhttp__internal__n_url_schema_delim_1, + s_n_llhttp__internal__n_url_schema_delim, + s_n_llhttp__internal__n_span_end_stub_schema, + s_n_llhttp__internal__n_url_schema, + s_n_llhttp__internal__n_url_start, + s_n_llhttp__internal__n_span_start_llhttp__on_url_1, + s_n_llhttp__internal__n_url_entry_normal, + s_n_llhttp__internal__n_span_start_llhttp__on_url, + s_n_llhttp__internal__n_url_entry_connect, + s_n_llhttp__internal__n_req_spaces_before_url, + s_n_llhttp__internal__n_req_first_space_before_url, + s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1, + s_n_llhttp__internal__n_after_start_req_2, + s_n_llhttp__internal__n_after_start_req_3, + s_n_llhttp__internal__n_after_start_req_1, + s_n_llhttp__internal__n_after_start_req_4, + s_n_llhttp__internal__n_after_start_req_6, + s_n_llhttp__internal__n_after_start_req_8, + s_n_llhttp__internal__n_after_start_req_9, + s_n_llhttp__internal__n_after_start_req_7, + s_n_llhttp__internal__n_after_start_req_5, + s_n_llhttp__internal__n_after_start_req_12, + s_n_llhttp__internal__n_after_start_req_13, + s_n_llhttp__internal__n_after_start_req_11, + s_n_llhttp__internal__n_after_start_req_10, + s_n_llhttp__internal__n_after_start_req_14, + s_n_llhttp__internal__n_after_start_req_17, + s_n_llhttp__internal__n_after_start_req_16, + s_n_llhttp__internal__n_after_start_req_15, + s_n_llhttp__internal__n_after_start_req_18, + s_n_llhttp__internal__n_after_start_req_20, + s_n_llhttp__internal__n_after_start_req_21, + s_n_llhttp__internal__n_after_start_req_19, + s_n_llhttp__internal__n_after_start_req_23, + s_n_llhttp__internal__n_after_start_req_24, + s_n_llhttp__internal__n_after_start_req_26, + s_n_llhttp__internal__n_after_start_req_28, + s_n_llhttp__internal__n_after_start_req_29, + s_n_llhttp__internal__n_after_start_req_27, + s_n_llhttp__internal__n_after_start_req_25, + s_n_llhttp__internal__n_after_start_req_30, + s_n_llhttp__internal__n_after_start_req_22, + s_n_llhttp__internal__n_after_start_req_31, + s_n_llhttp__internal__n_after_start_req_32, + s_n_llhttp__internal__n_after_start_req_35, + s_n_llhttp__internal__n_after_start_req_36, + s_n_llhttp__internal__n_after_start_req_34, + s_n_llhttp__internal__n_after_start_req_37, + s_n_llhttp__internal__n_after_start_req_38, + s_n_llhttp__internal__n_after_start_req_42, + s_n_llhttp__internal__n_after_start_req_43, + s_n_llhttp__internal__n_after_start_req_41, + s_n_llhttp__internal__n_after_start_req_40, + s_n_llhttp__internal__n_after_start_req_39, + s_n_llhttp__internal__n_after_start_req_45, + s_n_llhttp__internal__n_after_start_req_44, + s_n_llhttp__internal__n_after_start_req_33, + s_n_llhttp__internal__n_after_start_req_46, + s_n_llhttp__internal__n_after_start_req_49, + s_n_llhttp__internal__n_after_start_req_50, + s_n_llhttp__internal__n_after_start_req_51, + s_n_llhttp__internal__n_after_start_req_52, + s_n_llhttp__internal__n_after_start_req_48, + s_n_llhttp__internal__n_after_start_req_47, + s_n_llhttp__internal__n_after_start_req_55, + s_n_llhttp__internal__n_after_start_req_57, + s_n_llhttp__internal__n_after_start_req_58, + s_n_llhttp__internal__n_after_start_req_56, + s_n_llhttp__internal__n_after_start_req_54, + s_n_llhttp__internal__n_after_start_req_59, + s_n_llhttp__internal__n_after_start_req_60, + s_n_llhttp__internal__n_after_start_req_53, + s_n_llhttp__internal__n_after_start_req_62, + s_n_llhttp__internal__n_after_start_req_63, + s_n_llhttp__internal__n_after_start_req_61, + s_n_llhttp__internal__n_after_start_req_66, + s_n_llhttp__internal__n_after_start_req_68, + s_n_llhttp__internal__n_after_start_req_69, + s_n_llhttp__internal__n_after_start_req_67, + s_n_llhttp__internal__n_after_start_req_70, + s_n_llhttp__internal__n_after_start_req_65, + s_n_llhttp__internal__n_after_start_req_64, + s_n_llhttp__internal__n_after_start_req, + s_n_llhttp__internal__n_span_start_llhttp__on_method_1, + s_n_llhttp__internal__n_res_line_almost_done, + s_n_llhttp__internal__n_invoke_test_lenient_flags_30, + s_n_llhttp__internal__n_res_status, + s_n_llhttp__internal__n_span_start_llhttp__on_status, + s_n_llhttp__internal__n_res_status_code_otherwise, + s_n_llhttp__internal__n_res_status_code_digit_3, + s_n_llhttp__internal__n_res_status_code_digit_2, + s_n_llhttp__internal__n_res_status_code_digit_1, + s_n_llhttp__internal__n_res_after_version, + s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1, + s_n_llhttp__internal__n_error_89, + s_n_llhttp__internal__n_error_103, + s_n_llhttp__internal__n_res_http_minor, + s_n_llhttp__internal__n_error_104, + s_n_llhttp__internal__n_res_http_dot, + s_n_llhttp__internal__n_error_105, + s_n_llhttp__internal__n_res_http_major, + s_n_llhttp__internal__n_span_start_llhttp__on_version_1, + s_n_llhttp__internal__n_start_res, + s_n_llhttp__internal__n_invoke_llhttp__on_method_complete, + s_n_llhttp__internal__n_req_or_res_method_2, + s_n_llhttp__internal__n_invoke_update_type_1, + s_n_llhttp__internal__n_req_or_res_method_3, + s_n_llhttp__internal__n_req_or_res_method_1, + s_n_llhttp__internal__n_req_or_res_method, + s_n_llhttp__internal__n_span_start_llhttp__on_method, + s_n_llhttp__internal__n_start_req_or_res, + s_n_llhttp__internal__n_invoke_load_type, + s_n_llhttp__internal__n_invoke_update_finish, + s_n_llhttp__internal__n_start, +}; +typedef enum llparse_state_e llparse_state_t; + +int llhttp__on_method( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_url( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_version( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_header_field( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_header_value( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_body( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_chunk_extension_name( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_chunk_extension_value( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_status( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_load_initial_message_completed( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->initial_message_completed; +} + +int llhttp__on_reset( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_update_finish( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->finish = 2; + return 0; +} + +int llhttp__on_message_begin( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_load_type( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->type; +} + +int llhttp__internal__c_store_method( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + state->method = match; + return 0; +} + +int llhttp__on_method_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_is_equal_method( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->method == 5; +} + +int llhttp__internal__c_update_http_major( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->http_major = 0; + return 0; +} + +int llhttp__internal__c_update_http_minor( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->http_minor = 9; + return 0; +} + +int llhttp__on_url_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_test_lenient_flags( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->lenient_flags & 1) == 1; +} + +int llhttp__internal__c_test_lenient_flags_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->lenient_flags & 256) == 256; +} + +int llhttp__internal__c_test_flags( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->flags & 128) == 128; +} + +int llhttp__on_chunk_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_message_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_is_equal_upgrade( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->upgrade == 1; +} + +int llhttp__after_message_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_update_content_length( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->content_length = 0; + return 0; +} + +int llhttp__internal__c_update_initial_message_completed( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->initial_message_completed = 1; + return 0; +} + +int llhttp__internal__c_update_finish_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->finish = 0; + return 0; +} + +int llhttp__internal__c_test_lenient_flags_2( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->lenient_flags & 4) == 4; +} + +int llhttp__internal__c_test_lenient_flags_3( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->lenient_flags & 32) == 32; +} + +int llhttp__before_headers_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_headers_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__after_headers_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_mul_add_content_length( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + /* Multiplication overflow */ + if (state->content_length > 0xffffffffffffffffULL / 16) { + return 1; + } + + state->content_length *= 16; + + /* Addition overflow */ + if (match >= 0) { + if (state->content_length > 0xffffffffffffffffULL - match) { + return 1; + } + } else { + if (state->content_length < 0ULL - match) { + return 1; + } + } + state->content_length += match; + return 0; +} + +int llhttp__internal__c_test_lenient_flags_4( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->lenient_flags & 512) == 512; +} + +int llhttp__on_chunk_header( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_is_equal_content_length( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->content_length == 0; +} + +int llhttp__internal__c_test_lenient_flags_7( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->lenient_flags & 128) == 128; +} + +int llhttp__internal__c_or_flags( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 128; + return 0; +} + +int llhttp__internal__c_test_lenient_flags_8( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->lenient_flags & 64) == 64; +} + +int llhttp__on_chunk_extension_name_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_chunk_extension_value_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_update_finish_3( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->finish = 1; + return 0; +} + +int llhttp__internal__c_or_flags_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 64; + return 0; +} + +int llhttp__internal__c_update_upgrade( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->upgrade = 1; + return 0; +} + +int llhttp__internal__c_store_header_state( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + state->header_state = match; + return 0; +} + +int llhttp__on_header_field_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_load_header_state( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->header_state; +} + +int llhttp__internal__c_test_flags_4( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->flags & 512) == 512; +} + +int llhttp__internal__c_test_lenient_flags_22( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->lenient_flags & 2) == 2; +} + +int llhttp__internal__c_or_flags_5( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 1; + return 0; +} + +int llhttp__internal__c_update_header_state( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 1; + return 0; +} + +int llhttp__on_header_value_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_or_flags_6( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 2; + return 0; +} + +int llhttp__internal__c_or_flags_7( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 4; + return 0; +} + +int llhttp__internal__c_or_flags_8( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 8; + return 0; +} + +int llhttp__internal__c_update_header_state_3( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 6; + return 0; +} + +int llhttp__internal__c_update_header_state_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 0; + return 0; +} + +int llhttp__internal__c_update_header_state_6( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 5; + return 0; +} + +int llhttp__internal__c_update_header_state_7( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 7; + return 0; +} + +int llhttp__internal__c_test_flags_2( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->flags & 32) == 32; +} + +int llhttp__internal__c_mul_add_content_length_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + /* Multiplication overflow */ + if (state->content_length > 0xffffffffffffffffULL / 10) { + return 1; + } + + state->content_length *= 10; + + /* Addition overflow */ + if (match >= 0) { + if (state->content_length > 0xffffffffffffffffULL - match) { + return 1; + } + } else { + if (state->content_length < 0ULL - match) { + return 1; + } + } + state->content_length += match; + return 0; +} + +int llhttp__internal__c_or_flags_17( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 32; + return 0; +} + +int llhttp__internal__c_test_flags_3( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->flags & 8) == 8; +} + +int llhttp__internal__c_test_lenient_flags_20( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->lenient_flags & 8) == 8; +} + +int llhttp__internal__c_or_flags_18( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 512; + return 0; +} + +int llhttp__internal__c_and_flags( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags &= -9; + return 0; +} + +int llhttp__internal__c_update_header_state_8( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 8; + return 0; +} + +int llhttp__internal__c_or_flags_20( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 16; + return 0; +} + +int llhttp__internal__c_load_method( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->method; +} + +int llhttp__internal__c_store_http_major( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + state->http_major = match; + return 0; +} + +int llhttp__internal__c_store_http_minor( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + state->http_minor = match; + return 0; +} + +int llhttp__internal__c_test_lenient_flags_24( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->lenient_flags & 16) == 16; +} + +int llhttp__on_version_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_load_http_major( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->http_major; +} + +int llhttp__internal__c_load_http_minor( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->http_minor; +} + +int llhttp__internal__c_update_status_code( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->status_code = 0; + return 0; +} + +int llhttp__internal__c_mul_add_status_code( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + /* Multiplication overflow */ + if (state->status_code > 0xffff / 10) { + return 1; + } + + state->status_code *= 10; + + /* Addition overflow */ + if (match >= 0) { + if (state->status_code > 0xffff - match) { + return 1; + } + } else { + if (state->status_code < 0 - match) { + return 1; + } + } + state->status_code += match; + return 0; +} + +int llhttp__on_status_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_update_type( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->type = 1; + return 0; +} + +int llhttp__internal__c_update_type_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->type = 2; + return 0; +} + +int llhttp__internal_init(llhttp__internal_t* state) { + memset(state, 0, sizeof(*state)); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_start; + return 0; +} + +static llparse_state_t llhttp__internal__run( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + int match; + switch ((llparse_state_t) (intptr_t) state->_current) { + case s_n_llhttp__internal__n_closed: + s_n_llhttp__internal__n_closed: { + if (p == endp) { + return s_n_llhttp__internal__n_closed; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_closed; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_closed; + } + default: { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_3; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__after_message_complete: + s_n_llhttp__internal__n_invoke_llhttp__after_message_complete: { + switch (llhttp__after_message_complete(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_update_content_length; + default: + goto s_n_llhttp__internal__n_invoke_update_finish_1; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_pause_1: + s_n_llhttp__internal__n_pause_1: { + state->error = 0x16; + state->reason = "Pause on CONNECT/Upgrade"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_is_equal_upgrade: + s_n_llhttp__internal__n_invoke_is_equal_upgrade: { + switch (llhttp__internal__c_is_equal_upgrade(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; + default: + goto s_n_llhttp__internal__n_pause_1; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2: + s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2: { + switch (llhttp__on_message_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_is_equal_upgrade; + case 21: + goto s_n_llhttp__internal__n_pause_13; + default: + goto s_n_llhttp__internal__n_error_38; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_data_almost_done_1: + s_n_llhttp__internal__n_chunk_data_almost_done_1: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_data_almost_done_1; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete; + } + default: { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_7; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_data_almost_done: + s_n_llhttp__internal__n_chunk_data_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_data_almost_done; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_6; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_chunk_data_almost_done_1; + } + default: { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_7; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_consume_content_length: + s_n_llhttp__internal__n_consume_content_length: { + size_t avail; + uint64_t need; + + avail = endp - p; + need = state->content_length; + if (avail >= need) { + p += need; + state->content_length = 0; + goto s_n_llhttp__internal__n_span_end_llhttp__on_body; + } + + state->content_length -= avail; + return s_n_llhttp__internal__n_consume_content_length; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_body: + s_n_llhttp__internal__n_span_start_llhttp__on_body: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_body; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_body; + goto s_n_llhttp__internal__n_consume_content_length; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_is_equal_content_length: + s_n_llhttp__internal__n_invoke_is_equal_content_length: { + switch (llhttp__internal__c_is_equal_content_length(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_span_start_llhttp__on_body; + default: + goto s_n_llhttp__internal__n_invoke_or_flags; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_size_almost_done: + s_n_llhttp__internal__n_chunk_size_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_size_almost_done; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header; + } + default: { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_8; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_test_lenient_flags_9: + s_n_llhttp__internal__n_invoke_test_lenient_flags_9: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_chunk_size_almost_done; + default: + goto s_n_llhttp__internal__n_error_20; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete: + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete: { + switch (llhttp__on_chunk_extension_name_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_9; + case 21: + goto s_n_llhttp__internal__n_pause_5; + default: + goto s_n_llhttp__internal__n_error_19; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1: + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1: { + switch (llhttp__on_chunk_extension_name_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_chunk_size_almost_done; + case 21: + goto s_n_llhttp__internal__n_pause_6; + default: + goto s_n_llhttp__internal__n_error_21; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2: + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2: { + switch (llhttp__on_chunk_extension_name_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_chunk_extensions; + case 21: + goto s_n_llhttp__internal__n_pause_7; + default: + goto s_n_llhttp__internal__n_error_22; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_test_lenient_flags_10: + s_n_llhttp__internal__n_invoke_test_lenient_flags_10: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_chunk_size_almost_done; + default: + goto s_n_llhttp__internal__n_error_25; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete: + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete: { + switch (llhttp__on_chunk_extension_value_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_10; + case 21: + goto s_n_llhttp__internal__n_pause_8; + default: + goto s_n_llhttp__internal__n_error_24; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1: + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1: { + switch (llhttp__on_chunk_extension_value_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_chunk_size_almost_done; + case 21: + goto s_n_llhttp__internal__n_pause_9; + default: + goto s_n_llhttp__internal__n_error_26; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_extension_quoted_value_done: + s_n_llhttp__internal__n_chunk_extension_quoted_value_done: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_extension_quoted_value_done; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_11; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_chunk_size_almost_done; + } + case ';': { + p++; + goto s_n_llhttp__internal__n_chunk_extensions; + } + default: { + goto s_n_llhttp__internal__n_error_29; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2: + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2: { + switch (llhttp__on_chunk_extension_value_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_chunk_extension_quoted_value_done; + case 21: + goto s_n_llhttp__internal__n_pause_10; + default: + goto s_n_llhttp__internal__n_error_27; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_30: + s_n_llhttp__internal__n_error_30: { + state->error = 0x2; + state->reason = "Invalid quoted-pair in chunk extensions quoted value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_extension_quoted_value_quoted_pair: + s_n_llhttp__internal__n_chunk_extension_quoted_value_quoted_pair: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + if (p == endp) { + return s_n_llhttp__internal__n_chunk_extension_quoted_value_quoted_pair; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_chunk_extension_quoted_value; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_3; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_31: + s_n_llhttp__internal__n_error_31: { + state->error = 0x2; + state->reason = "Invalid character in chunk extensions quoted value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_extension_quoted_value: + s_n_llhttp__internal__n_chunk_extension_quoted_value: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + if (p == endp) { + return s_n_llhttp__internal__n_chunk_extension_quoted_value; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_chunk_extension_quoted_value; + } + case 2: { + p++; + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_2; + } + case 3: { + p++; + goto s_n_llhttp__internal__n_chunk_extension_quoted_value_quoted_pair; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_4; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3: + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3: { + switch (llhttp__on_chunk_extension_value_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_chunk_extensions; + case 21: + goto s_n_llhttp__internal__n_pause_11; + default: + goto s_n_llhttp__internal__n_error_32; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_33: + s_n_llhttp__internal__n_error_33: { + state->error = 0x2; + state->reason = "Invalid character in chunk extensions value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_extension_value: + s_n_llhttp__internal__n_chunk_extension_value: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3, 4, 3, 3, 3, 3, 3, 0, 0, 3, 3, 0, 3, 3, 0, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 5, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 0, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_chunk_extension_value; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_1; + } + case 3: { + p++; + goto s_n_llhttp__internal__n_chunk_extension_value; + } + case 4: { + p++; + goto s_n_llhttp__internal__n_chunk_extension_quoted_value; + } + case 5: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_5; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_6; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value: + s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_chunk_extension_value; + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_3; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_34: + s_n_llhttp__internal__n_error_34: { + state->error = 0x2; + state->reason = "Invalid character in chunk extensions name"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_extension_name: + s_n_llhttp__internal__n_chunk_extension_name: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3, 0, 3, 3, 3, 3, 3, 0, 0, 3, 3, 0, 3, 3, 0, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 4, 0, 5, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 0, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_chunk_extension_name; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_1; + } + case 3: { + p++; + goto s_n_llhttp__internal__n_chunk_extension_name; + } + case 4: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_2; + } + case 5: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_3; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_4; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name: + s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_chunk_extension_name; + goto s_n_llhttp__internal__n_chunk_extension_name; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_extensions: + s_n_llhttp__internal__n_chunk_extensions: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_extensions; + } + switch (*p) { + case 13: { + p++; + goto s_n_llhttp__internal__n_error_17; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_error_18; + } + default: { + goto s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_size_otherwise: + s_n_llhttp__internal__n_chunk_size_otherwise: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_size_otherwise; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_4; + } + case 10: { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_5; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_chunk_size_almost_done; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_4; + } + case ';': { + p++; + goto s_n_llhttp__internal__n_chunk_extensions; + } + default: { + goto s_n_llhttp__internal__n_error_35; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_size: + s_n_llhttp__internal__n_chunk_size: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_size; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'A': { + p++; + match = 10; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'B': { + p++; + match = 11; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'C': { + p++; + match = 12; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'D': { + p++; + match = 13; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'E': { + p++; + match = 14; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'F': { + p++; + match = 15; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'a': { + p++; + match = 10; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'b': { + p++; + match = 11; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'c': { + p++; + match = 12; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'd': { + p++; + match = 13; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'e': { + p++; + match = 14; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'f': { + p++; + match = 15; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + default: { + goto s_n_llhttp__internal__n_chunk_size_otherwise; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_size_digit: + s_n_llhttp__internal__n_chunk_size_digit: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_size_digit; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'A': { + p++; + match = 10; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'B': { + p++; + match = 11; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'C': { + p++; + match = 12; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'D': { + p++; + match = 13; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'E': { + p++; + match = 14; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'F': { + p++; + match = 15; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'a': { + p++; + match = 10; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'b': { + p++; + match = 11; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'c': { + p++; + match = 12; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'd': { + p++; + match = 13; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'e': { + p++; + match = 14; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'f': { + p++; + match = 15; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + default: { + goto s_n_llhttp__internal__n_error_37; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_update_content_length_1: + s_n_llhttp__internal__n_invoke_update_content_length_1: { + switch (llhttp__internal__c_update_content_length(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_chunk_size_digit; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_consume_content_length_1: + s_n_llhttp__internal__n_consume_content_length_1: { + size_t avail; + uint64_t need; + + avail = endp - p; + need = state->content_length; + if (avail >= need) { + p += need; + state->content_length = 0; + goto s_n_llhttp__internal__n_span_end_llhttp__on_body_1; + } + + state->content_length -= avail; + return s_n_llhttp__internal__n_consume_content_length_1; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_body_1: + s_n_llhttp__internal__n_span_start_llhttp__on_body_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_body_1; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_body; + goto s_n_llhttp__internal__n_consume_content_length_1; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_eof: + s_n_llhttp__internal__n_eof: { + if (p == endp) { + return s_n_llhttp__internal__n_eof; + } + p++; + goto s_n_llhttp__internal__n_eof; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_body_2: + s_n_llhttp__internal__n_span_start_llhttp__on_body_2: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_body_2; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_body; + goto s_n_llhttp__internal__n_eof; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete: + s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete: { + switch (llhttp__after_headers_complete(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_1; + case 2: + goto s_n_llhttp__internal__n_invoke_update_content_length_1; + case 3: + goto s_n_llhttp__internal__n_span_start_llhttp__on_body_1; + case 4: + goto s_n_llhttp__internal__n_invoke_update_finish_3; + case 5: + goto s_n_llhttp__internal__n_error_39; + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_5: + s_n_llhttp__internal__n_error_5: { + state->error = 0xa; + state->reason = "Invalid header field char"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_headers_almost_done: + s_n_llhttp__internal__n_headers_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_headers_almost_done; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_invoke_test_flags_1; + } + default: { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_12; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_colon_discard_ws: + s_n_llhttp__internal__n_header_field_colon_discard_ws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field_colon_discard_ws; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_field_colon_discard_ws; + } + default: { + goto s_n_llhttp__internal__n_header_field_colon; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete: + s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete: { + switch (llhttp__on_header_value_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_header_field_start; + case 21: + goto s_n_llhttp__internal__n_pause_18; + default: + goto s_n_llhttp__internal__n_error_48; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_header_value: + s_n_llhttp__internal__n_span_start_llhttp__on_header_value: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_header_value; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_header_value; + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_discard_lws: + s_n_llhttp__internal__n_header_value_discard_lws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_discard_lws; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_15; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_15; + } + default: { + goto s_n_llhttp__internal__n_invoke_load_header_state_1; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_discard_ws_almost_done: + s_n_llhttp__internal__n_header_value_discard_ws_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_discard_ws_almost_done; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_header_value_discard_lws; + } + default: { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_16; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_lws: + s_n_llhttp__internal__n_header_value_lws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_lws; + } + switch (*p) { + case 9: { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_18; + } + case ' ': { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_18; + } + default: { + goto s_n_llhttp__internal__n_invoke_load_header_state_5; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_almost_done: + s_n_llhttp__internal__n_header_value_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_almost_done; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_header_value_lws; + } + default: { + goto s_n_llhttp__internal__n_error_53; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_test_lenient_flags_17: + s_n_llhttp__internal__n_invoke_test_lenient_flags_17: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_header_value_almost_done; + default: + goto s_n_llhttp__internal__n_error_51; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_lenient: + s_n_llhttp__internal__n_header_value_lenient: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_lenient; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4; + } + case 13: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_5; + } + default: { + p++; + goto s_n_llhttp__internal__n_header_value_lenient; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_54: + s_n_llhttp__internal__n_error_54: { + state->error = 0xa; + state->reason = "Invalid header value char"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_otherwise: + s_n_llhttp__internal__n_header_value_otherwise: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_otherwise; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1; + } + case 13: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_2; + } + default: { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_19; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection_token: + s_n_llhttp__internal__n_header_value_connection_token: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection_token; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_header_value_connection_token; + } + case 2: { + p++; + goto s_n_llhttp__internal__n_header_value_connection; + } + default: { + goto s_n_llhttp__internal__n_header_value_otherwise; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection_ws: + s_n_llhttp__internal__n_header_value_connection_ws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection_ws; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_header_value_otherwise; + } + case 13: { + goto s_n_llhttp__internal__n_header_value_otherwise; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_connection_ws; + } + case ',': { + p++; + goto s_n_llhttp__internal__n_invoke_load_header_state_6; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_5; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection_1: + s_n_llhttp__internal__n_header_value_connection_1: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection_1; + } + match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob2, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_update_header_state_3; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_value_connection_1; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_header_value_connection_token; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection_2: + s_n_llhttp__internal__n_header_value_connection_2: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection_2; + } + match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob3, 9); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_update_header_state_6; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_value_connection_2; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_header_value_connection_token; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection_3: + s_n_llhttp__internal__n_header_value_connection_3: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection_3; + } + match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob4, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_update_header_state_7; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_value_connection_3; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_header_value_connection_token; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection: + s_n_llhttp__internal__n_header_value_connection: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection; + } + switch (((*p) >= 'A' && (*p) <= 'Z' ? (*p | 0x20) : (*p))) { + case 9: { + p++; + goto s_n_llhttp__internal__n_header_value_connection; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_connection; + } + case 'c': { + p++; + goto s_n_llhttp__internal__n_header_value_connection_1; + } + case 'k': { + p++; + goto s_n_llhttp__internal__n_header_value_connection_2; + } + case 'u': { + p++; + goto s_n_llhttp__internal__n_header_value_connection_3; + } + default: { + goto s_n_llhttp__internal__n_header_value_connection_token; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_56: + s_n_llhttp__internal__n_error_56: { + state->error = 0xb; + state->reason = "Content-Length overflow"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_57: + s_n_llhttp__internal__n_error_57: { + state->error = 0xb; + state->reason = "Invalid character in Content-Length"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_content_length_ws: + s_n_llhttp__internal__n_header_value_content_length_ws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_content_length_ws; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_invoke_or_flags_17; + } + case 13: { + goto s_n_llhttp__internal__n_invoke_or_flags_17; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_content_length_ws; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_7; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_content_length: + s_n_llhttp__internal__n_header_value_content_length: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_content_length; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + default: { + goto s_n_llhttp__internal__n_header_value_content_length_ws; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_59: + s_n_llhttp__internal__n_error_59: { + state->error = 0xf; + state->reason = "Invalid `Transfer-Encoding` header value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_58: + s_n_llhttp__internal__n_error_58: { + state->error = 0xf; + state->reason = "Invalid `Transfer-Encoding` header value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_te_token_ows: + s_n_llhttp__internal__n_header_value_te_token_ows: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_te_token_ows; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_header_value_te_token_ows; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_te_token_ows; + } + default: { + goto s_n_llhttp__internal__n_header_value_te_chunked; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value: + s_n_llhttp__internal__n_header_value: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + if (p == endp) { + return s_n_llhttp__internal__n_header_value; + } + #ifdef __SSE4_2__ + if (endp - p >= 16) { + __m128i ranges; + __m128i input; + int avail; + int match_len; + + /* Load input */ + input = _mm_loadu_si128((__m128i const*) p); + ranges = _mm_loadu_si128((__m128i const*) llparse_blob6); + + /* Find first character that does not match `ranges` */ + match_len = _mm_cmpestri(ranges, 6, + input, 16, + _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES | + _SIDD_NEGATIVE_POLARITY); + + if (match_len != 0) { + p += match_len; + goto s_n_llhttp__internal__n_header_value; + } + goto s_n_llhttp__internal__n_header_value_otherwise; + } + #endif /* __SSE4_2__ */ + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_header_value; + } + default: { + goto s_n_llhttp__internal__n_header_value_otherwise; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_te_token: + s_n_llhttp__internal__n_header_value_te_token: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + if (p == endp) { + return s_n_llhttp__internal__n_header_value_te_token; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_header_value_te_token; + } + case 2: { + p++; + goto s_n_llhttp__internal__n_header_value_te_token_ows; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_9; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_te_chunked_last: + s_n_llhttp__internal__n_header_value_te_chunked_last: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_te_chunked_last; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_invoke_update_header_state_8; + } + case 13: { + goto s_n_llhttp__internal__n_invoke_update_header_state_8; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_te_chunked_last; + } + case ',': { + goto s_n_llhttp__internal__n_invoke_load_type_1; + } + default: { + goto s_n_llhttp__internal__n_header_value_te_token; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_te_chunked: + s_n_llhttp__internal__n_header_value_te_chunked: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_value_te_chunked; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob5, 7); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_header_value_te_chunked_last; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_value_te_chunked; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_header_value_te_token; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1: + s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_header_value; + goto s_n_llhttp__internal__n_invoke_load_header_state_3; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_discard_ws: + s_n_llhttp__internal__n_header_value_discard_ws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_discard_ws; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + case 10: { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_14; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_header_value_discard_ws_almost_done; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + default: { + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_load_header_state: + s_n_llhttp__internal__n_invoke_load_header_state: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 2: + goto s_n_llhttp__internal__n_invoke_test_flags_4; + case 3: + goto s_n_llhttp__internal__n_invoke_test_flags_5; + default: + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete: + s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete: { + switch (llhttp__on_header_field_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_load_header_state; + case 21: + goto s_n_llhttp__internal__n_pause_19; + default: + goto s_n_llhttp__internal__n_error_45; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_general_otherwise: + s_n_llhttp__internal__n_header_field_general_otherwise: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field_general_otherwise; + } + switch (*p) { + case ':': { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field_2; + } + default: { + goto s_n_llhttp__internal__n_error_62; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_general: + s_n_llhttp__internal__n_header_field_general: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_header_field_general; + } + #ifdef __SSE4_2__ + if (endp - p >= 16) { + __m128i ranges; + __m128i input; + int avail; + int match_len; + + /* Load input */ + input = _mm_loadu_si128((__m128i const*) p); + ranges = _mm_loadu_si128((__m128i const*) llparse_blob7); + + /* Find first character that does not match `ranges` */ + match_len = _mm_cmpestri(ranges, 16, + input, 16, + _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES | + _SIDD_NEGATIVE_POLARITY); + + if (match_len != 0) { + p += match_len; + goto s_n_llhttp__internal__n_header_field_general; + } + ranges = _mm_loadu_si128((__m128i const*) llparse_blob8); + + /* Find first character that does not match `ranges` */ + match_len = _mm_cmpestri(ranges, 2, + input, 16, + _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES | + _SIDD_NEGATIVE_POLARITY); + + if (match_len != 0) { + p += match_len; + goto s_n_llhttp__internal__n_header_field_general; + } + goto s_n_llhttp__internal__n_header_field_general_otherwise; + } + #endif /* __SSE4_2__ */ + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_header_field_general; + } + default: { + goto s_n_llhttp__internal__n_header_field_general_otherwise; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_colon: + s_n_llhttp__internal__n_header_field_colon: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field_colon; + } + switch (*p) { + case ' ': { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_13; + } + case ':': { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field_1; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_10; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_3: + s_n_llhttp__internal__n_header_field_3: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_3; + } + match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob1, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_header_state; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_3; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_11; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_4: + s_n_llhttp__internal__n_header_field_4: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_4; + } + match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob9, 10); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_header_state; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_4; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_11; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_2: + s_n_llhttp__internal__n_header_field_2: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field_2; + } + switch (((*p) >= 'A' && (*p) <= 'Z' ? (*p | 0x20) : (*p))) { + case 'n': { + p++; + goto s_n_llhttp__internal__n_header_field_3; + } + case 't': { + p++; + goto s_n_llhttp__internal__n_header_field_4; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_11; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_1: + s_n_llhttp__internal__n_header_field_1: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_1; + } + match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob0, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_header_field_2; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_1; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_11; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_5: + s_n_llhttp__internal__n_header_field_5: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_5; + } + match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob10, 15); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_header_state; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_5; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_11; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_6: + s_n_llhttp__internal__n_header_field_6: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_6; + } + match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob11, 16); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_header_state; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_6; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_11; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_7: + s_n_llhttp__internal__n_header_field_7: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_7; + } + match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob12, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_header_state; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_7; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_11; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field: + s_n_llhttp__internal__n_header_field: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field; + } + switch (((*p) >= 'A' && (*p) <= 'Z' ? (*p | 0x20) : (*p))) { + case 'c': { + p++; + goto s_n_llhttp__internal__n_header_field_1; + } + case 'p': { + p++; + goto s_n_llhttp__internal__n_header_field_5; + } + case 't': { + p++; + goto s_n_llhttp__internal__n_header_field_6; + } + case 'u': { + p++; + goto s_n_llhttp__internal__n_header_field_7; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_11; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_header_field: + s_n_llhttp__internal__n_span_start_llhttp__on_header_field: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_header_field; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_header_field; + goto s_n_llhttp__internal__n_header_field; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_start: + s_n_llhttp__internal__n_header_field_start: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field_start; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_1; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_headers_almost_done; + } + case ':': { + goto s_n_llhttp__internal__n_error_44; + } + default: { + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_field; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_headers_start: + s_n_llhttp__internal__n_headers_start: { + if (p == endp) { + return s_n_llhttp__internal__n_headers_start; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags; + } + default: { + goto s_n_llhttp__internal__n_header_field_start; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_to_http_09: + s_n_llhttp__internal__n_url_to_http_09: { + if (p == endp) { + return s_n_llhttp__internal__n_url_to_http_09; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 12: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_http_major; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_skip_to_http09: + s_n_llhttp__internal__n_url_skip_to_http09: { + if (p == endp) { + return s_n_llhttp__internal__n_url_skip_to_http09; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 12: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + default: { + p++; + goto s_n_llhttp__internal__n_url_to_http_09; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_skip_lf_to_http09_1: + s_n_llhttp__internal__n_url_skip_lf_to_http09_1: { + if (p == endp) { + return s_n_llhttp__internal__n_url_skip_lf_to_http09_1; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_url_to_http_09; + } + default: { + goto s_n_llhttp__internal__n_error_63; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_skip_lf_to_http09: + s_n_llhttp__internal__n_url_skip_lf_to_http09: { + if (p == endp) { + return s_n_llhttp__internal__n_url_skip_lf_to_http09; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 12: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_url_skip_lf_to_http09_1; + } + default: { + goto s_n_llhttp__internal__n_error_63; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_pri_upgrade: + s_n_llhttp__internal__n_req_pri_upgrade: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_req_pri_upgrade; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob14, 10); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_error_71; + } + case kMatchPause: { + return s_n_llhttp__internal__n_req_pri_upgrade; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_72; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_complete_crlf: + s_n_llhttp__internal__n_req_http_complete_crlf: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_complete_crlf; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_headers_start; + } + default: { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_26; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_complete: + s_n_llhttp__internal__n_req_http_complete: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_complete; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_25; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_req_http_complete_crlf; + } + default: { + goto s_n_llhttp__internal__n_error_70; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_load_method_1: + s_n_llhttp__internal__n_invoke_load_method_1: { + switch (llhttp__internal__c_load_method(state, p, endp)) { + case 34: + goto s_n_llhttp__internal__n_req_pri_upgrade; + default: + goto s_n_llhttp__internal__n_req_http_complete; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_version_complete: + s_n_llhttp__internal__n_invoke_llhttp__on_version_complete: { + switch (llhttp__on_version_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_load_method_1; + case 21: + goto s_n_llhttp__internal__n_pause_21; + default: + goto s_n_llhttp__internal__n_error_67; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_66: + s_n_llhttp__internal__n_error_66: { + state->error = 0x9; + state->reason = "Invalid HTTP version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_73: + s_n_llhttp__internal__n_error_73: { + state->error = 0x9; + state->reason = "Invalid minor version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_minor: + s_n_llhttp__internal__n_req_http_minor: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_minor; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_2; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_74: + s_n_llhttp__internal__n_error_74: { + state->error = 0x9; + state->reason = "Expected dot"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_dot: + s_n_llhttp__internal__n_req_http_dot: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_dot; + } + switch (*p) { + case '.': { + p++; + goto s_n_llhttp__internal__n_req_http_minor; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_3; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_75: + s_n_llhttp__internal__n_error_75: { + state->error = 0x9; + state->reason = "Invalid major version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_major: + s_n_llhttp__internal__n_req_http_major: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_major; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_4; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_version: + s_n_llhttp__internal__n_span_start_llhttp__on_version: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_version; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_version; + goto s_n_llhttp__internal__n_req_http_major; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_start_1: + s_n_llhttp__internal__n_req_http_start_1: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_req_http_start_1; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob13, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_load_method; + } + case kMatchPause: { + return s_n_llhttp__internal__n_req_http_start_1; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_78; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_start_2: + s_n_llhttp__internal__n_req_http_start_2: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_req_http_start_2; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob15, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_load_method_2; + } + case kMatchPause: { + return s_n_llhttp__internal__n_req_http_start_2; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_78; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_start_3: + s_n_llhttp__internal__n_req_http_start_3: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_req_http_start_3; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob16, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_load_method_3; + } + case kMatchPause: { + return s_n_llhttp__internal__n_req_http_start_3; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_78; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_start: + s_n_llhttp__internal__n_req_http_start: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_start; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_req_http_start; + } + case 'H': { + p++; + goto s_n_llhttp__internal__n_req_http_start_1; + } + case 'I': { + p++; + goto s_n_llhttp__internal__n_req_http_start_2; + } + case 'R': { + p++; + goto s_n_llhttp__internal__n_req_http_start_3; + } + default: { + goto s_n_llhttp__internal__n_error_78; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_to_http: + s_n_llhttp__internal__n_url_to_http: { + if (p == endp) { + return s_n_llhttp__internal__n_url_to_http; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 12: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + default: { + goto s_n_llhttp__internal__n_invoke_llhttp__on_url_complete_1; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_skip_to_http: + s_n_llhttp__internal__n_url_skip_to_http: { + if (p == endp) { + return s_n_llhttp__internal__n_url_skip_to_http; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 12: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + default: { + p++; + goto s_n_llhttp__internal__n_url_to_http; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_fragment: + s_n_llhttp__internal__n_url_fragment: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_fragment; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_6; + } + case 3: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_7; + } + case 4: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_8; + } + case 5: { + p++; + goto s_n_llhttp__internal__n_url_fragment; + } + default: { + goto s_n_llhttp__internal__n_error_79; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_end_stub_query_3: + s_n_llhttp__internal__n_span_end_stub_query_3: { + if (p == endp) { + return s_n_llhttp__internal__n_span_end_stub_query_3; + } + p++; + goto s_n_llhttp__internal__n_url_fragment; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_query: + s_n_llhttp__internal__n_url_query: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_query; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_9; + } + case 3: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_10; + } + case 4: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_11; + } + case 5: { + p++; + goto s_n_llhttp__internal__n_url_query; + } + case 6: { + goto s_n_llhttp__internal__n_span_end_stub_query_3; + } + default: { + goto s_n_llhttp__internal__n_error_80; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_query_or_fragment: + s_n_llhttp__internal__n_url_query_or_fragment: { + if (p == endp) { + return s_n_llhttp__internal__n_url_query_or_fragment; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 10: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_3; + } + case 12: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 13: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_4; + } + case ' ': { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_5; + } + case '#': { + p++; + goto s_n_llhttp__internal__n_url_fragment; + } + case '?': { + p++; + goto s_n_llhttp__internal__n_url_query; + } + default: { + goto s_n_llhttp__internal__n_error_81; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_path: + s_n_llhttp__internal__n_url_path: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_path; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 2: { + p++; + goto s_n_llhttp__internal__n_url_path; + } + default: { + goto s_n_llhttp__internal__n_url_query_or_fragment; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_stub_path_2: + s_n_llhttp__internal__n_span_start_stub_path_2: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_stub_path_2; + } + p++; + goto s_n_llhttp__internal__n_url_path; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_stub_path: + s_n_llhttp__internal__n_span_start_stub_path: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_stub_path; + } + p++; + goto s_n_llhttp__internal__n_url_path; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_stub_path_1: + s_n_llhttp__internal__n_span_start_stub_path_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_stub_path_1; + } + p++; + goto s_n_llhttp__internal__n_url_path; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_server_with_at: + s_n_llhttp__internal__n_url_server_with_at: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 7, + 8, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 5, + 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_server_with_at; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_12; + } + case 3: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_13; + } + case 4: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_14; + } + case 5: { + p++; + goto s_n_llhttp__internal__n_url_server; + } + case 6: { + goto s_n_llhttp__internal__n_span_start_stub_path_1; + } + case 7: { + p++; + goto s_n_llhttp__internal__n_url_query; + } + case 8: { + p++; + goto s_n_llhttp__internal__n_error_82; + } + default: { + goto s_n_llhttp__internal__n_error_83; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_server: + s_n_llhttp__internal__n_url_server: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 7, + 8, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 5, + 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_server; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url; + } + case 3: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_1; + } + case 4: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_2; + } + case 5: { + p++; + goto s_n_llhttp__internal__n_url_server; + } + case 6: { + goto s_n_llhttp__internal__n_span_start_stub_path; + } + case 7: { + p++; + goto s_n_llhttp__internal__n_url_query; + } + case 8: { + p++; + goto s_n_llhttp__internal__n_url_server_with_at; + } + default: { + goto s_n_llhttp__internal__n_error_84; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_schema_delim_1: + s_n_llhttp__internal__n_url_schema_delim_1: { + if (p == endp) { + return s_n_llhttp__internal__n_url_schema_delim_1; + } + switch (*p) { + case '/': { + p++; + goto s_n_llhttp__internal__n_url_server; + } + default: { + goto s_n_llhttp__internal__n_error_85; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_schema_delim: + s_n_llhttp__internal__n_url_schema_delim: { + if (p == endp) { + return s_n_llhttp__internal__n_url_schema_delim; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 10: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 12: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case '/': { + p++; + goto s_n_llhttp__internal__n_url_schema_delim_1; + } + default: { + goto s_n_llhttp__internal__n_error_85; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_end_stub_schema: + s_n_llhttp__internal__n_span_end_stub_schema: { + if (p == endp) { + return s_n_llhttp__internal__n_span_end_stub_schema; + } + p++; + goto s_n_llhttp__internal__n_url_schema_delim; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_schema: + s_n_llhttp__internal__n_url_schema: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_schema; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_stub_schema; + } + case 3: { + p++; + goto s_n_llhttp__internal__n_url_schema; + } + default: { + goto s_n_llhttp__internal__n_error_86; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_start: + s_n_llhttp__internal__n_url_start: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_start; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 2: { + goto s_n_llhttp__internal__n_span_start_stub_path_2; + } + case 3: { + goto s_n_llhttp__internal__n_url_schema; + } + default: { + goto s_n_llhttp__internal__n_error_87; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_url_1: + s_n_llhttp__internal__n_span_start_llhttp__on_url_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_url_1; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_url; + goto s_n_llhttp__internal__n_url_start; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_entry_normal: + s_n_llhttp__internal__n_url_entry_normal: { + if (p == endp) { + return s_n_llhttp__internal__n_url_entry_normal; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 12: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + default: { + goto s_n_llhttp__internal__n_span_start_llhttp__on_url_1; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_url: + s_n_llhttp__internal__n_span_start_llhttp__on_url: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_url; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_url; + goto s_n_llhttp__internal__n_url_server; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_entry_connect: + s_n_llhttp__internal__n_url_entry_connect: { + if (p == endp) { + return s_n_llhttp__internal__n_url_entry_connect; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + case 12: { + p++; + goto s_n_llhttp__internal__n_error_2; + } + default: { + goto s_n_llhttp__internal__n_span_start_llhttp__on_url; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_spaces_before_url: + s_n_llhttp__internal__n_req_spaces_before_url: { + if (p == endp) { + return s_n_llhttp__internal__n_req_spaces_before_url; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_req_spaces_before_url; + } + default: { + goto s_n_llhttp__internal__n_invoke_is_equal_method; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_first_space_before_url: + s_n_llhttp__internal__n_req_first_space_before_url: { + if (p == endp) { + return s_n_llhttp__internal__n_req_first_space_before_url; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_req_spaces_before_url; + } + default: { + goto s_n_llhttp__internal__n_error_88; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1: + s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1: { + switch (llhttp__on_method_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_req_first_space_before_url; + case 21: + goto s_n_llhttp__internal__n_pause_26; + default: + goto s_n_llhttp__internal__n_error_107; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_2: + s_n_llhttp__internal__n_after_start_req_2: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_2; + } + switch (*p) { + case 'L': { + p++; + match = 19; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_3: + s_n_llhttp__internal__n_after_start_req_3: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_3; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob17, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 36; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_3; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_1: + s_n_llhttp__internal__n_after_start_req_1: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_1; + } + switch (*p) { + case 'C': { + p++; + goto s_n_llhttp__internal__n_after_start_req_2; + } + case 'N': { + p++; + goto s_n_llhttp__internal__n_after_start_req_3; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_4: + s_n_llhttp__internal__n_after_start_req_4: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_4; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob18, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 16; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_4; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_6: + s_n_llhttp__internal__n_after_start_req_6: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_6; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob19, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 22; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_6; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_8: + s_n_llhttp__internal__n_after_start_req_8: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_8; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob20, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_8; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_9: + s_n_llhttp__internal__n_after_start_req_9: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_9; + } + switch (*p) { + case 'Y': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_7: + s_n_llhttp__internal__n_after_start_req_7: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_7; + } + switch (*p) { + case 'N': { + p++; + goto s_n_llhttp__internal__n_after_start_req_8; + } + case 'P': { + p++; + goto s_n_llhttp__internal__n_after_start_req_9; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_5: + s_n_llhttp__internal__n_after_start_req_5: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_5; + } + switch (*p) { + case 'H': { + p++; + goto s_n_llhttp__internal__n_after_start_req_6; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_after_start_req_7; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_12: + s_n_llhttp__internal__n_after_start_req_12: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_12; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob21, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_12; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_13: + s_n_llhttp__internal__n_after_start_req_13: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_13; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob22, 5); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 35; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_13; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_11: + s_n_llhttp__internal__n_after_start_req_11: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_11; + } + switch (*p) { + case 'L': { + p++; + goto s_n_llhttp__internal__n_after_start_req_12; + } + case 'S': { + p++; + goto s_n_llhttp__internal__n_after_start_req_13; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_10: + s_n_llhttp__internal__n_after_start_req_10: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_10; + } + switch (*p) { + case 'E': { + p++; + goto s_n_llhttp__internal__n_after_start_req_11; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_14: + s_n_llhttp__internal__n_after_start_req_14: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_14; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob23, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 45; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_14; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_17: + s_n_llhttp__internal__n_after_start_req_17: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_17; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob25, 9); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 41; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_17; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_16: + s_n_llhttp__internal__n_after_start_req_16: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_16; + } + switch (*p) { + case '_': { + p++; + goto s_n_llhttp__internal__n_after_start_req_17; + } + default: { + match = 1; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_15: + s_n_llhttp__internal__n_after_start_req_15: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_15; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob24, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_after_start_req_16; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_15; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_18: + s_n_llhttp__internal__n_after_start_req_18: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_18; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob26, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_18; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_20: + s_n_llhttp__internal__n_after_start_req_20: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_20; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob27, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 31; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_20; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_21: + s_n_llhttp__internal__n_after_start_req_21: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_21; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob28, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_21; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_19: + s_n_llhttp__internal__n_after_start_req_19: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_19; + } + switch (*p) { + case 'I': { + p++; + goto s_n_llhttp__internal__n_after_start_req_20; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_after_start_req_21; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_23: + s_n_llhttp__internal__n_after_start_req_23: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_23; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob29, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 24; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_23; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_24: + s_n_llhttp__internal__n_after_start_req_24: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_24; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob30, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 23; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_24; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_26: + s_n_llhttp__internal__n_after_start_req_26: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_26; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob31, 7); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 21; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_26; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_28: + s_n_llhttp__internal__n_after_start_req_28: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_28; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob32, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 30; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_28; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_29: + s_n_llhttp__internal__n_after_start_req_29: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_29; + } + switch (*p) { + case 'L': { + p++; + match = 10; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_27: + s_n_llhttp__internal__n_after_start_req_27: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_27; + } + switch (*p) { + case 'A': { + p++; + goto s_n_llhttp__internal__n_after_start_req_28; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_after_start_req_29; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_25: + s_n_llhttp__internal__n_after_start_req_25: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_25; + } + switch (*p) { + case 'A': { + p++; + goto s_n_llhttp__internal__n_after_start_req_26; + } + case 'C': { + p++; + goto s_n_llhttp__internal__n_after_start_req_27; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_30: + s_n_llhttp__internal__n_after_start_req_30: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_30; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob33, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 11; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_30; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_22: + s_n_llhttp__internal__n_after_start_req_22: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_22; + } + switch (*p) { + case '-': { + p++; + goto s_n_llhttp__internal__n_after_start_req_23; + } + case 'E': { + p++; + goto s_n_llhttp__internal__n_after_start_req_24; + } + case 'K': { + p++; + goto s_n_llhttp__internal__n_after_start_req_25; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_after_start_req_30; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_31: + s_n_llhttp__internal__n_after_start_req_31: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_31; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob34, 5); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 25; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_31; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_32: + s_n_llhttp__internal__n_after_start_req_32: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_32; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob35, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_32; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_35: + s_n_llhttp__internal__n_after_start_req_35: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_35; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob36, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 28; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_35; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_36: + s_n_llhttp__internal__n_after_start_req_36: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_36; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob37, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 39; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_36; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_34: + s_n_llhttp__internal__n_after_start_req_34: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_34; + } + switch (*p) { + case 'T': { + p++; + goto s_n_llhttp__internal__n_after_start_req_35; + } + case 'U': { + p++; + goto s_n_llhttp__internal__n_after_start_req_36; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_37: + s_n_llhttp__internal__n_after_start_req_37: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_37; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob38, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 38; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_37; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_38: + s_n_llhttp__internal__n_after_start_req_38: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_38; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob39, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_38; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_42: + s_n_llhttp__internal__n_after_start_req_42: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_42; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob40, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 12; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_42; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_43: + s_n_llhttp__internal__n_after_start_req_43: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_43; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob41, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 13; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_43; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_41: + s_n_llhttp__internal__n_after_start_req_41: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_41; + } + switch (*p) { + case 'F': { + p++; + goto s_n_llhttp__internal__n_after_start_req_42; + } + case 'P': { + p++; + goto s_n_llhttp__internal__n_after_start_req_43; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_40: + s_n_llhttp__internal__n_after_start_req_40: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_40; + } + switch (*p) { + case 'P': { + p++; + goto s_n_llhttp__internal__n_after_start_req_41; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_39: + s_n_llhttp__internal__n_after_start_req_39: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_39; + } + switch (*p) { + case 'I': { + p++; + match = 34; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_after_start_req_40; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_45: + s_n_llhttp__internal__n_after_start_req_45: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_45; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob42, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 29; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_45; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_44: + s_n_llhttp__internal__n_after_start_req_44: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_44; + } + switch (*p) { + case 'R': { + p++; + goto s_n_llhttp__internal__n_after_start_req_45; + } + case 'T': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_33: + s_n_llhttp__internal__n_after_start_req_33: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_33; + } + switch (*p) { + case 'A': { + p++; + goto s_n_llhttp__internal__n_after_start_req_34; + } + case 'L': { + p++; + goto s_n_llhttp__internal__n_after_start_req_37; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_after_start_req_38; + } + case 'R': { + p++; + goto s_n_llhttp__internal__n_after_start_req_39; + } + case 'U': { + p++; + goto s_n_llhttp__internal__n_after_start_req_44; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_46: + s_n_llhttp__internal__n_after_start_req_46: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_46; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob43, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 46; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_46; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_49: + s_n_llhttp__internal__n_after_start_req_49: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_49; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob44, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 17; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_49; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_50: + s_n_llhttp__internal__n_after_start_req_50: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_50; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob45, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 44; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_50; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_51: + s_n_llhttp__internal__n_after_start_req_51: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_51; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob46, 5); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 43; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_51; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_52: + s_n_llhttp__internal__n_after_start_req_52: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_52; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob47, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 20; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_52; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_48: + s_n_llhttp__internal__n_after_start_req_48: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_48; + } + switch (*p) { + case 'B': { + p++; + goto s_n_llhttp__internal__n_after_start_req_49; + } + case 'C': { + p++; + goto s_n_llhttp__internal__n_after_start_req_50; + } + case 'D': { + p++; + goto s_n_llhttp__internal__n_after_start_req_51; + } + case 'P': { + p++; + goto s_n_llhttp__internal__n_after_start_req_52; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_47: + s_n_llhttp__internal__n_after_start_req_47: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_47; + } + switch (*p) { + case 'E': { + p++; + goto s_n_llhttp__internal__n_after_start_req_48; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_55: + s_n_llhttp__internal__n_after_start_req_55: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_55; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob48, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 14; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_55; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_57: + s_n_llhttp__internal__n_after_start_req_57: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_57; + } + switch (*p) { + case 'P': { + p++; + match = 37; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_58: + s_n_llhttp__internal__n_after_start_req_58: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_58; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob49, 9); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 42; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_58; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_56: + s_n_llhttp__internal__n_after_start_req_56: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_56; + } + switch (*p) { + case 'U': { + p++; + goto s_n_llhttp__internal__n_after_start_req_57; + } + case '_': { + p++; + goto s_n_llhttp__internal__n_after_start_req_58; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_54: + s_n_llhttp__internal__n_after_start_req_54: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_54; + } + switch (*p) { + case 'A': { + p++; + goto s_n_llhttp__internal__n_after_start_req_55; + } + case 'T': { + p++; + goto s_n_llhttp__internal__n_after_start_req_56; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_59: + s_n_llhttp__internal__n_after_start_req_59: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_59; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob50, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 33; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_59; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_60: + s_n_llhttp__internal__n_after_start_req_60: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_60; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob51, 7); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 26; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_60; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_53: + s_n_llhttp__internal__n_after_start_req_53: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_53; + } + switch (*p) { + case 'E': { + p++; + goto s_n_llhttp__internal__n_after_start_req_54; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_after_start_req_59; + } + case 'U': { + p++; + goto s_n_llhttp__internal__n_after_start_req_60; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_62: + s_n_llhttp__internal__n_after_start_req_62: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_62; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob52, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 40; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_62; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_63: + s_n_llhttp__internal__n_after_start_req_63: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_63; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob53, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_63; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_61: + s_n_llhttp__internal__n_after_start_req_61: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_61; + } + switch (*p) { + case 'E': { + p++; + goto s_n_llhttp__internal__n_after_start_req_62; + } + case 'R': { + p++; + goto s_n_llhttp__internal__n_after_start_req_63; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_66: + s_n_llhttp__internal__n_after_start_req_66: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_66; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob54, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 18; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_66; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_68: + s_n_llhttp__internal__n_after_start_req_68: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_68; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob55, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 32; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_68; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_69: + s_n_llhttp__internal__n_after_start_req_69: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_69; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob56, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 15; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_69; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_67: + s_n_llhttp__internal__n_after_start_req_67: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_67; + } + switch (*p) { + case 'I': { + p++; + goto s_n_llhttp__internal__n_after_start_req_68; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_after_start_req_69; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_70: + s_n_llhttp__internal__n_after_start_req_70: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_70; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob57, 8); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 27; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_after_start_req_70; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_65: + s_n_llhttp__internal__n_after_start_req_65: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_65; + } + switch (*p) { + case 'B': { + p++; + goto s_n_llhttp__internal__n_after_start_req_66; + } + case 'L': { + p++; + goto s_n_llhttp__internal__n_after_start_req_67; + } + case 'S': { + p++; + goto s_n_llhttp__internal__n_after_start_req_70; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req_64: + s_n_llhttp__internal__n_after_start_req_64: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req_64; + } + switch (*p) { + case 'N': { + p++; + goto s_n_llhttp__internal__n_after_start_req_65; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_after_start_req: + s_n_llhttp__internal__n_after_start_req: { + if (p == endp) { + return s_n_llhttp__internal__n_after_start_req; + } + switch (*p) { + case 'A': { + p++; + goto s_n_llhttp__internal__n_after_start_req_1; + } + case 'B': { + p++; + goto s_n_llhttp__internal__n_after_start_req_4; + } + case 'C': { + p++; + goto s_n_llhttp__internal__n_after_start_req_5; + } + case 'D': { + p++; + goto s_n_llhttp__internal__n_after_start_req_10; + } + case 'F': { + p++; + goto s_n_llhttp__internal__n_after_start_req_14; + } + case 'G': { + p++; + goto s_n_llhttp__internal__n_after_start_req_15; + } + case 'H': { + p++; + goto s_n_llhttp__internal__n_after_start_req_18; + } + case 'L': { + p++; + goto s_n_llhttp__internal__n_after_start_req_19; + } + case 'M': { + p++; + goto s_n_llhttp__internal__n_after_start_req_22; + } + case 'N': { + p++; + goto s_n_llhttp__internal__n_after_start_req_31; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_after_start_req_32; + } + case 'P': { + p++; + goto s_n_llhttp__internal__n_after_start_req_33; + } + case 'Q': { + p++; + goto s_n_llhttp__internal__n_after_start_req_46; + } + case 'R': { + p++; + goto s_n_llhttp__internal__n_after_start_req_47; + } + case 'S': { + p++; + goto s_n_llhttp__internal__n_after_start_req_53; + } + case 'T': { + p++; + goto s_n_llhttp__internal__n_after_start_req_61; + } + case 'U': { + p++; + goto s_n_llhttp__internal__n_after_start_req_64; + } + default: { + goto s_n_llhttp__internal__n_error_108; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_method_1: + s_n_llhttp__internal__n_span_start_llhttp__on_method_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_method_1; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_method; + goto s_n_llhttp__internal__n_after_start_req; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_line_almost_done: + s_n_llhttp__internal__n_res_line_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_res_line_almost_done; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete; + } + default: { + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_29; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_test_lenient_flags_30: + s_n_llhttp__internal__n_invoke_test_lenient_flags_30: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete; + default: + goto s_n_llhttp__internal__n_error_94; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_status: + s_n_llhttp__internal__n_res_status: { + if (p == endp) { + return s_n_llhttp__internal__n_res_status; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_status; + } + case 13: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_status_1; + } + default: { + p++; + goto s_n_llhttp__internal__n_res_status; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_status: + s_n_llhttp__internal__n_span_start_llhttp__on_status: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_status; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_status; + goto s_n_llhttp__internal__n_res_status; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_status_code_otherwise: + s_n_llhttp__internal__n_res_status_code_otherwise: { + if (p == endp) { + return s_n_llhttp__internal__n_res_status_code_otherwise; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_28; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_res_line_almost_done; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_span_start_llhttp__on_status; + } + default: { + goto s_n_llhttp__internal__n_error_95; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_status_code_digit_3: + s_n_llhttp__internal__n_res_status_code_digit_3: { + if (p == endp) { + return s_n_llhttp__internal__n_res_status_code_digit_3; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; + } + default: { + goto s_n_llhttp__internal__n_error_97; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_status_code_digit_2: + s_n_llhttp__internal__n_res_status_code_digit_2: { + if (p == endp) { + return s_n_llhttp__internal__n_res_status_code_digit_2; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; + } + default: { + goto s_n_llhttp__internal__n_error_99; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_status_code_digit_1: + s_n_llhttp__internal__n_res_status_code_digit_1: { + if (p == endp) { + return s_n_llhttp__internal__n_res_status_code_digit_1; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + default: { + goto s_n_llhttp__internal__n_error_101; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_after_version: + s_n_llhttp__internal__n_res_after_version: { + if (p == endp) { + return s_n_llhttp__internal__n_res_after_version; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_invoke_update_status_code; + } + default: { + goto s_n_llhttp__internal__n_error_102; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1: + s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1: { + switch (llhttp__on_version_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_res_after_version; + case 21: + goto s_n_llhttp__internal__n_pause_25; + default: + goto s_n_llhttp__internal__n_error_90; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_89: + s_n_llhttp__internal__n_error_89: { + state->error = 0x9; + state->reason = "Invalid HTTP version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_103: + s_n_llhttp__internal__n_error_103: { + state->error = 0x9; + state->reason = "Invalid minor version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_http_minor: + s_n_llhttp__internal__n_res_http_minor: { + if (p == endp) { + return s_n_llhttp__internal__n_res_http_minor; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_7; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_104: + s_n_llhttp__internal__n_error_104: { + state->error = 0x9; + state->reason = "Expected dot"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_http_dot: + s_n_llhttp__internal__n_res_http_dot: { + if (p == endp) { + return s_n_llhttp__internal__n_res_http_dot; + } + switch (*p) { + case '.': { + p++; + goto s_n_llhttp__internal__n_res_http_minor; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_8; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_105: + s_n_llhttp__internal__n_error_105: { + state->error = 0x9; + state->reason = "Invalid major version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_http_major: + s_n_llhttp__internal__n_res_http_major: { + if (p == endp) { + return s_n_llhttp__internal__n_res_http_major; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_9; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_version_1: + s_n_llhttp__internal__n_span_start_llhttp__on_version_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_version_1; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_version; + goto s_n_llhttp__internal__n_res_http_major; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_res: + s_n_llhttp__internal__n_start_res: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_res; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob58, 5); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_span_start_llhttp__on_version_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_res; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_109; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_method_complete: + s_n_llhttp__internal__n_invoke_llhttp__on_method_complete: { + switch (llhttp__on_method_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_req_first_space_before_url; + case 21: + goto s_n_llhttp__internal__n_pause_23; + default: + goto s_n_llhttp__internal__n_error_1; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_or_res_method_2: + s_n_llhttp__internal__n_req_or_res_method_2: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_req_or_res_method_2; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob59, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_method; + } + case kMatchPause: { + return s_n_llhttp__internal__n_req_or_res_method_2; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_106; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_update_type_1: + s_n_llhttp__internal__n_invoke_update_type_1: { + switch (llhttp__internal__c_update_type_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version_1; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_or_res_method_3: + s_n_llhttp__internal__n_req_or_res_method_3: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_req_or_res_method_3; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob60, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_span_end_llhttp__on_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_req_or_res_method_3; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_106; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_or_res_method_1: + s_n_llhttp__internal__n_req_or_res_method_1: { + if (p == endp) { + return s_n_llhttp__internal__n_req_or_res_method_1; + } + switch (*p) { + case 'E': { + p++; + goto s_n_llhttp__internal__n_req_or_res_method_2; + } + case 'T': { + p++; + goto s_n_llhttp__internal__n_req_or_res_method_3; + } + default: { + goto s_n_llhttp__internal__n_error_106; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_or_res_method: + s_n_llhttp__internal__n_req_or_res_method: { + if (p == endp) { + return s_n_llhttp__internal__n_req_or_res_method; + } + switch (*p) { + case 'H': { + p++; + goto s_n_llhttp__internal__n_req_or_res_method_1; + } + default: { + goto s_n_llhttp__internal__n_error_106; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_method: + s_n_llhttp__internal__n_span_start_llhttp__on_method: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_method; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_method; + goto s_n_llhttp__internal__n_req_or_res_method; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_or_res: + s_n_llhttp__internal__n_start_req_or_res: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_or_res; + } + switch (*p) { + case 'H': { + goto s_n_llhttp__internal__n_span_start_llhttp__on_method; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_type_2; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_load_type: + s_n_llhttp__internal__n_invoke_load_type: { + switch (llhttp__internal__c_load_type(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_span_start_llhttp__on_method_1; + case 2: + goto s_n_llhttp__internal__n_start_res; + default: + goto s_n_llhttp__internal__n_start_req_or_res; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_update_finish: + s_n_llhttp__internal__n_invoke_update_finish: { + switch (llhttp__internal__c_update_finish(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_begin; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start: + s_n_llhttp__internal__n_start: { + if (p == endp) { + return s_n_llhttp__internal__n_start; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_start; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_start; + } + default: { + goto s_n_llhttp__internal__n_invoke_load_initial_message_completed; + } + } + /* UNREACHABLE */; + abort(); + } + default: + /* UNREACHABLE */ + abort(); + } + s_n_llhttp__internal__n_error_2: { + state->error = 0x7; + state->reason = "Invalid characters in url"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_finish_2: { + switch (llhttp__internal__c_update_finish_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_start; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_initial_message_completed: { + switch (llhttp__internal__c_update_initial_message_completed(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_finish_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_content_length: { + switch (llhttp__internal__c_update_content_length(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_initial_message_completed; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_8: { + state->error = 0x5; + state->reason = "Data after `Connection: close`"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_3: { + switch (llhttp__internal__c_test_lenient_flags_3(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_closed; + default: + goto s_n_llhttp__internal__n_error_8; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_2: { + switch (llhttp__internal__c_test_lenient_flags_2(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_update_initial_message_completed; + default: + goto s_n_llhttp__internal__n_closed; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_finish_1: { + switch (llhttp__internal__c_update_finish_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_13: { + state->error = 0x15; + state->reason = "on_message_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_upgrade; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_38: { + state->error = 0x12; + state->reason = "`on_message_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_15: { + state->error = 0x15; + state->reason = "on_chunk_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_40: { + state->error = 0x14; + state->reason = "`on_chunk_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_1: { + switch (llhttp__on_chunk_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; + case 21: + goto s_n_llhttp__internal__n_pause_15; + default: + goto s_n_llhttp__internal__n_error_40; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_2: { + state->error = 0x15; + state->reason = "on_message_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_pause_1; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_9: { + state->error = 0x12; + state->reason = "`on_message_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_1: { + switch (llhttp__on_message_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_pause_1; + case 21: + goto s_n_llhttp__internal__n_pause_2; + default: + goto s_n_llhttp__internal__n_error_9; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_36: { + state->error = 0xc; + state->reason = "Chunk size overflow"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_10: { + state->error = 0xc; + state->reason = "Invalid character in chunk size"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_4: { + switch (llhttp__internal__c_test_lenient_flags_4(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_chunk_size_otherwise; + default: + goto s_n_llhttp__internal__n_error_10; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_3: { + state->error = 0x15; + state->reason = "on_chunk_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_update_content_length_1; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_14: { + state->error = 0x14; + state->reason = "`on_chunk_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete: { + switch (llhttp__on_chunk_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_update_content_length_1; + case 21: + goto s_n_llhttp__internal__n_pause_3; + default: + goto s_n_llhttp__internal__n_error_14; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_13: { + state->error = 0x19; + state->reason = "Missing expected CR after chunk data"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_6: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete; + default: + goto s_n_llhttp__internal__n_error_13; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_15: { + state->error = 0x2; + state->reason = "Expected LF after chunk data"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_7: { + switch (llhttp__internal__c_test_lenient_flags_7(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete; + default: + goto s_n_llhttp__internal__n_error_15; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_body: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_body(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_data_almost_done; + return s_error; + } + goto s_n_llhttp__internal__n_chunk_data_almost_done; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags: { + switch (llhttp__internal__c_or_flags(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_field_start; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_4: { + state->error = 0x15; + state->reason = "on_chunk_header pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_content_length; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_12: { + state->error = 0x13; + state->reason = "`on_chunk_header` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header: { + switch (llhttp__on_chunk_header(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_is_equal_content_length; + case 21: + goto s_n_llhttp__internal__n_pause_4; + default: + goto s_n_llhttp__internal__n_error_12; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_16: { + state->error = 0x2; + state->reason = "Expected LF after chunk size"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_8: { + switch (llhttp__internal__c_test_lenient_flags_8(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header; + default: + goto s_n_llhttp__internal__n_error_16; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_11: { + state->error = 0x19; + state->reason = "Missing expected CR after chunk size"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_5: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_chunk_size_almost_done; + default: + goto s_n_llhttp__internal__n_error_11; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_17: { + state->error = 0x2; + state->reason = "Invalid character in chunk extensions"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_18: { + state->error = 0x2; + state->reason = "Invalid character in chunk extensions"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_20: { + state->error = 0x19; + state->reason = "Missing expected CR after chunk extension name"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_5: { + state->error = 0x15; + state->reason = "on_chunk_extension_name pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_test_lenient_flags_9; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_19: { + state->error = 0x22; + state->reason = "`on_chunk_extension_name` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_name(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_6: { + state->error = 0x15; + state->reason = "on_chunk_extension_name pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_size_almost_done; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_21: { + state->error = 0x22; + state->reason = "`on_chunk_extension_name` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_name(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_7: { + state->error = 0x15; + state->reason = "on_chunk_extension_name pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_extensions; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_22: { + state->error = 0x22; + state->reason = "`on_chunk_extension_name` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_2: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_name(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_25: { + state->error = 0x19; + state->reason = "Missing expected CR after chunk extension value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_8: { + state->error = 0x15; + state->reason = "on_chunk_extension_value pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_test_lenient_flags_10; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_24: { + state->error = 0x23; + state->reason = "`on_chunk_extension_value` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_9: { + state->error = 0x15; + state->reason = "on_chunk_extension_value pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_size_almost_done; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_26: { + state->error = 0x23; + state->reason = "`on_chunk_extension_value` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_28: { + state->error = 0x19; + state->reason = "Missing expected CR after chunk extension value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_11: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_chunk_size_almost_done; + default: + goto s_n_llhttp__internal__n_error_28; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_29: { + state->error = 0x2; + state->reason = "Invalid character in chunk extensions quote value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_10: { + state->error = 0x15; + state->reason = "on_chunk_extension_value pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_extension_quoted_value_done; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_27: { + state->error = 0x23; + state->reason = "`on_chunk_extension_value` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_2: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_3: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_30; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_error_30; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_4: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_31; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_error_31; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_11: { + state->error = 0x15; + state->reason = "on_chunk_extension_value pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_extensions; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_32: { + state->error = 0x23; + state->reason = "`on_chunk_extension_value` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_5: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_6: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_33; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_error_33; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_12: { + state->error = 0x15; + state->reason = "on_chunk_extension_name pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_extension_value; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_23: { + state->error = 0x22; + state->reason = "`on_chunk_extension_name` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_3: { + switch (llhttp__on_chunk_extension_name_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_chunk_extension_value; + case 21: + goto s_n_llhttp__internal__n_pause_12; + default: + goto s_n_llhttp__internal__n_error_23; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_3: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_name(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_4: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_chunk_extension_name(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_34; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_error_34; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_35: { + state->error = 0xc; + state->reason = "Invalid character in chunk size"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_mul_add_content_length: { + switch (llhttp__internal__c_mul_add_content_length(state, p, endp, match)) { + case 1: + goto s_n_llhttp__internal__n_error_36; + default: + goto s_n_llhttp__internal__n_chunk_size; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_37: { + state->error = 0xc; + state->reason = "Invalid character in chunk size"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_body_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_body(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_finish_3: { + switch (llhttp__internal__c_update_finish_3(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_body_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_39: { + state->error = 0xf; + state->reason = "Request has invalid `Transfer-Encoding`"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause: { + state->error = 0x15; + state->reason = "on_message_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_7: { + state->error = 0x12; + state->reason = "`on_message_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_message_complete: { + switch (llhttp__on_message_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; + case 21: + goto s_n_llhttp__internal__n_pause; + default: + goto s_n_llhttp__internal__n_error_7; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_1: { + switch (llhttp__internal__c_or_flags_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_2: { + switch (llhttp__internal__c_or_flags_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_upgrade: { + switch (llhttp__internal__c_update_upgrade(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_or_flags_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_14: { + state->error = 0x15; + state->reason = "Paused by on_headers_complete"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_6: { + state->error = 0x11; + state->reason = "User callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete: { + switch (llhttp__on_headers_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + case 1: + goto s_n_llhttp__internal__n_invoke_or_flags_1; + case 2: + goto s_n_llhttp__internal__n_invoke_update_upgrade; + case 21: + goto s_n_llhttp__internal__n_pause_14; + default: + goto s_n_llhttp__internal__n_error_6; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete: { + switch (llhttp__before_headers_complete(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_flags: { + switch (llhttp__internal__c_test_flags(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_1; + default: + goto s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_1: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_test_flags; + default: + goto s_n_llhttp__internal__n_error_5; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_17: { + state->error = 0x15; + state->reason = "on_chunk_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_42: { + state->error = 0x14; + state->reason = "`on_chunk_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_2: { + switch (llhttp__on_chunk_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; + case 21: + goto s_n_llhttp__internal__n_pause_17; + default: + goto s_n_llhttp__internal__n_error_42; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_3: { + switch (llhttp__internal__c_or_flags_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_4: { + switch (llhttp__internal__c_or_flags_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_upgrade_1: { + switch (llhttp__internal__c_update_upgrade(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_or_flags_4; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_16: { + state->error = 0x15; + state->reason = "Paused by on_headers_complete"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_41: { + state->error = 0x11; + state->reason = "User callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete_1: { + switch (llhttp__on_headers_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + case 1: + goto s_n_llhttp__internal__n_invoke_or_flags_3; + case 2: + goto s_n_llhttp__internal__n_invoke_update_upgrade_1; + case 21: + goto s_n_llhttp__internal__n_pause_16; + default: + goto s_n_llhttp__internal__n_error_41; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete_1: { + switch (llhttp__before_headers_complete(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_flags_1: { + switch (llhttp__internal__c_test_flags(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_2; + default: + goto s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_43: { + state->error = 0x2; + state->reason = "Expected LF after headers"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_12: { + switch (llhttp__internal__c_test_lenient_flags_8(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_test_flags_1; + default: + goto s_n_llhttp__internal__n_error_43; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_44: { + state->error = 0xa; + state->reason = "Invalid header token"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_field: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_field(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_5; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_error_5; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_13: { + switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_header_field_colon_discard_ws; + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_60: { + state->error = 0xb; + state->reason = "Content-Length can't be present with Transfer-Encoding"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_47: { + state->error = 0xa; + state->reason = "Invalid header value char"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_15: { + switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_header_value_discard_ws; + default: + goto s_n_llhttp__internal__n_error_47; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_49: { + state->error = 0xb; + state->reason = "Empty Content-Length"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_18: { + state->error = 0x15; + state->reason = "on_header_value_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_field_start; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_48: { + state->error = 0x1d; + state->reason = "`on_header_value_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state: { + switch (llhttp__internal__c_update_header_state(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_5: { + switch (llhttp__internal__c_or_flags_5(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_6: { + switch (llhttp__internal__c_or_flags_6(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_7: { + switch (llhttp__internal__c_or_flags_7(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_8: { + switch (llhttp__internal__c_or_flags_8(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_header_state_2: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 5: + goto s_n_llhttp__internal__n_invoke_or_flags_5; + case 6: + goto s_n_llhttp__internal__n_invoke_or_flags_6; + case 7: + goto s_n_llhttp__internal__n_invoke_or_flags_7; + case 8: + goto s_n_llhttp__internal__n_invoke_or_flags_8; + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_header_state_1: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 2: + goto s_n_llhttp__internal__n_error_49; + default: + goto s_n_llhttp__internal__n_invoke_load_header_state_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_46: { + state->error = 0xa; + state->reason = "Invalid header value char"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_14: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_header_value_discard_lws; + default: + goto s_n_llhttp__internal__n_error_46; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_50: { + state->error = 0x2; + state->reason = "Expected LF after CR"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_16: { + switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_header_value_discard_lws; + default: + goto s_n_llhttp__internal__n_error_50; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_1: { + switch (llhttp__internal__c_update_header_state_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_header_state_4: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 8: + goto s_n_llhttp__internal__n_invoke_update_header_state_1; + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_52: { + state->error = 0xa; + state->reason = "Unexpected whitespace after header value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_18: { + switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_load_header_state_4; + default: + goto s_n_llhttp__internal__n_error_52; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_2: { + switch (llhttp__internal__c_update_header_state(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_9: { + switch (llhttp__internal__c_or_flags_5(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_10: { + switch (llhttp__internal__c_or_flags_6(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_11: { + switch (llhttp__internal__c_or_flags_7(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_12: { + switch (llhttp__internal__c_or_flags_8(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_header_state_5: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 5: + goto s_n_llhttp__internal__n_invoke_or_flags_9; + case 6: + goto s_n_llhttp__internal__n_invoke_or_flags_10; + case 7: + goto s_n_llhttp__internal__n_invoke_or_flags_11; + case 8: + goto s_n_llhttp__internal__n_invoke_or_flags_12; + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_53: { + state->error = 0x3; + state->reason = "Missing expected LF after header value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_51: { + state->error = 0x19; + state->reason = "Missing expected CR after header value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_test_lenient_flags_17; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_17; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_2: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_header_value_almost_done; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done; + return s_error; + } + goto s_n_llhttp__internal__n_header_value_almost_done; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_5: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_header_value_almost_done; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_54; + return s_error; + } + goto s_n_llhttp__internal__n_error_54; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_19: { + switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_header_value_lenient; + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_4: { + switch (llhttp__internal__c_update_header_state(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_13: { + switch (llhttp__internal__c_or_flags_5(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_4; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_14: { + switch (llhttp__internal__c_or_flags_6(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_4; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_15: { + switch (llhttp__internal__c_or_flags_7(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_4; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_16: { + switch (llhttp__internal__c_or_flags_8(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_header_state_6: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 5: + goto s_n_llhttp__internal__n_invoke_or_flags_13; + case 6: + goto s_n_llhttp__internal__n_invoke_or_flags_14; + case 7: + goto s_n_llhttp__internal__n_invoke_or_flags_15; + case 8: + goto s_n_llhttp__internal__n_invoke_or_flags_16; + default: + goto s_n_llhttp__internal__n_header_value_connection; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_5: { + switch (llhttp__internal__c_update_header_state_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection_token; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_3: { + switch (llhttp__internal__c_update_header_state_3(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection_ws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_6: { + switch (llhttp__internal__c_update_header_state_6(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection_ws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_7: { + switch (llhttp__internal__c_update_header_state_7(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection_ws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_6: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_56; + return s_error; + } + goto s_n_llhttp__internal__n_error_56; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_mul_add_content_length_1: { + switch (llhttp__internal__c_mul_add_content_length_1(state, p, endp, match)) { + case 1: + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_6; + default: + goto s_n_llhttp__internal__n_header_value_content_length; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_17: { + switch (llhttp__internal__c_or_flags_17(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_otherwise; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_7: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_57; + return s_error; + } + goto s_n_llhttp__internal__n_error_57; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_55: { + state->error = 0x4; + state->reason = "Duplicate Content-Length"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_flags_2: { + switch (llhttp__internal__c_test_flags_2(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_header_value_content_length; + default: + goto s_n_llhttp__internal__n_error_55; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_9: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_59; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_error_59; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_8: { + switch (llhttp__internal__c_update_header_state_8(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_otherwise; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_8: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_58; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_error_58; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_20: { + switch (llhttp__internal__c_test_lenient_flags_20(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_8; + default: + goto s_n_llhttp__internal__n_header_value_te_chunked; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_type_1: { + switch (llhttp__internal__c_load_type(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_20; + default: + goto s_n_llhttp__internal__n_header_value_te_chunked; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_9: { + switch (llhttp__internal__c_update_header_state_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_and_flags: { + switch (llhttp__internal__c_and_flags(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_te_chunked; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_19: { + switch (llhttp__internal__c_or_flags_18(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_and_flags; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_21: { + switch (llhttp__internal__c_test_lenient_flags_20(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_9; + default: + goto s_n_llhttp__internal__n_invoke_or_flags_19; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_type_2: { + switch (llhttp__internal__c_load_type(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_21; + default: + goto s_n_llhttp__internal__n_invoke_or_flags_19; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_18: { + switch (llhttp__internal__c_or_flags_18(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_and_flags; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_flags_3: { + switch (llhttp__internal__c_test_flags_3(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_load_type_2; + default: + goto s_n_llhttp__internal__n_invoke_or_flags_18; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_20: { + switch (llhttp__internal__c_or_flags_20(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_9; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_header_state_3: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_header_value_connection; + case 2: + goto s_n_llhttp__internal__n_invoke_test_flags_2; + case 3: + goto s_n_llhttp__internal__n_invoke_test_flags_3; + case 4: + goto s_n_llhttp__internal__n_invoke_or_flags_20; + default: + goto s_n_llhttp__internal__n_header_value; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_22: { + switch (llhttp__internal__c_test_lenient_flags_22(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_error_60; + default: + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_flags_4: { + switch (llhttp__internal__c_test_flags_4(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_22; + default: + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_61: { + state->error = 0xf; + state->reason = "Transfer-Encoding can't be present with Content-Length"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_23: { + switch (llhttp__internal__c_test_lenient_flags_22(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_error_61; + default: + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_flags_5: { + switch (llhttp__internal__c_test_flags_2(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_23; + default: + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_19: { + state->error = 0x15; + state->reason = "on_header_field_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_header_state; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_45: { + state->error = 0x1c; + state->reason = "`on_header_field_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_field_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_field(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_field_2: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_field(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_62: { + state->error = 0xa; + state->reason = "Invalid header token"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_10: { + switch (llhttp__internal__c_update_header_state_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_field_general; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_header_state: { + switch (llhttp__internal__c_store_header_state(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_header_field_colon; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_11: { + switch (llhttp__internal__c_update_header_state_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_field_general; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_4: { + state->error = 0x1e; + state->reason = "Unexpected space after start line"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags: { + switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_header_field_start; + default: + goto s_n_llhttp__internal__n_error_4; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_20: { + state->error = 0x15; + state->reason = "on_url_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_headers_start; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_3: { + state->error = 0x1a; + state->reason = "`on_url_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_url_complete: { + switch (llhttp__on_url_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_headers_start; + case 21: + goto s_n_llhttp__internal__n_pause_20; + default: + goto s_n_llhttp__internal__n_error_3; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_http_minor: { + switch (llhttp__internal__c_update_http_minor(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_url_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_http_major: { + switch (llhttp__internal__c_update_http_major(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_http_minor; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_3: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_63: { + state->error = 0x7; + state->reason = "Expected CRLF"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_4: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_lf_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_71: { + state->error = 0x17; + state->reason = "Pause on PRI/Upgrade"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_72: { + state->error = 0x9; + state->reason = "Expected HTTP/2 Connection Preface"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_69: { + state->error = 0x2; + state->reason = "Expected CRLF after version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_26: { + switch (llhttp__internal__c_test_lenient_flags_8(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_headers_start; + default: + goto s_n_llhttp__internal__n_error_69; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_68: { + state->error = 0x9; + state->reason = "Expected CRLF after version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_25: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_req_http_complete_crlf; + default: + goto s_n_llhttp__internal__n_error_68; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_70: { + state->error = 0x9; + state->reason = "Expected CRLF after version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_21: { + state->error = 0x15; + state->reason = "on_version_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_method_1; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_67: { + state->error = 0x21; + state->reason = "`on_version_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_version_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_version(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_version_complete; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_version_complete; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_version: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_version(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_66; + return s_error; + } + goto s_n_llhttp__internal__n_error_66; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_http_minor: { + switch (llhttp__internal__c_load_http_minor(state, p, endp)) { + case 9: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_1; + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_http_minor_1: { + switch (llhttp__internal__c_load_http_minor(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_1; + case 1: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_1; + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_http_minor_2: { + switch (llhttp__internal__c_load_http_minor(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_1; + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_http_major: { + switch (llhttp__internal__c_load_http_major(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_load_http_minor; + case 1: + goto s_n_llhttp__internal__n_invoke_load_http_minor_1; + case 2: + goto s_n_llhttp__internal__n_invoke_load_http_minor_2; + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_24: { + switch (llhttp__internal__c_test_lenient_flags_24(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_1; + default: + goto s_n_llhttp__internal__n_invoke_load_http_major; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_http_minor: { + switch (llhttp__internal__c_store_http_minor(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_24; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_version_2: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_version(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_73; + return s_error; + } + goto s_n_llhttp__internal__n_error_73; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_version_3: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_version(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_74; + return s_error; + } + goto s_n_llhttp__internal__n_error_74; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_http_major: { + switch (llhttp__internal__c_store_http_major(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_req_http_dot; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_version_4: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_version(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_75; + return s_error; + } + goto s_n_llhttp__internal__n_error_75; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_65: { + state->error = 0x8; + state->reason = "Invalid method for HTTP/x.x request"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_method: { + switch (llhttp__internal__c_load_method(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 1: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 2: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 3: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 4: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 5: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 6: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 7: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 8: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 9: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 10: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 11: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 12: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 13: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 14: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 15: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 16: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 17: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 18: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 19: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 20: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 21: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 22: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 23: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 24: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 25: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 26: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 27: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 28: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 29: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 30: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 31: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 32: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 33: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 34: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 46: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + default: + goto s_n_llhttp__internal__n_error_65; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_78: { + state->error = 0x8; + state->reason = "Expected HTTP/"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_76: { + state->error = 0x8; + state->reason = "Expected SOURCE method for ICE/x.x request"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_method_2: { + switch (llhttp__internal__c_load_method(state, p, endp)) { + case 33: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + default: + goto s_n_llhttp__internal__n_error_76; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_77: { + state->error = 0x8; + state->reason = "Invalid method for RTSP/x.x request"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_method_3: { + switch (llhttp__internal__c_load_method(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 3: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 6: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 35: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 36: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 37: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 38: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 39: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 40: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 41: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 42: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 43: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 44: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + case 45: + goto s_n_llhttp__internal__n_span_start_llhttp__on_version; + default: + goto s_n_llhttp__internal__n_error_77; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_22: { + state->error = 0x15; + state->reason = "on_url_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_req_http_start; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_64: { + state->error = 0x1a; + state->reason = "`on_url_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_url_complete_1: { + switch (llhttp__on_url_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_req_http_start; + case 21: + goto s_n_llhttp__internal__n_pause_22; + default: + goto s_n_llhttp__internal__n_error_64; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_5: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_6: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_7: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_lf_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_8: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_79: { + state->error = 0x7; + state->reason = "Invalid char in url fragment start"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_9: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_10: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_lf_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_11: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_80: { + state->error = 0x7; + state->reason = "Invalid char in url query"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_81: { + state->error = 0x7; + state->reason = "Invalid char in url path"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_lf_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_2: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_12: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_13: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_lf_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_14: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_82: { + state->error = 0x7; + state->reason = "Double @ in url"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_83: { + state->error = 0x7; + state->reason = "Unexpected char in url server"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_84: { + state->error = 0x7; + state->reason = "Unexpected char in url server"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_85: { + state->error = 0x7; + state->reason = "Unexpected char in url schema"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_86: { + state->error = 0x7; + state->reason = "Unexpected char in url schema"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_87: { + state->error = 0x7; + state->reason = "Unexpected start char in url"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_is_equal_method: { + switch (llhttp__internal__c_is_equal_method(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_url_entry_normal; + default: + goto s_n_llhttp__internal__n_url_entry_connect; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_88: { + state->error = 0x6; + state->reason = "Expected space after method"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_26: { + state->error = 0x15; + state->reason = "on_method_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_req_first_space_before_url; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_107: { + state->error = 0x20; + state->reason = "`on_method_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_method_2: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_method(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_method_1: { + switch (llhttp__internal__c_store_method(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_method_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_108: { + state->error = 0x6; + state->reason = "Invalid method encountered"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_100: { + state->error = 0xd; + state->reason = "Invalid status code"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_98: { + state->error = 0xd; + state->reason = "Invalid status code"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_96: { + state->error = 0xd; + state->reason = "Invalid status code"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_24: { + state->error = 0x15; + state->reason = "on_status_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_headers_start; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_92: { + state->error = 0x1b; + state->reason = "`on_status_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_status_complete: { + switch (llhttp__on_status_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_headers_start; + case 21: + goto s_n_llhttp__internal__n_pause_24; + default: + goto s_n_llhttp__internal__n_error_92; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_91: { + state->error = 0xd; + state->reason = "Invalid response status"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_28: { + switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete; + default: + goto s_n_llhttp__internal__n_error_91; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_93: { + state->error = 0x2; + state->reason = "Expected LF after CR"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_29: { + switch (llhttp__internal__c_test_lenient_flags_8(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete; + default: + goto s_n_llhttp__internal__n_error_93; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_94: { + state->error = 0x19; + state->reason = "Missing expected CR after response line"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_status: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_status(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_test_lenient_flags_30; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_30; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_status_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_status(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_res_line_almost_done; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_res_line_almost_done; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_95: { + state->error = 0xd; + state->reason = "Invalid response status"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_mul_add_status_code_2: { + switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) { + case 1: + goto s_n_llhttp__internal__n_error_96; + default: + goto s_n_llhttp__internal__n_res_status_code_otherwise; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_97: { + state->error = 0xd; + state->reason = "Invalid status code"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_mul_add_status_code_1: { + switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) { + case 1: + goto s_n_llhttp__internal__n_error_98; + default: + goto s_n_llhttp__internal__n_res_status_code_digit_3; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_99: { + state->error = 0xd; + state->reason = "Invalid status code"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_mul_add_status_code: { + switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) { + case 1: + goto s_n_llhttp__internal__n_error_100; + default: + goto s_n_llhttp__internal__n_res_status_code_digit_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_101: { + state->error = 0xd; + state->reason = "Invalid status code"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_status_code: { + switch (llhttp__internal__c_update_status_code(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_res_status_code_digit_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_102: { + state->error = 0x9; + state->reason = "Expected space after version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_25: { + state->error = 0x15; + state->reason = "on_version_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_res_after_version; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_90: { + state->error = 0x21; + state->reason = "`on_version_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_version_6: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_version(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_version_5: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_version(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_89; + return s_error; + } + goto s_n_llhttp__internal__n_error_89; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_http_minor_3: { + switch (llhttp__internal__c_load_http_minor(state, p, endp)) { + case 9: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_6; + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_5; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_http_minor_4: { + switch (llhttp__internal__c_load_http_minor(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_6; + case 1: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_6; + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_5; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_http_minor_5: { + switch (llhttp__internal__c_load_http_minor(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_6; + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_5; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_http_major_1: { + switch (llhttp__internal__c_load_http_major(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_load_http_minor_3; + case 1: + goto s_n_llhttp__internal__n_invoke_load_http_minor_4; + case 2: + goto s_n_llhttp__internal__n_invoke_load_http_minor_5; + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_5; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_lenient_flags_27: { + switch (llhttp__internal__c_test_lenient_flags_24(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_span_end_llhttp__on_version_6; + default: + goto s_n_llhttp__internal__n_invoke_load_http_major_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_http_minor_1: { + switch (llhttp__internal__c_store_http_minor(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_invoke_test_lenient_flags_27; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_version_7: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_version(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_103; + return s_error; + } + goto s_n_llhttp__internal__n_error_103; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_version_8: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_version(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_104; + return s_error; + } + goto s_n_llhttp__internal__n_error_104; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_http_major_1: { + switch (llhttp__internal__c_store_http_major(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_res_http_dot; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_version_9: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_version(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_105; + return s_error; + } + goto s_n_llhttp__internal__n_error_105; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_109: { + state->error = 0x8; + state->reason = "Expected HTTP/"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_23: { + state->error = 0x15; + state->reason = "on_method_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_req_first_space_before_url; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_1: { + state->error = 0x20; + state->reason = "`on_method_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_method: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_method(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_method_complete; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_method_complete; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_type: { + switch (llhttp__internal__c_update_type(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_span_end_llhttp__on_method; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_method: { + switch (llhttp__internal__c_store_method(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_invoke_update_type; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_106: { + state->error = 0x8; + state->reason = "Invalid word encountered"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_method_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_method(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_update_type_1; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_update_type_1; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_type_2: { + switch (llhttp__internal__c_update_type(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_method_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_27: { + state->error = 0x15; + state->reason = "on_message_begin pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_type; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error: { + state->error = 0x10; + state->reason = "`on_message_begin` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_message_begin: { + switch (llhttp__on_message_begin(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_load_type; + case 21: + goto s_n_llhttp__internal__n_pause_27; + default: + goto s_n_llhttp__internal__n_error; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_28: { + state->error = 0x15; + state->reason = "on_reset pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_update_finish; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_110: { + state->error = 0x1f; + state->reason = "`on_reset` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_reset: { + switch (llhttp__on_reset(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_update_finish; + case 21: + goto s_n_llhttp__internal__n_pause_28; + default: + goto s_n_llhttp__internal__n_error_110; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_initial_message_completed: { + switch (llhttp__internal__c_load_initial_message_completed(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_reset; + default: + goto s_n_llhttp__internal__n_invoke_update_finish; + } + /* UNREACHABLE */; + abort(); + } +} + +int llhttp__internal_execute(llhttp__internal_t* state, const char* p, const char* endp) { + llparse_state_t next; + + /* check lingering errors */ + if (state->error != 0) { + return state->error; + } + + /* restart spans */ + if (state->_span_pos0 != NULL) { + state->_span_pos0 = (void*) p; + } + + next = llhttp__internal__run(state, (const unsigned char*) p, (const unsigned char*) endp); + if (next == s_error) { + return state->error; + } + state->_current = (void*) (intptr_t) next; + + /* execute spans */ + if (state->_span_pos0 != NULL) { + int error; + + error = ((llhttp__internal__span_cb) state->_span_cb0)(state, state->_span_pos0, (const char*) endp); + if (error != 0) { + state->error = error; + state->error_pos = endp; + return error; + } + } + + return 0; +} \ No newline at end of file diff --git a/vendor/libgit2/deps/llhttp/llhttp.h b/vendor/libgit2/deps/llhttp/llhttp.h new file mode 100644 index 00000000..26f01c32 --- /dev/null +++ b/vendor/libgit2/deps/llhttp/llhttp.h @@ -0,0 +1,897 @@ + +#ifndef INCLUDE_LLHTTP_H_ +#define INCLUDE_LLHTTP_H_ + +#define LLHTTP_VERSION_MAJOR 9 +#define LLHTTP_VERSION_MINOR 2 +#define LLHTTP_VERSION_PATCH 1 + +#ifndef INCLUDE_LLHTTP_ITSELF_H_ +#define INCLUDE_LLHTTP_ITSELF_H_ +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef struct llhttp__internal_s llhttp__internal_t; +struct llhttp__internal_s { + int32_t _index; + void* _span_pos0; + void* _span_cb0; + int32_t error; + const char* reason; + const char* error_pos; + void* data; + void* _current; + uint64_t content_length; + uint8_t type; + uint8_t method; + uint8_t http_major; + uint8_t http_minor; + uint8_t header_state; + uint16_t lenient_flags; + uint8_t upgrade; + uint8_t finish; + uint16_t flags; + uint16_t status_code; + uint8_t initial_message_completed; + void* settings; +}; + +int llhttp__internal_init(llhttp__internal_t* s); +int llhttp__internal_execute(llhttp__internal_t* s, const char* p, const char* endp); + +#ifdef __cplusplus +} /* extern "C" */ +#endif +#endif /* INCLUDE_LLHTTP_ITSELF_H_ */ + + +#ifndef LLLLHTTP_C_HEADERS_ +#define LLLLHTTP_C_HEADERS_ +#ifdef __cplusplus +extern "C" { +#endif + +enum llhttp_errno { + HPE_OK = 0, + HPE_INTERNAL = 1, + HPE_STRICT = 2, + HPE_CR_EXPECTED = 25, + HPE_LF_EXPECTED = 3, + HPE_UNEXPECTED_CONTENT_LENGTH = 4, + HPE_UNEXPECTED_SPACE = 30, + HPE_CLOSED_CONNECTION = 5, + HPE_INVALID_METHOD = 6, + HPE_INVALID_URL = 7, + HPE_INVALID_CONSTANT = 8, + HPE_INVALID_VERSION = 9, + HPE_INVALID_HEADER_TOKEN = 10, + HPE_INVALID_CONTENT_LENGTH = 11, + HPE_INVALID_CHUNK_SIZE = 12, + HPE_INVALID_STATUS = 13, + HPE_INVALID_EOF_STATE = 14, + HPE_INVALID_TRANSFER_ENCODING = 15, + HPE_CB_MESSAGE_BEGIN = 16, + HPE_CB_HEADERS_COMPLETE = 17, + HPE_CB_MESSAGE_COMPLETE = 18, + HPE_CB_CHUNK_HEADER = 19, + HPE_CB_CHUNK_COMPLETE = 20, + HPE_PAUSED = 21, + HPE_PAUSED_UPGRADE = 22, + HPE_PAUSED_H2_UPGRADE = 23, + HPE_USER = 24, + HPE_CB_URL_COMPLETE = 26, + HPE_CB_STATUS_COMPLETE = 27, + HPE_CB_METHOD_COMPLETE = 32, + HPE_CB_VERSION_COMPLETE = 33, + HPE_CB_HEADER_FIELD_COMPLETE = 28, + HPE_CB_HEADER_VALUE_COMPLETE = 29, + HPE_CB_CHUNK_EXTENSION_NAME_COMPLETE = 34, + HPE_CB_CHUNK_EXTENSION_VALUE_COMPLETE = 35, + HPE_CB_RESET = 31 +}; +typedef enum llhttp_errno llhttp_errno_t; + +enum llhttp_flags { + F_CONNECTION_KEEP_ALIVE = 0x1, + F_CONNECTION_CLOSE = 0x2, + F_CONNECTION_UPGRADE = 0x4, + F_CHUNKED = 0x8, + F_UPGRADE = 0x10, + F_CONTENT_LENGTH = 0x20, + F_SKIPBODY = 0x40, + F_TRAILING = 0x80, + F_TRANSFER_ENCODING = 0x200 +}; +typedef enum llhttp_flags llhttp_flags_t; + +enum llhttp_lenient_flags { + LENIENT_HEADERS = 0x1, + LENIENT_CHUNKED_LENGTH = 0x2, + LENIENT_KEEP_ALIVE = 0x4, + LENIENT_TRANSFER_ENCODING = 0x8, + LENIENT_VERSION = 0x10, + LENIENT_DATA_AFTER_CLOSE = 0x20, + LENIENT_OPTIONAL_LF_AFTER_CR = 0x40, + LENIENT_OPTIONAL_CRLF_AFTER_CHUNK = 0x80, + LENIENT_OPTIONAL_CR_BEFORE_LF = 0x100, + LENIENT_SPACES_AFTER_CHUNK_SIZE = 0x200 +}; +typedef enum llhttp_lenient_flags llhttp_lenient_flags_t; + +enum llhttp_type { + HTTP_BOTH = 0, + HTTP_REQUEST = 1, + HTTP_RESPONSE = 2 +}; +typedef enum llhttp_type llhttp_type_t; + +enum llhttp_finish { + HTTP_FINISH_SAFE = 0, + HTTP_FINISH_SAFE_WITH_CB = 1, + HTTP_FINISH_UNSAFE = 2 +}; +typedef enum llhttp_finish llhttp_finish_t; + +enum llhttp_method { + HTTP_DELETE = 0, + HTTP_GET = 1, + HTTP_HEAD = 2, + HTTP_POST = 3, + HTTP_PUT = 4, + HTTP_CONNECT = 5, + HTTP_OPTIONS = 6, + HTTP_TRACE = 7, + HTTP_COPY = 8, + HTTP_LOCK = 9, + HTTP_MKCOL = 10, + HTTP_MOVE = 11, + HTTP_PROPFIND = 12, + HTTP_PROPPATCH = 13, + HTTP_SEARCH = 14, + HTTP_UNLOCK = 15, + HTTP_BIND = 16, + HTTP_REBIND = 17, + HTTP_UNBIND = 18, + HTTP_ACL = 19, + HTTP_REPORT = 20, + HTTP_MKACTIVITY = 21, + HTTP_CHECKOUT = 22, + HTTP_MERGE = 23, + HTTP_MSEARCH = 24, + HTTP_NOTIFY = 25, + HTTP_SUBSCRIBE = 26, + HTTP_UNSUBSCRIBE = 27, + HTTP_PATCH = 28, + HTTP_PURGE = 29, + HTTP_MKCALENDAR = 30, + HTTP_LINK = 31, + HTTP_UNLINK = 32, + HTTP_SOURCE = 33, + HTTP_PRI = 34, + HTTP_DESCRIBE = 35, + HTTP_ANNOUNCE = 36, + HTTP_SETUP = 37, + HTTP_PLAY = 38, + HTTP_PAUSE = 39, + HTTP_TEARDOWN = 40, + HTTP_GET_PARAMETER = 41, + HTTP_SET_PARAMETER = 42, + HTTP_REDIRECT = 43, + HTTP_RECORD = 44, + HTTP_FLUSH = 45, + HTTP_QUERY = 46 +}; +typedef enum llhttp_method llhttp_method_t; + +enum llhttp_status { + HTTP_STATUS_CONTINUE = 100, + HTTP_STATUS_SWITCHING_PROTOCOLS = 101, + HTTP_STATUS_PROCESSING = 102, + HTTP_STATUS_EARLY_HINTS = 103, + HTTP_STATUS_RESPONSE_IS_STALE = 110, + HTTP_STATUS_REVALIDATION_FAILED = 111, + HTTP_STATUS_DISCONNECTED_OPERATION = 112, + HTTP_STATUS_HEURISTIC_EXPIRATION = 113, + HTTP_STATUS_MISCELLANEOUS_WARNING = 199, + HTTP_STATUS_OK = 200, + HTTP_STATUS_CREATED = 201, + HTTP_STATUS_ACCEPTED = 202, + HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203, + HTTP_STATUS_NO_CONTENT = 204, + HTTP_STATUS_RESET_CONTENT = 205, + HTTP_STATUS_PARTIAL_CONTENT = 206, + HTTP_STATUS_MULTI_STATUS = 207, + HTTP_STATUS_ALREADY_REPORTED = 208, + HTTP_STATUS_TRANSFORMATION_APPLIED = 214, + HTTP_STATUS_IM_USED = 226, + HTTP_STATUS_MISCELLANEOUS_PERSISTENT_WARNING = 299, + HTTP_STATUS_MULTIPLE_CHOICES = 300, + HTTP_STATUS_MOVED_PERMANENTLY = 301, + HTTP_STATUS_FOUND = 302, + HTTP_STATUS_SEE_OTHER = 303, + HTTP_STATUS_NOT_MODIFIED = 304, + HTTP_STATUS_USE_PROXY = 305, + HTTP_STATUS_SWITCH_PROXY = 306, + HTTP_STATUS_TEMPORARY_REDIRECT = 307, + HTTP_STATUS_PERMANENT_REDIRECT = 308, + HTTP_STATUS_BAD_REQUEST = 400, + HTTP_STATUS_UNAUTHORIZED = 401, + HTTP_STATUS_PAYMENT_REQUIRED = 402, + HTTP_STATUS_FORBIDDEN = 403, + HTTP_STATUS_NOT_FOUND = 404, + HTTP_STATUS_METHOD_NOT_ALLOWED = 405, + HTTP_STATUS_NOT_ACCEPTABLE = 406, + HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407, + HTTP_STATUS_REQUEST_TIMEOUT = 408, + HTTP_STATUS_CONFLICT = 409, + HTTP_STATUS_GONE = 410, + HTTP_STATUS_LENGTH_REQUIRED = 411, + HTTP_STATUS_PRECONDITION_FAILED = 412, + HTTP_STATUS_PAYLOAD_TOO_LARGE = 413, + HTTP_STATUS_URI_TOO_LONG = 414, + HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415, + HTTP_STATUS_RANGE_NOT_SATISFIABLE = 416, + HTTP_STATUS_EXPECTATION_FAILED = 417, + HTTP_STATUS_IM_A_TEAPOT = 418, + HTTP_STATUS_PAGE_EXPIRED = 419, + HTTP_STATUS_ENHANCE_YOUR_CALM = 420, + HTTP_STATUS_MISDIRECTED_REQUEST = 421, + HTTP_STATUS_UNPROCESSABLE_ENTITY = 422, + HTTP_STATUS_LOCKED = 423, + HTTP_STATUS_FAILED_DEPENDENCY = 424, + HTTP_STATUS_TOO_EARLY = 425, + HTTP_STATUS_UPGRADE_REQUIRED = 426, + HTTP_STATUS_PRECONDITION_REQUIRED = 428, + HTTP_STATUS_TOO_MANY_REQUESTS = 429, + HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL = 430, + HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431, + HTTP_STATUS_LOGIN_TIMEOUT = 440, + HTTP_STATUS_NO_RESPONSE = 444, + HTTP_STATUS_RETRY_WITH = 449, + HTTP_STATUS_BLOCKED_BY_PARENTAL_CONTROL = 450, + HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS = 451, + HTTP_STATUS_CLIENT_CLOSED_LOAD_BALANCED_REQUEST = 460, + HTTP_STATUS_INVALID_X_FORWARDED_FOR = 463, + HTTP_STATUS_REQUEST_HEADER_TOO_LARGE = 494, + HTTP_STATUS_SSL_CERTIFICATE_ERROR = 495, + HTTP_STATUS_SSL_CERTIFICATE_REQUIRED = 496, + HTTP_STATUS_HTTP_REQUEST_SENT_TO_HTTPS_PORT = 497, + HTTP_STATUS_INVALID_TOKEN = 498, + HTTP_STATUS_CLIENT_CLOSED_REQUEST = 499, + HTTP_STATUS_INTERNAL_SERVER_ERROR = 500, + HTTP_STATUS_NOT_IMPLEMENTED = 501, + HTTP_STATUS_BAD_GATEWAY = 502, + HTTP_STATUS_SERVICE_UNAVAILABLE = 503, + HTTP_STATUS_GATEWAY_TIMEOUT = 504, + HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED = 505, + HTTP_STATUS_VARIANT_ALSO_NEGOTIATES = 506, + HTTP_STATUS_INSUFFICIENT_STORAGE = 507, + HTTP_STATUS_LOOP_DETECTED = 508, + HTTP_STATUS_BANDWIDTH_LIMIT_EXCEEDED = 509, + HTTP_STATUS_NOT_EXTENDED = 510, + HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511, + HTTP_STATUS_WEB_SERVER_UNKNOWN_ERROR = 520, + HTTP_STATUS_WEB_SERVER_IS_DOWN = 521, + HTTP_STATUS_CONNECTION_TIMEOUT = 522, + HTTP_STATUS_ORIGIN_IS_UNREACHABLE = 523, + HTTP_STATUS_TIMEOUT_OCCURED = 524, + HTTP_STATUS_SSL_HANDSHAKE_FAILED = 525, + HTTP_STATUS_INVALID_SSL_CERTIFICATE = 526, + HTTP_STATUS_RAILGUN_ERROR = 527, + HTTP_STATUS_SITE_IS_OVERLOADED = 529, + HTTP_STATUS_SITE_IS_FROZEN = 530, + HTTP_STATUS_IDENTITY_PROVIDER_AUTHENTICATION_ERROR = 561, + HTTP_STATUS_NETWORK_READ_TIMEOUT = 598, + HTTP_STATUS_NETWORK_CONNECT_TIMEOUT = 599 +}; +typedef enum llhttp_status llhttp_status_t; + +#define HTTP_ERRNO_MAP(XX) \ + XX(0, OK, OK) \ + XX(1, INTERNAL, INTERNAL) \ + XX(2, STRICT, STRICT) \ + XX(25, CR_EXPECTED, CR_EXPECTED) \ + XX(3, LF_EXPECTED, LF_EXPECTED) \ + XX(4, UNEXPECTED_CONTENT_LENGTH, UNEXPECTED_CONTENT_LENGTH) \ + XX(30, UNEXPECTED_SPACE, UNEXPECTED_SPACE) \ + XX(5, CLOSED_CONNECTION, CLOSED_CONNECTION) \ + XX(6, INVALID_METHOD, INVALID_METHOD) \ + XX(7, INVALID_URL, INVALID_URL) \ + XX(8, INVALID_CONSTANT, INVALID_CONSTANT) \ + XX(9, INVALID_VERSION, INVALID_VERSION) \ + XX(10, INVALID_HEADER_TOKEN, INVALID_HEADER_TOKEN) \ + XX(11, INVALID_CONTENT_LENGTH, INVALID_CONTENT_LENGTH) \ + XX(12, INVALID_CHUNK_SIZE, INVALID_CHUNK_SIZE) \ + XX(13, INVALID_STATUS, INVALID_STATUS) \ + XX(14, INVALID_EOF_STATE, INVALID_EOF_STATE) \ + XX(15, INVALID_TRANSFER_ENCODING, INVALID_TRANSFER_ENCODING) \ + XX(16, CB_MESSAGE_BEGIN, CB_MESSAGE_BEGIN) \ + XX(17, CB_HEADERS_COMPLETE, CB_HEADERS_COMPLETE) \ + XX(18, CB_MESSAGE_COMPLETE, CB_MESSAGE_COMPLETE) \ + XX(19, CB_CHUNK_HEADER, CB_CHUNK_HEADER) \ + XX(20, CB_CHUNK_COMPLETE, CB_CHUNK_COMPLETE) \ + XX(21, PAUSED, PAUSED) \ + XX(22, PAUSED_UPGRADE, PAUSED_UPGRADE) \ + XX(23, PAUSED_H2_UPGRADE, PAUSED_H2_UPGRADE) \ + XX(24, USER, USER) \ + XX(26, CB_URL_COMPLETE, CB_URL_COMPLETE) \ + XX(27, CB_STATUS_COMPLETE, CB_STATUS_COMPLETE) \ + XX(32, CB_METHOD_COMPLETE, CB_METHOD_COMPLETE) \ + XX(33, CB_VERSION_COMPLETE, CB_VERSION_COMPLETE) \ + XX(28, CB_HEADER_FIELD_COMPLETE, CB_HEADER_FIELD_COMPLETE) \ + XX(29, CB_HEADER_VALUE_COMPLETE, CB_HEADER_VALUE_COMPLETE) \ + XX(34, CB_CHUNK_EXTENSION_NAME_COMPLETE, CB_CHUNK_EXTENSION_NAME_COMPLETE) \ + XX(35, CB_CHUNK_EXTENSION_VALUE_COMPLETE, CB_CHUNK_EXTENSION_VALUE_COMPLETE) \ + XX(31, CB_RESET, CB_RESET) \ + + +#define HTTP_METHOD_MAP(XX) \ + XX(0, DELETE, DELETE) \ + XX(1, GET, GET) \ + XX(2, HEAD, HEAD) \ + XX(3, POST, POST) \ + XX(4, PUT, PUT) \ + XX(5, CONNECT, CONNECT) \ + XX(6, OPTIONS, OPTIONS) \ + XX(7, TRACE, TRACE) \ + XX(8, COPY, COPY) \ + XX(9, LOCK, LOCK) \ + XX(10, MKCOL, MKCOL) \ + XX(11, MOVE, MOVE) \ + XX(12, PROPFIND, PROPFIND) \ + XX(13, PROPPATCH, PROPPATCH) \ + XX(14, SEARCH, SEARCH) \ + XX(15, UNLOCK, UNLOCK) \ + XX(16, BIND, BIND) \ + XX(17, REBIND, REBIND) \ + XX(18, UNBIND, UNBIND) \ + XX(19, ACL, ACL) \ + XX(20, REPORT, REPORT) \ + XX(21, MKACTIVITY, MKACTIVITY) \ + XX(22, CHECKOUT, CHECKOUT) \ + XX(23, MERGE, MERGE) \ + XX(24, MSEARCH, M-SEARCH) \ + XX(25, NOTIFY, NOTIFY) \ + XX(26, SUBSCRIBE, SUBSCRIBE) \ + XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \ + XX(28, PATCH, PATCH) \ + XX(29, PURGE, PURGE) \ + XX(30, MKCALENDAR, MKCALENDAR) \ + XX(31, LINK, LINK) \ + XX(32, UNLINK, UNLINK) \ + XX(33, SOURCE, SOURCE) \ + XX(46, QUERY, QUERY) \ + + +#define RTSP_METHOD_MAP(XX) \ + XX(1, GET, GET) \ + XX(3, POST, POST) \ + XX(6, OPTIONS, OPTIONS) \ + XX(35, DESCRIBE, DESCRIBE) \ + XX(36, ANNOUNCE, ANNOUNCE) \ + XX(37, SETUP, SETUP) \ + XX(38, PLAY, PLAY) \ + XX(39, PAUSE, PAUSE) \ + XX(40, TEARDOWN, TEARDOWN) \ + XX(41, GET_PARAMETER, GET_PARAMETER) \ + XX(42, SET_PARAMETER, SET_PARAMETER) \ + XX(43, REDIRECT, REDIRECT) \ + XX(44, RECORD, RECORD) \ + XX(45, FLUSH, FLUSH) \ + + +#define HTTP_ALL_METHOD_MAP(XX) \ + XX(0, DELETE, DELETE) \ + XX(1, GET, GET) \ + XX(2, HEAD, HEAD) \ + XX(3, POST, POST) \ + XX(4, PUT, PUT) \ + XX(5, CONNECT, CONNECT) \ + XX(6, OPTIONS, OPTIONS) \ + XX(7, TRACE, TRACE) \ + XX(8, COPY, COPY) \ + XX(9, LOCK, LOCK) \ + XX(10, MKCOL, MKCOL) \ + XX(11, MOVE, MOVE) \ + XX(12, PROPFIND, PROPFIND) \ + XX(13, PROPPATCH, PROPPATCH) \ + XX(14, SEARCH, SEARCH) \ + XX(15, UNLOCK, UNLOCK) \ + XX(16, BIND, BIND) \ + XX(17, REBIND, REBIND) \ + XX(18, UNBIND, UNBIND) \ + XX(19, ACL, ACL) \ + XX(20, REPORT, REPORT) \ + XX(21, MKACTIVITY, MKACTIVITY) \ + XX(22, CHECKOUT, CHECKOUT) \ + XX(23, MERGE, MERGE) \ + XX(24, MSEARCH, M-SEARCH) \ + XX(25, NOTIFY, NOTIFY) \ + XX(26, SUBSCRIBE, SUBSCRIBE) \ + XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \ + XX(28, PATCH, PATCH) \ + XX(29, PURGE, PURGE) \ + XX(30, MKCALENDAR, MKCALENDAR) \ + XX(31, LINK, LINK) \ + XX(32, UNLINK, UNLINK) \ + XX(33, SOURCE, SOURCE) \ + XX(34, PRI, PRI) \ + XX(35, DESCRIBE, DESCRIBE) \ + XX(36, ANNOUNCE, ANNOUNCE) \ + XX(37, SETUP, SETUP) \ + XX(38, PLAY, PLAY) \ + XX(39, PAUSE, PAUSE) \ + XX(40, TEARDOWN, TEARDOWN) \ + XX(41, GET_PARAMETER, GET_PARAMETER) \ + XX(42, SET_PARAMETER, SET_PARAMETER) \ + XX(43, REDIRECT, REDIRECT) \ + XX(44, RECORD, RECORD) \ + XX(45, FLUSH, FLUSH) \ + XX(46, QUERY, QUERY) \ + + +#define HTTP_STATUS_MAP(XX) \ + XX(100, CONTINUE, CONTINUE) \ + XX(101, SWITCHING_PROTOCOLS, SWITCHING_PROTOCOLS) \ + XX(102, PROCESSING, PROCESSING) \ + XX(103, EARLY_HINTS, EARLY_HINTS) \ + XX(110, RESPONSE_IS_STALE, RESPONSE_IS_STALE) \ + XX(111, REVALIDATION_FAILED, REVALIDATION_FAILED) \ + XX(112, DISCONNECTED_OPERATION, DISCONNECTED_OPERATION) \ + XX(113, HEURISTIC_EXPIRATION, HEURISTIC_EXPIRATION) \ + XX(199, MISCELLANEOUS_WARNING, MISCELLANEOUS_WARNING) \ + XX(200, OK, OK) \ + XX(201, CREATED, CREATED) \ + XX(202, ACCEPTED, ACCEPTED) \ + XX(203, NON_AUTHORITATIVE_INFORMATION, NON_AUTHORITATIVE_INFORMATION) \ + XX(204, NO_CONTENT, NO_CONTENT) \ + XX(205, RESET_CONTENT, RESET_CONTENT) \ + XX(206, PARTIAL_CONTENT, PARTIAL_CONTENT) \ + XX(207, MULTI_STATUS, MULTI_STATUS) \ + XX(208, ALREADY_REPORTED, ALREADY_REPORTED) \ + XX(214, TRANSFORMATION_APPLIED, TRANSFORMATION_APPLIED) \ + XX(226, IM_USED, IM_USED) \ + XX(299, MISCELLANEOUS_PERSISTENT_WARNING, MISCELLANEOUS_PERSISTENT_WARNING) \ + XX(300, MULTIPLE_CHOICES, MULTIPLE_CHOICES) \ + XX(301, MOVED_PERMANENTLY, MOVED_PERMANENTLY) \ + XX(302, FOUND, FOUND) \ + XX(303, SEE_OTHER, SEE_OTHER) \ + XX(304, NOT_MODIFIED, NOT_MODIFIED) \ + XX(305, USE_PROXY, USE_PROXY) \ + XX(306, SWITCH_PROXY, SWITCH_PROXY) \ + XX(307, TEMPORARY_REDIRECT, TEMPORARY_REDIRECT) \ + XX(308, PERMANENT_REDIRECT, PERMANENT_REDIRECT) \ + XX(400, BAD_REQUEST, BAD_REQUEST) \ + XX(401, UNAUTHORIZED, UNAUTHORIZED) \ + XX(402, PAYMENT_REQUIRED, PAYMENT_REQUIRED) \ + XX(403, FORBIDDEN, FORBIDDEN) \ + XX(404, NOT_FOUND, NOT_FOUND) \ + XX(405, METHOD_NOT_ALLOWED, METHOD_NOT_ALLOWED) \ + XX(406, NOT_ACCEPTABLE, NOT_ACCEPTABLE) \ + XX(407, PROXY_AUTHENTICATION_REQUIRED, PROXY_AUTHENTICATION_REQUIRED) \ + XX(408, REQUEST_TIMEOUT, REQUEST_TIMEOUT) \ + XX(409, CONFLICT, CONFLICT) \ + XX(410, GONE, GONE) \ + XX(411, LENGTH_REQUIRED, LENGTH_REQUIRED) \ + XX(412, PRECONDITION_FAILED, PRECONDITION_FAILED) \ + XX(413, PAYLOAD_TOO_LARGE, PAYLOAD_TOO_LARGE) \ + XX(414, URI_TOO_LONG, URI_TOO_LONG) \ + XX(415, UNSUPPORTED_MEDIA_TYPE, UNSUPPORTED_MEDIA_TYPE) \ + XX(416, RANGE_NOT_SATISFIABLE, RANGE_NOT_SATISFIABLE) \ + XX(417, EXPECTATION_FAILED, EXPECTATION_FAILED) \ + XX(418, IM_A_TEAPOT, IM_A_TEAPOT) \ + XX(419, PAGE_EXPIRED, PAGE_EXPIRED) \ + XX(420, ENHANCE_YOUR_CALM, ENHANCE_YOUR_CALM) \ + XX(421, MISDIRECTED_REQUEST, MISDIRECTED_REQUEST) \ + XX(422, UNPROCESSABLE_ENTITY, UNPROCESSABLE_ENTITY) \ + XX(423, LOCKED, LOCKED) \ + XX(424, FAILED_DEPENDENCY, FAILED_DEPENDENCY) \ + XX(425, TOO_EARLY, TOO_EARLY) \ + XX(426, UPGRADE_REQUIRED, UPGRADE_REQUIRED) \ + XX(428, PRECONDITION_REQUIRED, PRECONDITION_REQUIRED) \ + XX(429, TOO_MANY_REQUESTS, TOO_MANY_REQUESTS) \ + XX(430, REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL, REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL) \ + XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, REQUEST_HEADER_FIELDS_TOO_LARGE) \ + XX(440, LOGIN_TIMEOUT, LOGIN_TIMEOUT) \ + XX(444, NO_RESPONSE, NO_RESPONSE) \ + XX(449, RETRY_WITH, RETRY_WITH) \ + XX(450, BLOCKED_BY_PARENTAL_CONTROL, BLOCKED_BY_PARENTAL_CONTROL) \ + XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, UNAVAILABLE_FOR_LEGAL_REASONS) \ + XX(460, CLIENT_CLOSED_LOAD_BALANCED_REQUEST, CLIENT_CLOSED_LOAD_BALANCED_REQUEST) \ + XX(463, INVALID_X_FORWARDED_FOR, INVALID_X_FORWARDED_FOR) \ + XX(494, REQUEST_HEADER_TOO_LARGE, REQUEST_HEADER_TOO_LARGE) \ + XX(495, SSL_CERTIFICATE_ERROR, SSL_CERTIFICATE_ERROR) \ + XX(496, SSL_CERTIFICATE_REQUIRED, SSL_CERTIFICATE_REQUIRED) \ + XX(497, HTTP_REQUEST_SENT_TO_HTTPS_PORT, HTTP_REQUEST_SENT_TO_HTTPS_PORT) \ + XX(498, INVALID_TOKEN, INVALID_TOKEN) \ + XX(499, CLIENT_CLOSED_REQUEST, CLIENT_CLOSED_REQUEST) \ + XX(500, INTERNAL_SERVER_ERROR, INTERNAL_SERVER_ERROR) \ + XX(501, NOT_IMPLEMENTED, NOT_IMPLEMENTED) \ + XX(502, BAD_GATEWAY, BAD_GATEWAY) \ + XX(503, SERVICE_UNAVAILABLE, SERVICE_UNAVAILABLE) \ + XX(504, GATEWAY_TIMEOUT, GATEWAY_TIMEOUT) \ + XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP_VERSION_NOT_SUPPORTED) \ + XX(506, VARIANT_ALSO_NEGOTIATES, VARIANT_ALSO_NEGOTIATES) \ + XX(507, INSUFFICIENT_STORAGE, INSUFFICIENT_STORAGE) \ + XX(508, LOOP_DETECTED, LOOP_DETECTED) \ + XX(509, BANDWIDTH_LIMIT_EXCEEDED, BANDWIDTH_LIMIT_EXCEEDED) \ + XX(510, NOT_EXTENDED, NOT_EXTENDED) \ + XX(511, NETWORK_AUTHENTICATION_REQUIRED, NETWORK_AUTHENTICATION_REQUIRED) \ + XX(520, WEB_SERVER_UNKNOWN_ERROR, WEB_SERVER_UNKNOWN_ERROR) \ + XX(521, WEB_SERVER_IS_DOWN, WEB_SERVER_IS_DOWN) \ + XX(522, CONNECTION_TIMEOUT, CONNECTION_TIMEOUT) \ + XX(523, ORIGIN_IS_UNREACHABLE, ORIGIN_IS_UNREACHABLE) \ + XX(524, TIMEOUT_OCCURED, TIMEOUT_OCCURED) \ + XX(525, SSL_HANDSHAKE_FAILED, SSL_HANDSHAKE_FAILED) \ + XX(526, INVALID_SSL_CERTIFICATE, INVALID_SSL_CERTIFICATE) \ + XX(527, RAILGUN_ERROR, RAILGUN_ERROR) \ + XX(529, SITE_IS_OVERLOADED, SITE_IS_OVERLOADED) \ + XX(530, SITE_IS_FROZEN, SITE_IS_FROZEN) \ + XX(561, IDENTITY_PROVIDER_AUTHENTICATION_ERROR, IDENTITY_PROVIDER_AUTHENTICATION_ERROR) \ + XX(598, NETWORK_READ_TIMEOUT, NETWORK_READ_TIMEOUT) \ + XX(599, NETWORK_CONNECT_TIMEOUT, NETWORK_CONNECT_TIMEOUT) \ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif +#endif /* LLLLHTTP_C_HEADERS_ */ + + +#ifndef INCLUDE_LLHTTP_API_H_ +#define INCLUDE_LLHTTP_API_H_ +#ifdef __cplusplus +extern "C" { +#endif +#include + +#define LLHTTP_EXPORT + +typedef llhttp__internal_t llhttp_t; +typedef struct llhttp_settings_s llhttp_settings_t; + +typedef int (*llhttp_data_cb)(llhttp_t*, const char *at, size_t length); +typedef int (*llhttp_cb)(llhttp_t*); + +struct llhttp_settings_s { + /* Possible return values 0, -1, `HPE_PAUSED` */ + llhttp_cb on_message_begin; + + /* Possible return values 0, -1, HPE_USER */ + llhttp_data_cb on_url; + llhttp_data_cb on_status; + llhttp_data_cb on_method; + llhttp_data_cb on_version; + llhttp_data_cb on_header_field; + llhttp_data_cb on_header_value; + llhttp_data_cb on_chunk_extension_name; + llhttp_data_cb on_chunk_extension_value; + + /* Possible return values: + * 0 - Proceed normally + * 1 - Assume that request/response has no body, and proceed to parsing the + * next message + * 2 - Assume absence of body (as above) and make `llhttp_execute()` return + * `HPE_PAUSED_UPGRADE` + * -1 - Error + * `HPE_PAUSED` + */ + llhttp_cb on_headers_complete; + + /* Possible return values 0, -1, HPE_USER */ + llhttp_data_cb on_body; + + /* Possible return values 0, -1, `HPE_PAUSED` */ + llhttp_cb on_message_complete; + llhttp_cb on_url_complete; + llhttp_cb on_status_complete; + llhttp_cb on_method_complete; + llhttp_cb on_version_complete; + llhttp_cb on_header_field_complete; + llhttp_cb on_header_value_complete; + llhttp_cb on_chunk_extension_name_complete; + llhttp_cb on_chunk_extension_value_complete; + + /* When on_chunk_header is called, the current chunk length is stored + * in parser->content_length. + * Possible return values 0, -1, `HPE_PAUSED` + */ + llhttp_cb on_chunk_header; + llhttp_cb on_chunk_complete; + llhttp_cb on_reset; +}; + +/* Initialize the parser with specific type and user settings. + * + * NOTE: lifetime of `settings` has to be at least the same as the lifetime of + * the `parser` here. In practice, `settings` has to be either a static + * variable or be allocated with `malloc`, `new`, etc. + */ +LLHTTP_EXPORT +void llhttp_init(llhttp_t* parser, llhttp_type_t type, + const llhttp_settings_t* settings); + +LLHTTP_EXPORT +llhttp_t* llhttp_alloc(llhttp_type_t type); + +LLHTTP_EXPORT +void llhttp_free(llhttp_t* parser); + +LLHTTP_EXPORT +uint8_t llhttp_get_type(llhttp_t* parser); + +LLHTTP_EXPORT +uint8_t llhttp_get_http_major(llhttp_t* parser); + +LLHTTP_EXPORT +uint8_t llhttp_get_http_minor(llhttp_t* parser); + +LLHTTP_EXPORT +uint8_t llhttp_get_method(llhttp_t* parser); + +LLHTTP_EXPORT +int llhttp_get_status_code(llhttp_t* parser); + +LLHTTP_EXPORT +uint8_t llhttp_get_upgrade(llhttp_t* parser); + +/* Reset an already initialized parser back to the start state, preserving the + * existing parser type, callback settings, user data, and lenient flags. + */ +LLHTTP_EXPORT +void llhttp_reset(llhttp_t* parser); + +/* Initialize the settings object */ +LLHTTP_EXPORT +void llhttp_settings_init(llhttp_settings_t* settings); + +/* Parse full or partial request/response, invoking user callbacks along the + * way. + * + * If any of `llhttp_data_cb` returns errno not equal to `HPE_OK` - the parsing + * interrupts, and such errno is returned from `llhttp_execute()`. If + * `HPE_PAUSED` was used as a errno, the execution can be resumed with + * `llhttp_resume()` call. + * + * In a special case of CONNECT/Upgrade request/response `HPE_PAUSED_UPGRADE` + * is returned after fully parsing the request/response. If the user wishes to + * continue parsing, they need to invoke `llhttp_resume_after_upgrade()`. + * + * NOTE: if this function ever returns a non-pause type error, it will continue + * to return the same error upon each successive call up until `llhttp_init()` + * is called. + */ +LLHTTP_EXPORT +llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len); + +/* This method should be called when the other side has no further bytes to + * send (e.g. shutdown of readable side of the TCP connection.) + * + * Requests without `Content-Length` and other messages might require treating + * all incoming bytes as the part of the body, up to the last byte of the + * connection. This method will invoke `on_message_complete()` callback if the + * request was terminated safely. Otherwise a error code would be returned. + */ +LLHTTP_EXPORT +llhttp_errno_t llhttp_finish(llhttp_t* parser); + +/* Returns `1` if the incoming message is parsed until the last byte, and has + * to be completed by calling `llhttp_finish()` on EOF + */ +LLHTTP_EXPORT +int llhttp_message_needs_eof(const llhttp_t* parser); + +/* Returns `1` if there might be any other messages following the last that was + * successfully parsed. + */ +LLHTTP_EXPORT +int llhttp_should_keep_alive(const llhttp_t* parser); + +/* Make further calls of `llhttp_execute()` return `HPE_PAUSED` and set + * appropriate error reason. + * + * Important: do not call this from user callbacks! User callbacks must return + * `HPE_PAUSED` if pausing is required. + */ +LLHTTP_EXPORT +void llhttp_pause(llhttp_t* parser); + +/* Might be called to resume the execution after the pause in user's callback. + * See `llhttp_execute()` above for details. + * + * Call this only if `llhttp_execute()` returns `HPE_PAUSED`. + */ +LLHTTP_EXPORT +void llhttp_resume(llhttp_t* parser); + +/* Might be called to resume the execution after the pause in user's callback. + * See `llhttp_execute()` above for details. + * + * Call this only if `llhttp_execute()` returns `HPE_PAUSED_UPGRADE` + */ +LLHTTP_EXPORT +void llhttp_resume_after_upgrade(llhttp_t* parser); + +/* Returns the latest return error */ +LLHTTP_EXPORT +llhttp_errno_t llhttp_get_errno(const llhttp_t* parser); + +/* Returns the verbal explanation of the latest returned error. + * + * Note: User callback should set error reason when returning the error. See + * `llhttp_set_error_reason()` for details. + */ +LLHTTP_EXPORT +const char* llhttp_get_error_reason(const llhttp_t* parser); + +/* Assign verbal description to the returned error. Must be called in user + * callbacks right before returning the errno. + * + * Note: `HPE_USER` error code might be useful in user callbacks. + */ +LLHTTP_EXPORT +void llhttp_set_error_reason(llhttp_t* parser, const char* reason); + +/* Returns the pointer to the last parsed byte before the returned error. The + * pointer is relative to the `data` argument of `llhttp_execute()`. + * + * Note: this method might be useful for counting the number of parsed bytes. + */ +LLHTTP_EXPORT +const char* llhttp_get_error_pos(const llhttp_t* parser); + +/* Returns textual name of error code */ +LLHTTP_EXPORT +const char* llhttp_errno_name(llhttp_errno_t err); + +/* Returns textual name of HTTP method */ +LLHTTP_EXPORT +const char* llhttp_method_name(llhttp_method_t method); + +/* Returns textual name of HTTP status */ +LLHTTP_EXPORT +const char* llhttp_status_name(llhttp_status_t status); + +/* Enables/disables lenient header value parsing (disabled by default). + * + * Lenient parsing disables header value token checks, extending llhttp's + * protocol support to highly non-compliant clients/server. No + * `HPE_INVALID_HEADER_TOKEN` will be raised for incorrect header values when + * lenient parsing is "on". + * + * **Enabling this flag can pose a security issue since you will be exposed to + * request smuggling attacks. USE WITH CAUTION!** + */ +LLHTTP_EXPORT +void llhttp_set_lenient_headers(llhttp_t* parser, int enabled); + + +/* Enables/disables lenient handling of conflicting `Transfer-Encoding` and + * `Content-Length` headers (disabled by default). + * + * Normally `llhttp` would error when `Transfer-Encoding` is present in + * conjunction with `Content-Length`. This error is important to prevent HTTP + * request smuggling, but may be less desirable for small number of cases + * involving legacy servers. + * + * **Enabling this flag can pose a security issue since you will be exposed to + * request smuggling attacks. USE WITH CAUTION!** + */ +LLHTTP_EXPORT +void llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled); + + +/* Enables/disables lenient handling of `Connection: close` and HTTP/1.0 + * requests responses. + * + * Normally `llhttp` would error on (in strict mode) or discard (in loose mode) + * the HTTP request/response after the request/response with `Connection: close` + * and `Content-Length`. This is important to prevent cache poisoning attacks, + * but might interact badly with outdated and insecure clients. With this flag + * the extra request/response will be parsed normally. + * + * **Enabling this flag can pose a security issue since you will be exposed to + * poisoning attacks. USE WITH CAUTION!** + */ +LLHTTP_EXPORT +void llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled); + +/* Enables/disables lenient handling of `Transfer-Encoding` header. + * + * Normally `llhttp` would error when a `Transfer-Encoding` has `chunked` value + * and another value after it (either in a single header or in multiple + * headers whose value are internally joined using `, `). + * This is mandated by the spec to reliably determine request body size and thus + * avoid request smuggling. + * With this flag the extra value will be parsed normally. + * + * **Enabling this flag can pose a security issue since you will be exposed to + * request smuggling attacks. USE WITH CAUTION!** + */ +LLHTTP_EXPORT +void llhttp_set_lenient_transfer_encoding(llhttp_t* parser, int enabled); + +/* Enables/disables lenient handling of HTTP version. + * + * Normally `llhttp` would error when the HTTP version in the request or status line + * is not `0.9`, `1.0`, `1.1` or `2.0`. + * With this flag the invalid value will be parsed normally. + * + * **Enabling this flag can pose a security issue since you will allow unsupported + * HTTP versions. USE WITH CAUTION!** + */ +LLHTTP_EXPORT +void llhttp_set_lenient_version(llhttp_t* parser, int enabled); + +/* Enables/disables lenient handling of additional data received after a message ends + * and keep-alive is disabled. + * + * Normally `llhttp` would error when additional unexpected data is received if the message + * contains the `Connection` header with `close` value. + * With this flag the extra data will discarded without throwing an error. + * + * **Enabling this flag can pose a security issue since you will be exposed to + * poisoning attacks. USE WITH CAUTION!** + */ +LLHTTP_EXPORT +void llhttp_set_lenient_data_after_close(llhttp_t* parser, int enabled); + +/* Enables/disables lenient handling of incomplete CRLF sequences. + * + * Normally `llhttp` would error when a CR is not followed by LF when terminating the + * request line, the status line, the headers or a chunk header. + * With this flag only a CR is required to terminate such sections. + * + * **Enabling this flag can pose a security issue since you will be exposed to + * request smuggling attacks. USE WITH CAUTION!** + */ +LLHTTP_EXPORT +void llhttp_set_lenient_optional_lf_after_cr(llhttp_t* parser, int enabled); + +/* + * Enables/disables lenient handling of line separators. + * + * Normally `llhttp` would error when a LF is not preceded by CR when terminating the + * request line, the status line, the headers, a chunk header or a chunk data. + * With this flag only a LF is required to terminate such sections. + * + * **Enabling this flag can pose a security issue since you will be exposed to + * request smuggling attacks. USE WITH CAUTION!** + */ +LLHTTP_EXPORT +void llhttp_set_lenient_optional_cr_before_lf(llhttp_t* parser, int enabled); + +/* Enables/disables lenient handling of chunks not separated via CRLF. + * + * Normally `llhttp` would error when after a chunk data a CRLF is missing before + * starting a new chunk. + * With this flag the new chunk can start immediately after the previous one. + * + * **Enabling this flag can pose a security issue since you will be exposed to + * request smuggling attacks. USE WITH CAUTION!** + */ +LLHTTP_EXPORT +void llhttp_set_lenient_optional_crlf_after_chunk(llhttp_t* parser, int enabled); + +/* Enables/disables lenient handling of spaces after chunk size. + * + * Normally `llhttp` would error when after a chunk size is followed by one or more + * spaces are present instead of a CRLF or `;`. + * With this flag this check is disabled. + * + * **Enabling this flag can pose a security issue since you will be exposed to + * request smuggling attacks. USE WITH CAUTION!** + */ +LLHTTP_EXPORT +void llhttp_set_lenient_spaces_after_chunk_size(llhttp_t* parser, int enabled); + +#ifdef __cplusplus +} /* extern "C" */ +#endif +#endif /* INCLUDE_LLHTTP_API_H_ */ + + +#endif /* INCLUDE_LLHTTP_H_ */ diff --git a/vendor/libgit2/deps/ntlmclient/CMakeLists.txt b/vendor/libgit2/deps/ntlmclient/CMakeLists.txt index 9c5e23d6..f1f5de16 100644 --- a/vendor/libgit2/deps/ntlmclient/CMakeLists.txt +++ b/vendor/libgit2/deps/ntlmclient/CMakeLists.txt @@ -20,16 +20,18 @@ if(USE_HTTPS STREQUAL "SecureTransport") set_source_files_properties("crypt_commoncrypto.c" COMPILE_FLAGS "-Wno-deprecated") elseif(USE_HTTPS STREQUAL "OpenSSL") add_definitions(-DCRYPT_OPENSSL) + add_definitions(-DOPENSSL_API_COMPAT=0x10100000L) include_directories(${OPENSSL_INCLUDE_DIR}) set(SRC_NTLMCLIENT_CRYPTO "crypt_openssl.c" "crypt_openssl.h") elseif(USE_HTTPS STREQUAL "OpenSSL-Dynamic") add_definitions(-DCRYPT_OPENSSL) add_definitions(-DCRYPT_OPENSSL_DYNAMIC) + add_definitions(-DOPENSSL_API_COMPAT=0x10100000L) set(SRC_NTLMCLIENT_CRYPTO "crypt_openssl.c" "crypt_openssl.h") elseif(USE_HTTPS STREQUAL "mbedTLS") add_definitions(-DCRYPT_MBEDTLS) include_directories(${MBEDTLS_INCLUDE_DIR}) - set(SRC_NTLMCLIENT_CRYPTO "crypt_mbedtls.c" "crypt_mbedtls.h") + set(SRC_NTLMCLIENT_CRYPTO "crypt_mbedtls.c" "crypt_mbedtls.h" "crypt_builtin_md4.c") else() message(FATAL_ERROR "Unable to use libgit2's HTTPS backend (${USE_HTTPS}) for NTLM crypto") endif() diff --git a/vendor/libgit2/deps/ntlmclient/crypt_builtin_md4.c b/vendor/libgit2/deps/ntlmclient/crypt_builtin_md4.c new file mode 100644 index 00000000..de9a85ca --- /dev/null +++ b/vendor/libgit2/deps/ntlmclient/crypt_builtin_md4.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) Edward Thomson. All rights reserved. + * + * This file is part of ntlmclient, distributed under the MIT license. + * For full terms and copyright information, and for third-party + * copyright information, see the included LICENSE.txt file. + */ + +#include +#include + +#include "ntlm.h" +#include "crypt.h" + +/* + * Below is the MD4 code from RFC 1320, with minor modifications + * to make it compile on a modern compiler. It is included since + * many system crypto libraries lack MD4, sensibly. + */ + +/* MD4C.C - RSA Data Security, Inc., MD4 message-digest algorithm + */ + +/* Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD4 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD4 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. + */ + +/* POINTER defines a generic pointer type */ +typedef unsigned char *POINTER; + +/* UINT2 defines a two byte word */ +typedef uint16_t UINT2; + +/* UINT4 defines a four byte word */ +typedef uint32_t UINT4; + +#define MD4_memcpy memcpy +#define MD4_memset memset + +/* MD4 context. */ +typedef struct { + UINT4 state[4]; /* state (ABCD) */ + UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD4_CTX; + +/* Constants for MD4Transform routine. + */ +#define S11 3 +#define S12 7 +#define S13 11 +#define S14 19 +#define S21 3 +#define S22 5 +#define S23 9 +#define S24 13 +#define S31 3 +#define S32 9 +#define S33 11 +#define S34 15 + +static void MD4Transform(UINT4 [4], const unsigned char [64]); +static void Encode (unsigned char *, UINT4 *, unsigned int); +static void Decode (UINT4 *, const unsigned char *, unsigned int); + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G and H are basic MD4 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG and HH are transformations for rounds 1, 2 and 3 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s) { \ + (a) += F ((b), (c), (d)) + (x); \ + (a) = ROTATE_LEFT ((a), (s)); \ + } +#define GG(a, b, c, d, x, s) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; \ + (a) = ROTATE_LEFT ((a), (s)); \ + } +#define HH(a, b, c, d, x, s) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; \ + (a) = ROTATE_LEFT ((a), (s)); \ + } + +/* MD4 initialization. Begins an MD4 operation, writing a new context. + */ +static void MD4Init (MD4_CTX *context) +{ + context->count[0] = context->count[1] = 0; + + /* Load magic initialization constants. + */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD4 block update operation. Continues an MD4 message-digest + operation, processing another message block, and updating the + context. + */ +static void MD4Update (MD4_CTX *context, const unsigned char *input, unsigned int inputLen) +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + /* Update number of bits */ + if ((context->count[0] += ((UINT4)inputLen << 3)) + < ((UINT4)inputLen << 3)) + context->count[1]++; + context->count[1] += ((UINT4)inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. + */ + if (inputLen >= partLen) { + MD4_memcpy + ((POINTER)&context->buffer[index], (POINTER)input, partLen); + MD4Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD4Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + MD4_memcpy + ((POINTER)&context->buffer[index], (POINTER)&input[i], + inputLen-i); +} + +/* MD4 finalization. Ends an MD4 message-digest operation, writing the + the message digest and zeroizing the context. + */ +static void MD4Final (unsigned char digest[16], MD4_CTX *context) +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64. + */ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD4Update (context, PADDING, padLen); + + /* Append length (before padding) */ + MD4Update (context, bits, 8); + /* Store state in digest */ + Encode (digest, context->state, 16); + + /* Zeroize sensitive information. + */ + MD4_memset ((POINTER)context, 0, sizeof (*context)); +} + +/* MD4 basic transformation. Transforms state based on block. + */ +static void MD4Transform (UINT4 state[4], const unsigned char block[64]) +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11); /* 1 */ + FF (d, a, b, c, x[ 1], S12); /* 2 */ + FF (c, d, a, b, x[ 2], S13); /* 3 */ + FF (b, c, d, a, x[ 3], S14); /* 4 */ + FF (a, b, c, d, x[ 4], S11); /* 5 */ + FF (d, a, b, c, x[ 5], S12); /* 6 */ + FF (c, d, a, b, x[ 6], S13); /* 7 */ + FF (b, c, d, a, x[ 7], S14); /* 8 */ + FF (a, b, c, d, x[ 8], S11); /* 9 */ + FF (d, a, b, c, x[ 9], S12); /* 10 */ + FF (c, d, a, b, x[10], S13); /* 11 */ + FF (b, c, d, a, x[11], S14); /* 12 */ + FF (a, b, c, d, x[12], S11); /* 13 */ + FF (d, a, b, c, x[13], S12); /* 14 */ + FF (c, d, a, b, x[14], S13); /* 15 */ + FF (b, c, d, a, x[15], S14); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 0], S21); /* 17 */ + GG (d, a, b, c, x[ 4], S22); /* 18 */ + GG (c, d, a, b, x[ 8], S23); /* 19 */ + GG (b, c, d, a, x[12], S24); /* 20 */ + GG (a, b, c, d, x[ 1], S21); /* 21 */ + GG (d, a, b, c, x[ 5], S22); /* 22 */ + GG (c, d, a, b, x[ 9], S23); /* 23 */ + GG (b, c, d, a, x[13], S24); /* 24 */ + GG (a, b, c, d, x[ 2], S21); /* 25 */ + GG (d, a, b, c, x[ 6], S22); /* 26 */ + GG (c, d, a, b, x[10], S23); /* 27 */ + GG (b, c, d, a, x[14], S24); /* 28 */ + GG (a, b, c, d, x[ 3], S21); /* 29 */ + GG (d, a, b, c, x[ 7], S22); /* 30 */ + GG (c, d, a, b, x[11], S23); /* 31 */ + GG (b, c, d, a, x[15], S24); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 0], S31); /* 33 */ + HH (d, a, b, c, x[ 8], S32); /* 34 */ + HH (c, d, a, b, x[ 4], S33); /* 35 */ + HH (b, c, d, a, x[12], S34); /* 36 */ + HH (a, b, c, d, x[ 2], S31); /* 37 */ + HH (d, a, b, c, x[10], S32); /* 38 */ + HH (c, d, a, b, x[ 6], S33); /* 39 */ + HH (b, c, d, a, x[14], S34); /* 40 */ + HH (a, b, c, d, x[ 1], S31); /* 41 */ + HH (d, a, b, c, x[ 9], S32); /* 42 */ + HH (c, d, a, b, x[ 5], S33); /* 43 */ + HH (b, c, d, a, x[13], S34); /* 44 */ + HH (a, b, c, d, x[ 3], S31); /* 45 */ + HH (d, a, b, c, x[11], S32); /* 46 */ + HH (c, d, a, b, x[ 7], S33); /* 47 */ + HH (b, c, d, a, x[15], S34); /* 48 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. + */ + MD4_memset ((POINTER)x, 0, sizeof (x)); +} + +/* Encodes input (UINT4) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void Encode (unsigned char *output, UINT4 *input, unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (UINT4). Assumes len is + a multiple of 4. + */ +static void Decode (UINT4 *output, const unsigned char *input, unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | + (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); +} + +bool ntlm_md4_digest( + unsigned char out[CRYPT_MD4_DIGESTSIZE], + ntlm_client *ntlm, + const unsigned char *in, + size_t in_len) +{ + MD4_CTX ctx; + + NTLM_UNUSED(ntlm); + + if (in_len > UINT_MAX) + return false; + + MD4Init(&ctx); + MD4Update(&ctx, in, (unsigned int)in_len); + MD4Final (out, &ctx); + + return true; +} diff --git a/vendor/libgit2/deps/ntlmclient/crypt_commoncrypto.c b/vendor/libgit2/deps/ntlmclient/crypt_commoncrypto.c index 4ff57edd..3c20469f 100644 --- a/vendor/libgit2/deps/ntlmclient/crypt_commoncrypto.c +++ b/vendor/libgit2/deps/ntlmclient/crypt_commoncrypto.c @@ -59,11 +59,12 @@ bool ntlm_des_encrypt( ntlm_des_block *plaintext, ntlm_des_block *key) { + CCCryptorStatus result; size_t written; NTLM_UNUSED(ntlm); - CCCryptorStatus result = CCCrypt(kCCEncrypt, + result = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode, key, sizeof(ntlm_des_block), NULL, plaintext, sizeof(ntlm_des_block), diff --git a/vendor/libgit2/deps/ntlmclient/crypt_mbedtls.c b/vendor/libgit2/deps/ntlmclient/crypt_mbedtls.c index 6283c3ee..4bbb8780 100644 --- a/vendor/libgit2/deps/ntlmclient/crypt_mbedtls.c +++ b/vendor/libgit2/deps/ntlmclient/crypt_mbedtls.c @@ -12,7 +12,6 @@ #include "mbedtls/ctr_drbg.h" #include "mbedtls/des.h" #include "mbedtls/entropy.h" -#include "mbedtls/md4.h" #include "ntlm.h" #include "crypt.h" @@ -88,25 +87,6 @@ bool ntlm_des_encrypt( return success; } -bool ntlm_md4_digest( - unsigned char out[CRYPT_MD4_DIGESTSIZE], - ntlm_client *ntlm, - const unsigned char *in, - size_t in_len) -{ - mbedtls_md4_context ctx; - - NTLM_UNUSED(ntlm); - - mbedtls_md4_init(&ctx); - mbedtls_md4_starts(&ctx); - mbedtls_md4_update(&ctx, in, in_len); - mbedtls_md4_finish(&ctx, out); - mbedtls_md4_free(&ctx); - - return true; -} - bool ntlm_hmac_md5_init( ntlm_client *ntlm, const unsigned char *key, diff --git a/vendor/libgit2/deps/ntlmclient/crypt_openssl.c b/vendor/libgit2/deps/ntlmclient/crypt_openssl.c index bab8276a..c4be129d 100644 --- a/vendor/libgit2/deps/ntlmclient/crypt_openssl.c +++ b/vendor/libgit2/deps/ntlmclient/crypt_openssl.c @@ -44,7 +44,9 @@ static inline void HMAC_CTX_free(HMAC_CTX *ctx) #endif -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !LIBRESSL_VERSION_NUMBER) || defined(CRYPT_OPENSSL_DYNAMIC) +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)) || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x03050000fL) || \ + defined(CRYPT_OPENSSL_DYNAMIC) static inline void HMAC_CTX_cleanup(HMAC_CTX *ctx) { diff --git a/vendor/libgit2/deps/ntlmclient/ntlm.c b/vendor/libgit2/deps/ntlmclient/ntlm.c index ad4de5de..6094a4a3 100644 --- a/vendor/libgit2/deps/ntlmclient/ntlm.c +++ b/vendor/libgit2/deps/ntlmclient/ntlm.c @@ -988,9 +988,9 @@ static inline bool generate_lm_hash( keystr2_len = (password_len > 7) ? MIN(14, password_len) - 7 : 0; for (i = 0; i < keystr1_len; i++) - keystr1[i] = (unsigned char)toupper(password[i]); + keystr1[i] = (unsigned char)toupper((unsigned char)password[i]); for (i = 0; i < keystr2_len; i++) - keystr2[i] = (unsigned char)toupper(password[i+7]); + keystr2[i] = (unsigned char)toupper((unsigned char)password[i+7]); /* DES encrypt the LM constant using the password as the key */ des_key_from_password(&key1, keystr1, keystr1_len); diff --git a/vendor/libgit2/deps/ntlmclient/unicode_builtin.c b/vendor/libgit2/deps/ntlmclient/unicode_builtin.c index e2ee0abf..6d398b7c 100644 --- a/vendor/libgit2/deps/ntlmclient/unicode_builtin.c +++ b/vendor/libgit2/deps/ntlmclient/unicode_builtin.c @@ -372,13 +372,13 @@ static inline bool unicode_builtin_encoding_convert( goto done; } + out_len = out_start - out; + if ((new_out = realloc(out, out_size)) == NULL) { ntlm_client_set_errmsg(ntlm, "out of memory"); goto done; } - out_len = out_start - out; - out = new_out; out_start = new_out + out_len; out_end = out + out_size; diff --git a/vendor/libgit2/deps/pcre/LICENCE b/vendor/libgit2/deps/pcre/LICENCE index 57a54481..803b4119 100644 --- a/vendor/libgit2/deps/pcre/LICENCE +++ b/vendor/libgit2/deps/pcre/LICENCE @@ -19,13 +19,13 @@ THE BASIC LIBRARY FUNCTIONS --------------------------- Written by: Philip Hazel -Email local part: ph10 -Email domain: cam.ac.uk +Email local part: Philip.Hazel +Email domain: gmail.com University of Cambridge Computing Service, Cambridge, England. -Copyright (c) 1997-2020 University of Cambridge +Copyright (c) 1997-2021 University of Cambridge All rights reserved. @@ -36,7 +36,7 @@ Written by: Zoltan Herczeg Email local part: hzmester Email domain: freemail.hu -Copyright(c) 2010-2020 Zoltan Herczeg +Copyright(c) 2010-2021 Zoltan Herczeg All rights reserved. @@ -47,7 +47,7 @@ Written by: Zoltan Herczeg Email local part: hzmester Email domain: freemail.hu -Copyright(c) 2009-2020 Zoltan Herczeg +Copyright(c) 2009-2021 Zoltan Herczeg All rights reserved. diff --git a/vendor/libgit2/deps/pcre/pcre.h b/vendor/libgit2/deps/pcre/pcre.h index 5b147b9f..821b50e8 100644 --- a/vendor/libgit2/deps/pcre/pcre.h +++ b/vendor/libgit2/deps/pcre/pcre.h @@ -42,9 +42,9 @@ POSSIBILITY OF SUCH DAMAGE. /* The current PCRE version information. */ #define PCRE_MAJOR 8 -#define PCRE_MINOR 44 +#define PCRE_MINOR 45 #define PCRE_PRERELEASE -#define PCRE_DATE 2020-02-12 +#define PCRE_DATE 2021-06-15 #define PCRE_EXP_DECL extern diff --git a/vendor/libgit2/deps/pcre/pcre_compile.c b/vendor/libgit2/deps/pcre/pcre_compile.c index a3f20fd3..43f852f4 100644 --- a/vendor/libgit2/deps/pcre/pcre_compile.c +++ b/vendor/libgit2/deps/pcre/pcre_compile.c @@ -6,7 +6,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel - Copyright (c) 1997-2020 University of Cambridge + Copyright (c) 1997-2021 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -9104,6 +9104,8 @@ pcre_uchar cworkspace[COMPILE_WORK_SIZE]; similar way to cworkspace, it can be expanded using malloc() if necessary. */ named_group named_groups[NAMED_GROUP_LIST_SIZE]; +cd->named_groups = named_groups; +cd->named_group_list_size = NAMED_GROUP_LIST_SIZE; /* Set this early so that early errors get offset 0. */ @@ -9377,8 +9379,6 @@ cd->hwm = cworkspace; cd->iscondassert = FALSE; cd->start_workspace = cworkspace; cd->workspace_size = COMPILE_WORK_SIZE; -cd->named_groups = named_groups; -cd->named_group_list_size = NAMED_GROUP_LIST_SIZE; cd->start_pattern = (const pcre_uchar *)pattern; cd->end_pattern = (const pcre_uchar *)(pattern + STRLEN_UC((const pcre_uchar *)pattern)); cd->req_varyopt = 0; @@ -9489,6 +9489,7 @@ if (cd->names_found > 0) add_name(cd, ng->name, ng->length, ng->number); if (cd->named_group_list_size > NAMED_GROUP_LIST_SIZE) (PUBL(free))((void *)cd->named_groups); + cd->named_group_list_size = 0; /* So we don't free it twice */ } /* Set up a starting, non-extracting bracket, then compile the expression. On @@ -9639,6 +9640,8 @@ if (errorcode != 0) { (PUBL(free))(re); PCRE_EARLY_ERROR_RETURN: + if (cd->named_group_list_size > NAMED_GROUP_LIST_SIZE) + (PUBL(free))((void *)cd->named_groups); *erroroffset = (int)(ptr - (const pcre_uchar *)pattern); PCRE_EARLY_ERROR_RETURN2: *errorptr = find_error_text(errorcode); diff --git a/vendor/libgit2/deps/pcre/pcre_exec.c b/vendor/libgit2/deps/pcre/pcre_exec.c index 3fd58cbe..5b96954f 100644 --- a/vendor/libgit2/deps/pcre/pcre_exec.c +++ b/vendor/libgit2/deps/pcre/pcre_exec.c @@ -6,7 +6,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel - Copyright (c) 1997-2018 University of Cambridge + Copyright (c) 1997-2021 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -758,7 +758,7 @@ for (;;) md->mark = NULL; /* In case previously set by assertion */ RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode] + ecode[1], offset_top, md, eptrb, RM55); - if ((rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) && + if ((rrc == MATCH_MATCH || rrc == MATCH_ACCEPT || rrc == MATCH_KETRPOS) && md->mark == NULL) md->mark = ecode + 2; /* A return of MATCH_SKIP_ARG means that matching failed at SKIP with an diff --git a/vendor/libgit2/deps/xdiff/CMakeLists.txt b/vendor/libgit2/deps/xdiff/CMakeLists.txt new file mode 100644 index 00000000..743ac636 --- /dev/null +++ b/vendor/libgit2/deps/xdiff/CMakeLists.txt @@ -0,0 +1,28 @@ + +file(GLOB SRC_XDIFF "*.c" "*.h") +list(SORT SRC_XDIFF) + +add_library(xdiff OBJECT ${SRC_XDIFF}) +target_include_directories(xdiff SYSTEM PRIVATE + "${PROJECT_SOURCE_DIR}/include" + "${PROJECT_SOURCE_DIR}/src/util" + "${PROJECT_BINARY_DIR}/src/util" + ${LIBGIT2_SYSTEM_INCLUDES} + ${LIBGIT2_DEPENDENCY_INCLUDES}) + +# the xdiff dependency is not (yet) warning-free, disable warnings +# as errors for the xdiff sources until we've sorted them out +if(MSVC) + set_source_files_properties(xdiffi.c PROPERTIES COMPILE_FLAGS -WX-) + set_source_files_properties(xemit.c PROPERTIES COMPILE_FLAGS -WX-) + set_source_files_properties(xhistogram.c PROPERTIES COMPILE_FLAGS -WX-) + set_source_files_properties(xmerge.c PROPERTIES COMPILE_FLAGS -WX-) + set_source_files_properties(xutils.c PROPERTIES COMPILE_FLAGS -WX-) + set_source_files_properties(xpatience.c PROPERTIES COMPILE_FLAGS -WX-) +else() + set_source_files_properties(xdiffi.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare -Wno-unused-parameter") + set_source_files_properties(xemit.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare -Wno-unused-parameter") + set_source_files_properties(xhistogram.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare") + set_source_files_properties(xutils.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare") + set_source_files_properties(xpatience.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare") +endif() diff --git a/vendor/libgit2/src/xdiff/git-xdiff.h b/vendor/libgit2/deps/xdiff/git-xdiff.h similarity index 91% rename from vendor/libgit2/src/xdiff/git-xdiff.h rename to vendor/libgit2/deps/xdiff/git-xdiff.h index b75dba81..1450ab3d 100644 --- a/vendor/libgit2/src/xdiff/git-xdiff.h +++ b/vendor/libgit2/deps/xdiff/git-xdiff.h @@ -27,11 +27,14 @@ # endif #endif +#define XDL_UNUSED GIT_UNUSED_ARG + #define xdl_malloc(x) git__malloc(x) +#define xdl_calloc(n, sz) git__calloc(n, sz) #define xdl_free(ptr) git__free(ptr) #define xdl_realloc(ptr, x) git__realloc(ptr, x) -#define XDL_BUG(msg) GIT_ASSERT(msg) +#define XDL_BUG(msg) GIT_ASSERT(!msg) #define xdl_regex_t git_regexp #define xdl_regmatch_t git_regmatch diff --git a/vendor/libgit2/src/xdiff/xdiff.h b/vendor/libgit2/deps/xdiff/xdiff.h similarity index 100% rename from vendor/libgit2/src/xdiff/xdiff.h rename to vendor/libgit2/deps/xdiff/xdiff.h diff --git a/vendor/libgit2/src/xdiff/xdiffi.c b/vendor/libgit2/deps/xdiff/xdiffi.c similarity index 97% rename from vendor/libgit2/src/xdiff/xdiffi.c rename to vendor/libgit2/deps/xdiff/xdiffi.c index af31b7f4..ea36143a 100644 --- a/vendor/libgit2/src/xdiff/xdiffi.c +++ b/vendor/libgit2/deps/xdiff/xdiffi.c @@ -315,16 +315,19 @@ int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, long *kvd, *kvdf, *kvdb; xdalgoenv_t xenv; diffdata_t dd1, dd2; + int res; - if (XDF_DIFF_ALG(xpp->flags) == XDF_PATIENCE_DIFF) - return xdl_do_patience_diff(mf1, mf2, xpp, xe); - - if (XDF_DIFF_ALG(xpp->flags) == XDF_HISTOGRAM_DIFF) - return xdl_do_histogram_diff(mf1, mf2, xpp, xe); + if (xdl_prepare_env(mf1, mf2, xpp, xe) < 0) + return -1; - if (xdl_prepare_env(mf1, mf2, xpp, xe) < 0) { + if (XDF_DIFF_ALG(xpp->flags) == XDF_PATIENCE_DIFF) { + res = xdl_do_patience_diff(xpp, xe); + goto out; + } - return -1; + if (XDF_DIFF_ALG(xpp->flags) == XDF_HISTOGRAM_DIFF) { + res = xdl_do_histogram_diff(xpp, xe); + goto out; } /* @@ -334,7 +337,7 @@ int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, * One is to store the forward path and one to store the backward path. */ ndiags = xe->xdf1.nreff + xe->xdf2.nreff + 3; - if (!(kvd = (long *) xdl_malloc((2 * ndiags + 2) * sizeof(long)))) { + if (!XDL_ALLOC_ARRAY(kvd, 2 * ndiags + 2)) { xdl_free_env(xe); return -1; @@ -359,17 +362,15 @@ int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, dd2.rchg = xe->xdf2.rchg; dd2.rindex = xe->xdf2.rindex; - if (xdl_recs_cmp(&dd1, 0, dd1.nrec, &dd2, 0, dd2.nrec, - kvdf, kvdb, (xpp->flags & XDF_NEED_MINIMAL) != 0, &xenv) < 0) { - - xdl_free(kvd); - xdl_free_env(xe); - return -1; - } - + res = xdl_recs_cmp(&dd1, 0, dd1.nrec, &dd2, 0, dd2.nrec, + kvdf, kvdb, (xpp->flags & XDF_NEED_MINIMAL) != 0, + &xenv); xdl_free(kvd); + out: + if (res < 0) + xdl_free_env(xe); - return 0; + return res; } @@ -972,7 +973,7 @@ void xdl_free_script(xdchange_t *xscr) { } } -static int xdl_call_hunk_func(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, +static int xdl_call_hunk_func(xdfenv_t *xe XDL_UNUSED, xdchange_t *xscr, xdemitcb_t *ecb, xdemitconf_t const *xecfg) { xdchange_t *xch, *xche; diff --git a/vendor/libgit2/src/xdiff/xdiffi.h b/vendor/libgit2/deps/xdiff/xdiffi.h similarity index 90% rename from vendor/libgit2/src/xdiff/xdiffi.h rename to vendor/libgit2/deps/xdiff/xdiffi.h index 8f1c7c8b..126c9d8f 100644 --- a/vendor/libgit2/src/xdiff/xdiffi.h +++ b/vendor/libgit2/deps/xdiff/xdiffi.h @@ -56,9 +56,7 @@ int xdl_build_script(xdfenv_t *xe, xdchange_t **xscr); void xdl_free_script(xdchange_t *xscr); int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, xdemitconf_t const *xecfg); -int xdl_do_patience_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, - xdfenv_t *env); -int xdl_do_histogram_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, - xdfenv_t *env); +int xdl_do_patience_diff(xpparam_t const *xpp, xdfenv_t *env); +int xdl_do_histogram_diff(xpparam_t const *xpp, xdfenv_t *env); #endif /* #if !defined(XDIFFI_H) */ diff --git a/vendor/libgit2/src/xdiff/xemit.c b/vendor/libgit2/deps/xdiff/xemit.c similarity index 98% rename from vendor/libgit2/src/xdiff/xemit.c rename to vendor/libgit2/deps/xdiff/xemit.c index 1cbf2b98..75f0fe49 100644 --- a/vendor/libgit2/src/xdiff/xemit.c +++ b/vendor/libgit2/deps/xdiff/xemit.c @@ -65,7 +65,7 @@ xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg) *xscr = xch; } - if (*xscr == NULL) + if (!*xscr) return NULL; lxch = *xscr; @@ -95,7 +95,7 @@ xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg) } -static long def_ff(const char *rec, long len, char *buf, long sz, void *priv) +static long def_ff(const char *rec, long len, char *buf, long sz) { if (len > 0 && (isalpha((unsigned char)*rec) || /* identifier? */ @@ -117,7 +117,7 @@ static long match_func_rec(xdfile_t *xdf, xdemitconf_t const *xecfg, long ri, const char *rec; long len = xdl_get_rec(xdf, ri, &rec); if (!xecfg->find_func) - return def_ff(rec, len, buf, sz, xecfg->find_func_priv); + return def_ff(rec, len, buf, sz); return xecfg->find_func(rec, len, buf, sz, xecfg->find_func_priv); } diff --git a/vendor/libgit2/src/xdiff/xemit.h b/vendor/libgit2/deps/xdiff/xemit.h similarity index 100% rename from vendor/libgit2/src/xdiff/xemit.h rename to vendor/libgit2/deps/xdiff/xemit.h diff --git a/vendor/libgit2/src/xdiff/xhistogram.c b/vendor/libgit2/deps/xdiff/xhistogram.c similarity index 92% rename from vendor/libgit2/src/xdiff/xhistogram.c rename to vendor/libgit2/deps/xdiff/xhistogram.c index 80794748..16a8fe2f 100644 --- a/vendor/libgit2/src/xdiff/xhistogram.c +++ b/vendor/libgit2/deps/xdiff/xhistogram.c @@ -251,7 +251,7 @@ static int find_lcs(xpparam_t const *xpp, xdfenv_t *env, int line1, int count1, int line2, int count2) { int b_ptr; - int sz, ret = -1; + int ret = -1; struct histindex index; memset(&index, 0, sizeof(index)); @@ -265,23 +265,16 @@ static int find_lcs(xpparam_t const *xpp, xdfenv_t *env, index.rcha.head = NULL; index.table_bits = xdl_hashbits(count1); - sz = index.records_size = 1 << index.table_bits; - sz *= sizeof(struct record *); - if (!(index.records = (struct record **) xdl_malloc(sz))) + index.records_size = 1 << index.table_bits; + if (!XDL_CALLOC_ARRAY(index.records, index.records_size)) goto cleanup; - memset(index.records, 0, sz); - sz = index.line_map_size = count1; - sz *= sizeof(struct record *); - if (!(index.line_map = (struct record **) xdl_malloc(sz))) + index.line_map_size = count1; + if (!XDL_CALLOC_ARRAY(index.line_map, index.line_map_size)) goto cleanup; - memset(index.line_map, 0, sz); - sz = index.line_map_size; - sz *= sizeof(unsigned int); - if (!(index.next_ptrs = (unsigned int *) xdl_malloc(sz))) + if (!XDL_CALLOC_ARRAY(index.next_ptrs, index.line_map_size)) goto cleanup; - memset(index.next_ptrs, 0, sz); /* lines / 4 + 1 comes from xprepare.c:xdl_prepare_ctx() */ if (xdl_cha_init(&index.rcha, sizeof(struct record), count1 / 4 + 1) < 0) @@ -369,12 +362,8 @@ static int histogram_diff(xpparam_t const *xpp, xdfenv_t *env, return result; } -int xdl_do_histogram_diff(mmfile_t *file1, mmfile_t *file2, - xpparam_t const *xpp, xdfenv_t *env) +int xdl_do_histogram_diff(xpparam_t const *xpp, xdfenv_t *env) { - if (xdl_prepare_env(file1, file2, xpp, env) < 0) - return -1; - return histogram_diff(xpp, env, env->xdf1.dstart + 1, env->xdf1.dend - env->xdf1.dstart + 1, env->xdf2.dstart + 1, env->xdf2.dend - env->xdf2.dstart + 1); diff --git a/vendor/libgit2/src/xdiff/xinclude.h b/vendor/libgit2/deps/xdiff/xinclude.h similarity index 100% rename from vendor/libgit2/src/xdiff/xinclude.h rename to vendor/libgit2/deps/xdiff/xinclude.h diff --git a/vendor/libgit2/deps/xdiff/xmacros.h b/vendor/libgit2/deps/xdiff/xmacros.h new file mode 100644 index 00000000..8487bb39 --- /dev/null +++ b/vendor/libgit2/deps/xdiff/xmacros.h @@ -0,0 +1,71 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * . + * + * Davide Libenzi + * + */ + +#if !defined(XMACROS_H) +#define XMACROS_H + + + + +#define XDL_MIN(a, b) ((a) < (b) ? (a): (b)) +#define XDL_MAX(a, b) ((a) > (b) ? (a): (b)) +#define XDL_ABS(v) ((v) >= 0 ? (v): -(v)) +#define XDL_ISDIGIT(c) ((c) >= '0' && (c) <= '9') +#define XDL_ISSPACE(c) (isspace((unsigned char)(c))) +#define XDL_ADDBITS(v,b) ((v) + ((v) >> (b))) +#define XDL_MASKBITS(b) ((1UL << (b)) - 1) +#define XDL_HASHLONG(v,b) (XDL_ADDBITS((unsigned long)(v), b) & XDL_MASKBITS(b)) +#define XDL_LE32_PUT(p, v) \ +do { \ + unsigned char *__p = (unsigned char *) (p); \ + *__p++ = (unsigned char) (v); \ + *__p++ = (unsigned char) ((v) >> 8); \ + *__p++ = (unsigned char) ((v) >> 16); \ + *__p = (unsigned char) ((v) >> 24); \ +} while (0) +#define XDL_LE32_GET(p, v) \ +do { \ + unsigned char const *__p = (unsigned char const *) (p); \ + (v) = (unsigned long) __p[0] | ((unsigned long) __p[1]) << 8 | \ + ((unsigned long) __p[2]) << 16 | ((unsigned long) __p[3]) << 24; \ +} while (0) + +/* Allocate an array of nr elements, returns NULL on failure */ +#define XDL_ALLOC_ARRAY(p, nr) \ + ((p) = SIZE_MAX / sizeof(*(p)) >= (size_t)(nr) \ + ? xdl_malloc((nr) * sizeof(*(p))) \ + : NULL) + +/* Allocate an array of nr zeroed out elements, returns NULL on failure */ +#define XDL_CALLOC_ARRAY(p, nr) ((p) = xdl_calloc(nr, sizeof(*(p)))) + +/* + * Ensure array p can accommodate at least nr elements, growing the + * array and updating alloc (which is the number of allocated + * elements) as necessary. Frees p and returns -1 on failure, returns + * 0 on success + */ +#define XDL_ALLOC_GROW(p, nr, alloc) \ + (-!((nr) <= (alloc) || \ + ((p) = xdl_alloc_grow_helper((p), (nr), &(alloc), sizeof(*(p)))))) + +#endif /* #if !defined(XMACROS_H) */ diff --git a/vendor/libgit2/src/xdiff/xmerge.c b/vendor/libgit2/deps/xdiff/xmerge.c similarity index 97% rename from vendor/libgit2/src/xdiff/xmerge.c rename to vendor/libgit2/deps/xdiff/xmerge.c index 433e2d74..6ebf73a9 100644 --- a/vendor/libgit2/src/xdiff/xmerge.c +++ b/vendor/libgit2/deps/xdiff/xmerge.c @@ -684,42 +684,42 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2, xmparam_t const *xmp, mmbuffer_t *result) { - xdchange_t *xscr1, *xscr2; + xdchange_t *xscr1 = NULL, *xscr2 = NULL; xdfenv_t xe1, xe2; - int status; + int status = -1; xpparam_t const *xpp = &xmp->xpp; result->ptr = NULL; result->size = 0; - if (xdl_do_diff(orig, mf1, xpp, &xe1) < 0) { + if (xdl_do_diff(orig, mf1, xpp, &xe1) < 0) return -1; - } - if (xdl_do_diff(orig, mf2, xpp, &xe2) < 0) { - xdl_free_env(&xe1); - return -1; - } + + if (xdl_do_diff(orig, mf2, xpp, &xe2) < 0) + goto free_xe1; /* avoid double free of xe2 */ + if (xdl_change_compact(&xe1.xdf1, &xe1.xdf2, xpp->flags) < 0 || xdl_change_compact(&xe1.xdf2, &xe1.xdf1, xpp->flags) < 0 || - xdl_build_script(&xe1, &xscr1) < 0) { - xdl_free_env(&xe1); - return -1; - } + xdl_build_script(&xe1, &xscr1) < 0) + goto out; + if (xdl_change_compact(&xe2.xdf1, &xe2.xdf2, xpp->flags) < 0 || xdl_change_compact(&xe2.xdf2, &xe2.xdf1, xpp->flags) < 0 || - xdl_build_script(&xe2, &xscr2) < 0) { - xdl_free_script(xscr1); - xdl_free_env(&xe1); - xdl_free_env(&xe2); - return -1; - } - status = 0; + xdl_build_script(&xe2, &xscr2) < 0) + goto out; + if (!xscr1) { result->ptr = xdl_malloc(mf2->size); + if (!result->ptr) + goto out; + status = 0; memcpy(result->ptr, mf2->ptr, mf2->size); result->size = mf2->size; } else if (!xscr2) { result->ptr = xdl_malloc(mf1->size); + if (!result->ptr) + goto out; + status = 0; memcpy(result->ptr, mf1->ptr, mf1->size); result->size = mf1->size; } else { @@ -727,11 +727,13 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2, &xe2, xscr2, xmp, result); } + out: xdl_free_script(xscr1); xdl_free_script(xscr2); - xdl_free_env(&xe1); xdl_free_env(&xe2); + free_xe1: + xdl_free_env(&xe1); return status; } diff --git a/vendor/libgit2/src/xdiff/xpatience.c b/vendor/libgit2/deps/xdiff/xpatience.c similarity index 88% rename from vendor/libgit2/src/xdiff/xpatience.c rename to vendor/libgit2/deps/xdiff/xpatience.c index c5d48e80..a2d89555 100644 --- a/vendor/libgit2/src/xdiff/xpatience.c +++ b/vendor/libgit2/deps/xdiff/xpatience.c @@ -69,7 +69,6 @@ struct hashmap { } *entries, *first, *last; /* were common records found? */ unsigned long has_matches; - mmfile_t *file1, *file2; xdfenv_t *env; xpparam_t const *xpp; }; @@ -139,23 +138,17 @@ static void insert_record(xpparam_t const *xpp, int line, struct hashmap *map, * * It is assumed that env has been prepared using xdl_prepare(). */ -static int fill_hashmap(mmfile_t *file1, mmfile_t *file2, - xpparam_t const *xpp, xdfenv_t *env, +static int fill_hashmap(xpparam_t const *xpp, xdfenv_t *env, struct hashmap *result, int line1, int count1, int line2, int count2) { - result->file1 = file1; - result->file2 = file2; result->xpp = xpp; result->env = env; /* We know exactly how large we want the hash map */ result->alloc = count1 * 2; - result->entries = (struct entry *) - xdl_malloc(result->alloc * sizeof(struct entry)); - if (!result->entries) + if (!XDL_CALLOC_ARRAY(result->entries, result->alloc)) return -1; - memset(result->entries, 0, result->alloc * sizeof(struct entry)); /* First, fill with entries from the first file */ while (count1--) @@ -198,9 +191,9 @@ static int binary_search(struct entry **sequence, int longest, * item per sequence length: the sequence with the smallest last * element (in terms of line2). */ -static struct entry *find_longest_common_sequence(struct hashmap *map) +static int find_longest_common_sequence(struct hashmap *map, struct entry **res) { - struct entry **sequence = xdl_malloc(map->nr * sizeof(struct entry *)); + struct entry **sequence; int longest = 0, i; struct entry *entry; @@ -211,6 +204,9 @@ static struct entry *find_longest_common_sequence(struct hashmap *map) */ int anchor_i = -1; + if (!XDL_ALLOC_ARRAY(sequence, map->nr)) + return -1; + for (entry = map->first; entry; entry = entry->next) { if (!entry->line2 || entry->line2 == NON_UNIQUE) continue; @@ -230,8 +226,9 @@ static struct entry *find_longest_common_sequence(struct hashmap *map) /* No common unique lines were found */ if (!longest) { + *res = NULL; xdl_free(sequence); - return NULL; + return 0; } /* Iterate starting at the last element, adjusting the "next" members */ @@ -241,8 +238,9 @@ static struct entry *find_longest_common_sequence(struct hashmap *map) entry->previous->next = entry; entry = entry->previous; } + *res = entry; xdl_free(sequence); - return entry; + return 0; } static int match(struct hashmap *map, int line1, int line2) @@ -252,8 +250,7 @@ static int match(struct hashmap *map, int line1, int line2) return record1->ha == record2->ha; } -static int patience_diff(mmfile_t *file1, mmfile_t *file2, - xpparam_t const *xpp, xdfenv_t *env, +static int patience_diff(xpparam_t const *xpp, xdfenv_t *env, int line1, int count1, int line2, int count2); static int walk_common_sequence(struct hashmap *map, struct entry *first, @@ -284,8 +281,7 @@ static int walk_common_sequence(struct hashmap *map, struct entry *first, /* Recurse */ if (next1 > line1 || next2 > line2) { - if (patience_diff(map->file1, map->file2, - map->xpp, map->env, + if (patience_diff(map->xpp, map->env, line1, next1 - line1, line2, next2 - line2)) return -1; @@ -324,8 +320,7 @@ static int fall_back_to_classic_diff(struct hashmap *map, * * This function assumes that env was prepared with xdl_prepare_env(). */ -static int patience_diff(mmfile_t *file1, mmfile_t *file2, - xpparam_t const *xpp, xdfenv_t *env, +static int patience_diff(xpparam_t const *xpp, xdfenv_t *env, int line1, int count1, int line2, int count2) { struct hashmap map; @@ -344,7 +339,7 @@ static int patience_diff(mmfile_t *file1, mmfile_t *file2, } memset(&map, 0, sizeof(map)); - if (fill_hashmap(file1, file2, xpp, env, &map, + if (fill_hashmap(xpp, env, &map, line1, count1, line2, count2)) return -1; @@ -358,25 +353,21 @@ static int patience_diff(mmfile_t *file1, mmfile_t *file2, return 0; } - first = find_longest_common_sequence(&map); + result = find_longest_common_sequence(&map, &first); + if (result) + goto out; if (first) result = walk_common_sequence(&map, first, line1, count1, line2, count2); else result = fall_back_to_classic_diff(&map, line1, count1, line2, count2); - + out: xdl_free(map.entries); return result; } -int xdl_do_patience_diff(mmfile_t *file1, mmfile_t *file2, - xpparam_t const *xpp, xdfenv_t *env) +int xdl_do_patience_diff(xpparam_t const *xpp, xdfenv_t *env) { - if (xdl_prepare_env(file1, file2, xpp, env) < 0) - return -1; - - /* environment is cleaned up in xdl_diff() */ - return patience_diff(file1, file2, xpp, env, - 1, env->xdf1.nrec, 1, env->xdf2.nrec); + return patience_diff(xpp, env, 1, env->xdf1.nrec, 1, env->xdf2.nrec); } diff --git a/vendor/libgit2/src/xdiff/xprepare.c b/vendor/libgit2/deps/xdiff/xprepare.c similarity index 90% rename from vendor/libgit2/src/xdiff/xprepare.c rename to vendor/libgit2/deps/xdiff/xprepare.c index 4527a4a0..c84549f6 100644 --- a/vendor/libgit2/src/xdiff/xprepare.c +++ b/vendor/libgit2/deps/xdiff/xprepare.c @@ -78,15 +78,14 @@ static int xdl_init_classifier(xdlclassifier_t *cf, long size, long flags) { return -1; } - if (!(cf->rchash = (xdlclass_t **) xdl_malloc(cf->hsize * sizeof(xdlclass_t *)))) { + if (!XDL_CALLOC_ARRAY(cf->rchash, cf->hsize)) { xdl_cha_free(&cf->ncha); return -1; } - memset(cf->rchash, 0, cf->hsize * sizeof(xdlclass_t *)); cf->alloc = size; - if (!(cf->rcrecs = (xdlclass_t **) xdl_malloc(cf->alloc * sizeof(xdlclass_t *)))) { + if (!XDL_ALLOC_ARRAY(cf->rcrecs, cf->alloc)) { xdl_free(cf->rchash); xdl_cha_free(&cf->ncha); @@ -112,7 +111,6 @@ static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t long hi; char const *line; xdlclass_t *rcrec; - xdlclass_t **rcrecs; line = rec->ptr; hi = (long) XDL_HASHLONG(rec->ha, cf->hbits); @@ -128,14 +126,8 @@ static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t return -1; } rcrec->idx = cf->count++; - if (cf->count > cf->alloc) { - cf->alloc *= 2; - if (!(rcrecs = (xdlclass_t **) xdl_realloc(cf->rcrecs, cf->alloc * sizeof(xdlclass_t *)))) { - + if (XDL_ALLOC_GROW(cf->rcrecs, cf->count, cf->alloc)) return -1; - } - cf->rcrecs = rcrecs; - } cf->rcrecs[rcrec->idx] = rcrec; rcrec->line = line; rcrec->size = rec->size; @@ -164,7 +156,7 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_ unsigned long hav; char const *blk, *cur, *top, *prev; xrecord_t *crec; - xrecord_t **recs, **rrecs; + xrecord_t **recs; xrecord_t **rhash; unsigned long *ha; char *rchg; @@ -178,26 +170,21 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_ if (xdl_cha_init(&xdf->rcha, sizeof(xrecord_t), narec / 4 + 1) < 0) goto abort; - if (!(recs = (xrecord_t **) xdl_malloc(narec * sizeof(xrecord_t *)))) + if (!XDL_ALLOC_ARRAY(recs, narec)) goto abort; hbits = xdl_hashbits((unsigned int) narec); hsize = 1 << hbits; - if (!(rhash = (xrecord_t **) xdl_malloc(hsize * sizeof(xrecord_t *)))) + if (!XDL_CALLOC_ARRAY(rhash, hsize)) goto abort; - memset(rhash, 0, hsize * sizeof(xrecord_t *)); nrec = 0; - if ((cur = blk = xdl_mmfile_first(mf, &bsize)) != NULL) { + if ((cur = blk = xdl_mmfile_first(mf, &bsize))) { for (top = blk + bsize; cur < top; ) { prev = cur; hav = xdl_hash_record(&cur, top, xpp->flags); - if (nrec >= narec) { - narec *= 2; - if (!(rrecs = (xrecord_t **) xdl_realloc(recs, narec * sizeof(xrecord_t *)))) - goto abort; - recs = rrecs; - } + if (XDL_ALLOC_GROW(recs, nrec + 1, narec)) + goto abort; if (!(crec = xdl_cha_alloc(&xdf->rcha))) goto abort; crec->ptr = prev; @@ -209,15 +196,14 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_ } } - if (!(rchg = (char *) xdl_malloc((nrec + 2) * sizeof(char)))) + if (!XDL_CALLOC_ARRAY(rchg, nrec + 2)) goto abort; - memset(rchg, 0, (nrec + 2) * sizeof(char)); if ((XDF_DIFF_ALG(xpp->flags) != XDF_PATIENCE_DIFF) && (XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF)) { - if (!(rindex = xdl_malloc((nrec + 1) * sizeof(*rindex)))) + if (!XDL_ALLOC_ARRAY(rindex, nrec + 1)) goto abort; - if (!(ha = xdl_malloc((nrec + 1) * sizeof(*ha)))) + if (!XDL_ALLOC_ARRAY(ha, nrec + 1)) goto abort; } @@ -383,11 +369,8 @@ static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xd xdlclass_t *rcrec; char *dis, *dis1, *dis2; - if (!(dis = (char *) xdl_malloc(xdf1->nrec + xdf2->nrec + 2))) { - + if (!XDL_CALLOC_ARRAY(dis, xdf1->nrec + xdf2->nrec + 2)) return -1; - } - memset(dis, 0, xdf1->nrec + xdf2->nrec + 2); dis1 = dis; dis2 = dis1 + xdf1->nrec + 1; diff --git a/vendor/libgit2/src/xdiff/xprepare.h b/vendor/libgit2/deps/xdiff/xprepare.h similarity index 100% rename from vendor/libgit2/src/xdiff/xprepare.h rename to vendor/libgit2/deps/xdiff/xprepare.h diff --git a/vendor/libgit2/src/xdiff/xtypes.h b/vendor/libgit2/deps/xdiff/xtypes.h similarity index 100% rename from vendor/libgit2/src/xdiff/xtypes.h rename to vendor/libgit2/deps/xdiff/xtypes.h diff --git a/vendor/libgit2/src/xdiff/xutils.c b/vendor/libgit2/deps/xdiff/xutils.c similarity index 96% rename from vendor/libgit2/src/xdiff/xutils.c rename to vendor/libgit2/deps/xdiff/xutils.c index cfa6e222..9e36f248 100644 --- a/vendor/libgit2/src/xdiff/xutils.c +++ b/vendor/libgit2/deps/xdiff/xutils.c @@ -122,7 +122,7 @@ long xdl_guess_lines(mmfile_t *mf, long sample) { long nl = 0, size, tsize = 0; char const *data, *cur, *top; - if ((cur = data = xdl_mmfile_first(mf, &size)) != NULL) { + if ((cur = data = xdl_mmfile_first(mf, &size))) { for (top = data + size; nl < sample && cur < top; ) { nl++; if (!(cur = memchr(cur, '\n', top - cur))) @@ -432,3 +432,20 @@ int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp, return 0; } + +void* xdl_alloc_grow_helper(void *p, long nr, long *alloc, size_t size) +{ + void *tmp = NULL; + size_t n = ((LONG_MAX - 16) / 2 >= *alloc) ? 2 * *alloc + 16 : LONG_MAX; + if (nr > n) + n = nr; + if (SIZE_MAX / size >= n) + tmp = xdl_realloc(p, n * size); + if (tmp) { + *alloc = n; + } else { + xdl_free(p); + *alloc = 0; + } + return tmp; +} diff --git a/vendor/libgit2/src/xdiff/xutils.h b/vendor/libgit2/deps/xdiff/xutils.h similarity index 93% rename from vendor/libgit2/src/xdiff/xutils.h rename to vendor/libgit2/deps/xdiff/xutils.h index fba7bae0..fd0bba94 100644 --- a/vendor/libgit2/src/xdiff/xutils.h +++ b/vendor/libgit2/deps/xdiff/xutils.h @@ -42,6 +42,7 @@ int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2, int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp, int line1, int count1, int line2, int count2); - +/* Do not call this function, use XDL_ALLOC_GROW instead */ +void* xdl_alloc_grow_helper(void* p, long nr, long* alloc, size_t size); #endif /* #if !defined(XUTILS_H) */ diff --git a/vendor/libgit2/deps/zlib/CMakeLists.txt b/vendor/libgit2/deps/zlib/CMakeLists.txt index 435877d8..078ce69b 100644 --- a/vendor/libgit2/deps/zlib/CMakeLists.txt +++ b/vendor/libgit2/deps/zlib/CMakeLists.txt @@ -1,5 +1,10 @@ disable_warnings(implicit-fallthrough) -add_definitions(-DNO_VIZ -DSTDC -DNO_GZIP) +add_definitions(-DNO_VIZ -DSTDC -DNO_GZIP -DHAVE_SYS_TYPES_H -DHAVE_STDINT_H -DHAVE_STDDEF_H) + +if(MINGW OR MSYS) + add_definitions(-DZ_HAVE_UNISTD_H -D_LFS64_LARGEFILE -D_LARGEFILE64_SOURCE=1) +endif() + file(GLOB SRC_ZLIB "*.c" "*.h") list(SORT SRC_ZLIB) include_directories(".") diff --git a/vendor/libgit2/deps/zlib/COPYING b/vendor/libgit2/deps/zlib/COPYING deleted file mode 100644 index e2e86d76..00000000 --- a/vendor/libgit2/deps/zlib/COPYING +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you - use this software in a product, an acknowledgment in the - product documentation would be appreciated but is not - required. - -2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source - distribution. - -Jean-loup Gailly Mark Adler - -The data format used by the zlib library is described by RFCs -(Request for Comments) 1950 to 1952 in the files rfc1950 (zlib -format), rfc1951 (deflate format) and rfc1952 (gzip format). diff --git a/vendor/libgit2/deps/zlib/LICENSE b/vendor/libgit2/deps/zlib/LICENSE new file mode 100644 index 00000000..ab8ee6f7 --- /dev/null +++ b/vendor/libgit2/deps/zlib/LICENSE @@ -0,0 +1,22 @@ +Copyright notice: + + (C) 1995-2022 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu diff --git a/vendor/libgit2/deps/zlib/adler32.c b/vendor/libgit2/deps/zlib/adler32.c index 444a5a80..04b81d29 100644 --- a/vendor/libgit2/deps/zlib/adler32.c +++ b/vendor/libgit2/deps/zlib/adler32.c @@ -7,8 +7,6 @@ #include "zutil.h" -local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); - #define BASE 65521U /* largest prime smaller than 65536 */ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ @@ -60,11 +58,7 @@ local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); #endif /* ========================================================================= */ -uLong ZEXPORT adler32_z(adler, buf, len) - uLong adler; - const Bytef *buf; - z_size_t len; -{ +uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, z_size_t len) { unsigned long sum2; unsigned n; @@ -131,20 +125,12 @@ uLong ZEXPORT adler32_z(adler, buf, len) } /* ========================================================================= */ -uLong ZEXPORT adler32(adler, buf, len) - uLong adler; - const Bytef *buf; - uInt len; -{ +uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len) { return adler32_z(adler, buf, len); } /* ========================================================================= */ -local uLong adler32_combine_(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off64_t len2; -{ +local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2) { unsigned long sum1; unsigned long sum2; unsigned rem; @@ -169,11 +155,10 @@ local uLong adler32_combine_(adler1, adler2, len2) } /* ========================================================================= */ -uLong ZEXPORT adler32_combine(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off_t len2; -{ +uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, z_off_t len2) { return adler32_combine_(adler1, adler2, len2); } +uLong ZEXPORT adler32_combine64(uLong adler1, uLong adler2, z_off64_t len2) { + return adler32_combine_(adler1, adler2, len2); +} diff --git a/vendor/libgit2/deps/zlib/crc32.c b/vendor/libgit2/deps/zlib/crc32.c index 1ee02845..6c38f5c0 100644 --- a/vendor/libgit2/deps/zlib/crc32.c +++ b/vendor/libgit2/deps/zlib/crc32.c @@ -1,12 +1,10 @@ /* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler + * Copyright (C) 1995-2022 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * - * Thanks to Rodney Brown for his contribution of faster - * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing - * tables for updating the shift register in one step with three exclusive-ors - * instead of four steps with four exclusive-ors. This results in about a - * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + * This interleaved implementation of a CRC makes use of pipelined multiple + * arithmetic-logic units, commonly found in modern CPU cores. It is due to + * Kadatch and Jenkins (2010). See doc/crc-doc.1.0.pdf in this distribution. */ /* @(#) $Id$ */ @@ -14,11 +12,12 @@ /* Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore protection on the static variables used to control the first-use generation - of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should first call get_crc_table() to initialize the tables before allowing more than one thread to use crc32(). - DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h. + MAKECRCH can be #defined to write out crc32.h. A main() routine is also + produced, so that this one source file can be compiled to an executable. */ #ifdef MAKECRCH @@ -28,408 +27,1023 @@ # endif /* !DYNAMIC_CRC_TABLE */ #endif /* MAKECRCH */ -#include "zutil.h" /* for STDC and FAR definitions */ +#include "zutil.h" /* for Z_U4, Z_U8, z_crc_t, and FAR definitions */ -/* Definitions for doing the crc four data bytes at a time. */ -#if !defined(NOBYFOUR) && defined(Z_U4) -# define BYFOUR + /* + A CRC of a message is computed on N braids of words in the message, where + each word consists of W bytes (4 or 8). If N is 3, for example, then three + running sparse CRCs are calculated respectively on each braid, at these + indices in the array of words: 0, 3, 6, ..., 1, 4, 7, ..., and 2, 5, 8, ... + This is done starting at a word boundary, and continues until as many blocks + of N * W bytes as are available have been processed. The results are combined + into a single CRC at the end. For this code, N must be in the range 1..6 and + W must be 4 or 8. The upper limit on N can be increased if desired by adding + more #if blocks, extending the patterns apparent in the code. In addition, + crc32.h would need to be regenerated, if the maximum N value is increased. + + N and W are chosen empirically by benchmarking the execution time on a given + processor. The choices for N and W below were based on testing on Intel Kaby + Lake i7, AMD Ryzen 7, ARM Cortex-A57, Sparc64-VII, PowerPC POWER9, and MIPS64 + Octeon II processors. The Intel, AMD, and ARM processors were all fastest + with N=5, W=8. The Sparc, PowerPC, and MIPS64 were all fastest at N=5, W=4. + They were all tested with either gcc or clang, all using the -O3 optimization + level. Your mileage may vary. + */ + +/* Define N */ +#ifdef Z_TESTN +# define N Z_TESTN +#else +# define N 5 +#endif +#if N < 1 || N > 6 +# error N must be in 1..6 #endif -#ifdef BYFOUR - local unsigned long crc32_little OF((unsigned long, - const unsigned char FAR *, z_size_t)); - local unsigned long crc32_big OF((unsigned long, - const unsigned char FAR *, z_size_t)); -# define TBLS 8 + +/* + z_crc_t must be at least 32 bits. z_word_t must be at least as long as + z_crc_t. It is assumed here that z_word_t is either 32 bits or 64 bits, and + that bytes are eight bits. + */ + +/* + Define W and the associated z_word_t type. If W is not defined, then a + braided calculation is not used, and the associated tables and code are not + compiled. + */ +#ifdef Z_TESTW +# if Z_TESTW-1 != -1 +# define W Z_TESTW +# endif #else -# define TBLS 1 -#endif /* BYFOUR */ +# ifdef MAKECRCH +# define W 8 /* required for MAKECRCH */ +# else +# if defined(__x86_64__) || defined(__aarch64__) +# define W 8 +# else +# define W 4 +# endif +# endif +#endif +#ifdef W +# if W == 8 && defined(Z_U8) + typedef Z_U8 z_word_t; +# elif defined(Z_U4) +# undef W +# define W 4 + typedef Z_U4 z_word_t; +# else +# undef W +# endif +#endif -/* Local functions for crc concatenation */ -local unsigned long gf2_matrix_times OF((unsigned long *mat, - unsigned long vec)); -local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); -local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2)); +/* If available, use the ARM processor CRC32 instruction. */ +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8 +# define ARMCRC32 +#endif +#if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) +/* + Swap the bytes in a z_word_t to convert between little and big endian. Any + self-respecting compiler will optimize this to a single machine byte-swap + instruction, if one is available. This assumes that word_t is either 32 bits + or 64 bits. + */ +local z_word_t byte_swap(z_word_t word) { +# if W == 8 + return + (word & 0xff00000000000000) >> 56 | + (word & 0xff000000000000) >> 40 | + (word & 0xff0000000000) >> 24 | + (word & 0xff00000000) >> 8 | + (word & 0xff000000) << 8 | + (word & 0xff0000) << 24 | + (word & 0xff00) << 40 | + (word & 0xff) << 56; +# else /* W == 4 */ + return + (word & 0xff000000) >> 24 | + (word & 0xff0000) >> 8 | + (word & 0xff00) << 8 | + (word & 0xff) << 24; +# endif +} +#endif #ifdef DYNAMIC_CRC_TABLE +/* ========================================================================= + * Table of powers of x for combining CRC-32s, filled in by make_crc_table() + * below. + */ + local z_crc_t FAR x2n_table[32]; +#else +/* ========================================================================= + * Tables for byte-wise and braided CRC-32 calculations, and a table of powers + * of x for combining CRC-32s, all made by make_crc_table(). + */ +# include "crc32.h" +#endif + +/* CRC polynomial. */ +#define POLY 0xedb88320 /* p(x) reflected, with x^32 implied */ -local volatile int crc_table_empty = 1; -local z_crc_t FAR crc_table[TBLS][256]; -local void make_crc_table OF((void)); +/* + Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial, + reflected. For speed, this requires that a not be zero. + */ +local z_crc_t multmodp(z_crc_t a, z_crc_t b) { + z_crc_t m, p; + + m = (z_crc_t)1 << 31; + p = 0; + for (;;) { + if (a & m) { + p ^= b; + if ((a & (m - 1)) == 0) + break; + } + m >>= 1; + b = b & 1 ? (b >> 1) ^ POLY : b >> 1; + } + return p; +} + +/* + Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been + initialized. + */ +local z_crc_t x2nmodp(z_off64_t n, unsigned k) { + z_crc_t p; + + p = (z_crc_t)1 << 31; /* x^0 == 1 */ + while (n) { + if (n & 1) + p = multmodp(x2n_table[k & 31], p); + n >>= 1; + k++; + } + return p; +} + +#ifdef DYNAMIC_CRC_TABLE +/* ========================================================================= + * Build the tables for byte-wise and braided CRC-32 calculations, and a table + * of powers of x for combining CRC-32s. + */ +local z_crc_t FAR crc_table[256]; +#ifdef W + local z_word_t FAR crc_big_table[256]; + local z_crc_t FAR crc_braid_table[W][256]; + local z_word_t FAR crc_braid_big_table[W][256]; + local void braid(z_crc_t [][256], z_word_t [][256], int, int); +#endif #ifdef MAKECRCH - local void write_table OF((FILE *, const z_crc_t FAR *)); + local void write_table(FILE *, const z_crc_t FAR *, int); + local void write_table32hi(FILE *, const z_word_t FAR *, int); + local void write_table64(FILE *, const z_word_t FAR *, int); #endif /* MAKECRCH */ + +/* + Define a once() function depending on the availability of atomics. If this is + compiled with DYNAMIC_CRC_TABLE defined, and if CRCs will be computed in + multiple threads, and if atomics are not available, then get_crc_table() must + be called to initialize the tables and must return before any threads are + allowed to compute or combine CRCs. + */ + +/* Definition of once functionality. */ +typedef struct once_s once_t; + +/* Check for the availability of atomics. */ +#if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \ + !defined(__STDC_NO_ATOMICS__) + +#include + +/* Structure for once(), which must be initialized with ONCE_INIT. */ +struct once_s { + atomic_flag begun; + atomic_int done; +}; +#define ONCE_INIT {ATOMIC_FLAG_INIT, 0} + +/* + Run the provided init() function exactly once, even if multiple threads + invoke once() at the same time. The state must be a once_t initialized with + ONCE_INIT. + */ +local void once(once_t *state, void (*init)(void)) { + if (!atomic_load(&state->done)) { + if (atomic_flag_test_and_set(&state->begun)) + while (!atomic_load(&state->done)) + ; + else { + init(); + atomic_store(&state->done, 1); + } + } +} + +#else /* no atomics */ + +/* Structure for once(), which must be initialized with ONCE_INIT. */ +struct once_s { + volatile int begun; + volatile int done; +}; +#define ONCE_INIT {0, 0} + +/* Test and set. Alas, not atomic, but tries to minimize the period of + vulnerability. */ +local int test_and_set(int volatile *flag) { + int was; + + was = *flag; + *flag = 1; + return was; +} + +/* Run the provided init() function once. This is not thread-safe. */ +local void once(once_t *state, void (*init)(void)) { + if (!state->done) { + if (test_and_set(&state->begun)) + while (!state->done) + ; + else { + init(); + state->done = 1; + } + } +} + +#endif + +/* State for once(). */ +local once_t made = ONCE_INIT; + /* Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. Polynomials over GF(2) are represented in binary, one bit per coefficient, - with the lowest powers in the most significant bit. Then adding polynomials + with the lowest powers in the most significant bit. Then adding polynomials is just exclusive-or, and multiplying a polynomial by x is a right shift by - one. If we call the above polynomial p, and represent a byte as the + one. If we call the above polynomial p, and represent a byte as the polynomial q, also with the lowest power in the most significant bit (so the - byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + byte 0xb1 is the polynomial x^7+x^3+x^2+1), then the CRC is (q*x^32) mod p, where a mod b means the remainder after dividing a by b. This calculation is done using the shift-register method of multiplying and - taking the remainder. The register is initialized to zero, and for each + taking the remainder. The register is initialized to zero, and for each incoming bit, x^32 is added mod p to the register if the bit is a one (where - x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by - x (which is shifting right by one and adding x^32 mod p if the bit shifted - out is a one). We start with the highest power (least significant bit) of - q and repeat for all eight bits of q. - - The first table is simply the CRC of all possible eight bit values. This is - all the information needed to generate CRCs on data a byte at a time for all - combinations of CRC register values and incoming bytes. The remaining tables - allow for word-at-a-time CRC calculation for both big-endian and little- - endian machines, where a word is four bytes. -*/ -local void make_crc_table() -{ - z_crc_t c; - int n, k; - z_crc_t poly; /* polynomial exclusive-or pattern */ - /* terms of polynomial defining this crc (except x^32): */ - static volatile int first = 1; /* flag to limit concurrent making */ - static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - /* See if another task is already doing this (not thread-safe, but better - than nothing -- significantly reduces duration of vulnerability in - case the advice about DYNAMIC_CRC_TABLE is ignored) */ - if (first) { - first = 0; - - /* make exclusive-or pattern from polynomial (0xedb88320UL) */ - poly = 0; - for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++) - poly |= (z_crc_t)1 << (31 - p[n]); - - /* generate a crc for every 8-bit value */ - for (n = 0; n < 256; n++) { - c = (z_crc_t)n; - for (k = 0; k < 8; k++) - c = c & 1 ? poly ^ (c >> 1) : c >> 1; - crc_table[0][n] = c; - } + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by x + (which is shifting right by one and adding x^32 mod p if the bit shifted out + is a one). We start with the highest power (least significant bit) of q and + repeat for all eight bits of q. -#ifdef BYFOUR - /* generate crc for each value followed by one, two, and three zeros, - and then the byte reversal of those as well as the first table */ - for (n = 0; n < 256; n++) { - c = crc_table[0][n]; - crc_table[4][n] = ZSWAP32(c); - for (k = 1; k < 4; k++) { - c = crc_table[0][c & 0xff] ^ (c >> 8); - crc_table[k][n] = c; - crc_table[k + 4][n] = ZSWAP32(c); - } - } -#endif /* BYFOUR */ + The table is simply the CRC of all possible eight bit values. This is all the + information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. + */ - crc_table_empty = 0; - } - else { /* not first */ - /* wait for the other guy to finish (not efficient, but rare) */ - while (crc_table_empty) - ; +local void make_crc_table(void) { + unsigned i, j, n; + z_crc_t p; + + /* initialize the CRC of bytes tables */ + for (i = 0; i < 256; i++) { + p = i; + for (j = 0; j < 8; j++) + p = p & 1 ? (p >> 1) ^ POLY : p >> 1; + crc_table[i] = p; +#ifdef W + crc_big_table[i] = byte_swap(p); +#endif } + /* initialize the x^2^n mod p(x) table */ + p = (z_crc_t)1 << 30; /* x^1 */ + x2n_table[0] = p; + for (n = 1; n < 32; n++) + x2n_table[n] = p = multmodp(p, p); + +#ifdef W + /* initialize the braiding tables -- needs x2n_table[] */ + braid(crc_braid_table, crc_braid_big_table, N, W); +#endif + #ifdef MAKECRCH - /* write out CRC tables to crc32.h */ { + /* + The crc32.h header file contains tables for both 32-bit and 64-bit + z_word_t's, and so requires a 64-bit type be available. In that case, + z_word_t must be defined to be 64-bits. This code then also generates + and writes out the tables for the case that z_word_t is 32 bits. + */ +#if !defined(W) || W != 8 +# error Need a 64-bit integer type in order to generate crc32.h. +#endif FILE *out; + int k, n; + z_crc_t ltl[8][256]; + z_word_t big[8][256]; out = fopen("crc32.h", "w"); if (out == NULL) return; - fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); - fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); - fprintf(out, "local const z_crc_t FAR "); - fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); - write_table(out, crc_table[0]); -# ifdef BYFOUR - fprintf(out, "#ifdef BYFOUR\n"); - for (k = 1; k < 8; k++) { - fprintf(out, " },\n {\n"); - write_table(out, crc_table[k]); + + /* write out little-endian CRC table to crc32.h */ + fprintf(out, + "/* crc32.h -- tables for rapid CRC calculation\n" + " * Generated automatically by crc32.c\n */\n" + "\n" + "local const z_crc_t FAR crc_table[] = {\n" + " "); + write_table(out, crc_table, 256); + fprintf(out, + "};\n"); + + /* write out big-endian CRC table for 64-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#ifdef W\n" + "\n" + "#if W == 8\n" + "\n" + "local const z_word_t FAR crc_big_table[] = {\n" + " "); + write_table64(out, crc_big_table, 256); + fprintf(out, + "};\n"); + + /* write out big-endian CRC table for 32-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#else /* W == 4 */\n" + "\n" + "local const z_word_t FAR crc_big_table[] = {\n" + " "); + write_table32hi(out, crc_big_table, 256); + fprintf(out, + "};\n" + "\n" + "#endif\n"); + + /* write out braid tables for each value of N */ + for (n = 1; n <= 6; n++) { + fprintf(out, + "\n" + "#if N == %d\n", n); + + /* compute braid tables for this N and 64-bit word_t */ + braid(ltl, big, n, 8); + + /* write out braid tables for 64-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#if W == 8\n" + "\n" + "local const z_crc_t FAR crc_braid_table[][256] = {\n"); + for (k = 0; k < 8; k++) { + fprintf(out, " {"); + write_table(out, ltl[k], 256); + fprintf(out, "}%s", k < 7 ? ",\n" : ""); + } + fprintf(out, + "};\n" + "\n" + "local const z_word_t FAR crc_braid_big_table[][256] = {\n"); + for (k = 0; k < 8; k++) { + fprintf(out, " {"); + write_table64(out, big[k], 256); + fprintf(out, "}%s", k < 7 ? ",\n" : ""); + } + fprintf(out, + "};\n"); + + /* compute braid tables for this N and 32-bit word_t */ + braid(ltl, big, n, 4); + + /* write out braid tables for 32-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#else /* W == 4 */\n" + "\n" + "local const z_crc_t FAR crc_braid_table[][256] = {\n"); + for (k = 0; k < 4; k++) { + fprintf(out, " {"); + write_table(out, ltl[k], 256); + fprintf(out, "}%s", k < 3 ? ",\n" : ""); + } + fprintf(out, + "};\n" + "\n" + "local const z_word_t FAR crc_braid_big_table[][256] = {\n"); + for (k = 0; k < 4; k++) { + fprintf(out, " {"); + write_table32hi(out, big[k], 256); + fprintf(out, "}%s", k < 3 ? ",\n" : ""); + } + fprintf(out, + "};\n" + "\n" + "#endif\n" + "\n" + "#endif\n"); } - fprintf(out, "#endif\n"); -# endif /* BYFOUR */ - fprintf(out, " }\n};\n"); + fprintf(out, + "\n" + "#endif\n"); + + /* write out zeros operator table to crc32.h */ + fprintf(out, + "\n" + "local const z_crc_t FAR x2n_table[] = {\n" + " "); + write_table(out, x2n_table, 32); + fprintf(out, + "};\n"); fclose(out); } #endif /* MAKECRCH */ } #ifdef MAKECRCH -local void write_table(out, table) - FILE *out; - const z_crc_t FAR *table; -{ + +/* + Write the 32-bit values in table[0..k-1] to out, five per line in + hexadecimal separated by commas. + */ +local void write_table(FILE *out, const z_crc_t FAR *table, int k) { int n; - for (n = 0; n < 256; n++) - fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", + for (n = 0; n < k; n++) + fprintf(out, "%s0x%08lx%s", n == 0 || n % 5 ? "" : " ", (unsigned long)(table[n]), - n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); + n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", ")); } + +/* + Write the high 32-bits of each value in table[0..k-1] to out, five per line + in hexadecimal separated by commas. + */ +local void write_table32hi(FILE *out, const z_word_t FAR *table, int k) { + int n; + + for (n = 0; n < k; n++) + fprintf(out, "%s0x%08lx%s", n == 0 || n % 5 ? "" : " ", + (unsigned long)(table[n] >> 32), + n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", ")); +} + +/* + Write the 64-bit values in table[0..k-1] to out, three per line in + hexadecimal separated by commas. This assumes that if there is a 64-bit + type, then there is also a long long integer type, and it is at least 64 + bits. If not, then the type cast and format string can be adjusted + accordingly. + */ +local void write_table64(FILE *out, const z_word_t FAR *table, int k) { + int n; + + for (n = 0; n < k; n++) + fprintf(out, "%s0x%016llx%s", n == 0 || n % 3 ? "" : " ", + (unsigned long long)(table[n]), + n == k - 1 ? "" : (n % 3 == 2 ? ",\n" : ", ")); +} + +/* Actually do the deed. */ +int main(void) { + make_crc_table(); + return 0; +} + #endif /* MAKECRCH */ -#else /* !DYNAMIC_CRC_TABLE */ -/* ======================================================================== - * Tables of CRC-32s of all single-byte values, made by make_crc_table(). +#ifdef W +/* + Generate the little and big-endian braid tables for the given n and z_word_t + size w. Each array must have room for w blocks of 256 elements. */ -#include "crc32.h" +local void braid(z_crc_t ltl[][256], z_word_t big[][256], int n, int w) { + int k; + z_crc_t i, p, q; + for (k = 0; k < w; k++) { + p = x2nmodp((n * w + 3 - k) << 3, 0); + ltl[k][0] = 0; + big[w - 1 - k][0] = 0; + for (i = 1; i < 256; i++) { + ltl[k][i] = q = multmodp(i << 24, p); + big[w - 1 - k][i] = byte_swap(q); + } + } +} +#endif + #endif /* DYNAMIC_CRC_TABLE */ /* ========================================================================= - * This function can be used by asm versions of crc32() + * This function can be used by asm versions of crc32(), and to force the + * generation of the CRC tables in a threaded application. */ -const z_crc_t FAR * ZEXPORT get_crc_table() -{ +const z_crc_t FAR * ZEXPORT get_crc_table(void) { #ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); + once(&made, make_crc_table); #endif /* DYNAMIC_CRC_TABLE */ return (const z_crc_t FAR *)crc_table; } -/* ========================================================================= */ -#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) -#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 +/* ========================================================================= + * Use ARM machine instructions if available. This will compute the CRC about + * ten times faster than the braided calculation. This code does not check for + * the presence of the CRC instruction at run time. __ARM_FEATURE_CRC32 will + * only be defined if the compilation specifies an ARM processor architecture + * that has the instructions. For example, compiling with -march=armv8.1-a or + * -march=armv8-a+crc, or -march=native if the compile machine has the crc32 + * instructions. + */ +#ifdef ARMCRC32 -/* ========================================================================= */ -unsigned long ZEXPORT crc32_z(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - z_size_t len; -{ - if (buf == Z_NULL) return 0UL; +/* + Constants empirically determined to maximize speed. These values are from + measurements on a Cortex-A57. Your mileage may vary. + */ +#define Z_BATCH 3990 /* number of words in a batch */ +#define Z_BATCH_ZEROS 0xa10d3d0c /* computed from Z_BATCH = 3990 */ +#define Z_BATCH_MIN 800 /* fewest words in a final batch */ + +unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf, + z_size_t len) { + z_crc_t val; + z_word_t crc1, crc2; + const z_word_t *word; + z_word_t val0, val1, val2; + z_size_t last, last2, i; + z_size_t num; + + /* Return initial CRC, if requested. */ + if (buf == Z_NULL) return 0; #ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); + once(&made, make_crc_table); #endif /* DYNAMIC_CRC_TABLE */ -#ifdef BYFOUR - if (sizeof(void *) == sizeof(ptrdiff_t)) { - z_crc_t endian; + /* Pre-condition the CRC */ + crc = (~crc) & 0xffffffff; - endian = 1; - if (*((unsigned char *)(&endian))) - return crc32_little(crc, buf, len); - else - return crc32_big(crc, buf, len); + /* Compute the CRC up to a word boundary. */ + while (len && ((z_size_t)buf & 7) != 0) { + len--; + val = *buf++; + __asm__ volatile("crc32b %w0, %w0, %w1" : "+r"(crc) : "r"(val)); } -#endif /* BYFOUR */ - crc = crc ^ 0xffffffffUL; - while (len >= 8) { - DO8; - len -= 8; + + /* Prepare to compute the CRC on full 64-bit words word[0..num-1]. */ + word = (z_word_t const *)buf; + num = len >> 3; + len &= 7; + + /* Do three interleaved CRCs to realize the throughput of one crc32x + instruction per cycle. Each CRC is calculated on Z_BATCH words. The + three CRCs are combined into a single CRC after each set of batches. */ + while (num >= 3 * Z_BATCH) { + crc1 = 0; + crc2 = 0; + for (i = 0; i < Z_BATCH; i++) { + val0 = word[i]; + val1 = word[i + Z_BATCH]; + val2 = word[i + 2 * Z_BATCH]; + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc1) : "r"(val1)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc2) : "r"(val2)); + } + word += 3 * Z_BATCH; + num -= 3 * Z_BATCH; + crc = multmodp(Z_BATCH_ZEROS, crc) ^ crc1; + crc = multmodp(Z_BATCH_ZEROS, crc) ^ crc2; } - if (len) do { - DO1; - } while (--len); - return crc ^ 0xffffffffUL; -} -/* ========================================================================= */ -unsigned long ZEXPORT crc32(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - uInt len; -{ - return crc32_z(crc, buf, len); + /* Do one last smaller batch with the remaining words, if there are enough + to pay for the combination of CRCs. */ + last = num / 3; + if (last >= Z_BATCH_MIN) { + last2 = last << 1; + crc1 = 0; + crc2 = 0; + for (i = 0; i < last; i++) { + val0 = word[i]; + val1 = word[i + last]; + val2 = word[i + last2]; + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc1) : "r"(val1)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc2) : "r"(val2)); + } + word += 3 * last; + num -= 3 * last; + val = x2nmodp(last, 6); + crc = multmodp(val, crc) ^ crc1; + crc = multmodp(val, crc) ^ crc2; + } + + /* Compute the CRC on any remaining words. */ + for (i = 0; i < num; i++) { + val0 = word[i]; + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); + } + word += num; + + /* Complete the CRC on any remaining bytes. */ + buf = (const unsigned char FAR *)word; + while (len) { + len--; + val = *buf++; + __asm__ volatile("crc32b %w0, %w0, %w1" : "+r"(crc) : "r"(val)); + } + + /* Return the CRC, post-conditioned. */ + return crc ^ 0xffffffff; } -#ifdef BYFOUR +#else + +#ifdef W /* - This BYFOUR code accesses the passed unsigned char * buffer with a 32-bit - integer pointer type. This violates the strict aliasing rule, where a - compiler can assume, for optimization purposes, that two pointers to - fundamentally different types won't ever point to the same memory. This can - manifest as a problem only if one of the pointers is written to. This code - only reads from those pointers. So long as this code remains isolated in - this compilation unit, there won't be a problem. For this reason, this code - should not be copied and pasted into a compilation unit in which other code - writes to the buffer that is passed to these routines. + Return the CRC of the W bytes in the word_t data, taking the + least-significant byte of the word as the first byte of data, without any pre + or post conditioning. This is used to combine the CRCs of each braid. */ +local z_crc_t crc_word(z_word_t data) { + int k; + for (k = 0; k < W; k++) + data = (data >> 8) ^ crc_table[data & 0xff]; + return (z_crc_t)data; +} -/* ========================================================================= */ -#define DOLIT4 c ^= *buf4++; \ - c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ - crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] -#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 +local z_word_t crc_word_big(z_word_t data) { + int k; + for (k = 0; k < W; k++) + data = (data << 8) ^ + crc_big_table[(data >> ((W - 1) << 3)) & 0xff]; + return data; +} + +#endif /* ========================================================================= */ -local unsigned long crc32_little(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - z_size_t len; -{ - register z_crc_t c; - register const z_crc_t FAR *buf4; - - c = (z_crc_t)crc; - c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { - c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); - len--; - } +unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf, + z_size_t len) { + /* Return initial CRC, if requested. */ + if (buf == Z_NULL) return 0; - buf4 = (const z_crc_t FAR *)(const void FAR *)buf; - while (len >= 32) { - DOLIT32; - len -= 32; - } - while (len >= 4) { - DOLIT4; - len -= 4; - } - buf = (const unsigned char FAR *)buf4; +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ - if (len) do { - c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); - } while (--len); - c = ~c; - return (unsigned long)c; -} + /* Pre-condition the CRC */ + crc = (~crc) & 0xffffffff; -/* ========================================================================= */ -#define DOBIG4 c ^= *buf4++; \ - c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ - crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] -#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 +#ifdef W -/* ========================================================================= */ -local unsigned long crc32_big(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - z_size_t len; -{ - register z_crc_t c; - register const z_crc_t FAR *buf4; - - c = ZSWAP32((z_crc_t)crc); - c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { - c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); - len--; + /* If provided enough bytes, do a braided CRC calculation. */ + if (len >= N * W + W - 1) { + z_size_t blks; + z_word_t const *words; + unsigned endian; + int k; + + /* Compute the CRC up to a z_word_t boundary. */ + while (len && ((z_size_t)buf & (W - 1)) != 0) { + len--; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + } + + /* Compute the CRC on as many N z_word_t blocks as are available. */ + blks = len / (N * W); + len -= blks * N * W; + words = (z_word_t const *)buf; + + /* Do endian check at execution time instead of compile time, since ARM + processors can change the endianness at execution time. If the + compiler knows what the endianness will be, it can optimize out the + check and the unused branch. */ + endian = 1; + if (*(unsigned char *)&endian) { + /* Little endian. */ + + z_crc_t crc0; + z_word_t word0; +#if N > 1 + z_crc_t crc1; + z_word_t word1; +#if N > 2 + z_crc_t crc2; + z_word_t word2; +#if N > 3 + z_crc_t crc3; + z_word_t word3; +#if N > 4 + z_crc_t crc4; + z_word_t word4; +#if N > 5 + z_crc_t crc5; + z_word_t word5; +#endif +#endif +#endif +#endif +#endif + + /* Initialize the CRC for each braid. */ + crc0 = crc; +#if N > 1 + crc1 = 0; +#if N > 2 + crc2 = 0; +#if N > 3 + crc3 = 0; +#if N > 4 + crc4 = 0; +#if N > 5 + crc5 = 0; +#endif +#endif +#endif +#endif +#endif + + /* + Process the first blks-1 blocks, computing the CRCs on each braid + independently. + */ + while (--blks) { + /* Load the word for each braid into registers. */ + word0 = crc0 ^ words[0]; +#if N > 1 + word1 = crc1 ^ words[1]; +#if N > 2 + word2 = crc2 ^ words[2]; +#if N > 3 + word3 = crc3 ^ words[3]; +#if N > 4 + word4 = crc4 ^ words[4]; +#if N > 5 + word5 = crc5 ^ words[5]; +#endif +#endif +#endif +#endif +#endif + words += N; + + /* Compute and update the CRC for each word. The loop should + get unrolled. */ + crc0 = crc_braid_table[0][word0 & 0xff]; +#if N > 1 + crc1 = crc_braid_table[0][word1 & 0xff]; +#if N > 2 + crc2 = crc_braid_table[0][word2 & 0xff]; +#if N > 3 + crc3 = crc_braid_table[0][word3 & 0xff]; +#if N > 4 + crc4 = crc_braid_table[0][word4 & 0xff]; +#if N > 5 + crc5 = crc_braid_table[0][word5 & 0xff]; +#endif +#endif +#endif +#endif +#endif + for (k = 1; k < W; k++) { + crc0 ^= crc_braid_table[k][(word0 >> (k << 3)) & 0xff]; +#if N > 1 + crc1 ^= crc_braid_table[k][(word1 >> (k << 3)) & 0xff]; +#if N > 2 + crc2 ^= crc_braid_table[k][(word2 >> (k << 3)) & 0xff]; +#if N > 3 + crc3 ^= crc_braid_table[k][(word3 >> (k << 3)) & 0xff]; +#if N > 4 + crc4 ^= crc_braid_table[k][(word4 >> (k << 3)) & 0xff]; +#if N > 5 + crc5 ^= crc_braid_table[k][(word5 >> (k << 3)) & 0xff]; +#endif +#endif +#endif +#endif +#endif + } + } + + /* + Process the last block, combining the CRCs of the N braids at the + same time. + */ + crc = crc_word(crc0 ^ words[0]); +#if N > 1 + crc = crc_word(crc1 ^ words[1] ^ crc); +#if N > 2 + crc = crc_word(crc2 ^ words[2] ^ crc); +#if N > 3 + crc = crc_word(crc3 ^ words[3] ^ crc); +#if N > 4 + crc = crc_word(crc4 ^ words[4] ^ crc); +#if N > 5 + crc = crc_word(crc5 ^ words[5] ^ crc); +#endif +#endif +#endif +#endif +#endif + words += N; + } + else { + /* Big endian. */ + + z_word_t crc0, word0, comb; +#if N > 1 + z_word_t crc1, word1; +#if N > 2 + z_word_t crc2, word2; +#if N > 3 + z_word_t crc3, word3; +#if N > 4 + z_word_t crc4, word4; +#if N > 5 + z_word_t crc5, word5; +#endif +#endif +#endif +#endif +#endif + + /* Initialize the CRC for each braid. */ + crc0 = byte_swap(crc); +#if N > 1 + crc1 = 0; +#if N > 2 + crc2 = 0; +#if N > 3 + crc3 = 0; +#if N > 4 + crc4 = 0; +#if N > 5 + crc5 = 0; +#endif +#endif +#endif +#endif +#endif + + /* + Process the first blks-1 blocks, computing the CRCs on each braid + independently. + */ + while (--blks) { + /* Load the word for each braid into registers. */ + word0 = crc0 ^ words[0]; +#if N > 1 + word1 = crc1 ^ words[1]; +#if N > 2 + word2 = crc2 ^ words[2]; +#if N > 3 + word3 = crc3 ^ words[3]; +#if N > 4 + word4 = crc4 ^ words[4]; +#if N > 5 + word5 = crc5 ^ words[5]; +#endif +#endif +#endif +#endif +#endif + words += N; + + /* Compute and update the CRC for each word. The loop should + get unrolled. */ + crc0 = crc_braid_big_table[0][word0 & 0xff]; +#if N > 1 + crc1 = crc_braid_big_table[0][word1 & 0xff]; +#if N > 2 + crc2 = crc_braid_big_table[0][word2 & 0xff]; +#if N > 3 + crc3 = crc_braid_big_table[0][word3 & 0xff]; +#if N > 4 + crc4 = crc_braid_big_table[0][word4 & 0xff]; +#if N > 5 + crc5 = crc_braid_big_table[0][word5 & 0xff]; +#endif +#endif +#endif +#endif +#endif + for (k = 1; k < W; k++) { + crc0 ^= crc_braid_big_table[k][(word0 >> (k << 3)) & 0xff]; +#if N > 1 + crc1 ^= crc_braid_big_table[k][(word1 >> (k << 3)) & 0xff]; +#if N > 2 + crc2 ^= crc_braid_big_table[k][(word2 >> (k << 3)) & 0xff]; +#if N > 3 + crc3 ^= crc_braid_big_table[k][(word3 >> (k << 3)) & 0xff]; +#if N > 4 + crc4 ^= crc_braid_big_table[k][(word4 >> (k << 3)) & 0xff]; +#if N > 5 + crc5 ^= crc_braid_big_table[k][(word5 >> (k << 3)) & 0xff]; +#endif +#endif +#endif +#endif +#endif + } + } + + /* + Process the last block, combining the CRCs of the N braids at the + same time. + */ + comb = crc_word_big(crc0 ^ words[0]); +#if N > 1 + comb = crc_word_big(crc1 ^ words[1] ^ comb); +#if N > 2 + comb = crc_word_big(crc2 ^ words[2] ^ comb); +#if N > 3 + comb = crc_word_big(crc3 ^ words[3] ^ comb); +#if N > 4 + comb = crc_word_big(crc4 ^ words[4] ^ comb); +#if N > 5 + comb = crc_word_big(crc5 ^ words[5] ^ comb); +#endif +#endif +#endif +#endif +#endif + words += N; + crc = byte_swap(comb); + } + + /* + Update the pointer to the remaining bytes to process. + */ + buf = (unsigned char const *)words; } - buf4 = (const z_crc_t FAR *)(const void FAR *)buf; - while (len >= 32) { - DOBIG32; - len -= 32; +#endif /* W */ + + /* Complete the computation of the CRC on any remaining bytes. */ + while (len >= 8) { + len -= 8; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; } - while (len >= 4) { - DOBIG4; - len -= 4; + while (len) { + len--; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; } - buf = (const unsigned char FAR *)buf4; - if (len) do { - c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); - } while (--len); - c = ~c; - return (unsigned long)(ZSWAP32(c)); + /* Return the CRC, post-conditioned. */ + return crc ^ 0xffffffff; } -#endif /* BYFOUR */ - -#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ +#endif /* ========================================================================= */ -local unsigned long gf2_matrix_times(mat, vec) - unsigned long *mat; - unsigned long vec; -{ - unsigned long sum; - - sum = 0; - while (vec) { - if (vec & 1) - sum ^= *mat; - vec >>= 1; - mat++; - } - return sum; +unsigned long ZEXPORT crc32(unsigned long crc, const unsigned char FAR *buf, + uInt len) { + return crc32_z(crc, buf, len); } /* ========================================================================= */ -local void gf2_matrix_square(square, mat) - unsigned long *square; - unsigned long *mat; -{ - int n; - - for (n = 0; n < GF2_DIM; n++) - square[n] = gf2_matrix_times(mat, mat[n]); +uLong ZEXPORT crc32_combine64(uLong crc1, uLong crc2, z_off64_t len2) { +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + return multmodp(x2nmodp(len2, 3), crc1) ^ (crc2 & 0xffffffff); } /* ========================================================================= */ -local uLong crc32_combine_(crc1, crc2, len2) - uLong crc1; - uLong crc2; - z_off64_t len2; -{ - int n; - unsigned long row; - unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ - unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ - - /* degenerate case (also disallow negative lengths) */ - if (len2 <= 0) - return crc1; - - /* put operator for one zero bit in odd */ - odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ - row = 1; - for (n = 1; n < GF2_DIM; n++) { - odd[n] = row; - row <<= 1; - } +uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2) { + return crc32_combine64(crc1, crc2, (z_off64_t)len2); +} - /* put operator for two zero bits in even */ - gf2_matrix_square(even, odd); - - /* put operator for four zero bits in odd */ - gf2_matrix_square(odd, even); - - /* apply len2 zeros to crc1 (first square will put the operator for one - zero byte, eight zero bits, in even) */ - do { - /* apply zeros operator for this bit of len2 */ - gf2_matrix_square(even, odd); - if (len2 & 1) - crc1 = gf2_matrix_times(even, crc1); - len2 >>= 1; - - /* if no more bits set, then done */ - if (len2 == 0) - break; - - /* another iteration of the loop with odd and even swapped */ - gf2_matrix_square(odd, even); - if (len2 & 1) - crc1 = gf2_matrix_times(odd, crc1); - len2 >>= 1; - - /* if no more bits set, then done */ - } while (len2 != 0); - - /* return combined crc */ - crc1 ^= crc2; - return crc1; +/* ========================================================================= */ +uLong ZEXPORT crc32_combine_gen64(z_off64_t len2) { +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + return x2nmodp(len2, 3); } /* ========================================================================= */ -uLong ZEXPORT crc32_combine(crc1, crc2, len2) - uLong crc1; - uLong crc2; - z_off_t len2; -{ - return crc32_combine_(crc1, crc2, len2); +uLong ZEXPORT crc32_combine_gen(z_off_t len2) { + return crc32_combine_gen64((z_off64_t)len2); } +/* ========================================================================= */ +uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op) { + return multmodp(op, crc1) ^ (crc2 & 0xffffffff); +} diff --git a/vendor/libgit2/deps/zlib/crc32.h b/vendor/libgit2/deps/zlib/crc32.h index 9e0c7781..137df68d 100644 --- a/vendor/libgit2/deps/zlib/crc32.h +++ b/vendor/libgit2/deps/zlib/crc32.h @@ -2,440 +2,9445 @@ * Generated automatically by crc32.c */ -local const z_crc_t FAR crc_table[TBLS][256] = -{ - { - 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, - 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, - 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, - 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, - 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, - 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, - 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, - 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, - 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, - 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, - 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, - 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, - 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, - 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, - 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, - 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, - 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, - 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, - 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, - 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, - 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, - 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, - 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, - 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, - 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, - 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, - 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, - 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, - 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, - 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, - 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, - 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, - 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, - 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, - 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, - 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, - 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, - 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, - 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, - 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, - 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, - 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, - 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, - 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, - 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, - 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, - 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, - 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, - 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, - 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, - 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, - 0x2d02ef8dUL -#ifdef BYFOUR - }, - { - 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, - 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, - 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, - 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, - 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, - 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, - 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, - 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, - 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, - 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, - 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, - 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, - 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, - 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, - 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, - 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, - 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, - 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, - 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, - 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, - 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, - 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, - 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, - 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, - 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, - 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, - 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, - 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, - 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, - 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, - 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, - 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, - 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, - 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, - 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, - 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, - 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, - 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, - 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, - 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, - 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, - 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, - 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, - 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, - 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, - 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, - 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, - 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, - 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, - 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, - 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, - 0x9324fd72UL - }, - { - 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, - 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, - 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, - 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, - 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, - 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, - 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, - 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, - 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, - 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, - 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, - 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, - 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, - 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, - 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, - 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, - 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, - 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, - 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, - 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, - 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, - 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, - 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, - 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, - 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, - 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, - 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, - 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, - 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, - 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, - 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, - 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, - 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, - 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, - 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, - 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, - 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, - 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, - 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, - 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, - 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, - 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, - 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, - 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, - 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, - 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, - 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, - 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, - 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, - 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, - 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, - 0xbe9834edUL - }, - { - 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, - 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, - 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, - 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, - 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, - 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, - 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, - 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, - 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, - 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, - 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, - 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, - 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, - 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, - 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, - 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, - 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, - 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, - 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, - 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, - 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, - 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, - 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, - 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, - 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, - 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, - 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, - 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, - 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, - 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, - 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, - 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, - 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, - 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, - 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, - 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, - 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, - 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, - 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, - 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, - 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, - 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, - 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, - 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, - 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, - 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, - 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, - 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, - 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, - 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, - 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, - 0xde0506f1UL - }, - { - 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, - 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, - 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, - 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, - 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, - 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, - 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, - 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, - 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, - 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, - 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, - 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, - 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, - 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, - 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, - 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, - 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, - 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, - 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, - 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, - 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, - 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, - 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, - 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, - 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, - 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, - 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, - 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, - 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, - 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, - 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, - 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, - 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, - 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, - 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, - 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, - 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, - 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, - 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, - 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, - 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, - 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, - 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, - 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, - 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, - 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, - 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, - 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, - 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, - 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, - 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, - 0x8def022dUL - }, - { - 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, - 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, - 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, - 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, - 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, - 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, - 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, - 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, - 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, - 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, - 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, - 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, - 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, - 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, - 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, - 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, - 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, - 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, - 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, - 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, - 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, - 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, - 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, - 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, - 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, - 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, - 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, - 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, - 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, - 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, - 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, - 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, - 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, - 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, - 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, - 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, - 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, - 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, - 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, - 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, - 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, - 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, - 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, - 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, - 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, - 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, - 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, - 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, - 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, - 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, - 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, - 0x72fd2493UL - }, - { - 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, - 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, - 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, - 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, - 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, - 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, - 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, - 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, - 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, - 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, - 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, - 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, - 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, - 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, - 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, - 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, - 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, - 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, - 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, - 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, - 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, - 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, - 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, - 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, - 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, - 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, - 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, - 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, - 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, - 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, - 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, - 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, - 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, - 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, - 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, - 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, - 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, - 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, - 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, - 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, - 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, - 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, - 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, - 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, - 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, - 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, - 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, - 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, - 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, - 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, - 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, - 0xed3498beUL - }, - { - 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, - 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, - 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, - 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, - 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, - 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, - 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, - 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, - 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, - 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, - 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, - 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, - 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, - 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, - 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, - 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, - 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, - 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, - 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, - 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, - 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, - 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, - 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, - 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, - 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, - 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, - 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, - 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, - 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, - 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, - 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, - 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, - 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, - 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, - 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, - 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, - 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, - 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, - 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, - 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, - 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, - 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, - 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, - 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, - 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, - 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, - 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, - 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, - 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, - 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, - 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, - 0xf10605deUL +local const z_crc_t FAR crc_table[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d}; + +#ifdef W + +#if W == 8 + +local const z_word_t FAR crc_big_table[] = { + 0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000, + 0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000, + 0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000, + 0xa4b8dc7900000000, 0x1ee9d5e000000000, 0x88d9d29700000000, + 0x2b4cb60900000000, 0xbd7cb17e00000000, 0x072db8e700000000, + 0x911dbf9000000000, 0x6410b71d00000000, 0xf220b06a00000000, + 0x4871b9f300000000, 0xde41be8400000000, 0x7dd4da1a00000000, + 0xebe4dd6d00000000, 0x51b5d4f400000000, 0xc785d38300000000, + 0x56986c1300000000, 0xc0a86b6400000000, 0x7af962fd00000000, + 0xecc9658a00000000, 0x4f5c011400000000, 0xd96c066300000000, + 0x633d0ffa00000000, 0xf50d088d00000000, 0xc8206e3b00000000, + 0x5e10694c00000000, 0xe44160d500000000, 0x727167a200000000, + 0xd1e4033c00000000, 0x47d4044b00000000, 0xfd850dd200000000, + 0x6bb50aa500000000, 0xfaa8b53500000000, 0x6c98b24200000000, + 0xd6c9bbdb00000000, 0x40f9bcac00000000, 0xe36cd83200000000, + 0x755cdf4500000000, 0xcf0dd6dc00000000, 0x593dd1ab00000000, + 0xac30d92600000000, 0x3a00de5100000000, 0x8051d7c800000000, + 0x1661d0bf00000000, 0xb5f4b42100000000, 0x23c4b35600000000, + 0x9995bacf00000000, 0x0fa5bdb800000000, 0x9eb8022800000000, + 0x0888055f00000000, 0xb2d90cc600000000, 0x24e90bb100000000, + 0x877c6f2f00000000, 0x114c685800000000, 0xab1d61c100000000, + 0x3d2d66b600000000, 0x9041dc7600000000, 0x0671db0100000000, + 0xbc20d29800000000, 0x2a10d5ef00000000, 0x8985b17100000000, + 0x1fb5b60600000000, 0xa5e4bf9f00000000, 0x33d4b8e800000000, + 0xa2c9077800000000, 0x34f9000f00000000, 0x8ea8099600000000, + 0x18980ee100000000, 0xbb0d6a7f00000000, 0x2d3d6d0800000000, + 0x976c649100000000, 0x015c63e600000000, 0xf4516b6b00000000, + 0x62616c1c00000000, 0xd830658500000000, 0x4e0062f200000000, + 0xed95066c00000000, 0x7ba5011b00000000, 0xc1f4088200000000, + 0x57c40ff500000000, 0xc6d9b06500000000, 0x50e9b71200000000, + 0xeab8be8b00000000, 0x7c88b9fc00000000, 0xdf1ddd6200000000, + 0x492dda1500000000, 0xf37cd38c00000000, 0x654cd4fb00000000, + 0x5861b24d00000000, 0xce51b53a00000000, 0x7400bca300000000, + 0xe230bbd400000000, 0x41a5df4a00000000, 0xd795d83d00000000, + 0x6dc4d1a400000000, 0xfbf4d6d300000000, 0x6ae9694300000000, + 0xfcd96e3400000000, 0x468867ad00000000, 0xd0b860da00000000, + 0x732d044400000000, 0xe51d033300000000, 0x5f4c0aaa00000000, + 0xc97c0ddd00000000, 0x3c71055000000000, 0xaa41022700000000, + 0x10100bbe00000000, 0x86200cc900000000, 0x25b5685700000000, + 0xb3856f2000000000, 0x09d466b900000000, 0x9fe461ce00000000, + 0x0ef9de5e00000000, 0x98c9d92900000000, 0x2298d0b000000000, + 0xb4a8d7c700000000, 0x173db35900000000, 0x810db42e00000000, + 0x3b5cbdb700000000, 0xad6cbac000000000, 0x2083b8ed00000000, + 0xb6b3bf9a00000000, 0x0ce2b60300000000, 0x9ad2b17400000000, + 0x3947d5ea00000000, 0xaf77d29d00000000, 0x1526db0400000000, + 0x8316dc7300000000, 0x120b63e300000000, 0x843b649400000000, + 0x3e6a6d0d00000000, 0xa85a6a7a00000000, 0x0bcf0ee400000000, + 0x9dff099300000000, 0x27ae000a00000000, 0xb19e077d00000000, + 0x44930ff000000000, 0xd2a3088700000000, 0x68f2011e00000000, + 0xfec2066900000000, 0x5d5762f700000000, 0xcb67658000000000, + 0x71366c1900000000, 0xe7066b6e00000000, 0x761bd4fe00000000, + 0xe02bd38900000000, 0x5a7ada1000000000, 0xcc4add6700000000, + 0x6fdfb9f900000000, 0xf9efbe8e00000000, 0x43beb71700000000, + 0xd58eb06000000000, 0xe8a3d6d600000000, 0x7e93d1a100000000, + 0xc4c2d83800000000, 0x52f2df4f00000000, 0xf167bbd100000000, + 0x6757bca600000000, 0xdd06b53f00000000, 0x4b36b24800000000, + 0xda2b0dd800000000, 0x4c1b0aaf00000000, 0xf64a033600000000, + 0x607a044100000000, 0xc3ef60df00000000, 0x55df67a800000000, + 0xef8e6e3100000000, 0x79be694600000000, 0x8cb361cb00000000, + 0x1a8366bc00000000, 0xa0d26f2500000000, 0x36e2685200000000, + 0x95770ccc00000000, 0x03470bbb00000000, 0xb916022200000000, + 0x2f26055500000000, 0xbe3bbac500000000, 0x280bbdb200000000, + 0x925ab42b00000000, 0x046ab35c00000000, 0xa7ffd7c200000000, + 0x31cfd0b500000000, 0x8b9ed92c00000000, 0x1daede5b00000000, + 0xb0c2649b00000000, 0x26f263ec00000000, 0x9ca36a7500000000, + 0x0a936d0200000000, 0xa906099c00000000, 0x3f360eeb00000000, + 0x8567077200000000, 0x1357000500000000, 0x824abf9500000000, + 0x147ab8e200000000, 0xae2bb17b00000000, 0x381bb60c00000000, + 0x9b8ed29200000000, 0x0dbed5e500000000, 0xb7efdc7c00000000, + 0x21dfdb0b00000000, 0xd4d2d38600000000, 0x42e2d4f100000000, + 0xf8b3dd6800000000, 0x6e83da1f00000000, 0xcd16be8100000000, + 0x5b26b9f600000000, 0xe177b06f00000000, 0x7747b71800000000, + 0xe65a088800000000, 0x706a0fff00000000, 0xca3b066600000000, + 0x5c0b011100000000, 0xff9e658f00000000, 0x69ae62f800000000, + 0xd3ff6b6100000000, 0x45cf6c1600000000, 0x78e20aa000000000, + 0xeed20dd700000000, 0x5483044e00000000, 0xc2b3033900000000, + 0x612667a700000000, 0xf71660d000000000, 0x4d47694900000000, + 0xdb776e3e00000000, 0x4a6ad1ae00000000, 0xdc5ad6d900000000, + 0x660bdf4000000000, 0xf03bd83700000000, 0x53aebca900000000, + 0xc59ebbde00000000, 0x7fcfb24700000000, 0xe9ffb53000000000, + 0x1cf2bdbd00000000, 0x8ac2baca00000000, 0x3093b35300000000, + 0xa6a3b42400000000, 0x0536d0ba00000000, 0x9306d7cd00000000, + 0x2957de5400000000, 0xbf67d92300000000, 0x2e7a66b300000000, + 0xb84a61c400000000, 0x021b685d00000000, 0x942b6f2a00000000, + 0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000, + 0x8def022d00000000}; + +#else /* W == 4 */ + +local const z_word_t FAR crc_big_table[] = { + 0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07, + 0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79, + 0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7, + 0x911dbf90, 0x6410b71d, 0xf220b06a, 0x4871b9f3, 0xde41be84, + 0x7dd4da1a, 0xebe4dd6d, 0x51b5d4f4, 0xc785d383, 0x56986c13, + 0xc0a86b64, 0x7af962fd, 0xecc9658a, 0x4f5c0114, 0xd96c0663, + 0x633d0ffa, 0xf50d088d, 0xc8206e3b, 0x5e10694c, 0xe44160d5, + 0x727167a2, 0xd1e4033c, 0x47d4044b, 0xfd850dd2, 0x6bb50aa5, + 0xfaa8b535, 0x6c98b242, 0xd6c9bbdb, 0x40f9bcac, 0xe36cd832, + 0x755cdf45, 0xcf0dd6dc, 0x593dd1ab, 0xac30d926, 0x3a00de51, + 0x8051d7c8, 0x1661d0bf, 0xb5f4b421, 0x23c4b356, 0x9995bacf, + 0x0fa5bdb8, 0x9eb80228, 0x0888055f, 0xb2d90cc6, 0x24e90bb1, + 0x877c6f2f, 0x114c6858, 0xab1d61c1, 0x3d2d66b6, 0x9041dc76, + 0x0671db01, 0xbc20d298, 0x2a10d5ef, 0x8985b171, 0x1fb5b606, + 0xa5e4bf9f, 0x33d4b8e8, 0xa2c90778, 0x34f9000f, 0x8ea80996, + 0x18980ee1, 0xbb0d6a7f, 0x2d3d6d08, 0x976c6491, 0x015c63e6, + 0xf4516b6b, 0x62616c1c, 0xd8306585, 0x4e0062f2, 0xed95066c, + 0x7ba5011b, 0xc1f40882, 0x57c40ff5, 0xc6d9b065, 0x50e9b712, + 0xeab8be8b, 0x7c88b9fc, 0xdf1ddd62, 0x492dda15, 0xf37cd38c, + 0x654cd4fb, 0x5861b24d, 0xce51b53a, 0x7400bca3, 0xe230bbd4, + 0x41a5df4a, 0xd795d83d, 0x6dc4d1a4, 0xfbf4d6d3, 0x6ae96943, + 0xfcd96e34, 0x468867ad, 0xd0b860da, 0x732d0444, 0xe51d0333, + 0x5f4c0aaa, 0xc97c0ddd, 0x3c710550, 0xaa410227, 0x10100bbe, + 0x86200cc9, 0x25b56857, 0xb3856f20, 0x09d466b9, 0x9fe461ce, + 0x0ef9de5e, 0x98c9d929, 0x2298d0b0, 0xb4a8d7c7, 0x173db359, + 0x810db42e, 0x3b5cbdb7, 0xad6cbac0, 0x2083b8ed, 0xb6b3bf9a, + 0x0ce2b603, 0x9ad2b174, 0x3947d5ea, 0xaf77d29d, 0x1526db04, + 0x8316dc73, 0x120b63e3, 0x843b6494, 0x3e6a6d0d, 0xa85a6a7a, + 0x0bcf0ee4, 0x9dff0993, 0x27ae000a, 0xb19e077d, 0x44930ff0, + 0xd2a30887, 0x68f2011e, 0xfec20669, 0x5d5762f7, 0xcb676580, + 0x71366c19, 0xe7066b6e, 0x761bd4fe, 0xe02bd389, 0x5a7ada10, + 0xcc4add67, 0x6fdfb9f9, 0xf9efbe8e, 0x43beb717, 0xd58eb060, + 0xe8a3d6d6, 0x7e93d1a1, 0xc4c2d838, 0x52f2df4f, 0xf167bbd1, + 0x6757bca6, 0xdd06b53f, 0x4b36b248, 0xda2b0dd8, 0x4c1b0aaf, + 0xf64a0336, 0x607a0441, 0xc3ef60df, 0x55df67a8, 0xef8e6e31, + 0x79be6946, 0x8cb361cb, 0x1a8366bc, 0xa0d26f25, 0x36e26852, + 0x95770ccc, 0x03470bbb, 0xb9160222, 0x2f260555, 0xbe3bbac5, + 0x280bbdb2, 0x925ab42b, 0x046ab35c, 0xa7ffd7c2, 0x31cfd0b5, + 0x8b9ed92c, 0x1daede5b, 0xb0c2649b, 0x26f263ec, 0x9ca36a75, + 0x0a936d02, 0xa906099c, 0x3f360eeb, 0x85670772, 0x13570005, + 0x824abf95, 0x147ab8e2, 0xae2bb17b, 0x381bb60c, 0x9b8ed292, + 0x0dbed5e5, 0xb7efdc7c, 0x21dfdb0b, 0xd4d2d386, 0x42e2d4f1, + 0xf8b3dd68, 0x6e83da1f, 0xcd16be81, 0x5b26b9f6, 0xe177b06f, + 0x7747b718, 0xe65a0888, 0x706a0fff, 0xca3b0666, 0x5c0b0111, + 0xff9e658f, 0x69ae62f8, 0xd3ff6b61, 0x45cf6c16, 0x78e20aa0, + 0xeed20dd7, 0x5483044e, 0xc2b30339, 0x612667a7, 0xf71660d0, + 0x4d476949, 0xdb776e3e, 0x4a6ad1ae, 0xdc5ad6d9, 0x660bdf40, + 0xf03bd837, 0x53aebca9, 0xc59ebbde, 0x7fcfb247, 0xe9ffb530, + 0x1cf2bdbd, 0x8ac2baca, 0x3093b353, 0xa6a3b424, 0x0536d0ba, + 0x9306d7cd, 0x2957de54, 0xbf67d923, 0x2e7a66b3, 0xb84a61c4, + 0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a, + 0x8def022d}; + +#endif + +#if N == 1 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, + 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, + 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232, + 0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8, + 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e, + 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa, + 0x69312319, 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b, + 0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f, + 0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719, + 0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, 0x496753e3, + 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa, + 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b, + 0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed, + 0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89, + 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25, + 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041, + 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c, + 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed, + 0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4, + 0x8c06e16a, 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758, + 0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e, + 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a, + 0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed, + 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889, + 0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df, + 0x37558441, 0xb9da83a2, 0x7570833c, 0x533b85da, 0x9f918544, + 0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d, + 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c, + 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1, + 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95, + 0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839, + 0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d, + 0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976, + 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7, + 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be, + 0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144, + 0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12, + 0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376, + 0xc37cc495, 0x0fd6c40b, 0x7aa64737, 0xb60c47a9, 0x3883404a, + 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e, + 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278, + 0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682, + 0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b, + 0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a, + 0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, 0x83d02561, + 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05, + 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9, + 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd, + 0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, + 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61, + 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, + 0x264b06e6}, + {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413, + 0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3, + 0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d, + 0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653, + 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9, + 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e, + 0x37e1e793, 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5, + 0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712, + 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8, + 0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, 0x0e14aee6, + 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068, + 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8, + 0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579, + 0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade, + 0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37, + 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590, + 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4, + 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64, + 0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea, + 0xd59d995e, 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678, + 0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282, + 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25, + 0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102, + 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5, + 0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f, + 0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, 0x8816eaf2, 0x2e61e146, + 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8, + 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08, + 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c, + 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b, + 0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972, + 0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5, + 0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d, + 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd, + 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833, + 0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d, + 0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7, + 0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60, + 0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2, + 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105, + 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff, + 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1, + 0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f, + 0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf, + 0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, 0x03a0a617, + 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0, + 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959, + 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe, + 0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca, + 0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a, + 0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184, + 0x92364a30}, + {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216, + 0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8, + 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170, + 0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035, + 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6, + 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145, + 0x39dc63eb, 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d, + 0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e, + 0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d, + 0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, 0xcf26d408, + 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0, + 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e, + 0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c, + 0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf, + 0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a, + 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9, + 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1, + 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f, + 0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987, + 0xfdd8ba22, 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4, + 0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37, + 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84, + 0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca, + 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79, + 0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba, + 0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d, + 0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5, + 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b, + 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643, + 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0, + 0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525, + 0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496, + 0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8, + 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026, + 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e, + 0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db, + 0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118, + 0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab, + 0x20c07205, 0xeb9ca1a0, 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf, + 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c, + 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf, + 0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a, + 0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32, + 0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec, + 0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, 0x16441b82, + 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31, + 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4, + 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957, + 0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f, + 0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1, + 0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869, + 0xe4c4abcc}, + {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0, + 0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271, + 0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61, + 0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52, + 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43, + 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333, + 0xdfd029e3, 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64, + 0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314, + 0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205, + 0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, 0x9c419136, + 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26, + 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997, + 0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849, + 0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739, + 0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8, + 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98, + 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b, + 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba, + 0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa, + 0xba43581a, 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d, + 0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c, + 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc, + 0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af, + 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf, + 0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce, + 0x0142247e, 0x46e25eae, 0x7b82771e, 0xb1e6b092, 0x8c869922, + 0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532, + 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183, + 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710, + 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860, + 0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1, + 0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1, + 0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956, + 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7, + 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7, + 0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4, + 0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5, + 0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5, + 0xaff7b675, 0x92979fc5, 0xe915e8db, 0xd475c16b, 0x93d5bbbb, + 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb, + 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da, + 0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9, + 0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9, + 0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48, + 0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, 0x28d4c7df, + 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af, + 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e, + 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e, + 0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d, + 0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c, + 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c, + 0xca64c78c}, + {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, + 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, + 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, + 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, + 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70, + 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, + 0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5, + 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, + 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086, + 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4, + 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, + 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, + 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d, + 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, + 0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, + 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, + 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, + 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028, + 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, + 0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, + 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec, + 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde, + 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817, + 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, + 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, + 0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e, + 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7, + 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, + 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4, + 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, + 0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, + 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, + 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52, + 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f, + 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, + 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, + 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675, + 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647, + 0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d, + 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, + 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, + 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc, + 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, + 0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, + 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138, + 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a, + 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, + 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, + 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, + 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d, + 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194, + 0xde0506f1}, + {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, + 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f, + 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a, + 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, + 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8, + 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, + 0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e, + 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, + 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84, + 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7, + 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, + 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, + 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0, + 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b, + 0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, + 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, + 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, + 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f, + 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, + 0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, + 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98, + 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873, + 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e, + 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, + 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, + 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7, + 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732, + 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, + 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0, + 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, + 0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26, + 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, + 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc, + 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef, + 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, + 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, + 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8, + 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43, + 0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e, + 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, + 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, + 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07, + 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, + 0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, + 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0, + 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b, + 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576, + 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, + 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, + 0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f, + 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, + 0xbe9834ed}, + {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, + 0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49, + 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, + 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, + 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859, + 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, + 0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620, + 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, + 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae, + 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2, + 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, + 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, + 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05, + 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40, + 0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, + 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, + 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, + 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d, + 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, + 0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, + 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af, + 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea, + 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74, + 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, + 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, + 0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a, + 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, + 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, + 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a, + 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, + 0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290, + 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, + 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed, + 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0, + 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, + 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, + 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0, + 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5, + 0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, + 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, + 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, + 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e, + 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, + 0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, + 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec, + 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9, + 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66, + 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, + 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, + 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4, + 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, + 0x9324fd72}, + {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000, + 0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000, + 0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000, + 0xa4b8dc7900000000, 0x1ee9d5e000000000, 0x88d9d29700000000, + 0x2b4cb60900000000, 0xbd7cb17e00000000, 0x072db8e700000000, + 0x911dbf9000000000, 0x6410b71d00000000, 0xf220b06a00000000, + 0x4871b9f300000000, 0xde41be8400000000, 0x7dd4da1a00000000, + 0xebe4dd6d00000000, 0x51b5d4f400000000, 0xc785d38300000000, + 0x56986c1300000000, 0xc0a86b6400000000, 0x7af962fd00000000, + 0xecc9658a00000000, 0x4f5c011400000000, 0xd96c066300000000, + 0x633d0ffa00000000, 0xf50d088d00000000, 0xc8206e3b00000000, + 0x5e10694c00000000, 0xe44160d500000000, 0x727167a200000000, + 0xd1e4033c00000000, 0x47d4044b00000000, 0xfd850dd200000000, + 0x6bb50aa500000000, 0xfaa8b53500000000, 0x6c98b24200000000, + 0xd6c9bbdb00000000, 0x40f9bcac00000000, 0xe36cd83200000000, + 0x755cdf4500000000, 0xcf0dd6dc00000000, 0x593dd1ab00000000, + 0xac30d92600000000, 0x3a00de5100000000, 0x8051d7c800000000, + 0x1661d0bf00000000, 0xb5f4b42100000000, 0x23c4b35600000000, + 0x9995bacf00000000, 0x0fa5bdb800000000, 0x9eb8022800000000, + 0x0888055f00000000, 0xb2d90cc600000000, 0x24e90bb100000000, + 0x877c6f2f00000000, 0x114c685800000000, 0xab1d61c100000000, + 0x3d2d66b600000000, 0x9041dc7600000000, 0x0671db0100000000, + 0xbc20d29800000000, 0x2a10d5ef00000000, 0x8985b17100000000, + 0x1fb5b60600000000, 0xa5e4bf9f00000000, 0x33d4b8e800000000, + 0xa2c9077800000000, 0x34f9000f00000000, 0x8ea8099600000000, + 0x18980ee100000000, 0xbb0d6a7f00000000, 0x2d3d6d0800000000, + 0x976c649100000000, 0x015c63e600000000, 0xf4516b6b00000000, + 0x62616c1c00000000, 0xd830658500000000, 0x4e0062f200000000, + 0xed95066c00000000, 0x7ba5011b00000000, 0xc1f4088200000000, + 0x57c40ff500000000, 0xc6d9b06500000000, 0x50e9b71200000000, + 0xeab8be8b00000000, 0x7c88b9fc00000000, 0xdf1ddd6200000000, + 0x492dda1500000000, 0xf37cd38c00000000, 0x654cd4fb00000000, + 0x5861b24d00000000, 0xce51b53a00000000, 0x7400bca300000000, + 0xe230bbd400000000, 0x41a5df4a00000000, 0xd795d83d00000000, + 0x6dc4d1a400000000, 0xfbf4d6d300000000, 0x6ae9694300000000, + 0xfcd96e3400000000, 0x468867ad00000000, 0xd0b860da00000000, + 0x732d044400000000, 0xe51d033300000000, 0x5f4c0aaa00000000, + 0xc97c0ddd00000000, 0x3c71055000000000, 0xaa41022700000000, + 0x10100bbe00000000, 0x86200cc900000000, 0x25b5685700000000, + 0xb3856f2000000000, 0x09d466b900000000, 0x9fe461ce00000000, + 0x0ef9de5e00000000, 0x98c9d92900000000, 0x2298d0b000000000, + 0xb4a8d7c700000000, 0x173db35900000000, 0x810db42e00000000, + 0x3b5cbdb700000000, 0xad6cbac000000000, 0x2083b8ed00000000, + 0xb6b3bf9a00000000, 0x0ce2b60300000000, 0x9ad2b17400000000, + 0x3947d5ea00000000, 0xaf77d29d00000000, 0x1526db0400000000, + 0x8316dc7300000000, 0x120b63e300000000, 0x843b649400000000, + 0x3e6a6d0d00000000, 0xa85a6a7a00000000, 0x0bcf0ee400000000, + 0x9dff099300000000, 0x27ae000a00000000, 0xb19e077d00000000, + 0x44930ff000000000, 0xd2a3088700000000, 0x68f2011e00000000, + 0xfec2066900000000, 0x5d5762f700000000, 0xcb67658000000000, + 0x71366c1900000000, 0xe7066b6e00000000, 0x761bd4fe00000000, + 0xe02bd38900000000, 0x5a7ada1000000000, 0xcc4add6700000000, + 0x6fdfb9f900000000, 0xf9efbe8e00000000, 0x43beb71700000000, + 0xd58eb06000000000, 0xe8a3d6d600000000, 0x7e93d1a100000000, + 0xc4c2d83800000000, 0x52f2df4f00000000, 0xf167bbd100000000, + 0x6757bca600000000, 0xdd06b53f00000000, 0x4b36b24800000000, + 0xda2b0dd800000000, 0x4c1b0aaf00000000, 0xf64a033600000000, + 0x607a044100000000, 0xc3ef60df00000000, 0x55df67a800000000, + 0xef8e6e3100000000, 0x79be694600000000, 0x8cb361cb00000000, + 0x1a8366bc00000000, 0xa0d26f2500000000, 0x36e2685200000000, + 0x95770ccc00000000, 0x03470bbb00000000, 0xb916022200000000, + 0x2f26055500000000, 0xbe3bbac500000000, 0x280bbdb200000000, + 0x925ab42b00000000, 0x046ab35c00000000, 0xa7ffd7c200000000, + 0x31cfd0b500000000, 0x8b9ed92c00000000, 0x1daede5b00000000, + 0xb0c2649b00000000, 0x26f263ec00000000, 0x9ca36a7500000000, + 0x0a936d0200000000, 0xa906099c00000000, 0x3f360eeb00000000, + 0x8567077200000000, 0x1357000500000000, 0x824abf9500000000, + 0x147ab8e200000000, 0xae2bb17b00000000, 0x381bb60c00000000, + 0x9b8ed29200000000, 0x0dbed5e500000000, 0xb7efdc7c00000000, + 0x21dfdb0b00000000, 0xd4d2d38600000000, 0x42e2d4f100000000, + 0xf8b3dd6800000000, 0x6e83da1f00000000, 0xcd16be8100000000, + 0x5b26b9f600000000, 0xe177b06f00000000, 0x7747b71800000000, + 0xe65a088800000000, 0x706a0fff00000000, 0xca3b066600000000, + 0x5c0b011100000000, 0xff9e658f00000000, 0x69ae62f800000000, + 0xd3ff6b6100000000, 0x45cf6c1600000000, 0x78e20aa000000000, + 0xeed20dd700000000, 0x5483044e00000000, 0xc2b3033900000000, + 0x612667a700000000, 0xf71660d000000000, 0x4d47694900000000, + 0xdb776e3e00000000, 0x4a6ad1ae00000000, 0xdc5ad6d900000000, + 0x660bdf4000000000, 0xf03bd83700000000, 0x53aebca900000000, + 0xc59ebbde00000000, 0x7fcfb24700000000, 0xe9ffb53000000000, + 0x1cf2bdbd00000000, 0x8ac2baca00000000, 0x3093b35300000000, + 0xa6a3b42400000000, 0x0536d0ba00000000, 0x9306d7cd00000000, + 0x2957de5400000000, 0xbf67d92300000000, 0x2e7a66b300000000, + 0xb84a61c400000000, 0x021b685d00000000, 0x942b6f2a00000000, + 0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000, + 0x8def022d00000000}, + {0x0000000000000000, 0x41311b1900000000, 0x8262363200000000, + 0xc3532d2b00000000, 0x04c56c6400000000, 0x45f4777d00000000, + 0x86a75a5600000000, 0xc796414f00000000, 0x088ad9c800000000, + 0x49bbc2d100000000, 0x8ae8effa00000000, 0xcbd9f4e300000000, + 0x0c4fb5ac00000000, 0x4d7eaeb500000000, 0x8e2d839e00000000, + 0xcf1c988700000000, 0x5112c24a00000000, 0x1023d95300000000, + 0xd370f47800000000, 0x9241ef6100000000, 0x55d7ae2e00000000, + 0x14e6b53700000000, 0xd7b5981c00000000, 0x9684830500000000, + 0x59981b8200000000, 0x18a9009b00000000, 0xdbfa2db000000000, + 0x9acb36a900000000, 0x5d5d77e600000000, 0x1c6c6cff00000000, + 0xdf3f41d400000000, 0x9e0e5acd00000000, 0xa224849500000000, + 0xe3159f8c00000000, 0x2046b2a700000000, 0x6177a9be00000000, + 0xa6e1e8f100000000, 0xe7d0f3e800000000, 0x2483dec300000000, + 0x65b2c5da00000000, 0xaaae5d5d00000000, 0xeb9f464400000000, + 0x28cc6b6f00000000, 0x69fd707600000000, 0xae6b313900000000, + 0xef5a2a2000000000, 0x2c09070b00000000, 0x6d381c1200000000, + 0xf33646df00000000, 0xb2075dc600000000, 0x715470ed00000000, + 0x30656bf400000000, 0xf7f32abb00000000, 0xb6c231a200000000, + 0x75911c8900000000, 0x34a0079000000000, 0xfbbc9f1700000000, + 0xba8d840e00000000, 0x79dea92500000000, 0x38efb23c00000000, + 0xff79f37300000000, 0xbe48e86a00000000, 0x7d1bc54100000000, + 0x3c2ade5800000000, 0x054f79f000000000, 0x447e62e900000000, + 0x872d4fc200000000, 0xc61c54db00000000, 0x018a159400000000, + 0x40bb0e8d00000000, 0x83e823a600000000, 0xc2d938bf00000000, + 0x0dc5a03800000000, 0x4cf4bb2100000000, 0x8fa7960a00000000, + 0xce968d1300000000, 0x0900cc5c00000000, 0x4831d74500000000, + 0x8b62fa6e00000000, 0xca53e17700000000, 0x545dbbba00000000, + 0x156ca0a300000000, 0xd63f8d8800000000, 0x970e969100000000, + 0x5098d7de00000000, 0x11a9ccc700000000, 0xd2fae1ec00000000, + 0x93cbfaf500000000, 0x5cd7627200000000, 0x1de6796b00000000, + 0xdeb5544000000000, 0x9f844f5900000000, 0x58120e1600000000, + 0x1923150f00000000, 0xda70382400000000, 0x9b41233d00000000, + 0xa76bfd6500000000, 0xe65ae67c00000000, 0x2509cb5700000000, + 0x6438d04e00000000, 0xa3ae910100000000, 0xe29f8a1800000000, + 0x21cca73300000000, 0x60fdbc2a00000000, 0xafe124ad00000000, + 0xeed03fb400000000, 0x2d83129f00000000, 0x6cb2098600000000, + 0xab2448c900000000, 0xea1553d000000000, 0x29467efb00000000, + 0x687765e200000000, 0xf6793f2f00000000, 0xb748243600000000, + 0x741b091d00000000, 0x352a120400000000, 0xf2bc534b00000000, + 0xb38d485200000000, 0x70de657900000000, 0x31ef7e6000000000, + 0xfef3e6e700000000, 0xbfc2fdfe00000000, 0x7c91d0d500000000, + 0x3da0cbcc00000000, 0xfa368a8300000000, 0xbb07919a00000000, + 0x7854bcb100000000, 0x3965a7a800000000, 0x4b98833b00000000, + 0x0aa9982200000000, 0xc9fab50900000000, 0x88cbae1000000000, + 0x4f5def5f00000000, 0x0e6cf44600000000, 0xcd3fd96d00000000, + 0x8c0ec27400000000, 0x43125af300000000, 0x022341ea00000000, + 0xc1706cc100000000, 0x804177d800000000, 0x47d7369700000000, + 0x06e62d8e00000000, 0xc5b500a500000000, 0x84841bbc00000000, + 0x1a8a417100000000, 0x5bbb5a6800000000, 0x98e8774300000000, + 0xd9d96c5a00000000, 0x1e4f2d1500000000, 0x5f7e360c00000000, + 0x9c2d1b2700000000, 0xdd1c003e00000000, 0x120098b900000000, + 0x533183a000000000, 0x9062ae8b00000000, 0xd153b59200000000, + 0x16c5f4dd00000000, 0x57f4efc400000000, 0x94a7c2ef00000000, + 0xd596d9f600000000, 0xe9bc07ae00000000, 0xa88d1cb700000000, + 0x6bde319c00000000, 0x2aef2a8500000000, 0xed796bca00000000, + 0xac4870d300000000, 0x6f1b5df800000000, 0x2e2a46e100000000, + 0xe136de6600000000, 0xa007c57f00000000, 0x6354e85400000000, + 0x2265f34d00000000, 0xe5f3b20200000000, 0xa4c2a91b00000000, + 0x6791843000000000, 0x26a09f2900000000, 0xb8aec5e400000000, + 0xf99fdefd00000000, 0x3accf3d600000000, 0x7bfde8cf00000000, + 0xbc6ba98000000000, 0xfd5ab29900000000, 0x3e099fb200000000, + 0x7f3884ab00000000, 0xb0241c2c00000000, 0xf115073500000000, + 0x32462a1e00000000, 0x7377310700000000, 0xb4e1704800000000, + 0xf5d06b5100000000, 0x3683467a00000000, 0x77b25d6300000000, + 0x4ed7facb00000000, 0x0fe6e1d200000000, 0xccb5ccf900000000, + 0x8d84d7e000000000, 0x4a1296af00000000, 0x0b238db600000000, + 0xc870a09d00000000, 0x8941bb8400000000, 0x465d230300000000, + 0x076c381a00000000, 0xc43f153100000000, 0x850e0e2800000000, + 0x42984f6700000000, 0x03a9547e00000000, 0xc0fa795500000000, + 0x81cb624c00000000, 0x1fc5388100000000, 0x5ef4239800000000, + 0x9da70eb300000000, 0xdc9615aa00000000, 0x1b0054e500000000, + 0x5a314ffc00000000, 0x996262d700000000, 0xd85379ce00000000, + 0x174fe14900000000, 0x567efa5000000000, 0x952dd77b00000000, + 0xd41ccc6200000000, 0x138a8d2d00000000, 0x52bb963400000000, + 0x91e8bb1f00000000, 0xd0d9a00600000000, 0xecf37e5e00000000, + 0xadc2654700000000, 0x6e91486c00000000, 0x2fa0537500000000, + 0xe836123a00000000, 0xa907092300000000, 0x6a54240800000000, + 0x2b653f1100000000, 0xe479a79600000000, 0xa548bc8f00000000, + 0x661b91a400000000, 0x272a8abd00000000, 0xe0bccbf200000000, + 0xa18dd0eb00000000, 0x62defdc000000000, 0x23efe6d900000000, + 0xbde1bc1400000000, 0xfcd0a70d00000000, 0x3f838a2600000000, + 0x7eb2913f00000000, 0xb924d07000000000, 0xf815cb6900000000, + 0x3b46e64200000000, 0x7a77fd5b00000000, 0xb56b65dc00000000, + 0xf45a7ec500000000, 0x370953ee00000000, 0x763848f700000000, + 0xb1ae09b800000000, 0xf09f12a100000000, 0x33cc3f8a00000000, + 0x72fd249300000000}, + {0x0000000000000000, 0x376ac20100000000, 0x6ed4840300000000, + 0x59be460200000000, 0xdca8090700000000, 0xebc2cb0600000000, + 0xb27c8d0400000000, 0x85164f0500000000, 0xb851130e00000000, + 0x8f3bd10f00000000, 0xd685970d00000000, 0xe1ef550c00000000, + 0x64f91a0900000000, 0x5393d80800000000, 0x0a2d9e0a00000000, + 0x3d475c0b00000000, 0x70a3261c00000000, 0x47c9e41d00000000, + 0x1e77a21f00000000, 0x291d601e00000000, 0xac0b2f1b00000000, + 0x9b61ed1a00000000, 0xc2dfab1800000000, 0xf5b5691900000000, + 0xc8f2351200000000, 0xff98f71300000000, 0xa626b11100000000, + 0x914c731000000000, 0x145a3c1500000000, 0x2330fe1400000000, + 0x7a8eb81600000000, 0x4de47a1700000000, 0xe0464d3800000000, + 0xd72c8f3900000000, 0x8e92c93b00000000, 0xb9f80b3a00000000, + 0x3cee443f00000000, 0x0b84863e00000000, 0x523ac03c00000000, + 0x6550023d00000000, 0x58175e3600000000, 0x6f7d9c3700000000, + 0x36c3da3500000000, 0x01a9183400000000, 0x84bf573100000000, + 0xb3d5953000000000, 0xea6bd33200000000, 0xdd01113300000000, + 0x90e56b2400000000, 0xa78fa92500000000, 0xfe31ef2700000000, + 0xc95b2d2600000000, 0x4c4d622300000000, 0x7b27a02200000000, + 0x2299e62000000000, 0x15f3242100000000, 0x28b4782a00000000, + 0x1fdeba2b00000000, 0x4660fc2900000000, 0x710a3e2800000000, + 0xf41c712d00000000, 0xc376b32c00000000, 0x9ac8f52e00000000, + 0xada2372f00000000, 0xc08d9a7000000000, 0xf7e7587100000000, + 0xae591e7300000000, 0x9933dc7200000000, 0x1c25937700000000, + 0x2b4f517600000000, 0x72f1177400000000, 0x459bd57500000000, + 0x78dc897e00000000, 0x4fb64b7f00000000, 0x16080d7d00000000, + 0x2162cf7c00000000, 0xa474807900000000, 0x931e427800000000, + 0xcaa0047a00000000, 0xfdcac67b00000000, 0xb02ebc6c00000000, + 0x87447e6d00000000, 0xdefa386f00000000, 0xe990fa6e00000000, + 0x6c86b56b00000000, 0x5bec776a00000000, 0x0252316800000000, + 0x3538f36900000000, 0x087faf6200000000, 0x3f156d6300000000, + 0x66ab2b6100000000, 0x51c1e96000000000, 0xd4d7a66500000000, + 0xe3bd646400000000, 0xba03226600000000, 0x8d69e06700000000, + 0x20cbd74800000000, 0x17a1154900000000, 0x4e1f534b00000000, + 0x7975914a00000000, 0xfc63de4f00000000, 0xcb091c4e00000000, + 0x92b75a4c00000000, 0xa5dd984d00000000, 0x989ac44600000000, + 0xaff0064700000000, 0xf64e404500000000, 0xc124824400000000, + 0x4432cd4100000000, 0x73580f4000000000, 0x2ae6494200000000, + 0x1d8c8b4300000000, 0x5068f15400000000, 0x6702335500000000, + 0x3ebc755700000000, 0x09d6b75600000000, 0x8cc0f85300000000, + 0xbbaa3a5200000000, 0xe2147c5000000000, 0xd57ebe5100000000, + 0xe839e25a00000000, 0xdf53205b00000000, 0x86ed665900000000, + 0xb187a45800000000, 0x3491eb5d00000000, 0x03fb295c00000000, + 0x5a456f5e00000000, 0x6d2fad5f00000000, 0x801b35e100000000, + 0xb771f7e000000000, 0xeecfb1e200000000, 0xd9a573e300000000, + 0x5cb33ce600000000, 0x6bd9fee700000000, 0x3267b8e500000000, + 0x050d7ae400000000, 0x384a26ef00000000, 0x0f20e4ee00000000, + 0x569ea2ec00000000, 0x61f460ed00000000, 0xe4e22fe800000000, + 0xd388ede900000000, 0x8a36abeb00000000, 0xbd5c69ea00000000, + 0xf0b813fd00000000, 0xc7d2d1fc00000000, 0x9e6c97fe00000000, + 0xa90655ff00000000, 0x2c101afa00000000, 0x1b7ad8fb00000000, + 0x42c49ef900000000, 0x75ae5cf800000000, 0x48e900f300000000, + 0x7f83c2f200000000, 0x263d84f000000000, 0x115746f100000000, + 0x944109f400000000, 0xa32bcbf500000000, 0xfa958df700000000, + 0xcdff4ff600000000, 0x605d78d900000000, 0x5737bad800000000, + 0x0e89fcda00000000, 0x39e33edb00000000, 0xbcf571de00000000, + 0x8b9fb3df00000000, 0xd221f5dd00000000, 0xe54b37dc00000000, + 0xd80c6bd700000000, 0xef66a9d600000000, 0xb6d8efd400000000, + 0x81b22dd500000000, 0x04a462d000000000, 0x33cea0d100000000, + 0x6a70e6d300000000, 0x5d1a24d200000000, 0x10fe5ec500000000, + 0x27949cc400000000, 0x7e2adac600000000, 0x494018c700000000, + 0xcc5657c200000000, 0xfb3c95c300000000, 0xa282d3c100000000, + 0x95e811c000000000, 0xa8af4dcb00000000, 0x9fc58fca00000000, + 0xc67bc9c800000000, 0xf1110bc900000000, 0x740744cc00000000, + 0x436d86cd00000000, 0x1ad3c0cf00000000, 0x2db902ce00000000, + 0x4096af9100000000, 0x77fc6d9000000000, 0x2e422b9200000000, + 0x1928e99300000000, 0x9c3ea69600000000, 0xab54649700000000, + 0xf2ea229500000000, 0xc580e09400000000, 0xf8c7bc9f00000000, + 0xcfad7e9e00000000, 0x9613389c00000000, 0xa179fa9d00000000, + 0x246fb59800000000, 0x1305779900000000, 0x4abb319b00000000, + 0x7dd1f39a00000000, 0x3035898d00000000, 0x075f4b8c00000000, + 0x5ee10d8e00000000, 0x698bcf8f00000000, 0xec9d808a00000000, + 0xdbf7428b00000000, 0x8249048900000000, 0xb523c68800000000, + 0x88649a8300000000, 0xbf0e588200000000, 0xe6b01e8000000000, + 0xd1dadc8100000000, 0x54cc938400000000, 0x63a6518500000000, + 0x3a18178700000000, 0x0d72d58600000000, 0xa0d0e2a900000000, + 0x97ba20a800000000, 0xce0466aa00000000, 0xf96ea4ab00000000, + 0x7c78ebae00000000, 0x4b1229af00000000, 0x12ac6fad00000000, + 0x25c6adac00000000, 0x1881f1a700000000, 0x2feb33a600000000, + 0x765575a400000000, 0x413fb7a500000000, 0xc429f8a000000000, + 0xf3433aa100000000, 0xaafd7ca300000000, 0x9d97bea200000000, + 0xd073c4b500000000, 0xe71906b400000000, 0xbea740b600000000, + 0x89cd82b700000000, 0x0cdbcdb200000000, 0x3bb10fb300000000, + 0x620f49b100000000, 0x55658bb000000000, 0x6822d7bb00000000, + 0x5f4815ba00000000, 0x06f653b800000000, 0x319c91b900000000, + 0xb48adebc00000000, 0x83e01cbd00000000, 0xda5e5abf00000000, + 0xed3498be00000000}, + {0x0000000000000000, 0x6567bcb800000000, 0x8bc809aa00000000, + 0xeeafb51200000000, 0x5797628f00000000, 0x32f0de3700000000, + 0xdc5f6b2500000000, 0xb938d79d00000000, 0xef28b4c500000000, + 0x8a4f087d00000000, 0x64e0bd6f00000000, 0x018701d700000000, + 0xb8bfd64a00000000, 0xddd86af200000000, 0x3377dfe000000000, + 0x5610635800000000, 0x9f57195000000000, 0xfa30a5e800000000, + 0x149f10fa00000000, 0x71f8ac4200000000, 0xc8c07bdf00000000, + 0xada7c76700000000, 0x4308727500000000, 0x266fcecd00000000, + 0x707fad9500000000, 0x1518112d00000000, 0xfbb7a43f00000000, + 0x9ed0188700000000, 0x27e8cf1a00000000, 0x428f73a200000000, + 0xac20c6b000000000, 0xc9477a0800000000, 0x3eaf32a000000000, + 0x5bc88e1800000000, 0xb5673b0a00000000, 0xd00087b200000000, + 0x6938502f00000000, 0x0c5fec9700000000, 0xe2f0598500000000, + 0x8797e53d00000000, 0xd187866500000000, 0xb4e03add00000000, + 0x5a4f8fcf00000000, 0x3f28337700000000, 0x8610e4ea00000000, + 0xe377585200000000, 0x0dd8ed4000000000, 0x68bf51f800000000, + 0xa1f82bf000000000, 0xc49f974800000000, 0x2a30225a00000000, + 0x4f579ee200000000, 0xf66f497f00000000, 0x9308f5c700000000, + 0x7da740d500000000, 0x18c0fc6d00000000, 0x4ed09f3500000000, + 0x2bb7238d00000000, 0xc518969f00000000, 0xa07f2a2700000000, + 0x1947fdba00000000, 0x7c20410200000000, 0x928ff41000000000, + 0xf7e848a800000000, 0x3d58149b00000000, 0x583fa82300000000, + 0xb6901d3100000000, 0xd3f7a18900000000, 0x6acf761400000000, + 0x0fa8caac00000000, 0xe1077fbe00000000, 0x8460c30600000000, + 0xd270a05e00000000, 0xb7171ce600000000, 0x59b8a9f400000000, + 0x3cdf154c00000000, 0x85e7c2d100000000, 0xe0807e6900000000, + 0x0e2fcb7b00000000, 0x6b4877c300000000, 0xa20f0dcb00000000, + 0xc768b17300000000, 0x29c7046100000000, 0x4ca0b8d900000000, + 0xf5986f4400000000, 0x90ffd3fc00000000, 0x7e5066ee00000000, + 0x1b37da5600000000, 0x4d27b90e00000000, 0x284005b600000000, + 0xc6efb0a400000000, 0xa3880c1c00000000, 0x1ab0db8100000000, + 0x7fd7673900000000, 0x9178d22b00000000, 0xf41f6e9300000000, + 0x03f7263b00000000, 0x66909a8300000000, 0x883f2f9100000000, + 0xed58932900000000, 0x546044b400000000, 0x3107f80c00000000, + 0xdfa84d1e00000000, 0xbacff1a600000000, 0xecdf92fe00000000, + 0x89b82e4600000000, 0x67179b5400000000, 0x027027ec00000000, + 0xbb48f07100000000, 0xde2f4cc900000000, 0x3080f9db00000000, + 0x55e7456300000000, 0x9ca03f6b00000000, 0xf9c783d300000000, + 0x176836c100000000, 0x720f8a7900000000, 0xcb375de400000000, + 0xae50e15c00000000, 0x40ff544e00000000, 0x2598e8f600000000, + 0x73888bae00000000, 0x16ef371600000000, 0xf840820400000000, + 0x9d273ebc00000000, 0x241fe92100000000, 0x4178559900000000, + 0xafd7e08b00000000, 0xcab05c3300000000, 0x3bb659ed00000000, + 0x5ed1e55500000000, 0xb07e504700000000, 0xd519ecff00000000, + 0x6c213b6200000000, 0x094687da00000000, 0xe7e932c800000000, + 0x828e8e7000000000, 0xd49eed2800000000, 0xb1f9519000000000, + 0x5f56e48200000000, 0x3a31583a00000000, 0x83098fa700000000, + 0xe66e331f00000000, 0x08c1860d00000000, 0x6da63ab500000000, + 0xa4e140bd00000000, 0xc186fc0500000000, 0x2f29491700000000, + 0x4a4ef5af00000000, 0xf376223200000000, 0x96119e8a00000000, + 0x78be2b9800000000, 0x1dd9972000000000, 0x4bc9f47800000000, + 0x2eae48c000000000, 0xc001fdd200000000, 0xa566416a00000000, + 0x1c5e96f700000000, 0x79392a4f00000000, 0x97969f5d00000000, + 0xf2f123e500000000, 0x05196b4d00000000, 0x607ed7f500000000, + 0x8ed162e700000000, 0xebb6de5f00000000, 0x528e09c200000000, + 0x37e9b57a00000000, 0xd946006800000000, 0xbc21bcd000000000, + 0xea31df8800000000, 0x8f56633000000000, 0x61f9d62200000000, + 0x049e6a9a00000000, 0xbda6bd0700000000, 0xd8c101bf00000000, + 0x366eb4ad00000000, 0x5309081500000000, 0x9a4e721d00000000, + 0xff29cea500000000, 0x11867bb700000000, 0x74e1c70f00000000, + 0xcdd9109200000000, 0xa8beac2a00000000, 0x4611193800000000, + 0x2376a58000000000, 0x7566c6d800000000, 0x10017a6000000000, + 0xfeaecf7200000000, 0x9bc973ca00000000, 0x22f1a45700000000, + 0x479618ef00000000, 0xa939adfd00000000, 0xcc5e114500000000, + 0x06ee4d7600000000, 0x6389f1ce00000000, 0x8d2644dc00000000, + 0xe841f86400000000, 0x51792ff900000000, 0x341e934100000000, + 0xdab1265300000000, 0xbfd69aeb00000000, 0xe9c6f9b300000000, + 0x8ca1450b00000000, 0x620ef01900000000, 0x07694ca100000000, + 0xbe519b3c00000000, 0xdb36278400000000, 0x3599929600000000, + 0x50fe2e2e00000000, 0x99b9542600000000, 0xfcdee89e00000000, + 0x12715d8c00000000, 0x7716e13400000000, 0xce2e36a900000000, + 0xab498a1100000000, 0x45e63f0300000000, 0x208183bb00000000, + 0x7691e0e300000000, 0x13f65c5b00000000, 0xfd59e94900000000, + 0x983e55f100000000, 0x2106826c00000000, 0x44613ed400000000, + 0xaace8bc600000000, 0xcfa9377e00000000, 0x38417fd600000000, + 0x5d26c36e00000000, 0xb389767c00000000, 0xd6eecac400000000, + 0x6fd61d5900000000, 0x0ab1a1e100000000, 0xe41e14f300000000, + 0x8179a84b00000000, 0xd769cb1300000000, 0xb20e77ab00000000, + 0x5ca1c2b900000000, 0x39c67e0100000000, 0x80fea99c00000000, + 0xe599152400000000, 0x0b36a03600000000, 0x6e511c8e00000000, + 0xa716668600000000, 0xc271da3e00000000, 0x2cde6f2c00000000, + 0x49b9d39400000000, 0xf081040900000000, 0x95e6b8b100000000, + 0x7b490da300000000, 0x1e2eb11b00000000, 0x483ed24300000000, + 0x2d596efb00000000, 0xc3f6dbe900000000, 0xa691675100000000, + 0x1fa9b0cc00000000, 0x7ace0c7400000000, 0x9461b96600000000, + 0xf10605de00000000}, + {0x0000000000000000, 0xb029603d00000000, 0x6053c07a00000000, + 0xd07aa04700000000, 0xc0a680f500000000, 0x708fe0c800000000, + 0xa0f5408f00000000, 0x10dc20b200000000, 0xc14b703000000000, + 0x7162100d00000000, 0xa118b04a00000000, 0x1131d07700000000, + 0x01edf0c500000000, 0xb1c490f800000000, 0x61be30bf00000000, + 0xd197508200000000, 0x8297e06000000000, 0x32be805d00000000, + 0xe2c4201a00000000, 0x52ed402700000000, 0x4231609500000000, + 0xf21800a800000000, 0x2262a0ef00000000, 0x924bc0d200000000, + 0x43dc905000000000, 0xf3f5f06d00000000, 0x238f502a00000000, + 0x93a6301700000000, 0x837a10a500000000, 0x3353709800000000, + 0xe329d0df00000000, 0x5300b0e200000000, 0x042fc1c100000000, + 0xb406a1fc00000000, 0x647c01bb00000000, 0xd455618600000000, + 0xc489413400000000, 0x74a0210900000000, 0xa4da814e00000000, + 0x14f3e17300000000, 0xc564b1f100000000, 0x754dd1cc00000000, + 0xa537718b00000000, 0x151e11b600000000, 0x05c2310400000000, + 0xb5eb513900000000, 0x6591f17e00000000, 0xd5b8914300000000, + 0x86b821a100000000, 0x3691419c00000000, 0xe6ebe1db00000000, + 0x56c281e600000000, 0x461ea15400000000, 0xf637c16900000000, + 0x264d612e00000000, 0x9664011300000000, 0x47f3519100000000, + 0xf7da31ac00000000, 0x27a091eb00000000, 0x9789f1d600000000, + 0x8755d16400000000, 0x377cb15900000000, 0xe706111e00000000, + 0x572f712300000000, 0x4958f35800000000, 0xf971936500000000, + 0x290b332200000000, 0x9922531f00000000, 0x89fe73ad00000000, + 0x39d7139000000000, 0xe9adb3d700000000, 0x5984d3ea00000000, + 0x8813836800000000, 0x383ae35500000000, 0xe840431200000000, + 0x5869232f00000000, 0x48b5039d00000000, 0xf89c63a000000000, + 0x28e6c3e700000000, 0x98cfa3da00000000, 0xcbcf133800000000, + 0x7be6730500000000, 0xab9cd34200000000, 0x1bb5b37f00000000, + 0x0b6993cd00000000, 0xbb40f3f000000000, 0x6b3a53b700000000, + 0xdb13338a00000000, 0x0a84630800000000, 0xbaad033500000000, + 0x6ad7a37200000000, 0xdafec34f00000000, 0xca22e3fd00000000, + 0x7a0b83c000000000, 0xaa71238700000000, 0x1a5843ba00000000, + 0x4d77329900000000, 0xfd5e52a400000000, 0x2d24f2e300000000, + 0x9d0d92de00000000, 0x8dd1b26c00000000, 0x3df8d25100000000, + 0xed82721600000000, 0x5dab122b00000000, 0x8c3c42a900000000, + 0x3c15229400000000, 0xec6f82d300000000, 0x5c46e2ee00000000, + 0x4c9ac25c00000000, 0xfcb3a26100000000, 0x2cc9022600000000, + 0x9ce0621b00000000, 0xcfe0d2f900000000, 0x7fc9b2c400000000, + 0xafb3128300000000, 0x1f9a72be00000000, 0x0f46520c00000000, + 0xbf6f323100000000, 0x6f15927600000000, 0xdf3cf24b00000000, + 0x0eaba2c900000000, 0xbe82c2f400000000, 0x6ef862b300000000, + 0xded1028e00000000, 0xce0d223c00000000, 0x7e24420100000000, + 0xae5ee24600000000, 0x1e77827b00000000, 0x92b0e6b100000000, + 0x2299868c00000000, 0xf2e326cb00000000, 0x42ca46f600000000, + 0x5216664400000000, 0xe23f067900000000, 0x3245a63e00000000, + 0x826cc60300000000, 0x53fb968100000000, 0xe3d2f6bc00000000, + 0x33a856fb00000000, 0x838136c600000000, 0x935d167400000000, + 0x2374764900000000, 0xf30ed60e00000000, 0x4327b63300000000, + 0x102706d100000000, 0xa00e66ec00000000, 0x7074c6ab00000000, + 0xc05da69600000000, 0xd081862400000000, 0x60a8e61900000000, + 0xb0d2465e00000000, 0x00fb266300000000, 0xd16c76e100000000, + 0x614516dc00000000, 0xb13fb69b00000000, 0x0116d6a600000000, + 0x11caf61400000000, 0xa1e3962900000000, 0x7199366e00000000, + 0xc1b0565300000000, 0x969f277000000000, 0x26b6474d00000000, + 0xf6cce70a00000000, 0x46e5873700000000, 0x5639a78500000000, + 0xe610c7b800000000, 0x366a67ff00000000, 0x864307c200000000, + 0x57d4574000000000, 0xe7fd377d00000000, 0x3787973a00000000, + 0x87aef70700000000, 0x9772d7b500000000, 0x275bb78800000000, + 0xf72117cf00000000, 0x470877f200000000, 0x1408c71000000000, + 0xa421a72d00000000, 0x745b076a00000000, 0xc472675700000000, + 0xd4ae47e500000000, 0x648727d800000000, 0xb4fd879f00000000, + 0x04d4e7a200000000, 0xd543b72000000000, 0x656ad71d00000000, + 0xb510775a00000000, 0x0539176700000000, 0x15e537d500000000, + 0xa5cc57e800000000, 0x75b6f7af00000000, 0xc59f979200000000, + 0xdbe815e900000000, 0x6bc175d400000000, 0xbbbbd59300000000, + 0x0b92b5ae00000000, 0x1b4e951c00000000, 0xab67f52100000000, + 0x7b1d556600000000, 0xcb34355b00000000, 0x1aa365d900000000, + 0xaa8a05e400000000, 0x7af0a5a300000000, 0xcad9c59e00000000, + 0xda05e52c00000000, 0x6a2c851100000000, 0xba56255600000000, + 0x0a7f456b00000000, 0x597ff58900000000, 0xe95695b400000000, + 0x392c35f300000000, 0x890555ce00000000, 0x99d9757c00000000, + 0x29f0154100000000, 0xf98ab50600000000, 0x49a3d53b00000000, + 0x983485b900000000, 0x281de58400000000, 0xf86745c300000000, + 0x484e25fe00000000, 0x5892054c00000000, 0xe8bb657100000000, + 0x38c1c53600000000, 0x88e8a50b00000000, 0xdfc7d42800000000, + 0x6feeb41500000000, 0xbf94145200000000, 0x0fbd746f00000000, + 0x1f6154dd00000000, 0xaf4834e000000000, 0x7f3294a700000000, + 0xcf1bf49a00000000, 0x1e8ca41800000000, 0xaea5c42500000000, + 0x7edf646200000000, 0xcef6045f00000000, 0xde2a24ed00000000, + 0x6e0344d000000000, 0xbe79e49700000000, 0x0e5084aa00000000, + 0x5d50344800000000, 0xed79547500000000, 0x3d03f43200000000, + 0x8d2a940f00000000, 0x9df6b4bd00000000, 0x2ddfd48000000000, + 0xfda574c700000000, 0x4d8c14fa00000000, 0x9c1b447800000000, + 0x2c32244500000000, 0xfc48840200000000, 0x4c61e43f00000000, + 0x5cbdc48d00000000, 0xec94a4b000000000, 0x3cee04f700000000, + 0x8cc764ca00000000}, + {0x0000000000000000, 0xa5d35ccb00000000, 0x0ba1c84d00000000, + 0xae72948600000000, 0x1642919b00000000, 0xb391cd5000000000, + 0x1de359d600000000, 0xb830051d00000000, 0x6d8253ec00000000, + 0xc8510f2700000000, 0x66239ba100000000, 0xc3f0c76a00000000, + 0x7bc0c27700000000, 0xde139ebc00000000, 0x70610a3a00000000, + 0xd5b256f100000000, 0x9b02d60300000000, 0x3ed18ac800000000, + 0x90a31e4e00000000, 0x3570428500000000, 0x8d40479800000000, + 0x28931b5300000000, 0x86e18fd500000000, 0x2332d31e00000000, + 0xf68085ef00000000, 0x5353d92400000000, 0xfd214da200000000, + 0x58f2116900000000, 0xe0c2147400000000, 0x451148bf00000000, + 0xeb63dc3900000000, 0x4eb080f200000000, 0x3605ac0700000000, + 0x93d6f0cc00000000, 0x3da4644a00000000, 0x9877388100000000, + 0x20473d9c00000000, 0x8594615700000000, 0x2be6f5d100000000, + 0x8e35a91a00000000, 0x5b87ffeb00000000, 0xfe54a32000000000, + 0x502637a600000000, 0xf5f56b6d00000000, 0x4dc56e7000000000, + 0xe81632bb00000000, 0x4664a63d00000000, 0xe3b7faf600000000, + 0xad077a0400000000, 0x08d426cf00000000, 0xa6a6b24900000000, + 0x0375ee8200000000, 0xbb45eb9f00000000, 0x1e96b75400000000, + 0xb0e423d200000000, 0x15377f1900000000, 0xc08529e800000000, + 0x6556752300000000, 0xcb24e1a500000000, 0x6ef7bd6e00000000, + 0xd6c7b87300000000, 0x7314e4b800000000, 0xdd66703e00000000, + 0x78b52cf500000000, 0x6c0a580f00000000, 0xc9d904c400000000, + 0x67ab904200000000, 0xc278cc8900000000, 0x7a48c99400000000, + 0xdf9b955f00000000, 0x71e901d900000000, 0xd43a5d1200000000, + 0x01880be300000000, 0xa45b572800000000, 0x0a29c3ae00000000, + 0xaffa9f6500000000, 0x17ca9a7800000000, 0xb219c6b300000000, + 0x1c6b523500000000, 0xb9b80efe00000000, 0xf7088e0c00000000, + 0x52dbd2c700000000, 0xfca9464100000000, 0x597a1a8a00000000, + 0xe14a1f9700000000, 0x4499435c00000000, 0xeaebd7da00000000, + 0x4f388b1100000000, 0x9a8adde000000000, 0x3f59812b00000000, + 0x912b15ad00000000, 0x34f8496600000000, 0x8cc84c7b00000000, + 0x291b10b000000000, 0x8769843600000000, 0x22bad8fd00000000, + 0x5a0ff40800000000, 0xffdca8c300000000, 0x51ae3c4500000000, + 0xf47d608e00000000, 0x4c4d659300000000, 0xe99e395800000000, + 0x47ecadde00000000, 0xe23ff11500000000, 0x378da7e400000000, + 0x925efb2f00000000, 0x3c2c6fa900000000, 0x99ff336200000000, + 0x21cf367f00000000, 0x841c6ab400000000, 0x2a6efe3200000000, + 0x8fbda2f900000000, 0xc10d220b00000000, 0x64de7ec000000000, + 0xcaacea4600000000, 0x6f7fb68d00000000, 0xd74fb39000000000, + 0x729cef5b00000000, 0xdcee7bdd00000000, 0x793d271600000000, + 0xac8f71e700000000, 0x095c2d2c00000000, 0xa72eb9aa00000000, + 0x02fde56100000000, 0xbacde07c00000000, 0x1f1ebcb700000000, + 0xb16c283100000000, 0x14bf74fa00000000, 0xd814b01e00000000, + 0x7dc7ecd500000000, 0xd3b5785300000000, 0x7666249800000000, + 0xce56218500000000, 0x6b857d4e00000000, 0xc5f7e9c800000000, + 0x6024b50300000000, 0xb596e3f200000000, 0x1045bf3900000000, + 0xbe372bbf00000000, 0x1be4777400000000, 0xa3d4726900000000, + 0x06072ea200000000, 0xa875ba2400000000, 0x0da6e6ef00000000, + 0x4316661d00000000, 0xe6c53ad600000000, 0x48b7ae5000000000, + 0xed64f29b00000000, 0x5554f78600000000, 0xf087ab4d00000000, + 0x5ef53fcb00000000, 0xfb26630000000000, 0x2e9435f100000000, + 0x8b47693a00000000, 0x2535fdbc00000000, 0x80e6a17700000000, + 0x38d6a46a00000000, 0x9d05f8a100000000, 0x33776c2700000000, + 0x96a430ec00000000, 0xee111c1900000000, 0x4bc240d200000000, + 0xe5b0d45400000000, 0x4063889f00000000, 0xf8538d8200000000, + 0x5d80d14900000000, 0xf3f245cf00000000, 0x5621190400000000, + 0x83934ff500000000, 0x2640133e00000000, 0x883287b800000000, + 0x2de1db7300000000, 0x95d1de6e00000000, 0x300282a500000000, + 0x9e70162300000000, 0x3ba34ae800000000, 0x7513ca1a00000000, + 0xd0c096d100000000, 0x7eb2025700000000, 0xdb615e9c00000000, + 0x63515b8100000000, 0xc682074a00000000, 0x68f093cc00000000, + 0xcd23cf0700000000, 0x189199f600000000, 0xbd42c53d00000000, + 0x133051bb00000000, 0xb6e30d7000000000, 0x0ed3086d00000000, + 0xab0054a600000000, 0x0572c02000000000, 0xa0a19ceb00000000, + 0xb41ee81100000000, 0x11cdb4da00000000, 0xbfbf205c00000000, + 0x1a6c7c9700000000, 0xa25c798a00000000, 0x078f254100000000, + 0xa9fdb1c700000000, 0x0c2eed0c00000000, 0xd99cbbfd00000000, + 0x7c4fe73600000000, 0xd23d73b000000000, 0x77ee2f7b00000000, + 0xcfde2a6600000000, 0x6a0d76ad00000000, 0xc47fe22b00000000, + 0x61acbee000000000, 0x2f1c3e1200000000, 0x8acf62d900000000, + 0x24bdf65f00000000, 0x816eaa9400000000, 0x395eaf8900000000, + 0x9c8df34200000000, 0x32ff67c400000000, 0x972c3b0f00000000, + 0x429e6dfe00000000, 0xe74d313500000000, 0x493fa5b300000000, + 0xececf97800000000, 0x54dcfc6500000000, 0xf10fa0ae00000000, + 0x5f7d342800000000, 0xfaae68e300000000, 0x821b441600000000, + 0x27c818dd00000000, 0x89ba8c5b00000000, 0x2c69d09000000000, + 0x9459d58d00000000, 0x318a894600000000, 0x9ff81dc000000000, + 0x3a2b410b00000000, 0xef9917fa00000000, 0x4a4a4b3100000000, + 0xe438dfb700000000, 0x41eb837c00000000, 0xf9db866100000000, + 0x5c08daaa00000000, 0xf27a4e2c00000000, 0x57a912e700000000, + 0x1919921500000000, 0xbccacede00000000, 0x12b85a5800000000, + 0xb76b069300000000, 0x0f5b038e00000000, 0xaa885f4500000000, + 0x04facbc300000000, 0xa129970800000000, 0x749bc1f900000000, + 0xd1489d3200000000, 0x7f3a09b400000000, 0xdae9557f00000000, + 0x62d9506200000000, 0xc70a0ca900000000, 0x6978982f00000000, + 0xccabc4e400000000}, + {0x0000000000000000, 0xb40b77a600000000, 0x29119f9700000000, + 0x9d1ae83100000000, 0x13244ff400000000, 0xa72f385200000000, + 0x3a35d06300000000, 0x8e3ea7c500000000, 0x674eef3300000000, + 0xd345989500000000, 0x4e5f70a400000000, 0xfa54070200000000, + 0x746aa0c700000000, 0xc061d76100000000, 0x5d7b3f5000000000, + 0xe97048f600000000, 0xce9cde6700000000, 0x7a97a9c100000000, + 0xe78d41f000000000, 0x5386365600000000, 0xddb8919300000000, + 0x69b3e63500000000, 0xf4a90e0400000000, 0x40a279a200000000, + 0xa9d2315400000000, 0x1dd946f200000000, 0x80c3aec300000000, + 0x34c8d96500000000, 0xbaf67ea000000000, 0x0efd090600000000, + 0x93e7e13700000000, 0x27ec969100000000, 0x9c39bdcf00000000, + 0x2832ca6900000000, 0xb528225800000000, 0x012355fe00000000, + 0x8f1df23b00000000, 0x3b16859d00000000, 0xa60c6dac00000000, + 0x12071a0a00000000, 0xfb7752fc00000000, 0x4f7c255a00000000, + 0xd266cd6b00000000, 0x666dbacd00000000, 0xe8531d0800000000, + 0x5c586aae00000000, 0xc142829f00000000, 0x7549f53900000000, + 0x52a563a800000000, 0xe6ae140e00000000, 0x7bb4fc3f00000000, + 0xcfbf8b9900000000, 0x41812c5c00000000, 0xf58a5bfa00000000, + 0x6890b3cb00000000, 0xdc9bc46d00000000, 0x35eb8c9b00000000, + 0x81e0fb3d00000000, 0x1cfa130c00000000, 0xa8f164aa00000000, + 0x26cfc36f00000000, 0x92c4b4c900000000, 0x0fde5cf800000000, + 0xbbd52b5e00000000, 0x79750b4400000000, 0xcd7e7ce200000000, + 0x506494d300000000, 0xe46fe37500000000, 0x6a5144b000000000, + 0xde5a331600000000, 0x4340db2700000000, 0xf74bac8100000000, + 0x1e3be47700000000, 0xaa3093d100000000, 0x372a7be000000000, + 0x83210c4600000000, 0x0d1fab8300000000, 0xb914dc2500000000, + 0x240e341400000000, 0x900543b200000000, 0xb7e9d52300000000, + 0x03e2a28500000000, 0x9ef84ab400000000, 0x2af33d1200000000, + 0xa4cd9ad700000000, 0x10c6ed7100000000, 0x8ddc054000000000, + 0x39d772e600000000, 0xd0a73a1000000000, 0x64ac4db600000000, + 0xf9b6a58700000000, 0x4dbdd22100000000, 0xc38375e400000000, + 0x7788024200000000, 0xea92ea7300000000, 0x5e999dd500000000, + 0xe54cb68b00000000, 0x5147c12d00000000, 0xcc5d291c00000000, + 0x78565eba00000000, 0xf668f97f00000000, 0x42638ed900000000, + 0xdf7966e800000000, 0x6b72114e00000000, 0x820259b800000000, + 0x36092e1e00000000, 0xab13c62f00000000, 0x1f18b18900000000, + 0x9126164c00000000, 0x252d61ea00000000, 0xb83789db00000000, + 0x0c3cfe7d00000000, 0x2bd068ec00000000, 0x9fdb1f4a00000000, + 0x02c1f77b00000000, 0xb6ca80dd00000000, 0x38f4271800000000, + 0x8cff50be00000000, 0x11e5b88f00000000, 0xa5eecf2900000000, + 0x4c9e87df00000000, 0xf895f07900000000, 0x658f184800000000, + 0xd1846fee00000000, 0x5fbac82b00000000, 0xebb1bf8d00000000, + 0x76ab57bc00000000, 0xc2a0201a00000000, 0xf2ea168800000000, + 0x46e1612e00000000, 0xdbfb891f00000000, 0x6ff0feb900000000, + 0xe1ce597c00000000, 0x55c52eda00000000, 0xc8dfc6eb00000000, + 0x7cd4b14d00000000, 0x95a4f9bb00000000, 0x21af8e1d00000000, + 0xbcb5662c00000000, 0x08be118a00000000, 0x8680b64f00000000, + 0x328bc1e900000000, 0xaf9129d800000000, 0x1b9a5e7e00000000, + 0x3c76c8ef00000000, 0x887dbf4900000000, 0x1567577800000000, + 0xa16c20de00000000, 0x2f52871b00000000, 0x9b59f0bd00000000, + 0x0643188c00000000, 0xb2486f2a00000000, 0x5b3827dc00000000, + 0xef33507a00000000, 0x7229b84b00000000, 0xc622cfed00000000, + 0x481c682800000000, 0xfc171f8e00000000, 0x610df7bf00000000, + 0xd506801900000000, 0x6ed3ab4700000000, 0xdad8dce100000000, + 0x47c234d000000000, 0xf3c9437600000000, 0x7df7e4b300000000, + 0xc9fc931500000000, 0x54e67b2400000000, 0xe0ed0c8200000000, + 0x099d447400000000, 0xbd9633d200000000, 0x208cdbe300000000, + 0x9487ac4500000000, 0x1ab90b8000000000, 0xaeb27c2600000000, + 0x33a8941700000000, 0x87a3e3b100000000, 0xa04f752000000000, + 0x1444028600000000, 0x895eeab700000000, 0x3d559d1100000000, + 0xb36b3ad400000000, 0x07604d7200000000, 0x9a7aa54300000000, + 0x2e71d2e500000000, 0xc7019a1300000000, 0x730aedb500000000, + 0xee10058400000000, 0x5a1b722200000000, 0xd425d5e700000000, + 0x602ea24100000000, 0xfd344a7000000000, 0x493f3dd600000000, + 0x8b9f1dcc00000000, 0x3f946a6a00000000, 0xa28e825b00000000, + 0x1685f5fd00000000, 0x98bb523800000000, 0x2cb0259e00000000, + 0xb1aacdaf00000000, 0x05a1ba0900000000, 0xecd1f2ff00000000, + 0x58da855900000000, 0xc5c06d6800000000, 0x71cb1ace00000000, + 0xfff5bd0b00000000, 0x4bfecaad00000000, 0xd6e4229c00000000, + 0x62ef553a00000000, 0x4503c3ab00000000, 0xf108b40d00000000, + 0x6c125c3c00000000, 0xd8192b9a00000000, 0x56278c5f00000000, + 0xe22cfbf900000000, 0x7f3613c800000000, 0xcb3d646e00000000, + 0x224d2c9800000000, 0x96465b3e00000000, 0x0b5cb30f00000000, + 0xbf57c4a900000000, 0x3169636c00000000, 0x856214ca00000000, + 0x1878fcfb00000000, 0xac738b5d00000000, 0x17a6a00300000000, + 0xa3add7a500000000, 0x3eb73f9400000000, 0x8abc483200000000, + 0x0482eff700000000, 0xb089985100000000, 0x2d93706000000000, + 0x999807c600000000, 0x70e84f3000000000, 0xc4e3389600000000, + 0x59f9d0a700000000, 0xedf2a70100000000, 0x63cc00c400000000, + 0xd7c7776200000000, 0x4add9f5300000000, 0xfed6e8f500000000, + 0xd93a7e6400000000, 0x6d3109c200000000, 0xf02be1f300000000, + 0x4420965500000000, 0xca1e319000000000, 0x7e15463600000000, + 0xe30fae0700000000, 0x5704d9a100000000, 0xbe74915700000000, + 0x0a7fe6f100000000, 0x97650ec000000000, 0x236e796600000000, + 0xad50dea300000000, 0x195ba90500000000, 0x8441413400000000, + 0x304a369200000000}, + {0x0000000000000000, 0x9e00aacc00000000, 0x7d07254200000000, + 0xe3078f8e00000000, 0xfa0e4a8400000000, 0x640ee04800000000, + 0x87096fc600000000, 0x1909c50a00000000, 0xb51be5d300000000, + 0x2b1b4f1f00000000, 0xc81cc09100000000, 0x561c6a5d00000000, + 0x4f15af5700000000, 0xd115059b00000000, 0x32128a1500000000, + 0xac1220d900000000, 0x2b31bb7c00000000, 0xb53111b000000000, + 0x56369e3e00000000, 0xc83634f200000000, 0xd13ff1f800000000, + 0x4f3f5b3400000000, 0xac38d4ba00000000, 0x32387e7600000000, + 0x9e2a5eaf00000000, 0x002af46300000000, 0xe32d7bed00000000, + 0x7d2dd12100000000, 0x6424142b00000000, 0xfa24bee700000000, + 0x1923316900000000, 0x87239ba500000000, 0x566276f900000000, + 0xc862dc3500000000, 0x2b6553bb00000000, 0xb565f97700000000, + 0xac6c3c7d00000000, 0x326c96b100000000, 0xd16b193f00000000, + 0x4f6bb3f300000000, 0xe379932a00000000, 0x7d7939e600000000, + 0x9e7eb66800000000, 0x007e1ca400000000, 0x1977d9ae00000000, + 0x8777736200000000, 0x6470fcec00000000, 0xfa70562000000000, + 0x7d53cd8500000000, 0xe353674900000000, 0x0054e8c700000000, + 0x9e54420b00000000, 0x875d870100000000, 0x195d2dcd00000000, + 0xfa5aa24300000000, 0x645a088f00000000, 0xc848285600000000, + 0x5648829a00000000, 0xb54f0d1400000000, 0x2b4fa7d800000000, + 0x324662d200000000, 0xac46c81e00000000, 0x4f41479000000000, + 0xd141ed5c00000000, 0xedc29d2900000000, 0x73c237e500000000, + 0x90c5b86b00000000, 0x0ec512a700000000, 0x17ccd7ad00000000, + 0x89cc7d6100000000, 0x6acbf2ef00000000, 0xf4cb582300000000, + 0x58d978fa00000000, 0xc6d9d23600000000, 0x25de5db800000000, + 0xbbdef77400000000, 0xa2d7327e00000000, 0x3cd798b200000000, + 0xdfd0173c00000000, 0x41d0bdf000000000, 0xc6f3265500000000, + 0x58f38c9900000000, 0xbbf4031700000000, 0x25f4a9db00000000, + 0x3cfd6cd100000000, 0xa2fdc61d00000000, 0x41fa499300000000, + 0xdffae35f00000000, 0x73e8c38600000000, 0xede8694a00000000, + 0x0eefe6c400000000, 0x90ef4c0800000000, 0x89e6890200000000, + 0x17e623ce00000000, 0xf4e1ac4000000000, 0x6ae1068c00000000, + 0xbba0ebd000000000, 0x25a0411c00000000, 0xc6a7ce9200000000, + 0x58a7645e00000000, 0x41aea15400000000, 0xdfae0b9800000000, + 0x3ca9841600000000, 0xa2a92eda00000000, 0x0ebb0e0300000000, + 0x90bba4cf00000000, 0x73bc2b4100000000, 0xedbc818d00000000, + 0xf4b5448700000000, 0x6ab5ee4b00000000, 0x89b261c500000000, + 0x17b2cb0900000000, 0x909150ac00000000, 0x0e91fa6000000000, + 0xed9675ee00000000, 0x7396df2200000000, 0x6a9f1a2800000000, + 0xf49fb0e400000000, 0x17983f6a00000000, 0x899895a600000000, + 0x258ab57f00000000, 0xbb8a1fb300000000, 0x588d903d00000000, + 0xc68d3af100000000, 0xdf84fffb00000000, 0x4184553700000000, + 0xa283dab900000000, 0x3c83707500000000, 0xda853b5300000000, + 0x4485919f00000000, 0xa7821e1100000000, 0x3982b4dd00000000, + 0x208b71d700000000, 0xbe8bdb1b00000000, 0x5d8c549500000000, + 0xc38cfe5900000000, 0x6f9ede8000000000, 0xf19e744c00000000, + 0x1299fbc200000000, 0x8c99510e00000000, 0x9590940400000000, + 0x0b903ec800000000, 0xe897b14600000000, 0x76971b8a00000000, + 0xf1b4802f00000000, 0x6fb42ae300000000, 0x8cb3a56d00000000, + 0x12b30fa100000000, 0x0bbacaab00000000, 0x95ba606700000000, + 0x76bdefe900000000, 0xe8bd452500000000, 0x44af65fc00000000, + 0xdaafcf3000000000, 0x39a840be00000000, 0xa7a8ea7200000000, + 0xbea12f7800000000, 0x20a185b400000000, 0xc3a60a3a00000000, + 0x5da6a0f600000000, 0x8ce74daa00000000, 0x12e7e76600000000, + 0xf1e068e800000000, 0x6fe0c22400000000, 0x76e9072e00000000, + 0xe8e9ade200000000, 0x0bee226c00000000, 0x95ee88a000000000, + 0x39fca87900000000, 0xa7fc02b500000000, 0x44fb8d3b00000000, + 0xdafb27f700000000, 0xc3f2e2fd00000000, 0x5df2483100000000, + 0xbef5c7bf00000000, 0x20f56d7300000000, 0xa7d6f6d600000000, + 0x39d65c1a00000000, 0xdad1d39400000000, 0x44d1795800000000, + 0x5dd8bc5200000000, 0xc3d8169e00000000, 0x20df991000000000, + 0xbedf33dc00000000, 0x12cd130500000000, 0x8ccdb9c900000000, + 0x6fca364700000000, 0xf1ca9c8b00000000, 0xe8c3598100000000, + 0x76c3f34d00000000, 0x95c47cc300000000, 0x0bc4d60f00000000, + 0x3747a67a00000000, 0xa9470cb600000000, 0x4a40833800000000, + 0xd44029f400000000, 0xcd49ecfe00000000, 0x5349463200000000, + 0xb04ec9bc00000000, 0x2e4e637000000000, 0x825c43a900000000, + 0x1c5ce96500000000, 0xff5b66eb00000000, 0x615bcc2700000000, + 0x7852092d00000000, 0xe652a3e100000000, 0x05552c6f00000000, + 0x9b5586a300000000, 0x1c761d0600000000, 0x8276b7ca00000000, + 0x6171384400000000, 0xff71928800000000, 0xe678578200000000, + 0x7878fd4e00000000, 0x9b7f72c000000000, 0x057fd80c00000000, + 0xa96df8d500000000, 0x376d521900000000, 0xd46add9700000000, + 0x4a6a775b00000000, 0x5363b25100000000, 0xcd63189d00000000, + 0x2e64971300000000, 0xb0643ddf00000000, 0x6125d08300000000, + 0xff257a4f00000000, 0x1c22f5c100000000, 0x82225f0d00000000, + 0x9b2b9a0700000000, 0x052b30cb00000000, 0xe62cbf4500000000, + 0x782c158900000000, 0xd43e355000000000, 0x4a3e9f9c00000000, + 0xa939101200000000, 0x3739bade00000000, 0x2e307fd400000000, + 0xb030d51800000000, 0x53375a9600000000, 0xcd37f05a00000000, + 0x4a146bff00000000, 0xd414c13300000000, 0x37134ebd00000000, + 0xa913e47100000000, 0xb01a217b00000000, 0x2e1a8bb700000000, + 0xcd1d043900000000, 0x531daef500000000, 0xff0f8e2c00000000, + 0x610f24e000000000, 0x8208ab6e00000000, 0x1c0801a200000000, + 0x0501c4a800000000, 0x9b016e6400000000, 0x7806e1ea00000000, + 0xe6064b2600000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, + 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, + 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, + 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, + 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70, + 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, + 0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5, + 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, + 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086, + 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4, + 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, + 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, + 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d, + 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, + 0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, + 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, + 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, + 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028, + 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, + 0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, + 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec, + 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde, + 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817, + 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, + 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, + 0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e, + 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7, + 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, + 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4, + 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, + 0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, + 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, + 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52, + 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f, + 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, + 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, + 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675, + 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647, + 0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d, + 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, + 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, + 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc, + 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, + 0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, + 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138, + 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a, + 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, + 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, + 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, + 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d, + 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194, + 0xde0506f1}, + {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, + 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f, + 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a, + 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, + 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8, + 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, + 0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e, + 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, + 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84, + 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7, + 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, + 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, + 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0, + 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b, + 0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, + 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, + 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, + 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f, + 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, + 0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, + 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98, + 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873, + 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e, + 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, + 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, + 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7, + 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732, + 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, + 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0, + 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, + 0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26, + 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, + 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc, + 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef, + 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, + 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, + 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8, + 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43, + 0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e, + 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, + 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, + 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07, + 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, + 0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, + 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0, + 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b, + 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576, + 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, + 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, + 0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f, + 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, + 0xbe9834ed}, + {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, + 0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49, + 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, + 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, + 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859, + 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, + 0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620, + 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, + 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae, + 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2, + 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, + 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, + 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05, + 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40, + 0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, + 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, + 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, + 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d, + 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, + 0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, + 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af, + 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea, + 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74, + 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, + 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, + 0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a, + 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, + 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, + 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a, + 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, + 0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290, + 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, + 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed, + 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0, + 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, + 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, + 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0, + 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5, + 0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, + 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, + 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, + 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e, + 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, + 0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, + 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec, + 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9, + 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66, + 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, + 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, + 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4, + 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, + 0x9324fd72}, + {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07, + 0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79, + 0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7, + 0x911dbf90, 0x6410b71d, 0xf220b06a, 0x4871b9f3, 0xde41be84, + 0x7dd4da1a, 0xebe4dd6d, 0x51b5d4f4, 0xc785d383, 0x56986c13, + 0xc0a86b64, 0x7af962fd, 0xecc9658a, 0x4f5c0114, 0xd96c0663, + 0x633d0ffa, 0xf50d088d, 0xc8206e3b, 0x5e10694c, 0xe44160d5, + 0x727167a2, 0xd1e4033c, 0x47d4044b, 0xfd850dd2, 0x6bb50aa5, + 0xfaa8b535, 0x6c98b242, 0xd6c9bbdb, 0x40f9bcac, 0xe36cd832, + 0x755cdf45, 0xcf0dd6dc, 0x593dd1ab, 0xac30d926, 0x3a00de51, + 0x8051d7c8, 0x1661d0bf, 0xb5f4b421, 0x23c4b356, 0x9995bacf, + 0x0fa5bdb8, 0x9eb80228, 0x0888055f, 0xb2d90cc6, 0x24e90bb1, + 0x877c6f2f, 0x114c6858, 0xab1d61c1, 0x3d2d66b6, 0x9041dc76, + 0x0671db01, 0xbc20d298, 0x2a10d5ef, 0x8985b171, 0x1fb5b606, + 0xa5e4bf9f, 0x33d4b8e8, 0xa2c90778, 0x34f9000f, 0x8ea80996, + 0x18980ee1, 0xbb0d6a7f, 0x2d3d6d08, 0x976c6491, 0x015c63e6, + 0xf4516b6b, 0x62616c1c, 0xd8306585, 0x4e0062f2, 0xed95066c, + 0x7ba5011b, 0xc1f40882, 0x57c40ff5, 0xc6d9b065, 0x50e9b712, + 0xeab8be8b, 0x7c88b9fc, 0xdf1ddd62, 0x492dda15, 0xf37cd38c, + 0x654cd4fb, 0x5861b24d, 0xce51b53a, 0x7400bca3, 0xe230bbd4, + 0x41a5df4a, 0xd795d83d, 0x6dc4d1a4, 0xfbf4d6d3, 0x6ae96943, + 0xfcd96e34, 0x468867ad, 0xd0b860da, 0x732d0444, 0xe51d0333, + 0x5f4c0aaa, 0xc97c0ddd, 0x3c710550, 0xaa410227, 0x10100bbe, + 0x86200cc9, 0x25b56857, 0xb3856f20, 0x09d466b9, 0x9fe461ce, + 0x0ef9de5e, 0x98c9d929, 0x2298d0b0, 0xb4a8d7c7, 0x173db359, + 0x810db42e, 0x3b5cbdb7, 0xad6cbac0, 0x2083b8ed, 0xb6b3bf9a, + 0x0ce2b603, 0x9ad2b174, 0x3947d5ea, 0xaf77d29d, 0x1526db04, + 0x8316dc73, 0x120b63e3, 0x843b6494, 0x3e6a6d0d, 0xa85a6a7a, + 0x0bcf0ee4, 0x9dff0993, 0x27ae000a, 0xb19e077d, 0x44930ff0, + 0xd2a30887, 0x68f2011e, 0xfec20669, 0x5d5762f7, 0xcb676580, + 0x71366c19, 0xe7066b6e, 0x761bd4fe, 0xe02bd389, 0x5a7ada10, + 0xcc4add67, 0x6fdfb9f9, 0xf9efbe8e, 0x43beb717, 0xd58eb060, + 0xe8a3d6d6, 0x7e93d1a1, 0xc4c2d838, 0x52f2df4f, 0xf167bbd1, + 0x6757bca6, 0xdd06b53f, 0x4b36b248, 0xda2b0dd8, 0x4c1b0aaf, + 0xf64a0336, 0x607a0441, 0xc3ef60df, 0x55df67a8, 0xef8e6e31, + 0x79be6946, 0x8cb361cb, 0x1a8366bc, 0xa0d26f25, 0x36e26852, + 0x95770ccc, 0x03470bbb, 0xb9160222, 0x2f260555, 0xbe3bbac5, + 0x280bbdb2, 0x925ab42b, 0x046ab35c, 0xa7ffd7c2, 0x31cfd0b5, + 0x8b9ed92c, 0x1daede5b, 0xb0c2649b, 0x26f263ec, 0x9ca36a75, + 0x0a936d02, 0xa906099c, 0x3f360eeb, 0x85670772, 0x13570005, + 0x824abf95, 0x147ab8e2, 0xae2bb17b, 0x381bb60c, 0x9b8ed292, + 0x0dbed5e5, 0xb7efdc7c, 0x21dfdb0b, 0xd4d2d386, 0x42e2d4f1, + 0xf8b3dd68, 0x6e83da1f, 0xcd16be81, 0x5b26b9f6, 0xe177b06f, + 0x7747b718, 0xe65a0888, 0x706a0fff, 0xca3b0666, 0x5c0b0111, + 0xff9e658f, 0x69ae62f8, 0xd3ff6b61, 0x45cf6c16, 0x78e20aa0, + 0xeed20dd7, 0x5483044e, 0xc2b30339, 0x612667a7, 0xf71660d0, + 0x4d476949, 0xdb776e3e, 0x4a6ad1ae, 0xdc5ad6d9, 0x660bdf40, + 0xf03bd837, 0x53aebca9, 0xc59ebbde, 0x7fcfb247, 0xe9ffb530, + 0x1cf2bdbd, 0x8ac2baca, 0x3093b353, 0xa6a3b424, 0x0536d0ba, + 0x9306d7cd, 0x2957de54, 0xbf67d923, 0x2e7a66b3, 0xb84a61c4, + 0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a, + 0x8def022d}, + {0x00000000, 0x41311b19, 0x82623632, 0xc3532d2b, 0x04c56c64, + 0x45f4777d, 0x86a75a56, 0xc796414f, 0x088ad9c8, 0x49bbc2d1, + 0x8ae8effa, 0xcbd9f4e3, 0x0c4fb5ac, 0x4d7eaeb5, 0x8e2d839e, + 0xcf1c9887, 0x5112c24a, 0x1023d953, 0xd370f478, 0x9241ef61, + 0x55d7ae2e, 0x14e6b537, 0xd7b5981c, 0x96848305, 0x59981b82, + 0x18a9009b, 0xdbfa2db0, 0x9acb36a9, 0x5d5d77e6, 0x1c6c6cff, + 0xdf3f41d4, 0x9e0e5acd, 0xa2248495, 0xe3159f8c, 0x2046b2a7, + 0x6177a9be, 0xa6e1e8f1, 0xe7d0f3e8, 0x2483dec3, 0x65b2c5da, + 0xaaae5d5d, 0xeb9f4644, 0x28cc6b6f, 0x69fd7076, 0xae6b3139, + 0xef5a2a20, 0x2c09070b, 0x6d381c12, 0xf33646df, 0xb2075dc6, + 0x715470ed, 0x30656bf4, 0xf7f32abb, 0xb6c231a2, 0x75911c89, + 0x34a00790, 0xfbbc9f17, 0xba8d840e, 0x79dea925, 0x38efb23c, + 0xff79f373, 0xbe48e86a, 0x7d1bc541, 0x3c2ade58, 0x054f79f0, + 0x447e62e9, 0x872d4fc2, 0xc61c54db, 0x018a1594, 0x40bb0e8d, + 0x83e823a6, 0xc2d938bf, 0x0dc5a038, 0x4cf4bb21, 0x8fa7960a, + 0xce968d13, 0x0900cc5c, 0x4831d745, 0x8b62fa6e, 0xca53e177, + 0x545dbbba, 0x156ca0a3, 0xd63f8d88, 0x970e9691, 0x5098d7de, + 0x11a9ccc7, 0xd2fae1ec, 0x93cbfaf5, 0x5cd76272, 0x1de6796b, + 0xdeb55440, 0x9f844f59, 0x58120e16, 0x1923150f, 0xda703824, + 0x9b41233d, 0xa76bfd65, 0xe65ae67c, 0x2509cb57, 0x6438d04e, + 0xa3ae9101, 0xe29f8a18, 0x21cca733, 0x60fdbc2a, 0xafe124ad, + 0xeed03fb4, 0x2d83129f, 0x6cb20986, 0xab2448c9, 0xea1553d0, + 0x29467efb, 0x687765e2, 0xf6793f2f, 0xb7482436, 0x741b091d, + 0x352a1204, 0xf2bc534b, 0xb38d4852, 0x70de6579, 0x31ef7e60, + 0xfef3e6e7, 0xbfc2fdfe, 0x7c91d0d5, 0x3da0cbcc, 0xfa368a83, + 0xbb07919a, 0x7854bcb1, 0x3965a7a8, 0x4b98833b, 0x0aa99822, + 0xc9fab509, 0x88cbae10, 0x4f5def5f, 0x0e6cf446, 0xcd3fd96d, + 0x8c0ec274, 0x43125af3, 0x022341ea, 0xc1706cc1, 0x804177d8, + 0x47d73697, 0x06e62d8e, 0xc5b500a5, 0x84841bbc, 0x1a8a4171, + 0x5bbb5a68, 0x98e87743, 0xd9d96c5a, 0x1e4f2d15, 0x5f7e360c, + 0x9c2d1b27, 0xdd1c003e, 0x120098b9, 0x533183a0, 0x9062ae8b, + 0xd153b592, 0x16c5f4dd, 0x57f4efc4, 0x94a7c2ef, 0xd596d9f6, + 0xe9bc07ae, 0xa88d1cb7, 0x6bde319c, 0x2aef2a85, 0xed796bca, + 0xac4870d3, 0x6f1b5df8, 0x2e2a46e1, 0xe136de66, 0xa007c57f, + 0x6354e854, 0x2265f34d, 0xe5f3b202, 0xa4c2a91b, 0x67918430, + 0x26a09f29, 0xb8aec5e4, 0xf99fdefd, 0x3accf3d6, 0x7bfde8cf, + 0xbc6ba980, 0xfd5ab299, 0x3e099fb2, 0x7f3884ab, 0xb0241c2c, + 0xf1150735, 0x32462a1e, 0x73773107, 0xb4e17048, 0xf5d06b51, + 0x3683467a, 0x77b25d63, 0x4ed7facb, 0x0fe6e1d2, 0xccb5ccf9, + 0x8d84d7e0, 0x4a1296af, 0x0b238db6, 0xc870a09d, 0x8941bb84, + 0x465d2303, 0x076c381a, 0xc43f1531, 0x850e0e28, 0x42984f67, + 0x03a9547e, 0xc0fa7955, 0x81cb624c, 0x1fc53881, 0x5ef42398, + 0x9da70eb3, 0xdc9615aa, 0x1b0054e5, 0x5a314ffc, 0x996262d7, + 0xd85379ce, 0x174fe149, 0x567efa50, 0x952dd77b, 0xd41ccc62, + 0x138a8d2d, 0x52bb9634, 0x91e8bb1f, 0xd0d9a006, 0xecf37e5e, + 0xadc26547, 0x6e91486c, 0x2fa05375, 0xe836123a, 0xa9070923, + 0x6a542408, 0x2b653f11, 0xe479a796, 0xa548bc8f, 0x661b91a4, + 0x272a8abd, 0xe0bccbf2, 0xa18dd0eb, 0x62defdc0, 0x23efe6d9, + 0xbde1bc14, 0xfcd0a70d, 0x3f838a26, 0x7eb2913f, 0xb924d070, + 0xf815cb69, 0x3b46e642, 0x7a77fd5b, 0xb56b65dc, 0xf45a7ec5, + 0x370953ee, 0x763848f7, 0xb1ae09b8, 0xf09f12a1, 0x33cc3f8a, + 0x72fd2493}, + {0x00000000, 0x376ac201, 0x6ed48403, 0x59be4602, 0xdca80907, + 0xebc2cb06, 0xb27c8d04, 0x85164f05, 0xb851130e, 0x8f3bd10f, + 0xd685970d, 0xe1ef550c, 0x64f91a09, 0x5393d808, 0x0a2d9e0a, + 0x3d475c0b, 0x70a3261c, 0x47c9e41d, 0x1e77a21f, 0x291d601e, + 0xac0b2f1b, 0x9b61ed1a, 0xc2dfab18, 0xf5b56919, 0xc8f23512, + 0xff98f713, 0xa626b111, 0x914c7310, 0x145a3c15, 0x2330fe14, + 0x7a8eb816, 0x4de47a17, 0xe0464d38, 0xd72c8f39, 0x8e92c93b, + 0xb9f80b3a, 0x3cee443f, 0x0b84863e, 0x523ac03c, 0x6550023d, + 0x58175e36, 0x6f7d9c37, 0x36c3da35, 0x01a91834, 0x84bf5731, + 0xb3d59530, 0xea6bd332, 0xdd011133, 0x90e56b24, 0xa78fa925, + 0xfe31ef27, 0xc95b2d26, 0x4c4d6223, 0x7b27a022, 0x2299e620, + 0x15f32421, 0x28b4782a, 0x1fdeba2b, 0x4660fc29, 0x710a3e28, + 0xf41c712d, 0xc376b32c, 0x9ac8f52e, 0xada2372f, 0xc08d9a70, + 0xf7e75871, 0xae591e73, 0x9933dc72, 0x1c259377, 0x2b4f5176, + 0x72f11774, 0x459bd575, 0x78dc897e, 0x4fb64b7f, 0x16080d7d, + 0x2162cf7c, 0xa4748079, 0x931e4278, 0xcaa0047a, 0xfdcac67b, + 0xb02ebc6c, 0x87447e6d, 0xdefa386f, 0xe990fa6e, 0x6c86b56b, + 0x5bec776a, 0x02523168, 0x3538f369, 0x087faf62, 0x3f156d63, + 0x66ab2b61, 0x51c1e960, 0xd4d7a665, 0xe3bd6464, 0xba032266, + 0x8d69e067, 0x20cbd748, 0x17a11549, 0x4e1f534b, 0x7975914a, + 0xfc63de4f, 0xcb091c4e, 0x92b75a4c, 0xa5dd984d, 0x989ac446, + 0xaff00647, 0xf64e4045, 0xc1248244, 0x4432cd41, 0x73580f40, + 0x2ae64942, 0x1d8c8b43, 0x5068f154, 0x67023355, 0x3ebc7557, + 0x09d6b756, 0x8cc0f853, 0xbbaa3a52, 0xe2147c50, 0xd57ebe51, + 0xe839e25a, 0xdf53205b, 0x86ed6659, 0xb187a458, 0x3491eb5d, + 0x03fb295c, 0x5a456f5e, 0x6d2fad5f, 0x801b35e1, 0xb771f7e0, + 0xeecfb1e2, 0xd9a573e3, 0x5cb33ce6, 0x6bd9fee7, 0x3267b8e5, + 0x050d7ae4, 0x384a26ef, 0x0f20e4ee, 0x569ea2ec, 0x61f460ed, + 0xe4e22fe8, 0xd388ede9, 0x8a36abeb, 0xbd5c69ea, 0xf0b813fd, + 0xc7d2d1fc, 0x9e6c97fe, 0xa90655ff, 0x2c101afa, 0x1b7ad8fb, + 0x42c49ef9, 0x75ae5cf8, 0x48e900f3, 0x7f83c2f2, 0x263d84f0, + 0x115746f1, 0x944109f4, 0xa32bcbf5, 0xfa958df7, 0xcdff4ff6, + 0x605d78d9, 0x5737bad8, 0x0e89fcda, 0x39e33edb, 0xbcf571de, + 0x8b9fb3df, 0xd221f5dd, 0xe54b37dc, 0xd80c6bd7, 0xef66a9d6, + 0xb6d8efd4, 0x81b22dd5, 0x04a462d0, 0x33cea0d1, 0x6a70e6d3, + 0x5d1a24d2, 0x10fe5ec5, 0x27949cc4, 0x7e2adac6, 0x494018c7, + 0xcc5657c2, 0xfb3c95c3, 0xa282d3c1, 0x95e811c0, 0xa8af4dcb, + 0x9fc58fca, 0xc67bc9c8, 0xf1110bc9, 0x740744cc, 0x436d86cd, + 0x1ad3c0cf, 0x2db902ce, 0x4096af91, 0x77fc6d90, 0x2e422b92, + 0x1928e993, 0x9c3ea696, 0xab546497, 0xf2ea2295, 0xc580e094, + 0xf8c7bc9f, 0xcfad7e9e, 0x9613389c, 0xa179fa9d, 0x246fb598, + 0x13057799, 0x4abb319b, 0x7dd1f39a, 0x3035898d, 0x075f4b8c, + 0x5ee10d8e, 0x698bcf8f, 0xec9d808a, 0xdbf7428b, 0x82490489, + 0xb523c688, 0x88649a83, 0xbf0e5882, 0xe6b01e80, 0xd1dadc81, + 0x54cc9384, 0x63a65185, 0x3a181787, 0x0d72d586, 0xa0d0e2a9, + 0x97ba20a8, 0xce0466aa, 0xf96ea4ab, 0x7c78ebae, 0x4b1229af, + 0x12ac6fad, 0x25c6adac, 0x1881f1a7, 0x2feb33a6, 0x765575a4, + 0x413fb7a5, 0xc429f8a0, 0xf3433aa1, 0xaafd7ca3, 0x9d97bea2, + 0xd073c4b5, 0xe71906b4, 0xbea740b6, 0x89cd82b7, 0x0cdbcdb2, + 0x3bb10fb3, 0x620f49b1, 0x55658bb0, 0x6822d7bb, 0x5f4815ba, + 0x06f653b8, 0x319c91b9, 0xb48adebc, 0x83e01cbd, 0xda5e5abf, + 0xed3498be}, + {0x00000000, 0x6567bcb8, 0x8bc809aa, 0xeeafb512, 0x5797628f, + 0x32f0de37, 0xdc5f6b25, 0xb938d79d, 0xef28b4c5, 0x8a4f087d, + 0x64e0bd6f, 0x018701d7, 0xb8bfd64a, 0xddd86af2, 0x3377dfe0, + 0x56106358, 0x9f571950, 0xfa30a5e8, 0x149f10fa, 0x71f8ac42, + 0xc8c07bdf, 0xada7c767, 0x43087275, 0x266fcecd, 0x707fad95, + 0x1518112d, 0xfbb7a43f, 0x9ed01887, 0x27e8cf1a, 0x428f73a2, + 0xac20c6b0, 0xc9477a08, 0x3eaf32a0, 0x5bc88e18, 0xb5673b0a, + 0xd00087b2, 0x6938502f, 0x0c5fec97, 0xe2f05985, 0x8797e53d, + 0xd1878665, 0xb4e03add, 0x5a4f8fcf, 0x3f283377, 0x8610e4ea, + 0xe3775852, 0x0dd8ed40, 0x68bf51f8, 0xa1f82bf0, 0xc49f9748, + 0x2a30225a, 0x4f579ee2, 0xf66f497f, 0x9308f5c7, 0x7da740d5, + 0x18c0fc6d, 0x4ed09f35, 0x2bb7238d, 0xc518969f, 0xa07f2a27, + 0x1947fdba, 0x7c204102, 0x928ff410, 0xf7e848a8, 0x3d58149b, + 0x583fa823, 0xb6901d31, 0xd3f7a189, 0x6acf7614, 0x0fa8caac, + 0xe1077fbe, 0x8460c306, 0xd270a05e, 0xb7171ce6, 0x59b8a9f4, + 0x3cdf154c, 0x85e7c2d1, 0xe0807e69, 0x0e2fcb7b, 0x6b4877c3, + 0xa20f0dcb, 0xc768b173, 0x29c70461, 0x4ca0b8d9, 0xf5986f44, + 0x90ffd3fc, 0x7e5066ee, 0x1b37da56, 0x4d27b90e, 0x284005b6, + 0xc6efb0a4, 0xa3880c1c, 0x1ab0db81, 0x7fd76739, 0x9178d22b, + 0xf41f6e93, 0x03f7263b, 0x66909a83, 0x883f2f91, 0xed589329, + 0x546044b4, 0x3107f80c, 0xdfa84d1e, 0xbacff1a6, 0xecdf92fe, + 0x89b82e46, 0x67179b54, 0x027027ec, 0xbb48f071, 0xde2f4cc9, + 0x3080f9db, 0x55e74563, 0x9ca03f6b, 0xf9c783d3, 0x176836c1, + 0x720f8a79, 0xcb375de4, 0xae50e15c, 0x40ff544e, 0x2598e8f6, + 0x73888bae, 0x16ef3716, 0xf8408204, 0x9d273ebc, 0x241fe921, + 0x41785599, 0xafd7e08b, 0xcab05c33, 0x3bb659ed, 0x5ed1e555, + 0xb07e5047, 0xd519ecff, 0x6c213b62, 0x094687da, 0xe7e932c8, + 0x828e8e70, 0xd49eed28, 0xb1f95190, 0x5f56e482, 0x3a31583a, + 0x83098fa7, 0xe66e331f, 0x08c1860d, 0x6da63ab5, 0xa4e140bd, + 0xc186fc05, 0x2f294917, 0x4a4ef5af, 0xf3762232, 0x96119e8a, + 0x78be2b98, 0x1dd99720, 0x4bc9f478, 0x2eae48c0, 0xc001fdd2, + 0xa566416a, 0x1c5e96f7, 0x79392a4f, 0x97969f5d, 0xf2f123e5, + 0x05196b4d, 0x607ed7f5, 0x8ed162e7, 0xebb6de5f, 0x528e09c2, + 0x37e9b57a, 0xd9460068, 0xbc21bcd0, 0xea31df88, 0x8f566330, + 0x61f9d622, 0x049e6a9a, 0xbda6bd07, 0xd8c101bf, 0x366eb4ad, + 0x53090815, 0x9a4e721d, 0xff29cea5, 0x11867bb7, 0x74e1c70f, + 0xcdd91092, 0xa8beac2a, 0x46111938, 0x2376a580, 0x7566c6d8, + 0x10017a60, 0xfeaecf72, 0x9bc973ca, 0x22f1a457, 0x479618ef, + 0xa939adfd, 0xcc5e1145, 0x06ee4d76, 0x6389f1ce, 0x8d2644dc, + 0xe841f864, 0x51792ff9, 0x341e9341, 0xdab12653, 0xbfd69aeb, + 0xe9c6f9b3, 0x8ca1450b, 0x620ef019, 0x07694ca1, 0xbe519b3c, + 0xdb362784, 0x35999296, 0x50fe2e2e, 0x99b95426, 0xfcdee89e, + 0x12715d8c, 0x7716e134, 0xce2e36a9, 0xab498a11, 0x45e63f03, + 0x208183bb, 0x7691e0e3, 0x13f65c5b, 0xfd59e949, 0x983e55f1, + 0x2106826c, 0x44613ed4, 0xaace8bc6, 0xcfa9377e, 0x38417fd6, + 0x5d26c36e, 0xb389767c, 0xd6eecac4, 0x6fd61d59, 0x0ab1a1e1, + 0xe41e14f3, 0x8179a84b, 0xd769cb13, 0xb20e77ab, 0x5ca1c2b9, + 0x39c67e01, 0x80fea99c, 0xe5991524, 0x0b36a036, 0x6e511c8e, + 0xa7166686, 0xc271da3e, 0x2cde6f2c, 0x49b9d394, 0xf0810409, + 0x95e6b8b1, 0x7b490da3, 0x1e2eb11b, 0x483ed243, 0x2d596efb, + 0xc3f6dbe9, 0xa6916751, 0x1fa9b0cc, 0x7ace0c74, 0x9461b966, + 0xf10605de}}; + +#endif + +#endif + +#if N == 2 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87, + 0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede, + 0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab, + 0x8eea673a, 0xe6273e9e, 0x484faf0f, 0x61871bfd, 0xcfef8a6c, + 0x32167219, 0x9c7ee388, 0xb5b6577a, 0x1bdec6eb, 0x9534a1d1, + 0x3b5c3040, 0x129484b2, 0xbcfc1523, 0x4105ed56, 0xef6d7cc7, + 0xc6a5c835, 0x68cd59a4, 0x173f7b7d, 0xb957eaec, 0x909f5e1e, + 0x3ef7cf8f, 0xc30e37fa, 0x6d66a66b, 0x44ae1299, 0xeac68308, + 0x642ce432, 0xca4475a3, 0xe38cc151, 0x4de450c0, 0xb01da8b5, + 0x1e753924, 0x37bd8dd6, 0x99d51c47, 0xf11845e3, 0x5f70d472, + 0x76b86080, 0xd8d0f111, 0x25290964, 0x8b4198f5, 0xa2892c07, + 0x0ce1bd96, 0x820bdaac, 0x2c634b3d, 0x05abffcf, 0xabc36e5e, + 0x563a962b, 0xf85207ba, 0xd19ab348, 0x7ff222d9, 0x2e7ef6fa, + 0x8016676b, 0xa9ded399, 0x07b64208, 0xfa4fba7d, 0x54272bec, + 0x7def9f1e, 0xd3870e8f, 0x5d6d69b5, 0xf305f824, 0xdacd4cd6, + 0x74a5dd47, 0x895c2532, 0x2734b4a3, 0x0efc0051, 0xa09491c0, + 0xc859c864, 0x663159f5, 0x4ff9ed07, 0xe1917c96, 0x1c6884e3, + 0xb2001572, 0x9bc8a180, 0x35a03011, 0xbb4a572b, 0x1522c6ba, + 0x3cea7248, 0x9282e3d9, 0x6f7b1bac, 0xc1138a3d, 0xe8db3ecf, + 0x46b3af5e, 0x39418d87, 0x97291c16, 0xbee1a8e4, 0x10893975, + 0xed70c100, 0x43185091, 0x6ad0e463, 0xc4b875f2, 0x4a5212c8, + 0xe43a8359, 0xcdf237ab, 0x639aa63a, 0x9e635e4f, 0x300bcfde, + 0x19c37b2c, 0xb7abeabd, 0xdf66b319, 0x710e2288, 0x58c6967a, + 0xf6ae07eb, 0x0b57ff9e, 0xa53f6e0f, 0x8cf7dafd, 0x229f4b6c, + 0xac752c56, 0x021dbdc7, 0x2bd50935, 0x85bd98a4, 0x784460d1, + 0xd62cf140, 0xffe445b2, 0x518cd423, 0x5cfdedf4, 0xf2957c65, + 0xdb5dc897, 0x75355906, 0x88cca173, 0x26a430e2, 0x0f6c8410, + 0xa1041581, 0x2fee72bb, 0x8186e32a, 0xa84e57d8, 0x0626c649, + 0xfbdf3e3c, 0x55b7afad, 0x7c7f1b5f, 0xd2178ace, 0xbadad36a, + 0x14b242fb, 0x3d7af609, 0x93126798, 0x6eeb9fed, 0xc0830e7c, + 0xe94bba8e, 0x47232b1f, 0xc9c94c25, 0x67a1ddb4, 0x4e696946, + 0xe001f8d7, 0x1df800a2, 0xb3909133, 0x9a5825c1, 0x3430b450, + 0x4bc29689, 0xe5aa0718, 0xcc62b3ea, 0x620a227b, 0x9ff3da0e, + 0x319b4b9f, 0x1853ff6d, 0xb63b6efc, 0x38d109c6, 0x96b99857, + 0xbf712ca5, 0x1119bd34, 0xece04541, 0x4288d4d0, 0x6b406022, + 0xc528f1b3, 0xade5a817, 0x038d3986, 0x2a458d74, 0x842d1ce5, + 0x79d4e490, 0xd7bc7501, 0xfe74c1f3, 0x501c5062, 0xdef63758, + 0x709ea6c9, 0x5956123b, 0xf73e83aa, 0x0ac77bdf, 0xa4afea4e, + 0x8d675ebc, 0x230fcf2d, 0x72831b0e, 0xdceb8a9f, 0xf5233e6d, + 0x5b4baffc, 0xa6b25789, 0x08dac618, 0x211272ea, 0x8f7ae37b, + 0x01908441, 0xaff815d0, 0x8630a122, 0x285830b3, 0xd5a1c8c6, + 0x7bc95957, 0x5201eda5, 0xfc697c34, 0x94a42590, 0x3accb401, + 0x130400f3, 0xbd6c9162, 0x40956917, 0xeefdf886, 0xc7354c74, + 0x695ddde5, 0xe7b7badf, 0x49df2b4e, 0x60179fbc, 0xce7f0e2d, + 0x3386f658, 0x9dee67c9, 0xb426d33b, 0x1a4e42aa, 0x65bc6073, + 0xcbd4f1e2, 0xe21c4510, 0x4c74d481, 0xb18d2cf4, 0x1fe5bd65, + 0x362d0997, 0x98459806, 0x16afff3c, 0xb8c76ead, 0x910fda5f, + 0x3f674bce, 0xc29eb3bb, 0x6cf6222a, 0x453e96d8, 0xeb560749, + 0x839b5eed, 0x2df3cf7c, 0x043b7b8e, 0xaa53ea1f, 0x57aa126a, + 0xf9c283fb, 0xd00a3709, 0x7e62a698, 0xf088c1a2, 0x5ee05033, + 0x7728e4c1, 0xd9407550, 0x24b98d25, 0x8ad11cb4, 0xa319a846, + 0x0d7139d7}, + {0x00000000, 0xb9fbdbe8, 0xa886b191, 0x117d6a79, 0x8a7c6563, + 0x3387be8b, 0x22fad4f2, 0x9b010f1a, 0xcf89cc87, 0x7672176f, + 0x670f7d16, 0xdef4a6fe, 0x45f5a9e4, 0xfc0e720c, 0xed731875, + 0x5488c39d, 0x44629f4f, 0xfd9944a7, 0xece42ede, 0x551ff536, + 0xce1efa2c, 0x77e521c4, 0x66984bbd, 0xdf639055, 0x8beb53c8, + 0x32108820, 0x236de259, 0x9a9639b1, 0x019736ab, 0xb86ced43, + 0xa911873a, 0x10ea5cd2, 0x88c53e9e, 0x313ee576, 0x20438f0f, + 0x99b854e7, 0x02b95bfd, 0xbb428015, 0xaa3fea6c, 0x13c43184, + 0x474cf219, 0xfeb729f1, 0xefca4388, 0x56319860, 0xcd30977a, + 0x74cb4c92, 0x65b626eb, 0xdc4dfd03, 0xcca7a1d1, 0x755c7a39, + 0x64211040, 0xdddacba8, 0x46dbc4b2, 0xff201f5a, 0xee5d7523, + 0x57a6aecb, 0x032e6d56, 0xbad5b6be, 0xaba8dcc7, 0x1253072f, + 0x89520835, 0x30a9d3dd, 0x21d4b9a4, 0x982f624c, 0xcafb7b7d, + 0x7300a095, 0x627dcaec, 0xdb861104, 0x40871e1e, 0xf97cc5f6, + 0xe801af8f, 0x51fa7467, 0x0572b7fa, 0xbc896c12, 0xadf4066b, + 0x140fdd83, 0x8f0ed299, 0x36f50971, 0x27886308, 0x9e73b8e0, + 0x8e99e432, 0x37623fda, 0x261f55a3, 0x9fe48e4b, 0x04e58151, + 0xbd1e5ab9, 0xac6330c0, 0x1598eb28, 0x411028b5, 0xf8ebf35d, + 0xe9969924, 0x506d42cc, 0xcb6c4dd6, 0x7297963e, 0x63eafc47, + 0xda1127af, 0x423e45e3, 0xfbc59e0b, 0xeab8f472, 0x53432f9a, + 0xc8422080, 0x71b9fb68, 0x60c49111, 0xd93f4af9, 0x8db78964, + 0x344c528c, 0x253138f5, 0x9ccae31d, 0x07cbec07, 0xbe3037ef, + 0xaf4d5d96, 0x16b6867e, 0x065cdaac, 0xbfa70144, 0xaeda6b3d, + 0x1721b0d5, 0x8c20bfcf, 0x35db6427, 0x24a60e5e, 0x9d5dd5b6, + 0xc9d5162b, 0x702ecdc3, 0x6153a7ba, 0xd8a87c52, 0x43a97348, + 0xfa52a8a0, 0xeb2fc2d9, 0x52d41931, 0x4e87f0bb, 0xf77c2b53, + 0xe601412a, 0x5ffa9ac2, 0xc4fb95d8, 0x7d004e30, 0x6c7d2449, + 0xd586ffa1, 0x810e3c3c, 0x38f5e7d4, 0x29888dad, 0x90735645, + 0x0b72595f, 0xb28982b7, 0xa3f4e8ce, 0x1a0f3326, 0x0ae56ff4, + 0xb31eb41c, 0xa263de65, 0x1b98058d, 0x80990a97, 0x3962d17f, + 0x281fbb06, 0x91e460ee, 0xc56ca373, 0x7c97789b, 0x6dea12e2, + 0xd411c90a, 0x4f10c610, 0xf6eb1df8, 0xe7967781, 0x5e6dac69, + 0xc642ce25, 0x7fb915cd, 0x6ec47fb4, 0xd73fa45c, 0x4c3eab46, + 0xf5c570ae, 0xe4b81ad7, 0x5d43c13f, 0x09cb02a2, 0xb030d94a, + 0xa14db333, 0x18b668db, 0x83b767c1, 0x3a4cbc29, 0x2b31d650, + 0x92ca0db8, 0x8220516a, 0x3bdb8a82, 0x2aa6e0fb, 0x935d3b13, + 0x085c3409, 0xb1a7efe1, 0xa0da8598, 0x19215e70, 0x4da99ded, + 0xf4524605, 0xe52f2c7c, 0x5cd4f794, 0xc7d5f88e, 0x7e2e2366, + 0x6f53491f, 0xd6a892f7, 0x847c8bc6, 0x3d87502e, 0x2cfa3a57, + 0x9501e1bf, 0x0e00eea5, 0xb7fb354d, 0xa6865f34, 0x1f7d84dc, + 0x4bf54741, 0xf20e9ca9, 0xe373f6d0, 0x5a882d38, 0xc1892222, + 0x7872f9ca, 0x690f93b3, 0xd0f4485b, 0xc01e1489, 0x79e5cf61, + 0x6898a518, 0xd1637ef0, 0x4a6271ea, 0xf399aa02, 0xe2e4c07b, + 0x5b1f1b93, 0x0f97d80e, 0xb66c03e6, 0xa711699f, 0x1eeab277, + 0x85ebbd6d, 0x3c106685, 0x2d6d0cfc, 0x9496d714, 0x0cb9b558, + 0xb5426eb0, 0xa43f04c9, 0x1dc4df21, 0x86c5d03b, 0x3f3e0bd3, + 0x2e4361aa, 0x97b8ba42, 0xc33079df, 0x7acba237, 0x6bb6c84e, + 0xd24d13a6, 0x494c1cbc, 0xf0b7c754, 0xe1caad2d, 0x583176c5, + 0x48db2a17, 0xf120f1ff, 0xe05d9b86, 0x59a6406e, 0xc2a74f74, + 0x7b5c949c, 0x6a21fee5, 0xd3da250d, 0x8752e690, 0x3ea93d78, + 0x2fd45701, 0x962f8ce9, 0x0d2e83f3, 0xb4d5581b, 0xa5a83262, + 0x1c53e98a}, + {0x00000000, 0x9d0fe176, 0xe16ec4ad, 0x7c6125db, 0x19ac8f1b, + 0x84a36e6d, 0xf8c24bb6, 0x65cdaac0, 0x33591e36, 0xae56ff40, + 0xd237da9b, 0x4f383bed, 0x2af5912d, 0xb7fa705b, 0xcb9b5580, + 0x5694b4f6, 0x66b23c6c, 0xfbbddd1a, 0x87dcf8c1, 0x1ad319b7, + 0x7f1eb377, 0xe2115201, 0x9e7077da, 0x037f96ac, 0x55eb225a, + 0xc8e4c32c, 0xb485e6f7, 0x298a0781, 0x4c47ad41, 0xd1484c37, + 0xad2969ec, 0x3026889a, 0xcd6478d8, 0x506b99ae, 0x2c0abc75, + 0xb1055d03, 0xd4c8f7c3, 0x49c716b5, 0x35a6336e, 0xa8a9d218, + 0xfe3d66ee, 0x63328798, 0x1f53a243, 0x825c4335, 0xe791e9f5, + 0x7a9e0883, 0x06ff2d58, 0x9bf0cc2e, 0xabd644b4, 0x36d9a5c2, + 0x4ab88019, 0xd7b7616f, 0xb27acbaf, 0x2f752ad9, 0x53140f02, + 0xce1bee74, 0x988f5a82, 0x0580bbf4, 0x79e19e2f, 0xe4ee7f59, + 0x8123d599, 0x1c2c34ef, 0x604d1134, 0xfd42f042, 0x41b9f7f1, + 0xdcb61687, 0xa0d7335c, 0x3dd8d22a, 0x581578ea, 0xc51a999c, + 0xb97bbc47, 0x24745d31, 0x72e0e9c7, 0xefef08b1, 0x938e2d6a, + 0x0e81cc1c, 0x6b4c66dc, 0xf64387aa, 0x8a22a271, 0x172d4307, + 0x270bcb9d, 0xba042aeb, 0xc6650f30, 0x5b6aee46, 0x3ea74486, + 0xa3a8a5f0, 0xdfc9802b, 0x42c6615d, 0x1452d5ab, 0x895d34dd, + 0xf53c1106, 0x6833f070, 0x0dfe5ab0, 0x90f1bbc6, 0xec909e1d, + 0x719f7f6b, 0x8cdd8f29, 0x11d26e5f, 0x6db34b84, 0xf0bcaaf2, + 0x95710032, 0x087ee144, 0x741fc49f, 0xe91025e9, 0xbf84911f, + 0x228b7069, 0x5eea55b2, 0xc3e5b4c4, 0xa6281e04, 0x3b27ff72, + 0x4746daa9, 0xda493bdf, 0xea6fb345, 0x77605233, 0x0b0177e8, + 0x960e969e, 0xf3c33c5e, 0x6eccdd28, 0x12adf8f3, 0x8fa21985, + 0xd936ad73, 0x44394c05, 0x385869de, 0xa55788a8, 0xc09a2268, + 0x5d95c31e, 0x21f4e6c5, 0xbcfb07b3, 0x8373efe2, 0x1e7c0e94, + 0x621d2b4f, 0xff12ca39, 0x9adf60f9, 0x07d0818f, 0x7bb1a454, + 0xe6be4522, 0xb02af1d4, 0x2d2510a2, 0x51443579, 0xcc4bd40f, + 0xa9867ecf, 0x34899fb9, 0x48e8ba62, 0xd5e75b14, 0xe5c1d38e, + 0x78ce32f8, 0x04af1723, 0x99a0f655, 0xfc6d5c95, 0x6162bde3, + 0x1d039838, 0x800c794e, 0xd698cdb8, 0x4b972cce, 0x37f60915, + 0xaaf9e863, 0xcf3442a3, 0x523ba3d5, 0x2e5a860e, 0xb3556778, + 0x4e17973a, 0xd318764c, 0xaf795397, 0x3276b2e1, 0x57bb1821, + 0xcab4f957, 0xb6d5dc8c, 0x2bda3dfa, 0x7d4e890c, 0xe041687a, + 0x9c204da1, 0x012facd7, 0x64e20617, 0xf9ede761, 0x858cc2ba, + 0x188323cc, 0x28a5ab56, 0xb5aa4a20, 0xc9cb6ffb, 0x54c48e8d, + 0x3109244d, 0xac06c53b, 0xd067e0e0, 0x4d680196, 0x1bfcb560, + 0x86f35416, 0xfa9271cd, 0x679d90bb, 0x02503a7b, 0x9f5fdb0d, + 0xe33efed6, 0x7e311fa0, 0xc2ca1813, 0x5fc5f965, 0x23a4dcbe, + 0xbeab3dc8, 0xdb669708, 0x4669767e, 0x3a0853a5, 0xa707b2d3, + 0xf1930625, 0x6c9ce753, 0x10fdc288, 0x8df223fe, 0xe83f893e, + 0x75306848, 0x09514d93, 0x945eace5, 0xa478247f, 0x3977c509, + 0x4516e0d2, 0xd81901a4, 0xbdd4ab64, 0x20db4a12, 0x5cba6fc9, + 0xc1b58ebf, 0x97213a49, 0x0a2edb3f, 0x764ffee4, 0xeb401f92, + 0x8e8db552, 0x13825424, 0x6fe371ff, 0xf2ec9089, 0x0fae60cb, + 0x92a181bd, 0xeec0a466, 0x73cf4510, 0x1602efd0, 0x8b0d0ea6, + 0xf76c2b7d, 0x6a63ca0b, 0x3cf77efd, 0xa1f89f8b, 0xdd99ba50, + 0x40965b26, 0x255bf1e6, 0xb8541090, 0xc435354b, 0x593ad43d, + 0x691c5ca7, 0xf413bdd1, 0x8872980a, 0x157d797c, 0x70b0d3bc, + 0xedbf32ca, 0x91de1711, 0x0cd1f667, 0x5a454291, 0xc74aa3e7, + 0xbb2b863c, 0x2624674a, 0x43e9cd8a, 0xdee62cfc, 0xa2870927, + 0x3f88e851}, + {0x00000000, 0xdd96d985, 0x605cb54b, 0xbdca6cce, 0xc0b96a96, + 0x1d2fb313, 0xa0e5dfdd, 0x7d730658, 0x5a03d36d, 0x87950ae8, + 0x3a5f6626, 0xe7c9bfa3, 0x9abab9fb, 0x472c607e, 0xfae60cb0, + 0x2770d535, 0xb407a6da, 0x69917f5f, 0xd45b1391, 0x09cdca14, + 0x74becc4c, 0xa92815c9, 0x14e27907, 0xc974a082, 0xee0475b7, + 0x3392ac32, 0x8e58c0fc, 0x53ce1979, 0x2ebd1f21, 0xf32bc6a4, + 0x4ee1aa6a, 0x937773ef, 0xb37e4bf5, 0x6ee89270, 0xd322febe, + 0x0eb4273b, 0x73c72163, 0xae51f8e6, 0x139b9428, 0xce0d4dad, + 0xe97d9898, 0x34eb411d, 0x89212dd3, 0x54b7f456, 0x29c4f20e, + 0xf4522b8b, 0x49984745, 0x940e9ec0, 0x0779ed2f, 0xdaef34aa, + 0x67255864, 0xbab381e1, 0xc7c087b9, 0x1a565e3c, 0xa79c32f2, + 0x7a0aeb77, 0x5d7a3e42, 0x80ece7c7, 0x3d268b09, 0xe0b0528c, + 0x9dc354d4, 0x40558d51, 0xfd9fe19f, 0x2009381a, 0xbd8d91ab, + 0x601b482e, 0xddd124e0, 0x0047fd65, 0x7d34fb3d, 0xa0a222b8, + 0x1d684e76, 0xc0fe97f3, 0xe78e42c6, 0x3a189b43, 0x87d2f78d, + 0x5a442e08, 0x27372850, 0xfaa1f1d5, 0x476b9d1b, 0x9afd449e, + 0x098a3771, 0xd41ceef4, 0x69d6823a, 0xb4405bbf, 0xc9335de7, + 0x14a58462, 0xa96fe8ac, 0x74f93129, 0x5389e41c, 0x8e1f3d99, + 0x33d55157, 0xee4388d2, 0x93308e8a, 0x4ea6570f, 0xf36c3bc1, + 0x2efae244, 0x0ef3da5e, 0xd36503db, 0x6eaf6f15, 0xb339b690, + 0xce4ab0c8, 0x13dc694d, 0xae160583, 0x7380dc06, 0x54f00933, + 0x8966d0b6, 0x34acbc78, 0xe93a65fd, 0x944963a5, 0x49dfba20, + 0xf415d6ee, 0x29830f6b, 0xbaf47c84, 0x6762a501, 0xdaa8c9cf, + 0x073e104a, 0x7a4d1612, 0xa7dbcf97, 0x1a11a359, 0xc7877adc, + 0xe0f7afe9, 0x3d61766c, 0x80ab1aa2, 0x5d3dc327, 0x204ec57f, + 0xfdd81cfa, 0x40127034, 0x9d84a9b1, 0xa06a2517, 0x7dfcfc92, + 0xc036905c, 0x1da049d9, 0x60d34f81, 0xbd459604, 0x008ffaca, + 0xdd19234f, 0xfa69f67a, 0x27ff2fff, 0x9a354331, 0x47a39ab4, + 0x3ad09cec, 0xe7464569, 0x5a8c29a7, 0x871af022, 0x146d83cd, + 0xc9fb5a48, 0x74313686, 0xa9a7ef03, 0xd4d4e95b, 0x094230de, + 0xb4885c10, 0x691e8595, 0x4e6e50a0, 0x93f88925, 0x2e32e5eb, + 0xf3a43c6e, 0x8ed73a36, 0x5341e3b3, 0xee8b8f7d, 0x331d56f8, + 0x13146ee2, 0xce82b767, 0x7348dba9, 0xaede022c, 0xd3ad0474, + 0x0e3bddf1, 0xb3f1b13f, 0x6e6768ba, 0x4917bd8f, 0x9481640a, + 0x294b08c4, 0xf4ddd141, 0x89aed719, 0x54380e9c, 0xe9f26252, + 0x3464bbd7, 0xa713c838, 0x7a8511bd, 0xc74f7d73, 0x1ad9a4f6, + 0x67aaa2ae, 0xba3c7b2b, 0x07f617e5, 0xda60ce60, 0xfd101b55, + 0x2086c2d0, 0x9d4cae1e, 0x40da779b, 0x3da971c3, 0xe03fa846, + 0x5df5c488, 0x80631d0d, 0x1de7b4bc, 0xc0716d39, 0x7dbb01f7, + 0xa02dd872, 0xdd5ede2a, 0x00c807af, 0xbd026b61, 0x6094b2e4, + 0x47e467d1, 0x9a72be54, 0x27b8d29a, 0xfa2e0b1f, 0x875d0d47, + 0x5acbd4c2, 0xe701b80c, 0x3a976189, 0xa9e01266, 0x7476cbe3, + 0xc9bca72d, 0x142a7ea8, 0x695978f0, 0xb4cfa175, 0x0905cdbb, + 0xd493143e, 0xf3e3c10b, 0x2e75188e, 0x93bf7440, 0x4e29adc5, + 0x335aab9d, 0xeecc7218, 0x53061ed6, 0x8e90c753, 0xae99ff49, + 0x730f26cc, 0xcec54a02, 0x13539387, 0x6e2095df, 0xb3b64c5a, + 0x0e7c2094, 0xd3eaf911, 0xf49a2c24, 0x290cf5a1, 0x94c6996f, + 0x495040ea, 0x342346b2, 0xe9b59f37, 0x547ff3f9, 0x89e92a7c, + 0x1a9e5993, 0xc7088016, 0x7ac2ecd8, 0xa754355d, 0xda273305, + 0x07b1ea80, 0xba7b864e, 0x67ed5fcb, 0x409d8afe, 0x9d0b537b, + 0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523, + 0x3dee8ca6}, + {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f, + 0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91, + 0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e, + 0x72949f71, 0x0c18edfc, 0x97bda193, 0xe0237363, 0x7b863f0c, + 0x0f1ed683, 0x94bb9aec, 0xe325481c, 0x78800473, 0x0a149b02, + 0x91b1d76d, 0xe62f059d, 0x7d8a49f2, 0x0912a07d, 0x92b7ec12, + 0xe5293ee2, 0x7e8c728d, 0x1831dbf8, 0x83949797, 0xf40a4567, + 0x6faf0908, 0x1b37e087, 0x8092ace8, 0xf70c7e18, 0x6ca93277, + 0x1e3dad06, 0x8598e169, 0xf2063399, 0x69a37ff6, 0x1d3b9679, + 0x869eda16, 0xf10008e6, 0x6aa54489, 0x14293604, 0x8f8c7a6b, + 0xf812a89b, 0x63b7e4f4, 0x172f0d7b, 0x8c8a4114, 0xfb1493e4, + 0x60b1df8b, 0x122540fa, 0x89800c95, 0xfe1ede65, 0x65bb920a, + 0x11237b85, 0x8a8637ea, 0xfd18e51a, 0x66bda975, 0x3063b7f0, + 0xabc6fb9f, 0xdc58296f, 0x47fd6500, 0x33658c8f, 0xa8c0c0e0, + 0xdf5e1210, 0x44fb5e7f, 0x366fc10e, 0xadca8d61, 0xda545f91, + 0x41f113fe, 0x3569fa71, 0xaeccb61e, 0xd95264ee, 0x42f72881, + 0x3c7b5a0c, 0xa7de1663, 0xd040c493, 0x4be588fc, 0x3f7d6173, + 0xa4d82d1c, 0xd346ffec, 0x48e3b383, 0x3a772cf2, 0xa1d2609d, + 0xd64cb26d, 0x4de9fe02, 0x3971178d, 0xa2d45be2, 0xd54a8912, + 0x4eefc57d, 0x28526c08, 0xb3f72067, 0xc469f297, 0x5fccbef8, + 0x2b545777, 0xb0f11b18, 0xc76fc9e8, 0x5cca8587, 0x2e5e1af6, + 0xb5fb5699, 0xc2658469, 0x59c0c806, 0x2d582189, 0xb6fd6de6, + 0xc163bf16, 0x5ac6f379, 0x244a81f4, 0xbfefcd9b, 0xc8711f6b, + 0x53d45304, 0x274cba8b, 0xbce9f6e4, 0xcb772414, 0x50d2687b, + 0x2246f70a, 0xb9e3bb65, 0xce7d6995, 0x55d825fa, 0x2140cc75, + 0xbae5801a, 0xcd7b52ea, 0x56de1e85, 0x60c76fe0, 0xfb62238f, + 0x8cfcf17f, 0x1759bd10, 0x63c1549f, 0xf86418f0, 0x8ffaca00, + 0x145f866f, 0x66cb191e, 0xfd6e5571, 0x8af08781, 0x1155cbee, + 0x65cd2261, 0xfe686e0e, 0x89f6bcfe, 0x1253f091, 0x6cdf821c, + 0xf77ace73, 0x80e41c83, 0x1b4150ec, 0x6fd9b963, 0xf47cf50c, + 0x83e227fc, 0x18476b93, 0x6ad3f4e2, 0xf176b88d, 0x86e86a7d, + 0x1d4d2612, 0x69d5cf9d, 0xf27083f2, 0x85ee5102, 0x1e4b1d6d, + 0x78f6b418, 0xe353f877, 0x94cd2a87, 0x0f6866e8, 0x7bf08f67, + 0xe055c308, 0x97cb11f8, 0x0c6e5d97, 0x7efac2e6, 0xe55f8e89, + 0x92c15c79, 0x09641016, 0x7dfcf999, 0xe659b5f6, 0x91c76706, + 0x0a622b69, 0x74ee59e4, 0xef4b158b, 0x98d5c77b, 0x03708b14, + 0x77e8629b, 0xec4d2ef4, 0x9bd3fc04, 0x0076b06b, 0x72e22f1a, + 0xe9476375, 0x9ed9b185, 0x057cfdea, 0x71e41465, 0xea41580a, + 0x9ddf8afa, 0x067ac695, 0x50a4d810, 0xcb01947f, 0xbc9f468f, + 0x273a0ae0, 0x53a2e36f, 0xc807af00, 0xbf997df0, 0x243c319f, + 0x56a8aeee, 0xcd0de281, 0xba933071, 0x21367c1e, 0x55ae9591, + 0xce0bd9fe, 0xb9950b0e, 0x22304761, 0x5cbc35ec, 0xc7197983, + 0xb087ab73, 0x2b22e71c, 0x5fba0e93, 0xc41f42fc, 0xb381900c, + 0x2824dc63, 0x5ab04312, 0xc1150f7d, 0xb68bdd8d, 0x2d2e91e2, + 0x59b6786d, 0xc2133402, 0xb58de6f2, 0x2e28aa9d, 0x489503e8, + 0xd3304f87, 0xa4ae9d77, 0x3f0bd118, 0x4b933897, 0xd03674f8, + 0xa7a8a608, 0x3c0dea67, 0x4e997516, 0xd53c3979, 0xa2a2eb89, + 0x3907a7e6, 0x4d9f4e69, 0xd63a0206, 0xa1a4d0f6, 0x3a019c99, + 0x448dee14, 0xdf28a27b, 0xa8b6708b, 0x33133ce4, 0x478bd56b, + 0xdc2e9904, 0xabb04bf4, 0x3015079b, 0x428198ea, 0xd924d485, + 0xaeba0675, 0x351f4a1a, 0x4187a395, 0xda22effa, 0xadbc3d0a, + 0x36197165}, + {0x00000000, 0xc18edfc0, 0x586cb9c1, 0x99e26601, 0xb0d97382, + 0x7157ac42, 0xe8b5ca43, 0x293b1583, 0xbac3e145, 0x7b4d3e85, + 0xe2af5884, 0x23218744, 0x0a1a92c7, 0xcb944d07, 0x52762b06, + 0x93f8f4c6, 0xaef6c4cb, 0x6f781b0b, 0xf69a7d0a, 0x3714a2ca, + 0x1e2fb749, 0xdfa16889, 0x46430e88, 0x87cdd148, 0x1435258e, + 0xd5bbfa4e, 0x4c599c4f, 0x8dd7438f, 0xa4ec560c, 0x656289cc, + 0xfc80efcd, 0x3d0e300d, 0x869c8fd7, 0x47125017, 0xdef03616, + 0x1f7ee9d6, 0x3645fc55, 0xf7cb2395, 0x6e294594, 0xafa79a54, + 0x3c5f6e92, 0xfdd1b152, 0x6433d753, 0xa5bd0893, 0x8c861d10, + 0x4d08c2d0, 0xd4eaa4d1, 0x15647b11, 0x286a4b1c, 0xe9e494dc, + 0x7006f2dd, 0xb1882d1d, 0x98b3389e, 0x593de75e, 0xc0df815f, + 0x01515e9f, 0x92a9aa59, 0x53277599, 0xcac51398, 0x0b4bcc58, + 0x2270d9db, 0xe3fe061b, 0x7a1c601a, 0xbb92bfda, 0xd64819ef, + 0x17c6c62f, 0x8e24a02e, 0x4faa7fee, 0x66916a6d, 0xa71fb5ad, + 0x3efdd3ac, 0xff730c6c, 0x6c8bf8aa, 0xad05276a, 0x34e7416b, + 0xf5699eab, 0xdc528b28, 0x1ddc54e8, 0x843e32e9, 0x45b0ed29, + 0x78bedd24, 0xb93002e4, 0x20d264e5, 0xe15cbb25, 0xc867aea6, + 0x09e97166, 0x900b1767, 0x5185c8a7, 0xc27d3c61, 0x03f3e3a1, + 0x9a1185a0, 0x5b9f5a60, 0x72a44fe3, 0xb32a9023, 0x2ac8f622, + 0xeb4629e2, 0x50d49638, 0x915a49f8, 0x08b82ff9, 0xc936f039, + 0xe00de5ba, 0x21833a7a, 0xb8615c7b, 0x79ef83bb, 0xea17777d, + 0x2b99a8bd, 0xb27bcebc, 0x73f5117c, 0x5ace04ff, 0x9b40db3f, + 0x02a2bd3e, 0xc32c62fe, 0xfe2252f3, 0x3fac8d33, 0xa64eeb32, + 0x67c034f2, 0x4efb2171, 0x8f75feb1, 0x169798b0, 0xd7194770, + 0x44e1b3b6, 0x856f6c76, 0x1c8d0a77, 0xdd03d5b7, 0xf438c034, + 0x35b61ff4, 0xac5479f5, 0x6ddaa635, 0x77e1359f, 0xb66fea5f, + 0x2f8d8c5e, 0xee03539e, 0xc738461d, 0x06b699dd, 0x9f54ffdc, + 0x5eda201c, 0xcd22d4da, 0x0cac0b1a, 0x954e6d1b, 0x54c0b2db, + 0x7dfba758, 0xbc757898, 0x25971e99, 0xe419c159, 0xd917f154, + 0x18992e94, 0x817b4895, 0x40f59755, 0x69ce82d6, 0xa8405d16, + 0x31a23b17, 0xf02ce4d7, 0x63d41011, 0xa25acfd1, 0x3bb8a9d0, + 0xfa367610, 0xd30d6393, 0x1283bc53, 0x8b61da52, 0x4aef0592, + 0xf17dba48, 0x30f36588, 0xa9110389, 0x689fdc49, 0x41a4c9ca, + 0x802a160a, 0x19c8700b, 0xd846afcb, 0x4bbe5b0d, 0x8a3084cd, + 0x13d2e2cc, 0xd25c3d0c, 0xfb67288f, 0x3ae9f74f, 0xa30b914e, + 0x62854e8e, 0x5f8b7e83, 0x9e05a143, 0x07e7c742, 0xc6691882, + 0xef520d01, 0x2edcd2c1, 0xb73eb4c0, 0x76b06b00, 0xe5489fc6, + 0x24c64006, 0xbd242607, 0x7caaf9c7, 0x5591ec44, 0x941f3384, + 0x0dfd5585, 0xcc738a45, 0xa1a92c70, 0x6027f3b0, 0xf9c595b1, + 0x384b4a71, 0x11705ff2, 0xd0fe8032, 0x491ce633, 0x889239f3, + 0x1b6acd35, 0xdae412f5, 0x430674f4, 0x8288ab34, 0xabb3beb7, + 0x6a3d6177, 0xf3df0776, 0x3251d8b6, 0x0f5fe8bb, 0xced1377b, + 0x5733517a, 0x96bd8eba, 0xbf869b39, 0x7e0844f9, 0xe7ea22f8, + 0x2664fd38, 0xb59c09fe, 0x7412d63e, 0xedf0b03f, 0x2c7e6fff, + 0x05457a7c, 0xc4cba5bc, 0x5d29c3bd, 0x9ca71c7d, 0x2735a3a7, + 0xe6bb7c67, 0x7f591a66, 0xbed7c5a6, 0x97ecd025, 0x56620fe5, + 0xcf8069e4, 0x0e0eb624, 0x9df642e2, 0x5c789d22, 0xc59afb23, + 0x041424e3, 0x2d2f3160, 0xeca1eea0, 0x754388a1, 0xb4cd5761, + 0x89c3676c, 0x484db8ac, 0xd1afdead, 0x1021016d, 0x391a14ee, + 0xf894cb2e, 0x6176ad2f, 0xa0f872ef, 0x33008629, 0xf28e59e9, + 0x6b6c3fe8, 0xaae2e028, 0x83d9f5ab, 0x42572a6b, 0xdbb54c6a, + 0x1a3b93aa}, + {0x00000000, 0xefc26b3e, 0x04f5d03d, 0xeb37bb03, 0x09eba07a, + 0xe629cb44, 0x0d1e7047, 0xe2dc1b79, 0x13d740f4, 0xfc152bca, + 0x172290c9, 0xf8e0fbf7, 0x1a3ce08e, 0xf5fe8bb0, 0x1ec930b3, + 0xf10b5b8d, 0x27ae81e8, 0xc86cead6, 0x235b51d5, 0xcc993aeb, + 0x2e452192, 0xc1874aac, 0x2ab0f1af, 0xc5729a91, 0x3479c11c, + 0xdbbbaa22, 0x308c1121, 0xdf4e7a1f, 0x3d926166, 0xd2500a58, + 0x3967b15b, 0xd6a5da65, 0x4f5d03d0, 0xa09f68ee, 0x4ba8d3ed, + 0xa46ab8d3, 0x46b6a3aa, 0xa974c894, 0x42437397, 0xad8118a9, + 0x5c8a4324, 0xb348281a, 0x587f9319, 0xb7bdf827, 0x5561e35e, + 0xbaa38860, 0x51943363, 0xbe56585d, 0x68f38238, 0x8731e906, + 0x6c065205, 0x83c4393b, 0x61182242, 0x8eda497c, 0x65edf27f, + 0x8a2f9941, 0x7b24c2cc, 0x94e6a9f2, 0x7fd112f1, 0x901379cf, + 0x72cf62b6, 0x9d0d0988, 0x763ab28b, 0x99f8d9b5, 0x9eba07a0, + 0x71786c9e, 0x9a4fd79d, 0x758dbca3, 0x9751a7da, 0x7893cce4, + 0x93a477e7, 0x7c661cd9, 0x8d6d4754, 0x62af2c6a, 0x89989769, + 0x665afc57, 0x8486e72e, 0x6b448c10, 0x80733713, 0x6fb15c2d, + 0xb9148648, 0x56d6ed76, 0xbde15675, 0x52233d4b, 0xb0ff2632, + 0x5f3d4d0c, 0xb40af60f, 0x5bc89d31, 0xaac3c6bc, 0x4501ad82, + 0xae361681, 0x41f47dbf, 0xa32866c6, 0x4cea0df8, 0xa7ddb6fb, + 0x481fddc5, 0xd1e70470, 0x3e256f4e, 0xd512d44d, 0x3ad0bf73, + 0xd80ca40a, 0x37cecf34, 0xdcf97437, 0x333b1f09, 0xc2304484, + 0x2df22fba, 0xc6c594b9, 0x2907ff87, 0xcbdbe4fe, 0x24198fc0, + 0xcf2e34c3, 0x20ec5ffd, 0xf6498598, 0x198beea6, 0xf2bc55a5, + 0x1d7e3e9b, 0xffa225e2, 0x10604edc, 0xfb57f5df, 0x14959ee1, + 0xe59ec56c, 0x0a5cae52, 0xe16b1551, 0x0ea97e6f, 0xec756516, + 0x03b70e28, 0xe880b52b, 0x0742de15, 0xe6050901, 0x09c7623f, + 0xe2f0d93c, 0x0d32b202, 0xefeea97b, 0x002cc245, 0xeb1b7946, + 0x04d91278, 0xf5d249f5, 0x1a1022cb, 0xf12799c8, 0x1ee5f2f6, + 0xfc39e98f, 0x13fb82b1, 0xf8cc39b2, 0x170e528c, 0xc1ab88e9, + 0x2e69e3d7, 0xc55e58d4, 0x2a9c33ea, 0xc8402893, 0x278243ad, + 0xccb5f8ae, 0x23779390, 0xd27cc81d, 0x3dbea323, 0xd6891820, + 0x394b731e, 0xdb976867, 0x34550359, 0xdf62b85a, 0x30a0d364, + 0xa9580ad1, 0x469a61ef, 0xadaddaec, 0x426fb1d2, 0xa0b3aaab, + 0x4f71c195, 0xa4467a96, 0x4b8411a8, 0xba8f4a25, 0x554d211b, + 0xbe7a9a18, 0x51b8f126, 0xb364ea5f, 0x5ca68161, 0xb7913a62, + 0x5853515c, 0x8ef68b39, 0x6134e007, 0x8a035b04, 0x65c1303a, + 0x871d2b43, 0x68df407d, 0x83e8fb7e, 0x6c2a9040, 0x9d21cbcd, + 0x72e3a0f3, 0x99d41bf0, 0x761670ce, 0x94ca6bb7, 0x7b080089, + 0x903fbb8a, 0x7ffdd0b4, 0x78bf0ea1, 0x977d659f, 0x7c4ade9c, + 0x9388b5a2, 0x7154aedb, 0x9e96c5e5, 0x75a17ee6, 0x9a6315d8, + 0x6b684e55, 0x84aa256b, 0x6f9d9e68, 0x805ff556, 0x6283ee2f, + 0x8d418511, 0x66763e12, 0x89b4552c, 0x5f118f49, 0xb0d3e477, + 0x5be45f74, 0xb426344a, 0x56fa2f33, 0xb938440d, 0x520fff0e, + 0xbdcd9430, 0x4cc6cfbd, 0xa304a483, 0x48331f80, 0xa7f174be, + 0x452d6fc7, 0xaaef04f9, 0x41d8bffa, 0xae1ad4c4, 0x37e20d71, + 0xd820664f, 0x3317dd4c, 0xdcd5b672, 0x3e09ad0b, 0xd1cbc635, + 0x3afc7d36, 0xd53e1608, 0x24354d85, 0xcbf726bb, 0x20c09db8, + 0xcf02f686, 0x2ddeedff, 0xc21c86c1, 0x292b3dc2, 0xc6e956fc, + 0x104c8c99, 0xff8ee7a7, 0x14b95ca4, 0xfb7b379a, 0x19a72ce3, + 0xf66547dd, 0x1d52fcde, 0xf29097e0, 0x039bcc6d, 0xec59a753, + 0x076e1c50, 0xe8ac776e, 0x0a706c17, 0xe5b20729, 0x0e85bc2a, + 0xe147d714}, + {0x00000000, 0x177b1443, 0x2ef62886, 0x398d3cc5, 0x5dec510c, + 0x4a97454f, 0x731a798a, 0x64616dc9, 0xbbd8a218, 0xaca3b65b, + 0x952e8a9e, 0x82559edd, 0xe634f314, 0xf14fe757, 0xc8c2db92, + 0xdfb9cfd1, 0xacc04271, 0xbbbb5632, 0x82366af7, 0x954d7eb4, + 0xf12c137d, 0xe657073e, 0xdfda3bfb, 0xc8a12fb8, 0x1718e069, + 0x0063f42a, 0x39eec8ef, 0x2e95dcac, 0x4af4b165, 0x5d8fa526, + 0x640299e3, 0x73798da0, 0x82f182a3, 0x958a96e0, 0xac07aa25, + 0xbb7cbe66, 0xdf1dd3af, 0xc866c7ec, 0xf1ebfb29, 0xe690ef6a, + 0x392920bb, 0x2e5234f8, 0x17df083d, 0x00a41c7e, 0x64c571b7, + 0x73be65f4, 0x4a335931, 0x5d484d72, 0x2e31c0d2, 0x394ad491, + 0x00c7e854, 0x17bcfc17, 0x73dd91de, 0x64a6859d, 0x5d2bb958, + 0x4a50ad1b, 0x95e962ca, 0x82927689, 0xbb1f4a4c, 0xac645e0f, + 0xc80533c6, 0xdf7e2785, 0xe6f31b40, 0xf1880f03, 0xde920307, + 0xc9e91744, 0xf0642b81, 0xe71f3fc2, 0x837e520b, 0x94054648, + 0xad887a8d, 0xbaf36ece, 0x654aa11f, 0x7231b55c, 0x4bbc8999, + 0x5cc79dda, 0x38a6f013, 0x2fdde450, 0x1650d895, 0x012bccd6, + 0x72524176, 0x65295535, 0x5ca469f0, 0x4bdf7db3, 0x2fbe107a, + 0x38c50439, 0x014838fc, 0x16332cbf, 0xc98ae36e, 0xdef1f72d, + 0xe77ccbe8, 0xf007dfab, 0x9466b262, 0x831da621, 0xba909ae4, + 0xadeb8ea7, 0x5c6381a4, 0x4b1895e7, 0x7295a922, 0x65eebd61, + 0x018fd0a8, 0x16f4c4eb, 0x2f79f82e, 0x3802ec6d, 0xe7bb23bc, + 0xf0c037ff, 0xc94d0b3a, 0xde361f79, 0xba5772b0, 0xad2c66f3, + 0x94a15a36, 0x83da4e75, 0xf0a3c3d5, 0xe7d8d796, 0xde55eb53, + 0xc92eff10, 0xad4f92d9, 0xba34869a, 0x83b9ba5f, 0x94c2ae1c, + 0x4b7b61cd, 0x5c00758e, 0x658d494b, 0x72f65d08, 0x169730c1, + 0x01ec2482, 0x38611847, 0x2f1a0c04, 0x6655004f, 0x712e140c, + 0x48a328c9, 0x5fd83c8a, 0x3bb95143, 0x2cc24500, 0x154f79c5, + 0x02346d86, 0xdd8da257, 0xcaf6b614, 0xf37b8ad1, 0xe4009e92, + 0x8061f35b, 0x971ae718, 0xae97dbdd, 0xb9eccf9e, 0xca95423e, + 0xddee567d, 0xe4636ab8, 0xf3187efb, 0x97791332, 0x80020771, + 0xb98f3bb4, 0xaef42ff7, 0x714de026, 0x6636f465, 0x5fbbc8a0, + 0x48c0dce3, 0x2ca1b12a, 0x3bdaa569, 0x025799ac, 0x152c8def, + 0xe4a482ec, 0xf3df96af, 0xca52aa6a, 0xdd29be29, 0xb948d3e0, + 0xae33c7a3, 0x97befb66, 0x80c5ef25, 0x5f7c20f4, 0x480734b7, + 0x718a0872, 0x66f11c31, 0x029071f8, 0x15eb65bb, 0x2c66597e, + 0x3b1d4d3d, 0x4864c09d, 0x5f1fd4de, 0x6692e81b, 0x71e9fc58, + 0x15889191, 0x02f385d2, 0x3b7eb917, 0x2c05ad54, 0xf3bc6285, + 0xe4c776c6, 0xdd4a4a03, 0xca315e40, 0xae503389, 0xb92b27ca, + 0x80a61b0f, 0x97dd0f4c, 0xb8c70348, 0xafbc170b, 0x96312bce, + 0x814a3f8d, 0xe52b5244, 0xf2504607, 0xcbdd7ac2, 0xdca66e81, + 0x031fa150, 0x1464b513, 0x2de989d6, 0x3a929d95, 0x5ef3f05c, + 0x4988e41f, 0x7005d8da, 0x677ecc99, 0x14074139, 0x037c557a, + 0x3af169bf, 0x2d8a7dfc, 0x49eb1035, 0x5e900476, 0x671d38b3, + 0x70662cf0, 0xafdfe321, 0xb8a4f762, 0x8129cba7, 0x9652dfe4, + 0xf233b22d, 0xe548a66e, 0xdcc59aab, 0xcbbe8ee8, 0x3a3681eb, + 0x2d4d95a8, 0x14c0a96d, 0x03bbbd2e, 0x67dad0e7, 0x70a1c4a4, + 0x492cf861, 0x5e57ec22, 0x81ee23f3, 0x969537b0, 0xaf180b75, + 0xb8631f36, 0xdc0272ff, 0xcb7966bc, 0xf2f45a79, 0xe58f4e3a, + 0x96f6c39a, 0x818dd7d9, 0xb800eb1c, 0xaf7bff5f, 0xcb1a9296, + 0xdc6186d5, 0xe5ecba10, 0xf297ae53, 0x2d2e6182, 0x3a5575c1, + 0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808, + 0x494f0c4b}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0x43147b1700000000, 0x8628f62e00000000, + 0xc53c8d3900000000, 0x0c51ec5d00000000, 0x4f45974a00000000, + 0x8a791a7300000000, 0xc96d616400000000, 0x18a2d8bb00000000, + 0x5bb6a3ac00000000, 0x9e8a2e9500000000, 0xdd9e558200000000, + 0x14f334e600000000, 0x57e74ff100000000, 0x92dbc2c800000000, + 0xd1cfb9df00000000, 0x7142c0ac00000000, 0x3256bbbb00000000, + 0xf76a368200000000, 0xb47e4d9500000000, 0x7d132cf100000000, + 0x3e0757e600000000, 0xfb3bdadf00000000, 0xb82fa1c800000000, + 0x69e0181700000000, 0x2af4630000000000, 0xefc8ee3900000000, + 0xacdc952e00000000, 0x65b1f44a00000000, 0x26a58f5d00000000, + 0xe399026400000000, 0xa08d797300000000, 0xa382f18200000000, + 0xe0968a9500000000, 0x25aa07ac00000000, 0x66be7cbb00000000, + 0xafd31ddf00000000, 0xecc766c800000000, 0x29fbebf100000000, + 0x6aef90e600000000, 0xbb20293900000000, 0xf834522e00000000, + 0x3d08df1700000000, 0x7e1ca40000000000, 0xb771c56400000000, + 0xf465be7300000000, 0x3159334a00000000, 0x724d485d00000000, + 0xd2c0312e00000000, 0x91d44a3900000000, 0x54e8c70000000000, + 0x17fcbc1700000000, 0xde91dd7300000000, 0x9d85a66400000000, + 0x58b92b5d00000000, 0x1bad504a00000000, 0xca62e99500000000, + 0x8976928200000000, 0x4c4a1fbb00000000, 0x0f5e64ac00000000, + 0xc63305c800000000, 0x85277edf00000000, 0x401bf3e600000000, + 0x030f88f100000000, 0x070392de00000000, 0x4417e9c900000000, + 0x812b64f000000000, 0xc23f1fe700000000, 0x0b527e8300000000, + 0x4846059400000000, 0x8d7a88ad00000000, 0xce6ef3ba00000000, + 0x1fa14a6500000000, 0x5cb5317200000000, 0x9989bc4b00000000, + 0xda9dc75c00000000, 0x13f0a63800000000, 0x50e4dd2f00000000, + 0x95d8501600000000, 0xd6cc2b0100000000, 0x7641527200000000, + 0x3555296500000000, 0xf069a45c00000000, 0xb37ddf4b00000000, + 0x7a10be2f00000000, 0x3904c53800000000, 0xfc38480100000000, + 0xbf2c331600000000, 0x6ee38ac900000000, 0x2df7f1de00000000, + 0xe8cb7ce700000000, 0xabdf07f000000000, 0x62b2669400000000, + 0x21a61d8300000000, 0xe49a90ba00000000, 0xa78eebad00000000, + 0xa481635c00000000, 0xe795184b00000000, 0x22a9957200000000, + 0x61bdee6500000000, 0xa8d08f0100000000, 0xebc4f41600000000, + 0x2ef8792f00000000, 0x6dec023800000000, 0xbc23bbe700000000, + 0xff37c0f000000000, 0x3a0b4dc900000000, 0x791f36de00000000, + 0xb07257ba00000000, 0xf3662cad00000000, 0x365aa19400000000, + 0x754eda8300000000, 0xd5c3a3f000000000, 0x96d7d8e700000000, + 0x53eb55de00000000, 0x10ff2ec900000000, 0xd9924fad00000000, + 0x9a8634ba00000000, 0x5fbab98300000000, 0x1caec29400000000, + 0xcd617b4b00000000, 0x8e75005c00000000, 0x4b498d6500000000, + 0x085df67200000000, 0xc130971600000000, 0x8224ec0100000000, + 0x4718613800000000, 0x040c1a2f00000000, 0x4f00556600000000, + 0x0c142e7100000000, 0xc928a34800000000, 0x8a3cd85f00000000, + 0x4351b93b00000000, 0x0045c22c00000000, 0xc5794f1500000000, + 0x866d340200000000, 0x57a28ddd00000000, 0x14b6f6ca00000000, + 0xd18a7bf300000000, 0x929e00e400000000, 0x5bf3618000000000, + 0x18e71a9700000000, 0xdddb97ae00000000, 0x9ecfecb900000000, + 0x3e4295ca00000000, 0x7d56eedd00000000, 0xb86a63e400000000, + 0xfb7e18f300000000, 0x3213799700000000, 0x7107028000000000, + 0xb43b8fb900000000, 0xf72ff4ae00000000, 0x26e04d7100000000, + 0x65f4366600000000, 0xa0c8bb5f00000000, 0xe3dcc04800000000, + 0x2ab1a12c00000000, 0x69a5da3b00000000, 0xac99570200000000, + 0xef8d2c1500000000, 0xec82a4e400000000, 0xaf96dff300000000, + 0x6aaa52ca00000000, 0x29be29dd00000000, 0xe0d348b900000000, + 0xa3c733ae00000000, 0x66fbbe9700000000, 0x25efc58000000000, + 0xf4207c5f00000000, 0xb734074800000000, 0x72088a7100000000, + 0x311cf16600000000, 0xf871900200000000, 0xbb65eb1500000000, + 0x7e59662c00000000, 0x3d4d1d3b00000000, 0x9dc0644800000000, + 0xded41f5f00000000, 0x1be8926600000000, 0x58fce97100000000, + 0x9191881500000000, 0xd285f30200000000, 0x17b97e3b00000000, + 0x54ad052c00000000, 0x8562bcf300000000, 0xc676c7e400000000, + 0x034a4add00000000, 0x405e31ca00000000, 0x893350ae00000000, + 0xca272bb900000000, 0x0f1ba68000000000, 0x4c0fdd9700000000, + 0x4803c7b800000000, 0x0b17bcaf00000000, 0xce2b319600000000, + 0x8d3f4a8100000000, 0x44522be500000000, 0x074650f200000000, + 0xc27addcb00000000, 0x816ea6dc00000000, 0x50a11f0300000000, + 0x13b5641400000000, 0xd689e92d00000000, 0x959d923a00000000, + 0x5cf0f35e00000000, 0x1fe4884900000000, 0xdad8057000000000, + 0x99cc7e6700000000, 0x3941071400000000, 0x7a557c0300000000, + 0xbf69f13a00000000, 0xfc7d8a2d00000000, 0x3510eb4900000000, + 0x7604905e00000000, 0xb3381d6700000000, 0xf02c667000000000, + 0x21e3dfaf00000000, 0x62f7a4b800000000, 0xa7cb298100000000, + 0xe4df529600000000, 0x2db233f200000000, 0x6ea648e500000000, + 0xab9ac5dc00000000, 0xe88ebecb00000000, 0xeb81363a00000000, + 0xa8954d2d00000000, 0x6da9c01400000000, 0x2ebdbb0300000000, + 0xe7d0da6700000000, 0xa4c4a17000000000, 0x61f82c4900000000, + 0x22ec575e00000000, 0xf323ee8100000000, 0xb037959600000000, + 0x750b18af00000000, 0x361f63b800000000, 0xff7202dc00000000, + 0xbc6679cb00000000, 0x795af4f200000000, 0x3a4e8fe500000000, + 0x9ac3f69600000000, 0xd9d78d8100000000, 0x1ceb00b800000000, + 0x5fff7baf00000000, 0x96921acb00000000, 0xd58661dc00000000, + 0x10baece500000000, 0x53ae97f200000000, 0x82612e2d00000000, + 0xc175553a00000000, 0x0449d80300000000, 0x475da31400000000, + 0x8e30c27000000000, 0xcd24b96700000000, 0x0818345e00000000, + 0x4b0c4f4900000000}, + {0x0000000000000000, 0x3e6bc2ef00000000, 0x3dd0f50400000000, + 0x03bb37eb00000000, 0x7aa0eb0900000000, 0x44cb29e600000000, + 0x47701e0d00000000, 0x791bdce200000000, 0xf440d71300000000, + 0xca2b15fc00000000, 0xc990221700000000, 0xf7fbe0f800000000, + 0x8ee03c1a00000000, 0xb08bfef500000000, 0xb330c91e00000000, + 0x8d5b0bf100000000, 0xe881ae2700000000, 0xd6ea6cc800000000, + 0xd5515b2300000000, 0xeb3a99cc00000000, 0x9221452e00000000, + 0xac4a87c100000000, 0xaff1b02a00000000, 0x919a72c500000000, + 0x1cc1793400000000, 0x22aabbdb00000000, 0x21118c3000000000, + 0x1f7a4edf00000000, 0x6661923d00000000, 0x580a50d200000000, + 0x5bb1673900000000, 0x65daa5d600000000, 0xd0035d4f00000000, + 0xee689fa000000000, 0xedd3a84b00000000, 0xd3b86aa400000000, + 0xaaa3b64600000000, 0x94c874a900000000, 0x9773434200000000, + 0xa91881ad00000000, 0x24438a5c00000000, 0x1a2848b300000000, + 0x19937f5800000000, 0x27f8bdb700000000, 0x5ee3615500000000, + 0x6088a3ba00000000, 0x6333945100000000, 0x5d5856be00000000, + 0x3882f36800000000, 0x06e9318700000000, 0x0552066c00000000, + 0x3b39c48300000000, 0x4222186100000000, 0x7c49da8e00000000, + 0x7ff2ed6500000000, 0x41992f8a00000000, 0xccc2247b00000000, + 0xf2a9e69400000000, 0xf112d17f00000000, 0xcf79139000000000, + 0xb662cf7200000000, 0x88090d9d00000000, 0x8bb23a7600000000, + 0xb5d9f89900000000, 0xa007ba9e00000000, 0x9e6c787100000000, + 0x9dd74f9a00000000, 0xa3bc8d7500000000, 0xdaa7519700000000, + 0xe4cc937800000000, 0xe777a49300000000, 0xd91c667c00000000, + 0x54476d8d00000000, 0x6a2caf6200000000, 0x6997988900000000, + 0x57fc5a6600000000, 0x2ee7868400000000, 0x108c446b00000000, + 0x1337738000000000, 0x2d5cb16f00000000, 0x488614b900000000, + 0x76edd65600000000, 0x7556e1bd00000000, 0x4b3d235200000000, + 0x3226ffb000000000, 0x0c4d3d5f00000000, 0x0ff60ab400000000, + 0x319dc85b00000000, 0xbcc6c3aa00000000, 0x82ad014500000000, + 0x811636ae00000000, 0xbf7df44100000000, 0xc66628a300000000, + 0xf80dea4c00000000, 0xfbb6dda700000000, 0xc5dd1f4800000000, + 0x7004e7d100000000, 0x4e6f253e00000000, 0x4dd412d500000000, + 0x73bfd03a00000000, 0x0aa40cd800000000, 0x34cfce3700000000, + 0x3774f9dc00000000, 0x091f3b3300000000, 0x844430c200000000, + 0xba2ff22d00000000, 0xb994c5c600000000, 0x87ff072900000000, + 0xfee4dbcb00000000, 0xc08f192400000000, 0xc3342ecf00000000, + 0xfd5fec2000000000, 0x988549f600000000, 0xa6ee8b1900000000, + 0xa555bcf200000000, 0x9b3e7e1d00000000, 0xe225a2ff00000000, + 0xdc4e601000000000, 0xdff557fb00000000, 0xe19e951400000000, + 0x6cc59ee500000000, 0x52ae5c0a00000000, 0x51156be100000000, + 0x6f7ea90e00000000, 0x166575ec00000000, 0x280eb70300000000, + 0x2bb580e800000000, 0x15de420700000000, 0x010905e600000000, + 0x3f62c70900000000, 0x3cd9f0e200000000, 0x02b2320d00000000, + 0x7ba9eeef00000000, 0x45c22c0000000000, 0x46791beb00000000, + 0x7812d90400000000, 0xf549d2f500000000, 0xcb22101a00000000, + 0xc89927f100000000, 0xf6f2e51e00000000, 0x8fe939fc00000000, + 0xb182fb1300000000, 0xb239ccf800000000, 0x8c520e1700000000, + 0xe988abc100000000, 0xd7e3692e00000000, 0xd4585ec500000000, + 0xea339c2a00000000, 0x932840c800000000, 0xad43822700000000, + 0xaef8b5cc00000000, 0x9093772300000000, 0x1dc87cd200000000, + 0x23a3be3d00000000, 0x201889d600000000, 0x1e734b3900000000, + 0x676897db00000000, 0x5903553400000000, 0x5ab862df00000000, + 0x64d3a03000000000, 0xd10a58a900000000, 0xef619a4600000000, + 0xecdaadad00000000, 0xd2b16f4200000000, 0xabaab3a000000000, + 0x95c1714f00000000, 0x967a46a400000000, 0xa811844b00000000, + 0x254a8fba00000000, 0x1b214d5500000000, 0x189a7abe00000000, + 0x26f1b85100000000, 0x5fea64b300000000, 0x6181a65c00000000, + 0x623a91b700000000, 0x5c51535800000000, 0x398bf68e00000000, + 0x07e0346100000000, 0x045b038a00000000, 0x3a30c16500000000, + 0x432b1d8700000000, 0x7d40df6800000000, 0x7efbe88300000000, + 0x40902a6c00000000, 0xcdcb219d00000000, 0xf3a0e37200000000, + 0xf01bd49900000000, 0xce70167600000000, 0xb76bca9400000000, + 0x8900087b00000000, 0x8abb3f9000000000, 0xb4d0fd7f00000000, + 0xa10ebf7800000000, 0x9f657d9700000000, 0x9cde4a7c00000000, + 0xa2b5889300000000, 0xdbae547100000000, 0xe5c5969e00000000, + 0xe67ea17500000000, 0xd815639a00000000, 0x554e686b00000000, + 0x6b25aa8400000000, 0x689e9d6f00000000, 0x56f55f8000000000, + 0x2fee836200000000, 0x1185418d00000000, 0x123e766600000000, + 0x2c55b48900000000, 0x498f115f00000000, 0x77e4d3b000000000, + 0x745fe45b00000000, 0x4a3426b400000000, 0x332ffa5600000000, + 0x0d4438b900000000, 0x0eff0f5200000000, 0x3094cdbd00000000, + 0xbdcfc64c00000000, 0x83a404a300000000, 0x801f334800000000, + 0xbe74f1a700000000, 0xc76f2d4500000000, 0xf904efaa00000000, + 0xfabfd84100000000, 0xc4d41aae00000000, 0x710de23700000000, + 0x4f6620d800000000, 0x4cdd173300000000, 0x72b6d5dc00000000, + 0x0bad093e00000000, 0x35c6cbd100000000, 0x367dfc3a00000000, + 0x08163ed500000000, 0x854d352400000000, 0xbb26f7cb00000000, + 0xb89dc02000000000, 0x86f602cf00000000, 0xffedde2d00000000, + 0xc1861cc200000000, 0xc23d2b2900000000, 0xfc56e9c600000000, + 0x998c4c1000000000, 0xa7e78eff00000000, 0xa45cb91400000000, + 0x9a377bfb00000000, 0xe32ca71900000000, 0xdd4765f600000000, + 0xdefc521d00000000, 0xe09790f200000000, 0x6dcc9b0300000000, + 0x53a759ec00000000, 0x501c6e0700000000, 0x6e77ace800000000, + 0x176c700a00000000, 0x2907b2e500000000, 0x2abc850e00000000, + 0x14d747e100000000}, + {0x0000000000000000, 0xc0df8ec100000000, 0xc1b96c5800000000, + 0x0166e29900000000, 0x8273d9b000000000, 0x42ac577100000000, + 0x43cab5e800000000, 0x83153b2900000000, 0x45e1c3ba00000000, + 0x853e4d7b00000000, 0x8458afe200000000, 0x4487212300000000, + 0xc7921a0a00000000, 0x074d94cb00000000, 0x062b765200000000, + 0xc6f4f89300000000, 0xcbc4f6ae00000000, 0x0b1b786f00000000, + 0x0a7d9af600000000, 0xcaa2143700000000, 0x49b72f1e00000000, + 0x8968a1df00000000, 0x880e434600000000, 0x48d1cd8700000000, + 0x8e25351400000000, 0x4efabbd500000000, 0x4f9c594c00000000, + 0x8f43d78d00000000, 0x0c56eca400000000, 0xcc89626500000000, + 0xcdef80fc00000000, 0x0d300e3d00000000, 0xd78f9c8600000000, + 0x1750124700000000, 0x1636f0de00000000, 0xd6e97e1f00000000, + 0x55fc453600000000, 0x9523cbf700000000, 0x9445296e00000000, + 0x549aa7af00000000, 0x926e5f3c00000000, 0x52b1d1fd00000000, + 0x53d7336400000000, 0x9308bda500000000, 0x101d868c00000000, + 0xd0c2084d00000000, 0xd1a4ead400000000, 0x117b641500000000, + 0x1c4b6a2800000000, 0xdc94e4e900000000, 0xddf2067000000000, + 0x1d2d88b100000000, 0x9e38b39800000000, 0x5ee73d5900000000, + 0x5f81dfc000000000, 0x9f5e510100000000, 0x59aaa99200000000, + 0x9975275300000000, 0x9813c5ca00000000, 0x58cc4b0b00000000, + 0xdbd9702200000000, 0x1b06fee300000000, 0x1a601c7a00000000, + 0xdabf92bb00000000, 0xef1948d600000000, 0x2fc6c61700000000, + 0x2ea0248e00000000, 0xee7faa4f00000000, 0x6d6a916600000000, + 0xadb51fa700000000, 0xacd3fd3e00000000, 0x6c0c73ff00000000, + 0xaaf88b6c00000000, 0x6a2705ad00000000, 0x6b41e73400000000, + 0xab9e69f500000000, 0x288b52dc00000000, 0xe854dc1d00000000, + 0xe9323e8400000000, 0x29edb04500000000, 0x24ddbe7800000000, + 0xe40230b900000000, 0xe564d22000000000, 0x25bb5ce100000000, + 0xa6ae67c800000000, 0x6671e90900000000, 0x67170b9000000000, + 0xa7c8855100000000, 0x613c7dc200000000, 0xa1e3f30300000000, + 0xa085119a00000000, 0x605a9f5b00000000, 0xe34fa47200000000, + 0x23902ab300000000, 0x22f6c82a00000000, 0xe22946eb00000000, + 0x3896d45000000000, 0xf8495a9100000000, 0xf92fb80800000000, + 0x39f036c900000000, 0xbae50de000000000, 0x7a3a832100000000, + 0x7b5c61b800000000, 0xbb83ef7900000000, 0x7d7717ea00000000, + 0xbda8992b00000000, 0xbcce7bb200000000, 0x7c11f57300000000, + 0xff04ce5a00000000, 0x3fdb409b00000000, 0x3ebda20200000000, + 0xfe622cc300000000, 0xf35222fe00000000, 0x338dac3f00000000, + 0x32eb4ea600000000, 0xf234c06700000000, 0x7121fb4e00000000, + 0xb1fe758f00000000, 0xb098971600000000, 0x704719d700000000, + 0xb6b3e14400000000, 0x766c6f8500000000, 0x770a8d1c00000000, + 0xb7d503dd00000000, 0x34c038f400000000, 0xf41fb63500000000, + 0xf57954ac00000000, 0x35a6da6d00000000, 0x9f35e17700000000, + 0x5fea6fb600000000, 0x5e8c8d2f00000000, 0x9e5303ee00000000, + 0x1d4638c700000000, 0xdd99b60600000000, 0xdcff549f00000000, + 0x1c20da5e00000000, 0xdad422cd00000000, 0x1a0bac0c00000000, + 0x1b6d4e9500000000, 0xdbb2c05400000000, 0x58a7fb7d00000000, + 0x987875bc00000000, 0x991e972500000000, 0x59c119e400000000, + 0x54f117d900000000, 0x942e991800000000, 0x95487b8100000000, + 0x5597f54000000000, 0xd682ce6900000000, 0x165d40a800000000, + 0x173ba23100000000, 0xd7e42cf000000000, 0x1110d46300000000, + 0xd1cf5aa200000000, 0xd0a9b83b00000000, 0x107636fa00000000, + 0x93630dd300000000, 0x53bc831200000000, 0x52da618b00000000, + 0x9205ef4a00000000, 0x48ba7df100000000, 0x8865f33000000000, + 0x890311a900000000, 0x49dc9f6800000000, 0xcac9a44100000000, + 0x0a162a8000000000, 0x0b70c81900000000, 0xcbaf46d800000000, + 0x0d5bbe4b00000000, 0xcd84308a00000000, 0xcce2d21300000000, + 0x0c3d5cd200000000, 0x8f2867fb00000000, 0x4ff7e93a00000000, + 0x4e910ba300000000, 0x8e4e856200000000, 0x837e8b5f00000000, + 0x43a1059e00000000, 0x42c7e70700000000, 0x821869c600000000, + 0x010d52ef00000000, 0xc1d2dc2e00000000, 0xc0b43eb700000000, + 0x006bb07600000000, 0xc69f48e500000000, 0x0640c62400000000, + 0x072624bd00000000, 0xc7f9aa7c00000000, 0x44ec915500000000, + 0x84331f9400000000, 0x8555fd0d00000000, 0x458a73cc00000000, + 0x702ca9a100000000, 0xb0f3276000000000, 0xb195c5f900000000, + 0x714a4b3800000000, 0xf25f701100000000, 0x3280fed000000000, + 0x33e61c4900000000, 0xf339928800000000, 0x35cd6a1b00000000, + 0xf512e4da00000000, 0xf474064300000000, 0x34ab888200000000, + 0xb7beb3ab00000000, 0x77613d6a00000000, 0x7607dff300000000, + 0xb6d8513200000000, 0xbbe85f0f00000000, 0x7b37d1ce00000000, + 0x7a51335700000000, 0xba8ebd9600000000, 0x399b86bf00000000, + 0xf944087e00000000, 0xf822eae700000000, 0x38fd642600000000, + 0xfe099cb500000000, 0x3ed6127400000000, 0x3fb0f0ed00000000, + 0xff6f7e2c00000000, 0x7c7a450500000000, 0xbca5cbc400000000, + 0xbdc3295d00000000, 0x7d1ca79c00000000, 0xa7a3352700000000, + 0x677cbbe600000000, 0x661a597f00000000, 0xa6c5d7be00000000, + 0x25d0ec9700000000, 0xe50f625600000000, 0xe46980cf00000000, + 0x24b60e0e00000000, 0xe242f69d00000000, 0x229d785c00000000, + 0x23fb9ac500000000, 0xe324140400000000, 0x60312f2d00000000, + 0xa0eea1ec00000000, 0xa188437500000000, 0x6157cdb400000000, + 0x6c67c38900000000, 0xacb84d4800000000, 0xaddeafd100000000, + 0x6d01211000000000, 0xee141a3900000000, 0x2ecb94f800000000, + 0x2fad766100000000, 0xef72f8a000000000, 0x2986003300000000, + 0xe9598ef200000000, 0xe83f6c6b00000000, 0x28e0e2aa00000000, + 0xabf5d98300000000, 0x6b2a574200000000, 0x6a4cb5db00000000, + 0xaa933b1a00000000}, + {0x0000000000000000, 0x6f4ca59b00000000, 0x9f9e3bec00000000, + 0xf0d29e7700000000, 0x7f3b060300000000, 0x1077a39800000000, + 0xe0a53def00000000, 0x8fe9987400000000, 0xfe760c0600000000, + 0x913aa99d00000000, 0x61e837ea00000000, 0x0ea4927100000000, + 0x814d0a0500000000, 0xee01af9e00000000, 0x1ed331e900000000, + 0x719f947200000000, 0xfced180c00000000, 0x93a1bd9700000000, + 0x637323e000000000, 0x0c3f867b00000000, 0x83d61e0f00000000, + 0xec9abb9400000000, 0x1c4825e300000000, 0x7304807800000000, + 0x029b140a00000000, 0x6dd7b19100000000, 0x9d052fe600000000, + 0xf2498a7d00000000, 0x7da0120900000000, 0x12ecb79200000000, + 0xe23e29e500000000, 0x8d728c7e00000000, 0xf8db311800000000, + 0x9797948300000000, 0x67450af400000000, 0x0809af6f00000000, + 0x87e0371b00000000, 0xe8ac928000000000, 0x187e0cf700000000, + 0x7732a96c00000000, 0x06ad3d1e00000000, 0x69e1988500000000, + 0x993306f200000000, 0xf67fa36900000000, 0x79963b1d00000000, + 0x16da9e8600000000, 0xe60800f100000000, 0x8944a56a00000000, + 0x0436291400000000, 0x6b7a8c8f00000000, 0x9ba812f800000000, + 0xf4e4b76300000000, 0x7b0d2f1700000000, 0x14418a8c00000000, + 0xe49314fb00000000, 0x8bdfb16000000000, 0xfa40251200000000, + 0x950c808900000000, 0x65de1efe00000000, 0x0a92bb6500000000, + 0x857b231100000000, 0xea37868a00000000, 0x1ae518fd00000000, + 0x75a9bd6600000000, 0xf0b7633000000000, 0x9ffbc6ab00000000, + 0x6f2958dc00000000, 0x0065fd4700000000, 0x8f8c653300000000, + 0xe0c0c0a800000000, 0x10125edf00000000, 0x7f5efb4400000000, + 0x0ec16f3600000000, 0x618dcaad00000000, 0x915f54da00000000, + 0xfe13f14100000000, 0x71fa693500000000, 0x1eb6ccae00000000, + 0xee6452d900000000, 0x8128f74200000000, 0x0c5a7b3c00000000, + 0x6316dea700000000, 0x93c440d000000000, 0xfc88e54b00000000, + 0x73617d3f00000000, 0x1c2dd8a400000000, 0xecff46d300000000, + 0x83b3e34800000000, 0xf22c773a00000000, 0x9d60d2a100000000, + 0x6db24cd600000000, 0x02fee94d00000000, 0x8d17713900000000, + 0xe25bd4a200000000, 0x12894ad500000000, 0x7dc5ef4e00000000, + 0x086c522800000000, 0x6720f7b300000000, 0x97f269c400000000, + 0xf8becc5f00000000, 0x7757542b00000000, 0x181bf1b000000000, + 0xe8c96fc700000000, 0x8785ca5c00000000, 0xf61a5e2e00000000, + 0x9956fbb500000000, 0x698465c200000000, 0x06c8c05900000000, + 0x8921582d00000000, 0xe66dfdb600000000, 0x16bf63c100000000, + 0x79f3c65a00000000, 0xf4814a2400000000, 0x9bcdefbf00000000, + 0x6b1f71c800000000, 0x0453d45300000000, 0x8bba4c2700000000, + 0xe4f6e9bc00000000, 0x142477cb00000000, 0x7b68d25000000000, + 0x0af7462200000000, 0x65bbe3b900000000, 0x95697dce00000000, + 0xfa25d85500000000, 0x75cc402100000000, 0x1a80e5ba00000000, + 0xea527bcd00000000, 0x851ede5600000000, 0xe06fc76000000000, + 0x8f2362fb00000000, 0x7ff1fc8c00000000, 0x10bd591700000000, + 0x9f54c16300000000, 0xf01864f800000000, 0x00cafa8f00000000, + 0x6f865f1400000000, 0x1e19cb6600000000, 0x71556efd00000000, + 0x8187f08a00000000, 0xeecb551100000000, 0x6122cd6500000000, + 0x0e6e68fe00000000, 0xfebcf68900000000, 0x91f0531200000000, + 0x1c82df6c00000000, 0x73ce7af700000000, 0x831ce48000000000, + 0xec50411b00000000, 0x63b9d96f00000000, 0x0cf57cf400000000, + 0xfc27e28300000000, 0x936b471800000000, 0xe2f4d36a00000000, + 0x8db876f100000000, 0x7d6ae88600000000, 0x12264d1d00000000, + 0x9dcfd56900000000, 0xf28370f200000000, 0x0251ee8500000000, + 0x6d1d4b1e00000000, 0x18b4f67800000000, 0x77f853e300000000, + 0x872acd9400000000, 0xe866680f00000000, 0x678ff07b00000000, + 0x08c355e000000000, 0xf811cb9700000000, 0x975d6e0c00000000, + 0xe6c2fa7e00000000, 0x898e5fe500000000, 0x795cc19200000000, + 0x1610640900000000, 0x99f9fc7d00000000, 0xf6b559e600000000, + 0x0667c79100000000, 0x692b620a00000000, 0xe459ee7400000000, + 0x8b154bef00000000, 0x7bc7d59800000000, 0x148b700300000000, + 0x9b62e87700000000, 0xf42e4dec00000000, 0x04fcd39b00000000, + 0x6bb0760000000000, 0x1a2fe27200000000, 0x756347e900000000, + 0x85b1d99e00000000, 0xeafd7c0500000000, 0x6514e47100000000, + 0x0a5841ea00000000, 0xfa8adf9d00000000, 0x95c67a0600000000, + 0x10d8a45000000000, 0x7f9401cb00000000, 0x8f469fbc00000000, + 0xe00a3a2700000000, 0x6fe3a25300000000, 0x00af07c800000000, + 0xf07d99bf00000000, 0x9f313c2400000000, 0xeeaea85600000000, + 0x81e20dcd00000000, 0x713093ba00000000, 0x1e7c362100000000, + 0x9195ae5500000000, 0xfed90bce00000000, 0x0e0b95b900000000, + 0x6147302200000000, 0xec35bc5c00000000, 0x837919c700000000, + 0x73ab87b000000000, 0x1ce7222b00000000, 0x930eba5f00000000, + 0xfc421fc400000000, 0x0c9081b300000000, 0x63dc242800000000, + 0x1243b05a00000000, 0x7d0f15c100000000, 0x8ddd8bb600000000, + 0xe2912e2d00000000, 0x6d78b65900000000, 0x023413c200000000, + 0xf2e68db500000000, 0x9daa282e00000000, 0xe803954800000000, + 0x874f30d300000000, 0x779daea400000000, 0x18d10b3f00000000, + 0x9738934b00000000, 0xf87436d000000000, 0x08a6a8a700000000, + 0x67ea0d3c00000000, 0x1675994e00000000, 0x79393cd500000000, + 0x89eba2a200000000, 0xe6a7073900000000, 0x694e9f4d00000000, + 0x06023ad600000000, 0xf6d0a4a100000000, 0x999c013a00000000, + 0x14ee8d4400000000, 0x7ba228df00000000, 0x8b70b6a800000000, + 0xe43c133300000000, 0x6bd58b4700000000, 0x04992edc00000000, + 0xf44bb0ab00000000, 0x9b07153000000000, 0xea98814200000000, + 0x85d424d900000000, 0x7506baae00000000, 0x1a4a1f3500000000, + 0x95a3874100000000, 0xfaef22da00000000, 0x0a3dbcad00000000, + 0x6571193600000000}, + {0x0000000000000000, 0x85d996dd00000000, 0x4bb55c6000000000, + 0xce6ccabd00000000, 0x966ab9c000000000, 0x13b32f1d00000000, + 0xdddfe5a000000000, 0x5806737d00000000, 0x6dd3035a00000000, + 0xe80a958700000000, 0x26665f3a00000000, 0xa3bfc9e700000000, + 0xfbb9ba9a00000000, 0x7e602c4700000000, 0xb00ce6fa00000000, + 0x35d5702700000000, 0xdaa607b400000000, 0x5f7f916900000000, + 0x91135bd400000000, 0x14cacd0900000000, 0x4cccbe7400000000, + 0xc91528a900000000, 0x0779e21400000000, 0x82a074c900000000, + 0xb77504ee00000000, 0x32ac923300000000, 0xfcc0588e00000000, + 0x7919ce5300000000, 0x211fbd2e00000000, 0xa4c62bf300000000, + 0x6aaae14e00000000, 0xef73779300000000, 0xf54b7eb300000000, + 0x7092e86e00000000, 0xbefe22d300000000, 0x3b27b40e00000000, + 0x6321c77300000000, 0xe6f851ae00000000, 0x28949b1300000000, + 0xad4d0dce00000000, 0x98987de900000000, 0x1d41eb3400000000, + 0xd32d218900000000, 0x56f4b75400000000, 0x0ef2c42900000000, + 0x8b2b52f400000000, 0x4547984900000000, 0xc09e0e9400000000, + 0x2fed790700000000, 0xaa34efda00000000, 0x6458256700000000, + 0xe181b3ba00000000, 0xb987c0c700000000, 0x3c5e561a00000000, + 0xf2329ca700000000, 0x77eb0a7a00000000, 0x423e7a5d00000000, + 0xc7e7ec8000000000, 0x098b263d00000000, 0x8c52b0e000000000, + 0xd454c39d00000000, 0x518d554000000000, 0x9fe19ffd00000000, + 0x1a38092000000000, 0xab918dbd00000000, 0x2e481b6000000000, + 0xe024d1dd00000000, 0x65fd470000000000, 0x3dfb347d00000000, + 0xb822a2a000000000, 0x764e681d00000000, 0xf397fec000000000, + 0xc6428ee700000000, 0x439b183a00000000, 0x8df7d28700000000, + 0x082e445a00000000, 0x5028372700000000, 0xd5f1a1fa00000000, + 0x1b9d6b4700000000, 0x9e44fd9a00000000, 0x71378a0900000000, + 0xf4ee1cd400000000, 0x3a82d66900000000, 0xbf5b40b400000000, + 0xe75d33c900000000, 0x6284a51400000000, 0xace86fa900000000, + 0x2931f97400000000, 0x1ce4895300000000, 0x993d1f8e00000000, + 0x5751d53300000000, 0xd28843ee00000000, 0x8a8e309300000000, + 0x0f57a64e00000000, 0xc13b6cf300000000, 0x44e2fa2e00000000, + 0x5edaf30e00000000, 0xdb0365d300000000, 0x156faf6e00000000, + 0x90b639b300000000, 0xc8b04ace00000000, 0x4d69dc1300000000, + 0x830516ae00000000, 0x06dc807300000000, 0x3309f05400000000, + 0xb6d0668900000000, 0x78bcac3400000000, 0xfd653ae900000000, + 0xa563499400000000, 0x20badf4900000000, 0xeed615f400000000, + 0x6b0f832900000000, 0x847cf4ba00000000, 0x01a5626700000000, + 0xcfc9a8da00000000, 0x4a103e0700000000, 0x12164d7a00000000, + 0x97cfdba700000000, 0x59a3111a00000000, 0xdc7a87c700000000, + 0xe9aff7e000000000, 0x6c76613d00000000, 0xa21aab8000000000, + 0x27c33d5d00000000, 0x7fc54e2000000000, 0xfa1cd8fd00000000, + 0x3470124000000000, 0xb1a9849d00000000, 0x17256aa000000000, + 0x92fcfc7d00000000, 0x5c9036c000000000, 0xd949a01d00000000, + 0x814fd36000000000, 0x049645bd00000000, 0xcafa8f0000000000, + 0x4f2319dd00000000, 0x7af669fa00000000, 0xff2fff2700000000, + 0x3143359a00000000, 0xb49aa34700000000, 0xec9cd03a00000000, + 0x694546e700000000, 0xa7298c5a00000000, 0x22f01a8700000000, + 0xcd836d1400000000, 0x485afbc900000000, 0x8636317400000000, + 0x03efa7a900000000, 0x5be9d4d400000000, 0xde30420900000000, + 0x105c88b400000000, 0x95851e6900000000, 0xa0506e4e00000000, + 0x2589f89300000000, 0xebe5322e00000000, 0x6e3ca4f300000000, + 0x363ad78e00000000, 0xb3e3415300000000, 0x7d8f8bee00000000, + 0xf8561d3300000000, 0xe26e141300000000, 0x67b782ce00000000, + 0xa9db487300000000, 0x2c02deae00000000, 0x7404add300000000, + 0xf1dd3b0e00000000, 0x3fb1f1b300000000, 0xba68676e00000000, + 0x8fbd174900000000, 0x0a64819400000000, 0xc4084b2900000000, + 0x41d1ddf400000000, 0x19d7ae8900000000, 0x9c0e385400000000, + 0x5262f2e900000000, 0xd7bb643400000000, 0x38c813a700000000, + 0xbd11857a00000000, 0x737d4fc700000000, 0xf6a4d91a00000000, + 0xaea2aa6700000000, 0x2b7b3cba00000000, 0xe517f60700000000, + 0x60ce60da00000000, 0x551b10fd00000000, 0xd0c2862000000000, + 0x1eae4c9d00000000, 0x9b77da4000000000, 0xc371a93d00000000, + 0x46a83fe000000000, 0x88c4f55d00000000, 0x0d1d638000000000, + 0xbcb4e71d00000000, 0x396d71c000000000, 0xf701bb7d00000000, + 0x72d82da000000000, 0x2ade5edd00000000, 0xaf07c80000000000, + 0x616b02bd00000000, 0xe4b2946000000000, 0xd167e44700000000, + 0x54be729a00000000, 0x9ad2b82700000000, 0x1f0b2efa00000000, + 0x470d5d8700000000, 0xc2d4cb5a00000000, 0x0cb801e700000000, + 0x8961973a00000000, 0x6612e0a900000000, 0xe3cb767400000000, + 0x2da7bcc900000000, 0xa87e2a1400000000, 0xf078596900000000, + 0x75a1cfb400000000, 0xbbcd050900000000, 0x3e1493d400000000, + 0x0bc1e3f300000000, 0x8e18752e00000000, 0x4074bf9300000000, + 0xc5ad294e00000000, 0x9dab5a3300000000, 0x1872ccee00000000, + 0xd61e065300000000, 0x53c7908e00000000, 0x49ff99ae00000000, + 0xcc260f7300000000, 0x024ac5ce00000000, 0x8793531300000000, + 0xdf95206e00000000, 0x5a4cb6b300000000, 0x94207c0e00000000, + 0x11f9ead300000000, 0x242c9af400000000, 0xa1f50c2900000000, + 0x6f99c69400000000, 0xea40504900000000, 0xb246233400000000, + 0x379fb5e900000000, 0xf9f37f5400000000, 0x7c2ae98900000000, + 0x93599e1a00000000, 0x168008c700000000, 0xd8ecc27a00000000, + 0x5d3554a700000000, 0x053327da00000000, 0x80eab10700000000, + 0x4e867bba00000000, 0xcb5fed6700000000, 0xfe8a9d4000000000, + 0x7b530b9d00000000, 0xb53fc12000000000, 0x30e657fd00000000, + 0x68e0248000000000, 0xed39b25d00000000, 0x235578e000000000, + 0xa68cee3d00000000}, + {0x0000000000000000, 0x76e10f9d00000000, 0xadc46ee100000000, + 0xdb25617c00000000, 0x1b8fac1900000000, 0x6d6ea38400000000, + 0xb64bc2f800000000, 0xc0aacd6500000000, 0x361e593300000000, + 0x40ff56ae00000000, 0x9bda37d200000000, 0xed3b384f00000000, + 0x2d91f52a00000000, 0x5b70fab700000000, 0x80559bcb00000000, + 0xf6b4945600000000, 0x6c3cb26600000000, 0x1addbdfb00000000, + 0xc1f8dc8700000000, 0xb719d31a00000000, 0x77b31e7f00000000, + 0x015211e200000000, 0xda77709e00000000, 0xac967f0300000000, + 0x5a22eb5500000000, 0x2cc3e4c800000000, 0xf7e685b400000000, + 0x81078a2900000000, 0x41ad474c00000000, 0x374c48d100000000, + 0xec6929ad00000000, 0x9a88263000000000, 0xd87864cd00000000, + 0xae996b5000000000, 0x75bc0a2c00000000, 0x035d05b100000000, + 0xc3f7c8d400000000, 0xb516c74900000000, 0x6e33a63500000000, + 0x18d2a9a800000000, 0xee663dfe00000000, 0x9887326300000000, + 0x43a2531f00000000, 0x35435c8200000000, 0xf5e991e700000000, + 0x83089e7a00000000, 0x582dff0600000000, 0x2eccf09b00000000, + 0xb444d6ab00000000, 0xc2a5d93600000000, 0x1980b84a00000000, + 0x6f61b7d700000000, 0xafcb7ab200000000, 0xd92a752f00000000, + 0x020f145300000000, 0x74ee1bce00000000, 0x825a8f9800000000, + 0xf4bb800500000000, 0x2f9ee17900000000, 0x597feee400000000, + 0x99d5238100000000, 0xef342c1c00000000, 0x34114d6000000000, + 0x42f042fd00000000, 0xf1f7b94100000000, 0x8716b6dc00000000, + 0x5c33d7a000000000, 0x2ad2d83d00000000, 0xea78155800000000, + 0x9c991ac500000000, 0x47bc7bb900000000, 0x315d742400000000, + 0xc7e9e07200000000, 0xb108efef00000000, 0x6a2d8e9300000000, + 0x1ccc810e00000000, 0xdc664c6b00000000, 0xaa8743f600000000, + 0x71a2228a00000000, 0x07432d1700000000, 0x9dcb0b2700000000, + 0xeb2a04ba00000000, 0x300f65c600000000, 0x46ee6a5b00000000, + 0x8644a73e00000000, 0xf0a5a8a300000000, 0x2b80c9df00000000, + 0x5d61c64200000000, 0xabd5521400000000, 0xdd345d8900000000, + 0x06113cf500000000, 0x70f0336800000000, 0xb05afe0d00000000, + 0xc6bbf19000000000, 0x1d9e90ec00000000, 0x6b7f9f7100000000, + 0x298fdd8c00000000, 0x5f6ed21100000000, 0x844bb36d00000000, + 0xf2aabcf000000000, 0x3200719500000000, 0x44e17e0800000000, + 0x9fc41f7400000000, 0xe92510e900000000, 0x1f9184bf00000000, + 0x69708b2200000000, 0xb255ea5e00000000, 0xc4b4e5c300000000, + 0x041e28a600000000, 0x72ff273b00000000, 0xa9da464700000000, + 0xdf3b49da00000000, 0x45b36fea00000000, 0x3352607700000000, + 0xe877010b00000000, 0x9e960e9600000000, 0x5e3cc3f300000000, + 0x28ddcc6e00000000, 0xf3f8ad1200000000, 0x8519a28f00000000, + 0x73ad36d900000000, 0x054c394400000000, 0xde69583800000000, + 0xa88857a500000000, 0x68229ac000000000, 0x1ec3955d00000000, + 0xc5e6f42100000000, 0xb307fbbc00000000, 0xe2ef738300000000, + 0x940e7c1e00000000, 0x4f2b1d6200000000, 0x39ca12ff00000000, + 0xf960df9a00000000, 0x8f81d00700000000, 0x54a4b17b00000000, + 0x2245bee600000000, 0xd4f12ab000000000, 0xa210252d00000000, + 0x7935445100000000, 0x0fd44bcc00000000, 0xcf7e86a900000000, + 0xb99f893400000000, 0x62bae84800000000, 0x145be7d500000000, + 0x8ed3c1e500000000, 0xf832ce7800000000, 0x2317af0400000000, + 0x55f6a09900000000, 0x955c6dfc00000000, 0xe3bd626100000000, + 0x3898031d00000000, 0x4e790c8000000000, 0xb8cd98d600000000, + 0xce2c974b00000000, 0x1509f63700000000, 0x63e8f9aa00000000, + 0xa34234cf00000000, 0xd5a33b5200000000, 0x0e865a2e00000000, + 0x786755b300000000, 0x3a97174e00000000, 0x4c7618d300000000, + 0x975379af00000000, 0xe1b2763200000000, 0x2118bb5700000000, + 0x57f9b4ca00000000, 0x8cdcd5b600000000, 0xfa3dda2b00000000, + 0x0c894e7d00000000, 0x7a6841e000000000, 0xa14d209c00000000, + 0xd7ac2f0100000000, 0x1706e26400000000, 0x61e7edf900000000, + 0xbac28c8500000000, 0xcc23831800000000, 0x56aba52800000000, + 0x204aaab500000000, 0xfb6fcbc900000000, 0x8d8ec45400000000, + 0x4d24093100000000, 0x3bc506ac00000000, 0xe0e067d000000000, + 0x9601684d00000000, 0x60b5fc1b00000000, 0x1654f38600000000, + 0xcd7192fa00000000, 0xbb909d6700000000, 0x7b3a500200000000, + 0x0ddb5f9f00000000, 0xd6fe3ee300000000, 0xa01f317e00000000, + 0x1318cac200000000, 0x65f9c55f00000000, 0xbedca42300000000, + 0xc83dabbe00000000, 0x089766db00000000, 0x7e76694600000000, + 0xa553083a00000000, 0xd3b207a700000000, 0x250693f100000000, + 0x53e79c6c00000000, 0x88c2fd1000000000, 0xfe23f28d00000000, + 0x3e893fe800000000, 0x4868307500000000, 0x934d510900000000, + 0xe5ac5e9400000000, 0x7f2478a400000000, 0x09c5773900000000, + 0xd2e0164500000000, 0xa40119d800000000, 0x64abd4bd00000000, + 0x124adb2000000000, 0xc96fba5c00000000, 0xbf8eb5c100000000, + 0x493a219700000000, 0x3fdb2e0a00000000, 0xe4fe4f7600000000, + 0x921f40eb00000000, 0x52b58d8e00000000, 0x2454821300000000, + 0xff71e36f00000000, 0x8990ecf200000000, 0xcb60ae0f00000000, + 0xbd81a19200000000, 0x66a4c0ee00000000, 0x1045cf7300000000, + 0xd0ef021600000000, 0xa60e0d8b00000000, 0x7d2b6cf700000000, + 0x0bca636a00000000, 0xfd7ef73c00000000, 0x8b9ff8a100000000, + 0x50ba99dd00000000, 0x265b964000000000, 0xe6f15b2500000000, + 0x901054b800000000, 0x4b3535c400000000, 0x3dd43a5900000000, + 0xa75c1c6900000000, 0xd1bd13f400000000, 0x0a98728800000000, + 0x7c797d1500000000, 0xbcd3b07000000000, 0xca32bfed00000000, + 0x1117de9100000000, 0x67f6d10c00000000, 0x9142455a00000000, + 0xe7a34ac700000000, 0x3c862bbb00000000, 0x4a67242600000000, + 0x8acde94300000000, 0xfc2ce6de00000000, 0x270987a200000000, + 0x51e8883f00000000}, + {0x0000000000000000, 0xe8dbfbb900000000, 0x91b186a800000000, + 0x796a7d1100000000, 0x63657c8a00000000, 0x8bbe873300000000, + 0xf2d4fa2200000000, 0x1a0f019b00000000, 0x87cc89cf00000000, + 0x6f17727600000000, 0x167d0f6700000000, 0xfea6f4de00000000, + 0xe4a9f54500000000, 0x0c720efc00000000, 0x751873ed00000000, + 0x9dc3885400000000, 0x4f9f624400000000, 0xa74499fd00000000, + 0xde2ee4ec00000000, 0x36f51f5500000000, 0x2cfa1ece00000000, + 0xc421e57700000000, 0xbd4b986600000000, 0x559063df00000000, + 0xc853eb8b00000000, 0x2088103200000000, 0x59e26d2300000000, + 0xb139969a00000000, 0xab36970100000000, 0x43ed6cb800000000, + 0x3a8711a900000000, 0xd25cea1000000000, 0x9e3ec58800000000, + 0x76e53e3100000000, 0x0f8f432000000000, 0xe754b89900000000, + 0xfd5bb90200000000, 0x158042bb00000000, 0x6cea3faa00000000, + 0x8431c41300000000, 0x19f24c4700000000, 0xf129b7fe00000000, + 0x8843caef00000000, 0x6098315600000000, 0x7a9730cd00000000, + 0x924ccb7400000000, 0xeb26b66500000000, 0x03fd4ddc00000000, + 0xd1a1a7cc00000000, 0x397a5c7500000000, 0x4010216400000000, + 0xa8cbdadd00000000, 0xb2c4db4600000000, 0x5a1f20ff00000000, + 0x23755dee00000000, 0xcbaea65700000000, 0x566d2e0300000000, + 0xbeb6d5ba00000000, 0xc7dca8ab00000000, 0x2f07531200000000, + 0x3508528900000000, 0xddd3a93000000000, 0xa4b9d42100000000, + 0x4c622f9800000000, 0x7d7bfbca00000000, 0x95a0007300000000, + 0xecca7d6200000000, 0x041186db00000000, 0x1e1e874000000000, + 0xf6c57cf900000000, 0x8faf01e800000000, 0x6774fa5100000000, + 0xfab7720500000000, 0x126c89bc00000000, 0x6b06f4ad00000000, + 0x83dd0f1400000000, 0x99d20e8f00000000, 0x7109f53600000000, + 0x0863882700000000, 0xe0b8739e00000000, 0x32e4998e00000000, + 0xda3f623700000000, 0xa3551f2600000000, 0x4b8ee49f00000000, + 0x5181e50400000000, 0xb95a1ebd00000000, 0xc03063ac00000000, + 0x28eb981500000000, 0xb528104100000000, 0x5df3ebf800000000, + 0x249996e900000000, 0xcc426d5000000000, 0xd64d6ccb00000000, + 0x3e96977200000000, 0x47fcea6300000000, 0xaf2711da00000000, + 0xe3453e4200000000, 0x0b9ec5fb00000000, 0x72f4b8ea00000000, + 0x9a2f435300000000, 0x802042c800000000, 0x68fbb97100000000, + 0x1191c46000000000, 0xf94a3fd900000000, 0x6489b78d00000000, + 0x8c524c3400000000, 0xf538312500000000, 0x1de3ca9c00000000, + 0x07eccb0700000000, 0xef3730be00000000, 0x965d4daf00000000, + 0x7e86b61600000000, 0xacda5c0600000000, 0x4401a7bf00000000, + 0x3d6bdaae00000000, 0xd5b0211700000000, 0xcfbf208c00000000, + 0x2764db3500000000, 0x5e0ea62400000000, 0xb6d55d9d00000000, + 0x2b16d5c900000000, 0xc3cd2e7000000000, 0xbaa7536100000000, + 0x527ca8d800000000, 0x4873a94300000000, 0xa0a852fa00000000, + 0xd9c22feb00000000, 0x3119d45200000000, 0xbbf0874e00000000, + 0x532b7cf700000000, 0x2a4101e600000000, 0xc29afa5f00000000, + 0xd895fbc400000000, 0x304e007d00000000, 0x49247d6c00000000, + 0xa1ff86d500000000, 0x3c3c0e8100000000, 0xd4e7f53800000000, + 0xad8d882900000000, 0x4556739000000000, 0x5f59720b00000000, + 0xb78289b200000000, 0xcee8f4a300000000, 0x26330f1a00000000, + 0xf46fe50a00000000, 0x1cb41eb300000000, 0x65de63a200000000, + 0x8d05981b00000000, 0x970a998000000000, 0x7fd1623900000000, + 0x06bb1f2800000000, 0xee60e49100000000, 0x73a36cc500000000, + 0x9b78977c00000000, 0xe212ea6d00000000, 0x0ac911d400000000, + 0x10c6104f00000000, 0xf81debf600000000, 0x817796e700000000, + 0x69ac6d5e00000000, 0x25ce42c600000000, 0xcd15b97f00000000, + 0xb47fc46e00000000, 0x5ca43fd700000000, 0x46ab3e4c00000000, + 0xae70c5f500000000, 0xd71ab8e400000000, 0x3fc1435d00000000, + 0xa202cb0900000000, 0x4ad930b000000000, 0x33b34da100000000, + 0xdb68b61800000000, 0xc167b78300000000, 0x29bc4c3a00000000, + 0x50d6312b00000000, 0xb80dca9200000000, 0x6a51208200000000, + 0x828adb3b00000000, 0xfbe0a62a00000000, 0x133b5d9300000000, + 0x09345c0800000000, 0xe1efa7b100000000, 0x9885daa000000000, + 0x705e211900000000, 0xed9da94d00000000, 0x054652f400000000, + 0x7c2c2fe500000000, 0x94f7d45c00000000, 0x8ef8d5c700000000, + 0x66232e7e00000000, 0x1f49536f00000000, 0xf792a8d600000000, + 0xc68b7c8400000000, 0x2e50873d00000000, 0x573afa2c00000000, + 0xbfe1019500000000, 0xa5ee000e00000000, 0x4d35fbb700000000, + 0x345f86a600000000, 0xdc847d1f00000000, 0x4147f54b00000000, + 0xa99c0ef200000000, 0xd0f673e300000000, 0x382d885a00000000, + 0x222289c100000000, 0xcaf9727800000000, 0xb3930f6900000000, + 0x5b48f4d000000000, 0x89141ec000000000, 0x61cfe57900000000, + 0x18a5986800000000, 0xf07e63d100000000, 0xea71624a00000000, + 0x02aa99f300000000, 0x7bc0e4e200000000, 0x931b1f5b00000000, + 0x0ed8970f00000000, 0xe6036cb600000000, 0x9f6911a700000000, + 0x77b2ea1e00000000, 0x6dbdeb8500000000, 0x8566103c00000000, + 0xfc0c6d2d00000000, 0x14d7969400000000, 0x58b5b90c00000000, + 0xb06e42b500000000, 0xc9043fa400000000, 0x21dfc41d00000000, + 0x3bd0c58600000000, 0xd30b3e3f00000000, 0xaa61432e00000000, + 0x42bab89700000000, 0xdf7930c300000000, 0x37a2cb7a00000000, + 0x4ec8b66b00000000, 0xa6134dd200000000, 0xbc1c4c4900000000, + 0x54c7b7f000000000, 0x2dadcae100000000, 0xc576315800000000, + 0x172adb4800000000, 0xfff120f100000000, 0x869b5de000000000, + 0x6e40a65900000000, 0x744fa7c200000000, 0x9c945c7b00000000, + 0xe5fe216a00000000, 0x0d25dad300000000, 0x90e6528700000000, + 0x783da93e00000000, 0x0157d42f00000000, 0xe98c2f9600000000, + 0xf3832e0d00000000, 0x1b58d5b400000000, 0x6232a8a500000000, + 0x8ae9531c00000000}, + {0x0000000000000000, 0x919168ae00000000, 0x6325a08700000000, + 0xf2b4c82900000000, 0x874c31d400000000, 0x16dd597a00000000, + 0xe469915300000000, 0x75f8f9fd00000000, 0x4f9f137300000000, + 0xde0e7bdd00000000, 0x2cbab3f400000000, 0xbd2bdb5a00000000, + 0xc8d322a700000000, 0x59424a0900000000, 0xabf6822000000000, + 0x3a67ea8e00000000, 0x9e3e27e600000000, 0x0faf4f4800000000, + 0xfd1b876100000000, 0x6c8aefcf00000000, 0x1972163200000000, + 0x88e37e9c00000000, 0x7a57b6b500000000, 0xebc6de1b00000000, + 0xd1a1349500000000, 0x40305c3b00000000, 0xb284941200000000, + 0x2315fcbc00000000, 0x56ed054100000000, 0xc77c6def00000000, + 0x35c8a5c600000000, 0xa459cd6800000000, 0x7d7b3f1700000000, + 0xecea57b900000000, 0x1e5e9f9000000000, 0x8fcff73e00000000, + 0xfa370ec300000000, 0x6ba6666d00000000, 0x9912ae4400000000, + 0x0883c6ea00000000, 0x32e42c6400000000, 0xa37544ca00000000, + 0x51c18ce300000000, 0xc050e44d00000000, 0xb5a81db000000000, + 0x2439751e00000000, 0xd68dbd3700000000, 0x471cd59900000000, + 0xe34518f100000000, 0x72d4705f00000000, 0x8060b87600000000, + 0x11f1d0d800000000, 0x6409292500000000, 0xf598418b00000000, + 0x072c89a200000000, 0x96bde10c00000000, 0xacda0b8200000000, + 0x3d4b632c00000000, 0xcfffab0500000000, 0x5e6ec3ab00000000, + 0x2b963a5600000000, 0xba0752f800000000, 0x48b39ad100000000, + 0xd922f27f00000000, 0xfaf67e2e00000000, 0x6b67168000000000, + 0x99d3dea900000000, 0x0842b60700000000, 0x7dba4ffa00000000, + 0xec2b275400000000, 0x1e9fef7d00000000, 0x8f0e87d300000000, + 0xb5696d5d00000000, 0x24f805f300000000, 0xd64ccdda00000000, + 0x47dda57400000000, 0x32255c8900000000, 0xa3b4342700000000, + 0x5100fc0e00000000, 0xc09194a000000000, 0x64c859c800000000, + 0xf559316600000000, 0x07edf94f00000000, 0x967c91e100000000, + 0xe384681c00000000, 0x721500b200000000, 0x80a1c89b00000000, + 0x1130a03500000000, 0x2b574abb00000000, 0xbac6221500000000, + 0x4872ea3c00000000, 0xd9e3829200000000, 0xac1b7b6f00000000, + 0x3d8a13c100000000, 0xcf3edbe800000000, 0x5eafb34600000000, + 0x878d413900000000, 0x161c299700000000, 0xe4a8e1be00000000, + 0x7539891000000000, 0x00c170ed00000000, 0x9150184300000000, + 0x63e4d06a00000000, 0xf275b8c400000000, 0xc812524a00000000, + 0x59833ae400000000, 0xab37f2cd00000000, 0x3aa69a6300000000, + 0x4f5e639e00000000, 0xdecf0b3000000000, 0x2c7bc31900000000, + 0xbdeaabb700000000, 0x19b366df00000000, 0x88220e7100000000, + 0x7a96c65800000000, 0xeb07aef600000000, 0x9eff570b00000000, + 0x0f6e3fa500000000, 0xfddaf78c00000000, 0x6c4b9f2200000000, + 0x562c75ac00000000, 0xc7bd1d0200000000, 0x3509d52b00000000, + 0xa498bd8500000000, 0xd160447800000000, 0x40f12cd600000000, + 0xb245e4ff00000000, 0x23d48c5100000000, 0xf4edfd5c00000000, + 0x657c95f200000000, 0x97c85ddb00000000, 0x0659357500000000, + 0x73a1cc8800000000, 0xe230a42600000000, 0x10846c0f00000000, + 0x811504a100000000, 0xbb72ee2f00000000, 0x2ae3868100000000, + 0xd8574ea800000000, 0x49c6260600000000, 0x3c3edffb00000000, + 0xadafb75500000000, 0x5f1b7f7c00000000, 0xce8a17d200000000, + 0x6ad3daba00000000, 0xfb42b21400000000, 0x09f67a3d00000000, + 0x9867129300000000, 0xed9feb6e00000000, 0x7c0e83c000000000, + 0x8eba4be900000000, 0x1f2b234700000000, 0x254cc9c900000000, + 0xb4dda16700000000, 0x4669694e00000000, 0xd7f801e000000000, + 0xa200f81d00000000, 0x339190b300000000, 0xc125589a00000000, + 0x50b4303400000000, 0x8996c24b00000000, 0x1807aae500000000, + 0xeab362cc00000000, 0x7b220a6200000000, 0x0edaf39f00000000, + 0x9f4b9b3100000000, 0x6dff531800000000, 0xfc6e3bb600000000, + 0xc609d13800000000, 0x5798b99600000000, 0xa52c71bf00000000, + 0x34bd191100000000, 0x4145e0ec00000000, 0xd0d4884200000000, + 0x2260406b00000000, 0xb3f128c500000000, 0x17a8e5ad00000000, + 0x86398d0300000000, 0x748d452a00000000, 0xe51c2d8400000000, + 0x90e4d47900000000, 0x0175bcd700000000, 0xf3c174fe00000000, + 0x62501c5000000000, 0x5837f6de00000000, 0xc9a69e7000000000, + 0x3b12565900000000, 0xaa833ef700000000, 0xdf7bc70a00000000, + 0x4eeaafa400000000, 0xbc5e678d00000000, 0x2dcf0f2300000000, + 0x0e1b837200000000, 0x9f8aebdc00000000, 0x6d3e23f500000000, + 0xfcaf4b5b00000000, 0x8957b2a600000000, 0x18c6da0800000000, + 0xea72122100000000, 0x7be37a8f00000000, 0x4184900100000000, + 0xd015f8af00000000, 0x22a1308600000000, 0xb330582800000000, + 0xc6c8a1d500000000, 0x5759c97b00000000, 0xa5ed015200000000, + 0x347c69fc00000000, 0x9025a49400000000, 0x01b4cc3a00000000, + 0xf300041300000000, 0x62916cbd00000000, 0x1769954000000000, + 0x86f8fdee00000000, 0x744c35c700000000, 0xe5dd5d6900000000, + 0xdfbab7e700000000, 0x4e2bdf4900000000, 0xbc9f176000000000, + 0x2d0e7fce00000000, 0x58f6863300000000, 0xc967ee9d00000000, + 0x3bd326b400000000, 0xaa424e1a00000000, 0x7360bc6500000000, + 0xe2f1d4cb00000000, 0x10451ce200000000, 0x81d4744c00000000, + 0xf42c8db100000000, 0x65bde51f00000000, 0x97092d3600000000, + 0x0698459800000000, 0x3cffaf1600000000, 0xad6ec7b800000000, + 0x5fda0f9100000000, 0xce4b673f00000000, 0xbbb39ec200000000, + 0x2a22f66c00000000, 0xd8963e4500000000, 0x490756eb00000000, + 0xed5e9b8300000000, 0x7ccff32d00000000, 0x8e7b3b0400000000, + 0x1fea53aa00000000, 0x6a12aa5700000000, 0xfb83c2f900000000, + 0x09370ad000000000, 0x98a6627e00000000, 0xa2c188f000000000, + 0x3350e05e00000000, 0xc1e4287700000000, 0x507540d900000000, + 0x258db92400000000, 0xb41cd18a00000000, 0x46a819a300000000, + 0xd739710d00000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, + 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, + 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232, + 0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8, + 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e, + 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa, + 0x69312319, 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b, + 0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f, + 0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719, + 0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, 0x496753e3, + 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa, + 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b, + 0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed, + 0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89, + 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25, + 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041, + 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c, + 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed, + 0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4, + 0x8c06e16a, 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758, + 0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e, + 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a, + 0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed, + 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889, + 0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df, + 0x37558441, 0xb9da83a2, 0x7570833c, 0x533b85da, 0x9f918544, + 0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d, + 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c, + 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1, + 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95, + 0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839, + 0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d, + 0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976, + 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7, + 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be, + 0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144, + 0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12, + 0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376, + 0xc37cc495, 0x0fd6c40b, 0x7aa64737, 0xb60c47a9, 0x3883404a, + 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e, + 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278, + 0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682, + 0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b, + 0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a, + 0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, 0x83d02561, + 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05, + 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9, + 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd, + 0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, + 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61, + 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, + 0x264b06e6}, + {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413, + 0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3, + 0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d, + 0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653, + 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9, + 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e, + 0x37e1e793, 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5, + 0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712, + 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8, + 0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, 0x0e14aee6, + 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068, + 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8, + 0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579, + 0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade, + 0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37, + 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590, + 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4, + 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64, + 0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea, + 0xd59d995e, 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678, + 0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282, + 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25, + 0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102, + 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5, + 0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f, + 0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, 0x8816eaf2, 0x2e61e146, + 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8, + 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08, + 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c, + 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b, + 0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972, + 0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5, + 0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d, + 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd, + 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833, + 0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d, + 0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7, + 0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60, + 0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2, + 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105, + 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff, + 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1, + 0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f, + 0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf, + 0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, 0x03a0a617, + 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0, + 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959, + 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe, + 0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca, + 0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a, + 0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184, + 0x92364a30}, + {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216, + 0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8, + 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170, + 0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035, + 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6, + 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145, + 0x39dc63eb, 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d, + 0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e, + 0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d, + 0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, 0xcf26d408, + 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0, + 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e, + 0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c, + 0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf, + 0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a, + 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9, + 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1, + 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f, + 0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987, + 0xfdd8ba22, 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4, + 0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37, + 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84, + 0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca, + 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79, + 0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba, + 0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d, + 0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5, + 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b, + 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643, + 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0, + 0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525, + 0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496, + 0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8, + 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026, + 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e, + 0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db, + 0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118, + 0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab, + 0x20c07205, 0xeb9ca1a0, 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf, + 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c, + 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf, + 0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a, + 0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32, + 0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec, + 0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, 0x16441b82, + 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31, + 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4, + 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957, + 0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f, + 0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1, + 0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869, + 0xe4c4abcc}, + {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0, + 0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271, + 0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61, + 0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52, + 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43, + 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333, + 0xdfd029e3, 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64, + 0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314, + 0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205, + 0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, 0x9c419136, + 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26, + 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997, + 0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849, + 0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739, + 0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8, + 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98, + 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b, + 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba, + 0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa, + 0xba43581a, 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d, + 0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c, + 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc, + 0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af, + 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf, + 0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce, + 0x0142247e, 0x46e25eae, 0x7b82771e, 0xb1e6b092, 0x8c869922, + 0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532, + 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183, + 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710, + 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860, + 0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1, + 0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1, + 0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956, + 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7, + 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7, + 0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4, + 0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5, + 0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5, + 0xaff7b675, 0x92979fc5, 0xe915e8db, 0xd475c16b, 0x93d5bbbb, + 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb, + 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da, + 0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9, + 0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9, + 0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48, + 0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, 0x28d4c7df, + 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af, + 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e, + 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e, + 0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d, + 0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c, + 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c, + 0xca64c78c}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0xb029603d, 0x6053c07a, 0xd07aa047, 0xc0a680f5, + 0x708fe0c8, 0xa0f5408f, 0x10dc20b2, 0xc14b7030, 0x7162100d, + 0xa118b04a, 0x1131d077, 0x01edf0c5, 0xb1c490f8, 0x61be30bf, + 0xd1975082, 0x8297e060, 0x32be805d, 0xe2c4201a, 0x52ed4027, + 0x42316095, 0xf21800a8, 0x2262a0ef, 0x924bc0d2, 0x43dc9050, + 0xf3f5f06d, 0x238f502a, 0x93a63017, 0x837a10a5, 0x33537098, + 0xe329d0df, 0x5300b0e2, 0x042fc1c1, 0xb406a1fc, 0x647c01bb, + 0xd4556186, 0xc4894134, 0x74a02109, 0xa4da814e, 0x14f3e173, + 0xc564b1f1, 0x754dd1cc, 0xa537718b, 0x151e11b6, 0x05c23104, + 0xb5eb5139, 0x6591f17e, 0xd5b89143, 0x86b821a1, 0x3691419c, + 0xe6ebe1db, 0x56c281e6, 0x461ea154, 0xf637c169, 0x264d612e, + 0x96640113, 0x47f35191, 0xf7da31ac, 0x27a091eb, 0x9789f1d6, + 0x8755d164, 0x377cb159, 0xe706111e, 0x572f7123, 0x4958f358, + 0xf9719365, 0x290b3322, 0x9922531f, 0x89fe73ad, 0x39d71390, + 0xe9adb3d7, 0x5984d3ea, 0x88138368, 0x383ae355, 0xe8404312, + 0x5869232f, 0x48b5039d, 0xf89c63a0, 0x28e6c3e7, 0x98cfa3da, + 0xcbcf1338, 0x7be67305, 0xab9cd342, 0x1bb5b37f, 0x0b6993cd, + 0xbb40f3f0, 0x6b3a53b7, 0xdb13338a, 0x0a846308, 0xbaad0335, + 0x6ad7a372, 0xdafec34f, 0xca22e3fd, 0x7a0b83c0, 0xaa712387, + 0x1a5843ba, 0x4d773299, 0xfd5e52a4, 0x2d24f2e3, 0x9d0d92de, + 0x8dd1b26c, 0x3df8d251, 0xed827216, 0x5dab122b, 0x8c3c42a9, + 0x3c152294, 0xec6f82d3, 0x5c46e2ee, 0x4c9ac25c, 0xfcb3a261, + 0x2cc90226, 0x9ce0621b, 0xcfe0d2f9, 0x7fc9b2c4, 0xafb31283, + 0x1f9a72be, 0x0f46520c, 0xbf6f3231, 0x6f159276, 0xdf3cf24b, + 0x0eaba2c9, 0xbe82c2f4, 0x6ef862b3, 0xded1028e, 0xce0d223c, + 0x7e244201, 0xae5ee246, 0x1e77827b, 0x92b0e6b1, 0x2299868c, + 0xf2e326cb, 0x42ca46f6, 0x52166644, 0xe23f0679, 0x3245a63e, + 0x826cc603, 0x53fb9681, 0xe3d2f6bc, 0x33a856fb, 0x838136c6, + 0x935d1674, 0x23747649, 0xf30ed60e, 0x4327b633, 0x102706d1, + 0xa00e66ec, 0x7074c6ab, 0xc05da696, 0xd0818624, 0x60a8e619, + 0xb0d2465e, 0x00fb2663, 0xd16c76e1, 0x614516dc, 0xb13fb69b, + 0x0116d6a6, 0x11caf614, 0xa1e39629, 0x7199366e, 0xc1b05653, + 0x969f2770, 0x26b6474d, 0xf6cce70a, 0x46e58737, 0x5639a785, + 0xe610c7b8, 0x366a67ff, 0x864307c2, 0x57d45740, 0xe7fd377d, + 0x3787973a, 0x87aef707, 0x9772d7b5, 0x275bb788, 0xf72117cf, + 0x470877f2, 0x1408c710, 0xa421a72d, 0x745b076a, 0xc4726757, + 0xd4ae47e5, 0x648727d8, 0xb4fd879f, 0x04d4e7a2, 0xd543b720, + 0x656ad71d, 0xb510775a, 0x05391767, 0x15e537d5, 0xa5cc57e8, + 0x75b6f7af, 0xc59f9792, 0xdbe815e9, 0x6bc175d4, 0xbbbbd593, + 0x0b92b5ae, 0x1b4e951c, 0xab67f521, 0x7b1d5566, 0xcb34355b, + 0x1aa365d9, 0xaa8a05e4, 0x7af0a5a3, 0xcad9c59e, 0xda05e52c, + 0x6a2c8511, 0xba562556, 0x0a7f456b, 0x597ff589, 0xe95695b4, + 0x392c35f3, 0x890555ce, 0x99d9757c, 0x29f01541, 0xf98ab506, + 0x49a3d53b, 0x983485b9, 0x281de584, 0xf86745c3, 0x484e25fe, + 0x5892054c, 0xe8bb6571, 0x38c1c536, 0x88e8a50b, 0xdfc7d428, + 0x6feeb415, 0xbf941452, 0x0fbd746f, 0x1f6154dd, 0xaf4834e0, + 0x7f3294a7, 0xcf1bf49a, 0x1e8ca418, 0xaea5c425, 0x7edf6462, + 0xcef6045f, 0xde2a24ed, 0x6e0344d0, 0xbe79e497, 0x0e5084aa, + 0x5d503448, 0xed795475, 0x3d03f432, 0x8d2a940f, 0x9df6b4bd, + 0x2ddfd480, 0xfda574c7, 0x4d8c14fa, 0x9c1b4478, 0x2c322445, + 0xfc488402, 0x4c61e43f, 0x5cbdc48d, 0xec94a4b0, 0x3cee04f7, + 0x8cc764ca}, + {0x00000000, 0xa5d35ccb, 0x0ba1c84d, 0xae729486, 0x1642919b, + 0xb391cd50, 0x1de359d6, 0xb830051d, 0x6d8253ec, 0xc8510f27, + 0x66239ba1, 0xc3f0c76a, 0x7bc0c277, 0xde139ebc, 0x70610a3a, + 0xd5b256f1, 0x9b02d603, 0x3ed18ac8, 0x90a31e4e, 0x35704285, + 0x8d404798, 0x28931b53, 0x86e18fd5, 0x2332d31e, 0xf68085ef, + 0x5353d924, 0xfd214da2, 0x58f21169, 0xe0c21474, 0x451148bf, + 0xeb63dc39, 0x4eb080f2, 0x3605ac07, 0x93d6f0cc, 0x3da4644a, + 0x98773881, 0x20473d9c, 0x85946157, 0x2be6f5d1, 0x8e35a91a, + 0x5b87ffeb, 0xfe54a320, 0x502637a6, 0xf5f56b6d, 0x4dc56e70, + 0xe81632bb, 0x4664a63d, 0xe3b7faf6, 0xad077a04, 0x08d426cf, + 0xa6a6b249, 0x0375ee82, 0xbb45eb9f, 0x1e96b754, 0xb0e423d2, + 0x15377f19, 0xc08529e8, 0x65567523, 0xcb24e1a5, 0x6ef7bd6e, + 0xd6c7b873, 0x7314e4b8, 0xdd66703e, 0x78b52cf5, 0x6c0a580f, + 0xc9d904c4, 0x67ab9042, 0xc278cc89, 0x7a48c994, 0xdf9b955f, + 0x71e901d9, 0xd43a5d12, 0x01880be3, 0xa45b5728, 0x0a29c3ae, + 0xaffa9f65, 0x17ca9a78, 0xb219c6b3, 0x1c6b5235, 0xb9b80efe, + 0xf7088e0c, 0x52dbd2c7, 0xfca94641, 0x597a1a8a, 0xe14a1f97, + 0x4499435c, 0xeaebd7da, 0x4f388b11, 0x9a8adde0, 0x3f59812b, + 0x912b15ad, 0x34f84966, 0x8cc84c7b, 0x291b10b0, 0x87698436, + 0x22bad8fd, 0x5a0ff408, 0xffdca8c3, 0x51ae3c45, 0xf47d608e, + 0x4c4d6593, 0xe99e3958, 0x47ecadde, 0xe23ff115, 0x378da7e4, + 0x925efb2f, 0x3c2c6fa9, 0x99ff3362, 0x21cf367f, 0x841c6ab4, + 0x2a6efe32, 0x8fbda2f9, 0xc10d220b, 0x64de7ec0, 0xcaacea46, + 0x6f7fb68d, 0xd74fb390, 0x729cef5b, 0xdcee7bdd, 0x793d2716, + 0xac8f71e7, 0x095c2d2c, 0xa72eb9aa, 0x02fde561, 0xbacde07c, + 0x1f1ebcb7, 0xb16c2831, 0x14bf74fa, 0xd814b01e, 0x7dc7ecd5, + 0xd3b57853, 0x76662498, 0xce562185, 0x6b857d4e, 0xc5f7e9c8, + 0x6024b503, 0xb596e3f2, 0x1045bf39, 0xbe372bbf, 0x1be47774, + 0xa3d47269, 0x06072ea2, 0xa875ba24, 0x0da6e6ef, 0x4316661d, + 0xe6c53ad6, 0x48b7ae50, 0xed64f29b, 0x5554f786, 0xf087ab4d, + 0x5ef53fcb, 0xfb266300, 0x2e9435f1, 0x8b47693a, 0x2535fdbc, + 0x80e6a177, 0x38d6a46a, 0x9d05f8a1, 0x33776c27, 0x96a430ec, + 0xee111c19, 0x4bc240d2, 0xe5b0d454, 0x4063889f, 0xf8538d82, + 0x5d80d149, 0xf3f245cf, 0x56211904, 0x83934ff5, 0x2640133e, + 0x883287b8, 0x2de1db73, 0x95d1de6e, 0x300282a5, 0x9e701623, + 0x3ba34ae8, 0x7513ca1a, 0xd0c096d1, 0x7eb20257, 0xdb615e9c, + 0x63515b81, 0xc682074a, 0x68f093cc, 0xcd23cf07, 0x189199f6, + 0xbd42c53d, 0x133051bb, 0xb6e30d70, 0x0ed3086d, 0xab0054a6, + 0x0572c020, 0xa0a19ceb, 0xb41ee811, 0x11cdb4da, 0xbfbf205c, + 0x1a6c7c97, 0xa25c798a, 0x078f2541, 0xa9fdb1c7, 0x0c2eed0c, + 0xd99cbbfd, 0x7c4fe736, 0xd23d73b0, 0x77ee2f7b, 0xcfde2a66, + 0x6a0d76ad, 0xc47fe22b, 0x61acbee0, 0x2f1c3e12, 0x8acf62d9, + 0x24bdf65f, 0x816eaa94, 0x395eaf89, 0x9c8df342, 0x32ff67c4, + 0x972c3b0f, 0x429e6dfe, 0xe74d3135, 0x493fa5b3, 0xececf978, + 0x54dcfc65, 0xf10fa0ae, 0x5f7d3428, 0xfaae68e3, 0x821b4416, + 0x27c818dd, 0x89ba8c5b, 0x2c69d090, 0x9459d58d, 0x318a8946, + 0x9ff81dc0, 0x3a2b410b, 0xef9917fa, 0x4a4a4b31, 0xe438dfb7, + 0x41eb837c, 0xf9db8661, 0x5c08daaa, 0xf27a4e2c, 0x57a912e7, + 0x19199215, 0xbccacede, 0x12b85a58, 0xb76b0693, 0x0f5b038e, + 0xaa885f45, 0x04facbc3, 0xa1299708, 0x749bc1f9, 0xd1489d32, + 0x7f3a09b4, 0xdae9557f, 0x62d95062, 0xc70a0ca9, 0x6978982f, + 0xccabc4e4}, + {0x00000000, 0xb40b77a6, 0x29119f97, 0x9d1ae831, 0x13244ff4, + 0xa72f3852, 0x3a35d063, 0x8e3ea7c5, 0x674eef33, 0xd3459895, + 0x4e5f70a4, 0xfa540702, 0x746aa0c7, 0xc061d761, 0x5d7b3f50, + 0xe97048f6, 0xce9cde67, 0x7a97a9c1, 0xe78d41f0, 0x53863656, + 0xddb89193, 0x69b3e635, 0xf4a90e04, 0x40a279a2, 0xa9d23154, + 0x1dd946f2, 0x80c3aec3, 0x34c8d965, 0xbaf67ea0, 0x0efd0906, + 0x93e7e137, 0x27ec9691, 0x9c39bdcf, 0x2832ca69, 0xb5282258, + 0x012355fe, 0x8f1df23b, 0x3b16859d, 0xa60c6dac, 0x12071a0a, + 0xfb7752fc, 0x4f7c255a, 0xd266cd6b, 0x666dbacd, 0xe8531d08, + 0x5c586aae, 0xc142829f, 0x7549f539, 0x52a563a8, 0xe6ae140e, + 0x7bb4fc3f, 0xcfbf8b99, 0x41812c5c, 0xf58a5bfa, 0x6890b3cb, + 0xdc9bc46d, 0x35eb8c9b, 0x81e0fb3d, 0x1cfa130c, 0xa8f164aa, + 0x26cfc36f, 0x92c4b4c9, 0x0fde5cf8, 0xbbd52b5e, 0x79750b44, + 0xcd7e7ce2, 0x506494d3, 0xe46fe375, 0x6a5144b0, 0xde5a3316, + 0x4340db27, 0xf74bac81, 0x1e3be477, 0xaa3093d1, 0x372a7be0, + 0x83210c46, 0x0d1fab83, 0xb914dc25, 0x240e3414, 0x900543b2, + 0xb7e9d523, 0x03e2a285, 0x9ef84ab4, 0x2af33d12, 0xa4cd9ad7, + 0x10c6ed71, 0x8ddc0540, 0x39d772e6, 0xd0a73a10, 0x64ac4db6, + 0xf9b6a587, 0x4dbdd221, 0xc38375e4, 0x77880242, 0xea92ea73, + 0x5e999dd5, 0xe54cb68b, 0x5147c12d, 0xcc5d291c, 0x78565eba, + 0xf668f97f, 0x42638ed9, 0xdf7966e8, 0x6b72114e, 0x820259b8, + 0x36092e1e, 0xab13c62f, 0x1f18b189, 0x9126164c, 0x252d61ea, + 0xb83789db, 0x0c3cfe7d, 0x2bd068ec, 0x9fdb1f4a, 0x02c1f77b, + 0xb6ca80dd, 0x38f42718, 0x8cff50be, 0x11e5b88f, 0xa5eecf29, + 0x4c9e87df, 0xf895f079, 0x658f1848, 0xd1846fee, 0x5fbac82b, + 0xebb1bf8d, 0x76ab57bc, 0xc2a0201a, 0xf2ea1688, 0x46e1612e, + 0xdbfb891f, 0x6ff0feb9, 0xe1ce597c, 0x55c52eda, 0xc8dfc6eb, + 0x7cd4b14d, 0x95a4f9bb, 0x21af8e1d, 0xbcb5662c, 0x08be118a, + 0x8680b64f, 0x328bc1e9, 0xaf9129d8, 0x1b9a5e7e, 0x3c76c8ef, + 0x887dbf49, 0x15675778, 0xa16c20de, 0x2f52871b, 0x9b59f0bd, + 0x0643188c, 0xb2486f2a, 0x5b3827dc, 0xef33507a, 0x7229b84b, + 0xc622cfed, 0x481c6828, 0xfc171f8e, 0x610df7bf, 0xd5068019, + 0x6ed3ab47, 0xdad8dce1, 0x47c234d0, 0xf3c94376, 0x7df7e4b3, + 0xc9fc9315, 0x54e67b24, 0xe0ed0c82, 0x099d4474, 0xbd9633d2, + 0x208cdbe3, 0x9487ac45, 0x1ab90b80, 0xaeb27c26, 0x33a89417, + 0x87a3e3b1, 0xa04f7520, 0x14440286, 0x895eeab7, 0x3d559d11, + 0xb36b3ad4, 0x07604d72, 0x9a7aa543, 0x2e71d2e5, 0xc7019a13, + 0x730aedb5, 0xee100584, 0x5a1b7222, 0xd425d5e7, 0x602ea241, + 0xfd344a70, 0x493f3dd6, 0x8b9f1dcc, 0x3f946a6a, 0xa28e825b, + 0x1685f5fd, 0x98bb5238, 0x2cb0259e, 0xb1aacdaf, 0x05a1ba09, + 0xecd1f2ff, 0x58da8559, 0xc5c06d68, 0x71cb1ace, 0xfff5bd0b, + 0x4bfecaad, 0xd6e4229c, 0x62ef553a, 0x4503c3ab, 0xf108b40d, + 0x6c125c3c, 0xd8192b9a, 0x56278c5f, 0xe22cfbf9, 0x7f3613c8, + 0xcb3d646e, 0x224d2c98, 0x96465b3e, 0x0b5cb30f, 0xbf57c4a9, + 0x3169636c, 0x856214ca, 0x1878fcfb, 0xac738b5d, 0x17a6a003, + 0xa3add7a5, 0x3eb73f94, 0x8abc4832, 0x0482eff7, 0xb0899851, + 0x2d937060, 0x999807c6, 0x70e84f30, 0xc4e33896, 0x59f9d0a7, + 0xedf2a701, 0x63cc00c4, 0xd7c77762, 0x4add9f53, 0xfed6e8f5, + 0xd93a7e64, 0x6d3109c2, 0xf02be1f3, 0x44209655, 0xca1e3190, + 0x7e154636, 0xe30fae07, 0x5704d9a1, 0xbe749157, 0x0a7fe6f1, + 0x97650ec0, 0x236e7966, 0xad50dea3, 0x195ba905, 0x84414134, + 0x304a3692}, + {0x00000000, 0x9e00aacc, 0x7d072542, 0xe3078f8e, 0xfa0e4a84, + 0x640ee048, 0x87096fc6, 0x1909c50a, 0xb51be5d3, 0x2b1b4f1f, + 0xc81cc091, 0x561c6a5d, 0x4f15af57, 0xd115059b, 0x32128a15, + 0xac1220d9, 0x2b31bb7c, 0xb53111b0, 0x56369e3e, 0xc83634f2, + 0xd13ff1f8, 0x4f3f5b34, 0xac38d4ba, 0x32387e76, 0x9e2a5eaf, + 0x002af463, 0xe32d7bed, 0x7d2dd121, 0x6424142b, 0xfa24bee7, + 0x19233169, 0x87239ba5, 0x566276f9, 0xc862dc35, 0x2b6553bb, + 0xb565f977, 0xac6c3c7d, 0x326c96b1, 0xd16b193f, 0x4f6bb3f3, + 0xe379932a, 0x7d7939e6, 0x9e7eb668, 0x007e1ca4, 0x1977d9ae, + 0x87777362, 0x6470fcec, 0xfa705620, 0x7d53cd85, 0xe3536749, + 0x0054e8c7, 0x9e54420b, 0x875d8701, 0x195d2dcd, 0xfa5aa243, + 0x645a088f, 0xc8482856, 0x5648829a, 0xb54f0d14, 0x2b4fa7d8, + 0x324662d2, 0xac46c81e, 0x4f414790, 0xd141ed5c, 0xedc29d29, + 0x73c237e5, 0x90c5b86b, 0x0ec512a7, 0x17ccd7ad, 0x89cc7d61, + 0x6acbf2ef, 0xf4cb5823, 0x58d978fa, 0xc6d9d236, 0x25de5db8, + 0xbbdef774, 0xa2d7327e, 0x3cd798b2, 0xdfd0173c, 0x41d0bdf0, + 0xc6f32655, 0x58f38c99, 0xbbf40317, 0x25f4a9db, 0x3cfd6cd1, + 0xa2fdc61d, 0x41fa4993, 0xdffae35f, 0x73e8c386, 0xede8694a, + 0x0eefe6c4, 0x90ef4c08, 0x89e68902, 0x17e623ce, 0xf4e1ac40, + 0x6ae1068c, 0xbba0ebd0, 0x25a0411c, 0xc6a7ce92, 0x58a7645e, + 0x41aea154, 0xdfae0b98, 0x3ca98416, 0xa2a92eda, 0x0ebb0e03, + 0x90bba4cf, 0x73bc2b41, 0xedbc818d, 0xf4b54487, 0x6ab5ee4b, + 0x89b261c5, 0x17b2cb09, 0x909150ac, 0x0e91fa60, 0xed9675ee, + 0x7396df22, 0x6a9f1a28, 0xf49fb0e4, 0x17983f6a, 0x899895a6, + 0x258ab57f, 0xbb8a1fb3, 0x588d903d, 0xc68d3af1, 0xdf84fffb, + 0x41845537, 0xa283dab9, 0x3c837075, 0xda853b53, 0x4485919f, + 0xa7821e11, 0x3982b4dd, 0x208b71d7, 0xbe8bdb1b, 0x5d8c5495, + 0xc38cfe59, 0x6f9ede80, 0xf19e744c, 0x1299fbc2, 0x8c99510e, + 0x95909404, 0x0b903ec8, 0xe897b146, 0x76971b8a, 0xf1b4802f, + 0x6fb42ae3, 0x8cb3a56d, 0x12b30fa1, 0x0bbacaab, 0x95ba6067, + 0x76bdefe9, 0xe8bd4525, 0x44af65fc, 0xdaafcf30, 0x39a840be, + 0xa7a8ea72, 0xbea12f78, 0x20a185b4, 0xc3a60a3a, 0x5da6a0f6, + 0x8ce74daa, 0x12e7e766, 0xf1e068e8, 0x6fe0c224, 0x76e9072e, + 0xe8e9ade2, 0x0bee226c, 0x95ee88a0, 0x39fca879, 0xa7fc02b5, + 0x44fb8d3b, 0xdafb27f7, 0xc3f2e2fd, 0x5df24831, 0xbef5c7bf, + 0x20f56d73, 0xa7d6f6d6, 0x39d65c1a, 0xdad1d394, 0x44d17958, + 0x5dd8bc52, 0xc3d8169e, 0x20df9910, 0xbedf33dc, 0x12cd1305, + 0x8ccdb9c9, 0x6fca3647, 0xf1ca9c8b, 0xe8c35981, 0x76c3f34d, + 0x95c47cc3, 0x0bc4d60f, 0x3747a67a, 0xa9470cb6, 0x4a408338, + 0xd44029f4, 0xcd49ecfe, 0x53494632, 0xb04ec9bc, 0x2e4e6370, + 0x825c43a9, 0x1c5ce965, 0xff5b66eb, 0x615bcc27, 0x7852092d, + 0xe652a3e1, 0x05552c6f, 0x9b5586a3, 0x1c761d06, 0x8276b7ca, + 0x61713844, 0xff719288, 0xe6785782, 0x7878fd4e, 0x9b7f72c0, + 0x057fd80c, 0xa96df8d5, 0x376d5219, 0xd46add97, 0x4a6a775b, + 0x5363b251, 0xcd63189d, 0x2e649713, 0xb0643ddf, 0x6125d083, + 0xff257a4f, 0x1c22f5c1, 0x82225f0d, 0x9b2b9a07, 0x052b30cb, + 0xe62cbf45, 0x782c1589, 0xd43e3550, 0x4a3e9f9c, 0xa9391012, + 0x3739bade, 0x2e307fd4, 0xb030d518, 0x53375a96, 0xcd37f05a, + 0x4a146bff, 0xd414c133, 0x37134ebd, 0xa913e471, 0xb01a217b, + 0x2e1a8bb7, 0xcd1d0439, 0x531daef5, 0xff0f8e2c, 0x610f24e0, + 0x8208ab6e, 0x1c0801a2, 0x0501c4a8, 0x9b016e64, 0x7806e1ea, + 0xe6064b26}}; + #endif - } -}; + +#endif + +#if N == 3 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f, + 0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999, + 0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee, + 0xe3150bc9, 0x7f6b7f3d, 0xfe4e1a1a, 0xa650b332, 0x2775d615, + 0x166de162, 0x97488445, 0xcf562d6d, 0x4e73484a, 0xad664383, + 0x2c4326a4, 0x745d8f8c, 0xf578eaab, 0xc460dddc, 0x4545b8fb, + 0x1d5b11d3, 0x9c7e74f4, 0xfed6fe7a, 0x7ff39b5d, 0x27ed3275, + 0xa6c85752, 0x97d06025, 0x16f50502, 0x4eebac2a, 0xcfcec90d, + 0x2cdbc2c4, 0xadfea7e3, 0xf5e00ecb, 0x74c56bec, 0x45dd5c9b, + 0xc4f839bc, 0x9ce69094, 0x1dc3f5b3, 0x81bd8147, 0x0098e460, + 0x58864d48, 0xd9a3286f, 0xe8bb1f18, 0x699e7a3f, 0x3180d317, + 0xb0a5b630, 0x53b0bdf9, 0xd295d8de, 0x8a8b71f6, 0x0bae14d1, + 0x3ab623a6, 0xbb934681, 0xe38defa9, 0x62a88a8e, 0x26dcfab5, + 0xa7f99f92, 0xffe736ba, 0x7ec2539d, 0x4fda64ea, 0xceff01cd, + 0x96e1a8e5, 0x17c4cdc2, 0xf4d1c60b, 0x75f4a32c, 0x2dea0a04, + 0xaccf6f23, 0x9dd75854, 0x1cf23d73, 0x44ec945b, 0xc5c9f17c, + 0x59b78588, 0xd892e0af, 0x808c4987, 0x01a92ca0, 0x30b11bd7, + 0xb1947ef0, 0xe98ad7d8, 0x68afb2ff, 0x8bbab936, 0x0a9fdc11, + 0x52817539, 0xd3a4101e, 0xe2bc2769, 0x6399424e, 0x3b87eb66, + 0xbaa28e41, 0xd80a04cf, 0x592f61e8, 0x0131c8c0, 0x8014ade7, + 0xb10c9a90, 0x3029ffb7, 0x6837569f, 0xe91233b8, 0x0a073871, + 0x8b225d56, 0xd33cf47e, 0x52199159, 0x6301a62e, 0xe224c309, + 0xba3a6a21, 0x3b1f0f06, 0xa7617bf2, 0x26441ed5, 0x7e5ab7fd, + 0xff7fd2da, 0xce67e5ad, 0x4f42808a, 0x175c29a2, 0x96794c85, + 0x756c474c, 0xf449226b, 0xac578b43, 0x2d72ee64, 0x1c6ad913, + 0x9d4fbc34, 0xc551151c, 0x4474703b, 0x4db9f56a, 0xcc9c904d, + 0x94823965, 0x15a75c42, 0x24bf6b35, 0xa59a0e12, 0xfd84a73a, + 0x7ca1c21d, 0x9fb4c9d4, 0x1e91acf3, 0x468f05db, 0xc7aa60fc, + 0xf6b2578b, 0x779732ac, 0x2f899b84, 0xaeacfea3, 0x32d28a57, + 0xb3f7ef70, 0xebe94658, 0x6acc237f, 0x5bd41408, 0xdaf1712f, + 0x82efd807, 0x03cabd20, 0xe0dfb6e9, 0x61fad3ce, 0x39e47ae6, + 0xb8c11fc1, 0x89d928b6, 0x08fc4d91, 0x50e2e4b9, 0xd1c7819e, + 0xb36f0b10, 0x324a6e37, 0x6a54c71f, 0xeb71a238, 0xda69954f, + 0x5b4cf068, 0x03525940, 0x82773c67, 0x616237ae, 0xe0475289, + 0xb859fba1, 0x397c9e86, 0x0864a9f1, 0x8941ccd6, 0xd15f65fe, + 0x507a00d9, 0xcc04742d, 0x4d21110a, 0x153fb822, 0x941add05, + 0xa502ea72, 0x24278f55, 0x7c39267d, 0xfd1c435a, 0x1e094893, + 0x9f2c2db4, 0xc732849c, 0x4617e1bb, 0x770fd6cc, 0xf62ab3eb, + 0xae341ac3, 0x2f117fe4, 0x6b650fdf, 0xea406af8, 0xb25ec3d0, + 0x337ba6f7, 0x02639180, 0x8346f4a7, 0xdb585d8f, 0x5a7d38a8, + 0xb9683361, 0x384d5646, 0x6053ff6e, 0xe1769a49, 0xd06ead3e, + 0x514bc819, 0x09556131, 0x88700416, 0x140e70e2, 0x952b15c5, + 0xcd35bced, 0x4c10d9ca, 0x7d08eebd, 0xfc2d8b9a, 0xa43322b2, + 0x25164795, 0xc6034c5c, 0x4726297b, 0x1f388053, 0x9e1de574, + 0xaf05d203, 0x2e20b724, 0x763e1e0c, 0xf71b7b2b, 0x95b3f1a5, + 0x14969482, 0x4c883daa, 0xcdad588d, 0xfcb56ffa, 0x7d900add, + 0x258ea3f5, 0xa4abc6d2, 0x47becd1b, 0xc69ba83c, 0x9e850114, + 0x1fa06433, 0x2eb85344, 0xaf9d3663, 0xf7839f4b, 0x76a6fa6c, + 0xead88e98, 0x6bfdebbf, 0x33e34297, 0xb2c627b0, 0x83de10c7, + 0x02fb75e0, 0x5ae5dcc8, 0xdbc0b9ef, 0x38d5b226, 0xb9f0d701, + 0xe1ee7e29, 0x60cb1b0e, 0x51d32c79, 0xd0f6495e, 0x88e8e076, + 0x09cd8551}, + {0x00000000, 0x9b73ead4, 0xed96d3e9, 0x76e5393d, 0x005ca193, + 0x9b2f4b47, 0xedca727a, 0x76b998ae, 0x00b94326, 0x9bcaa9f2, + 0xed2f90cf, 0x765c7a1b, 0x00e5e2b5, 0x9b960861, 0xed73315c, + 0x7600db88, 0x0172864c, 0x9a016c98, 0xece455a5, 0x7797bf71, + 0x012e27df, 0x9a5dcd0b, 0xecb8f436, 0x77cb1ee2, 0x01cbc56a, + 0x9ab82fbe, 0xec5d1683, 0x772efc57, 0x019764f9, 0x9ae48e2d, + 0xec01b710, 0x77725dc4, 0x02e50c98, 0x9996e64c, 0xef73df71, + 0x740035a5, 0x02b9ad0b, 0x99ca47df, 0xef2f7ee2, 0x745c9436, + 0x025c4fbe, 0x992fa56a, 0xefca9c57, 0x74b97683, 0x0200ee2d, + 0x997304f9, 0xef963dc4, 0x74e5d710, 0x03978ad4, 0x98e46000, + 0xee01593d, 0x7572b3e9, 0x03cb2b47, 0x98b8c193, 0xee5df8ae, + 0x752e127a, 0x032ec9f2, 0x985d2326, 0xeeb81a1b, 0x75cbf0cf, + 0x03726861, 0x980182b5, 0xeee4bb88, 0x7597515c, 0x05ca1930, + 0x9eb9f3e4, 0xe85ccad9, 0x732f200d, 0x0596b8a3, 0x9ee55277, + 0xe8006b4a, 0x7373819e, 0x05735a16, 0x9e00b0c2, 0xe8e589ff, + 0x7396632b, 0x052ffb85, 0x9e5c1151, 0xe8b9286c, 0x73cac2b8, + 0x04b89f7c, 0x9fcb75a8, 0xe92e4c95, 0x725da641, 0x04e43eef, + 0x9f97d43b, 0xe972ed06, 0x720107d2, 0x0401dc5a, 0x9f72368e, + 0xe9970fb3, 0x72e4e567, 0x045d7dc9, 0x9f2e971d, 0xe9cbae20, + 0x72b844f4, 0x072f15a8, 0x9c5cff7c, 0xeab9c641, 0x71ca2c95, + 0x0773b43b, 0x9c005eef, 0xeae567d2, 0x71968d06, 0x0796568e, + 0x9ce5bc5a, 0xea008567, 0x71736fb3, 0x07caf71d, 0x9cb91dc9, + 0xea5c24f4, 0x712fce20, 0x065d93e4, 0x9d2e7930, 0xebcb400d, + 0x70b8aad9, 0x06013277, 0x9d72d8a3, 0xeb97e19e, 0x70e40b4a, + 0x06e4d0c2, 0x9d973a16, 0xeb72032b, 0x7001e9ff, 0x06b87151, + 0x9dcb9b85, 0xeb2ea2b8, 0x705d486c, 0x0b943260, 0x90e7d8b4, + 0xe602e189, 0x7d710b5d, 0x0bc893f3, 0x90bb7927, 0xe65e401a, + 0x7d2daace, 0x0b2d7146, 0x905e9b92, 0xe6bba2af, 0x7dc8487b, + 0x0b71d0d5, 0x90023a01, 0xe6e7033c, 0x7d94e9e8, 0x0ae6b42c, + 0x91955ef8, 0xe77067c5, 0x7c038d11, 0x0aba15bf, 0x91c9ff6b, + 0xe72cc656, 0x7c5f2c82, 0x0a5ff70a, 0x912c1dde, 0xe7c924e3, + 0x7cbace37, 0x0a035699, 0x9170bc4d, 0xe7958570, 0x7ce66fa4, + 0x09713ef8, 0x9202d42c, 0xe4e7ed11, 0x7f9407c5, 0x092d9f6b, + 0x925e75bf, 0xe4bb4c82, 0x7fc8a656, 0x09c87dde, 0x92bb970a, + 0xe45eae37, 0x7f2d44e3, 0x0994dc4d, 0x92e73699, 0xe4020fa4, + 0x7f71e570, 0x0803b8b4, 0x93705260, 0xe5956b5d, 0x7ee68189, + 0x085f1927, 0x932cf3f3, 0xe5c9cace, 0x7eba201a, 0x08bafb92, + 0x93c91146, 0xe52c287b, 0x7e5fc2af, 0x08e65a01, 0x9395b0d5, + 0xe57089e8, 0x7e03633c, 0x0e5e2b50, 0x952dc184, 0xe3c8f8b9, + 0x78bb126d, 0x0e028ac3, 0x95716017, 0xe394592a, 0x78e7b3fe, + 0x0ee76876, 0x959482a2, 0xe371bb9f, 0x7802514b, 0x0ebbc9e5, + 0x95c82331, 0xe32d1a0c, 0x785ef0d8, 0x0f2cad1c, 0x945f47c8, + 0xe2ba7ef5, 0x79c99421, 0x0f700c8f, 0x9403e65b, 0xe2e6df66, + 0x799535b2, 0x0f95ee3a, 0x94e604ee, 0xe2033dd3, 0x7970d707, + 0x0fc94fa9, 0x94baa57d, 0xe25f9c40, 0x792c7694, 0x0cbb27c8, + 0x97c8cd1c, 0xe12df421, 0x7a5e1ef5, 0x0ce7865b, 0x97946c8f, + 0xe17155b2, 0x7a02bf66, 0x0c0264ee, 0x97718e3a, 0xe194b707, + 0x7ae75dd3, 0x0c5ec57d, 0x972d2fa9, 0xe1c81694, 0x7abbfc40, + 0x0dc9a184, 0x96ba4b50, 0xe05f726d, 0x7b2c98b9, 0x0d950017, + 0x96e6eac3, 0xe003d3fe, 0x7b70392a, 0x0d70e2a2, 0x96030876, + 0xe0e6314b, 0x7b95db9f, 0x0d2c4331, 0x965fa9e5, 0xe0ba90d8, + 0x7bc97a0c}, + {0x00000000, 0x172864c0, 0x2e50c980, 0x3978ad40, 0x5ca19300, + 0x4b89f7c0, 0x72f15a80, 0x65d93e40, 0xb9432600, 0xae6b42c0, + 0x9713ef80, 0x803b8b40, 0xe5e2b500, 0xf2cad1c0, 0xcbb27c80, + 0xdc9a1840, 0xa9f74a41, 0xbedf2e81, 0x87a783c1, 0x908fe701, + 0xf556d941, 0xe27ebd81, 0xdb0610c1, 0xcc2e7401, 0x10b46c41, + 0x079c0881, 0x3ee4a5c1, 0x29ccc101, 0x4c15ff41, 0x5b3d9b81, + 0x624536c1, 0x756d5201, 0x889f92c3, 0x9fb7f603, 0xa6cf5b43, + 0xb1e73f83, 0xd43e01c3, 0xc3166503, 0xfa6ec843, 0xed46ac83, + 0x31dcb4c3, 0x26f4d003, 0x1f8c7d43, 0x08a41983, 0x6d7d27c3, + 0x7a554303, 0x432dee43, 0x54058a83, 0x2168d882, 0x3640bc42, + 0x0f381102, 0x181075c2, 0x7dc94b82, 0x6ae12f42, 0x53998202, + 0x44b1e6c2, 0x982bfe82, 0x8f039a42, 0xb67b3702, 0xa15353c2, + 0xc48a6d82, 0xd3a20942, 0xeadaa402, 0xfdf2c0c2, 0xca4e23c7, + 0xdd664707, 0xe41eea47, 0xf3368e87, 0x96efb0c7, 0x81c7d407, + 0xb8bf7947, 0xaf971d87, 0x730d05c7, 0x64256107, 0x5d5dcc47, + 0x4a75a887, 0x2fac96c7, 0x3884f207, 0x01fc5f47, 0x16d43b87, + 0x63b96986, 0x74910d46, 0x4de9a006, 0x5ac1c4c6, 0x3f18fa86, + 0x28309e46, 0x11483306, 0x066057c6, 0xdafa4f86, 0xcdd22b46, + 0xf4aa8606, 0xe382e2c6, 0x865bdc86, 0x9173b846, 0xa80b1506, + 0xbf2371c6, 0x42d1b104, 0x55f9d5c4, 0x6c817884, 0x7ba91c44, + 0x1e702204, 0x095846c4, 0x3020eb84, 0x27088f44, 0xfb929704, + 0xecbaf3c4, 0xd5c25e84, 0xc2ea3a44, 0xa7330404, 0xb01b60c4, + 0x8963cd84, 0x9e4ba944, 0xeb26fb45, 0xfc0e9f85, 0xc57632c5, + 0xd25e5605, 0xb7876845, 0xa0af0c85, 0x99d7a1c5, 0x8effc505, + 0x5265dd45, 0x454db985, 0x7c3514c5, 0x6b1d7005, 0x0ec44e45, + 0x19ec2a85, 0x209487c5, 0x37bce305, 0x4fed41cf, 0x58c5250f, + 0x61bd884f, 0x7695ec8f, 0x134cd2cf, 0x0464b60f, 0x3d1c1b4f, + 0x2a347f8f, 0xf6ae67cf, 0xe186030f, 0xd8feae4f, 0xcfd6ca8f, + 0xaa0ff4cf, 0xbd27900f, 0x845f3d4f, 0x9377598f, 0xe61a0b8e, + 0xf1326f4e, 0xc84ac20e, 0xdf62a6ce, 0xbabb988e, 0xad93fc4e, + 0x94eb510e, 0x83c335ce, 0x5f592d8e, 0x4871494e, 0x7109e40e, + 0x662180ce, 0x03f8be8e, 0x14d0da4e, 0x2da8770e, 0x3a8013ce, + 0xc772d30c, 0xd05ab7cc, 0xe9221a8c, 0xfe0a7e4c, 0x9bd3400c, + 0x8cfb24cc, 0xb583898c, 0xa2abed4c, 0x7e31f50c, 0x691991cc, + 0x50613c8c, 0x4749584c, 0x2290660c, 0x35b802cc, 0x0cc0af8c, + 0x1be8cb4c, 0x6e85994d, 0x79adfd8d, 0x40d550cd, 0x57fd340d, + 0x32240a4d, 0x250c6e8d, 0x1c74c3cd, 0x0b5ca70d, 0xd7c6bf4d, + 0xc0eedb8d, 0xf99676cd, 0xeebe120d, 0x8b672c4d, 0x9c4f488d, + 0xa537e5cd, 0xb21f810d, 0x85a36208, 0x928b06c8, 0xabf3ab88, + 0xbcdbcf48, 0xd902f108, 0xce2a95c8, 0xf7523888, 0xe07a5c48, + 0x3ce04408, 0x2bc820c8, 0x12b08d88, 0x0598e948, 0x6041d708, + 0x7769b3c8, 0x4e111e88, 0x59397a48, 0x2c542849, 0x3b7c4c89, + 0x0204e1c9, 0x152c8509, 0x70f5bb49, 0x67dddf89, 0x5ea572c9, + 0x498d1609, 0x95170e49, 0x823f6a89, 0xbb47c7c9, 0xac6fa309, + 0xc9b69d49, 0xde9ef989, 0xe7e654c9, 0xf0ce3009, 0x0d3cf0cb, + 0x1a14940b, 0x236c394b, 0x34445d8b, 0x519d63cb, 0x46b5070b, + 0x7fcdaa4b, 0x68e5ce8b, 0xb47fd6cb, 0xa357b20b, 0x9a2f1f4b, + 0x8d077b8b, 0xe8de45cb, 0xfff6210b, 0xc68e8c4b, 0xd1a6e88b, + 0xa4cbba8a, 0xb3e3de4a, 0x8a9b730a, 0x9db317ca, 0xf86a298a, + 0xef424d4a, 0xd63ae00a, 0xc11284ca, 0x1d889c8a, 0x0aa0f84a, + 0x33d8550a, 0x24f031ca, 0x41290f8a, 0x56016b4a, 0x6f79c60a, + 0x7851a2ca}, + {0x00000000, 0x9fda839e, 0xe4c4017d, 0x7b1e82e3, 0x12f904bb, + 0x8d238725, 0xf63d05c6, 0x69e78658, 0x25f20976, 0xba288ae8, + 0xc136080b, 0x5eec8b95, 0x370b0dcd, 0xa8d18e53, 0xd3cf0cb0, + 0x4c158f2e, 0x4be412ec, 0xd43e9172, 0xaf201391, 0x30fa900f, + 0x591d1657, 0xc6c795c9, 0xbdd9172a, 0x220394b4, 0x6e161b9a, + 0xf1cc9804, 0x8ad21ae7, 0x15089979, 0x7cef1f21, 0xe3359cbf, + 0x982b1e5c, 0x07f19dc2, 0x97c825d8, 0x0812a646, 0x730c24a5, + 0xecd6a73b, 0x85312163, 0x1aeba2fd, 0x61f5201e, 0xfe2fa380, + 0xb23a2cae, 0x2de0af30, 0x56fe2dd3, 0xc924ae4d, 0xa0c32815, + 0x3f19ab8b, 0x44072968, 0xdbddaaf6, 0xdc2c3734, 0x43f6b4aa, + 0x38e83649, 0xa732b5d7, 0xced5338f, 0x510fb011, 0x2a1132f2, + 0xb5cbb16c, 0xf9de3e42, 0x6604bddc, 0x1d1a3f3f, 0x82c0bca1, + 0xeb273af9, 0x74fdb967, 0x0fe33b84, 0x9039b81a, 0xf4e14df1, + 0x6b3bce6f, 0x10254c8c, 0x8fffcf12, 0xe618494a, 0x79c2cad4, + 0x02dc4837, 0x9d06cba9, 0xd1134487, 0x4ec9c719, 0x35d745fa, + 0xaa0dc664, 0xc3ea403c, 0x5c30c3a2, 0x272e4141, 0xb8f4c2df, + 0xbf055f1d, 0x20dfdc83, 0x5bc15e60, 0xc41bddfe, 0xadfc5ba6, + 0x3226d838, 0x49385adb, 0xd6e2d945, 0x9af7566b, 0x052dd5f5, + 0x7e335716, 0xe1e9d488, 0x880e52d0, 0x17d4d14e, 0x6cca53ad, + 0xf310d033, 0x63296829, 0xfcf3ebb7, 0x87ed6954, 0x1837eaca, + 0x71d06c92, 0xee0aef0c, 0x95146def, 0x0aceee71, 0x46db615f, + 0xd901e2c1, 0xa21f6022, 0x3dc5e3bc, 0x542265e4, 0xcbf8e67a, + 0xb0e66499, 0x2f3ce707, 0x28cd7ac5, 0xb717f95b, 0xcc097bb8, + 0x53d3f826, 0x3a347e7e, 0xa5eefde0, 0xdef07f03, 0x412afc9d, + 0x0d3f73b3, 0x92e5f02d, 0xe9fb72ce, 0x7621f150, 0x1fc67708, + 0x801cf496, 0xfb027675, 0x64d8f5eb, 0x32b39da3, 0xad691e3d, + 0xd6779cde, 0x49ad1f40, 0x204a9918, 0xbf901a86, 0xc48e9865, + 0x5b541bfb, 0x174194d5, 0x889b174b, 0xf38595a8, 0x6c5f1636, + 0x05b8906e, 0x9a6213f0, 0xe17c9113, 0x7ea6128d, 0x79578f4f, + 0xe68d0cd1, 0x9d938e32, 0x02490dac, 0x6bae8bf4, 0xf474086a, + 0x8f6a8a89, 0x10b00917, 0x5ca58639, 0xc37f05a7, 0xb8618744, + 0x27bb04da, 0x4e5c8282, 0xd186011c, 0xaa9883ff, 0x35420061, + 0xa57bb87b, 0x3aa13be5, 0x41bfb906, 0xde653a98, 0xb782bcc0, + 0x28583f5e, 0x5346bdbd, 0xcc9c3e23, 0x8089b10d, 0x1f533293, + 0x644db070, 0xfb9733ee, 0x9270b5b6, 0x0daa3628, 0x76b4b4cb, + 0xe96e3755, 0xee9faa97, 0x71452909, 0x0a5babea, 0x95812874, + 0xfc66ae2c, 0x63bc2db2, 0x18a2af51, 0x87782ccf, 0xcb6da3e1, + 0x54b7207f, 0x2fa9a29c, 0xb0732102, 0xd994a75a, 0x464e24c4, + 0x3d50a627, 0xa28a25b9, 0xc652d052, 0x598853cc, 0x2296d12f, + 0xbd4c52b1, 0xd4abd4e9, 0x4b715777, 0x306fd594, 0xafb5560a, + 0xe3a0d924, 0x7c7a5aba, 0x0764d859, 0x98be5bc7, 0xf159dd9f, + 0x6e835e01, 0x159ddce2, 0x8a475f7c, 0x8db6c2be, 0x126c4120, + 0x6972c3c3, 0xf6a8405d, 0x9f4fc605, 0x0095459b, 0x7b8bc778, + 0xe45144e6, 0xa844cbc8, 0x379e4856, 0x4c80cab5, 0xd35a492b, + 0xbabdcf73, 0x25674ced, 0x5e79ce0e, 0xc1a34d90, 0x519af58a, + 0xce407614, 0xb55ef4f7, 0x2a847769, 0x4363f131, 0xdcb972af, + 0xa7a7f04c, 0x387d73d2, 0x7468fcfc, 0xebb27f62, 0x90acfd81, + 0x0f767e1f, 0x6691f847, 0xf94b7bd9, 0x8255f93a, 0x1d8f7aa4, + 0x1a7ee766, 0x85a464f8, 0xfebae61b, 0x61606585, 0x0887e3dd, + 0x975d6043, 0xec43e2a0, 0x7399613e, 0x3f8cee10, 0xa0566d8e, + 0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6, + 0x566b6848}, + {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59, + 0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4, + 0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67, + 0x7c9f7021, 0xe0c6ab25, 0x85a19063, 0x2a08dda9, 0x4f6fe6ef, + 0xae2b407c, 0xcb4c7b3a, 0x64e536f0, 0x01820db6, 0x7d1d7d97, + 0x187a46d1, 0xb7d30b1b, 0xd2b4305d, 0x33f096ce, 0x5697ad88, + 0xf93ee042, 0x9c59db04, 0x1afc500b, 0x7f9b6b4d, 0xd0322687, + 0xb5551dc1, 0x5411bb52, 0x31768014, 0x9edfcdde, 0xfbb8f698, + 0x872786b9, 0xe240bdff, 0x4de9f035, 0x288ecb73, 0xc9ca6de0, + 0xacad56a6, 0x03041b6c, 0x6663202a, 0xfa3afb2e, 0x9f5dc068, + 0x30f48da2, 0x5593b6e4, 0xb4d71077, 0xd1b02b31, 0x7e1966fb, + 0x1b7e5dbd, 0x67e12d9c, 0x028616da, 0xad2f5b10, 0xc8486056, + 0x290cc6c5, 0x4c6bfd83, 0xe3c2b049, 0x86a58b0f, 0x35f8a016, + 0x509f9b50, 0xff36d69a, 0x9a51eddc, 0x7b154b4f, 0x1e727009, + 0xb1db3dc3, 0xd4bc0685, 0xa82376a4, 0xcd444de2, 0x62ed0028, + 0x078a3b6e, 0xe6ce9dfd, 0x83a9a6bb, 0x2c00eb71, 0x4967d037, + 0xd53e0b33, 0xb0593075, 0x1ff07dbf, 0x7a9746f9, 0x9bd3e06a, + 0xfeb4db2c, 0x511d96e6, 0x347aada0, 0x48e5dd81, 0x2d82e6c7, + 0x822bab0d, 0xe74c904b, 0x060836d8, 0x636f0d9e, 0xccc64054, + 0xa9a17b12, 0x2f04f01d, 0x4a63cb5b, 0xe5ca8691, 0x80adbdd7, + 0x61e91b44, 0x048e2002, 0xab276dc8, 0xce40568e, 0xb2df26af, + 0xd7b81de9, 0x78115023, 0x1d766b65, 0xfc32cdf6, 0x9955f6b0, + 0x36fcbb7a, 0x539b803c, 0xcfc25b38, 0xaaa5607e, 0x050c2db4, + 0x606b16f2, 0x812fb061, 0xe4488b27, 0x4be1c6ed, 0x2e86fdab, + 0x52198d8a, 0x377eb6cc, 0x98d7fb06, 0xfdb0c040, 0x1cf466d3, + 0x79935d95, 0xd63a105f, 0xb35d2b19, 0x6bf1402c, 0x0e967b6a, + 0xa13f36a0, 0xc4580de6, 0x251cab75, 0x407b9033, 0xefd2ddf9, + 0x8ab5e6bf, 0xf62a969e, 0x934dadd8, 0x3ce4e012, 0x5983db54, + 0xb8c77dc7, 0xdda04681, 0x72090b4b, 0x176e300d, 0x8b37eb09, + 0xee50d04f, 0x41f99d85, 0x249ea6c3, 0xc5da0050, 0xa0bd3b16, + 0x0f1476dc, 0x6a734d9a, 0x16ec3dbb, 0x738b06fd, 0xdc224b37, + 0xb9457071, 0x5801d6e2, 0x3d66eda4, 0x92cfa06e, 0xf7a89b28, + 0x710d1027, 0x146a2b61, 0xbbc366ab, 0xdea45ded, 0x3fe0fb7e, + 0x5a87c038, 0xf52e8df2, 0x9049b6b4, 0xecd6c695, 0x89b1fdd3, + 0x2618b019, 0x437f8b5f, 0xa23b2dcc, 0xc75c168a, 0x68f55b40, + 0x0d926006, 0x91cbbb02, 0xf4ac8044, 0x5b05cd8e, 0x3e62f6c8, + 0xdf26505b, 0xba416b1d, 0x15e826d7, 0x708f1d91, 0x0c106db0, + 0x697756f6, 0xc6de1b3c, 0xa3b9207a, 0x42fd86e9, 0x279abdaf, + 0x8833f065, 0xed54cb23, 0x5e09e03a, 0x3b6edb7c, 0x94c796b6, + 0xf1a0adf0, 0x10e40b63, 0x75833025, 0xda2a7def, 0xbf4d46a9, + 0xc3d23688, 0xa6b50dce, 0x091c4004, 0x6c7b7b42, 0x8d3fddd1, + 0xe858e697, 0x47f1ab5d, 0x2296901b, 0xbecf4b1f, 0xdba87059, + 0x74013d93, 0x116606d5, 0xf022a046, 0x95459b00, 0x3aecd6ca, + 0x5f8bed8c, 0x23149dad, 0x4673a6eb, 0xe9daeb21, 0x8cbdd067, + 0x6df976f4, 0x089e4db2, 0xa7370078, 0xc2503b3e, 0x44f5b031, + 0x21928b77, 0x8e3bc6bd, 0xeb5cfdfb, 0x0a185b68, 0x6f7f602e, + 0xc0d62de4, 0xa5b116a2, 0xd92e6683, 0xbc495dc5, 0x13e0100f, + 0x76872b49, 0x97c38dda, 0xf2a4b69c, 0x5d0dfb56, 0x386ac010, + 0xa4331b14, 0xc1542052, 0x6efd6d98, 0x0b9a56de, 0xeadef04d, + 0x8fb9cb0b, 0x201086c1, 0x4577bd87, 0x39e8cda6, 0x5c8ff6e0, + 0xf326bb2a, 0x9641806c, 0x770526ff, 0x12621db9, 0xbdcb5073, + 0xd8ac6b35}, + {0x00000000, 0xd7e28058, 0x74b406f1, 0xa35686a9, 0xe9680de2, + 0x3e8a8dba, 0x9ddc0b13, 0x4a3e8b4b, 0x09a11d85, 0xde439ddd, + 0x7d151b74, 0xaaf79b2c, 0xe0c91067, 0x372b903f, 0x947d1696, + 0x439f96ce, 0x13423b0a, 0xc4a0bb52, 0x67f63dfb, 0xb014bda3, + 0xfa2a36e8, 0x2dc8b6b0, 0x8e9e3019, 0x597cb041, 0x1ae3268f, + 0xcd01a6d7, 0x6e57207e, 0xb9b5a026, 0xf38b2b6d, 0x2469ab35, + 0x873f2d9c, 0x50ddadc4, 0x26847614, 0xf166f64c, 0x523070e5, + 0x85d2f0bd, 0xcfec7bf6, 0x180efbae, 0xbb587d07, 0x6cbafd5f, + 0x2f256b91, 0xf8c7ebc9, 0x5b916d60, 0x8c73ed38, 0xc64d6673, + 0x11afe62b, 0xb2f96082, 0x651be0da, 0x35c64d1e, 0xe224cd46, + 0x41724bef, 0x9690cbb7, 0xdcae40fc, 0x0b4cc0a4, 0xa81a460d, + 0x7ff8c655, 0x3c67509b, 0xeb85d0c3, 0x48d3566a, 0x9f31d632, + 0xd50f5d79, 0x02eddd21, 0xa1bb5b88, 0x7659dbd0, 0x4d08ec28, + 0x9aea6c70, 0x39bcead9, 0xee5e6a81, 0xa460e1ca, 0x73826192, + 0xd0d4e73b, 0x07366763, 0x44a9f1ad, 0x934b71f5, 0x301df75c, + 0xe7ff7704, 0xadc1fc4f, 0x7a237c17, 0xd975fabe, 0x0e977ae6, + 0x5e4ad722, 0x89a8577a, 0x2afed1d3, 0xfd1c518b, 0xb722dac0, + 0x60c05a98, 0xc396dc31, 0x14745c69, 0x57ebcaa7, 0x80094aff, + 0x235fcc56, 0xf4bd4c0e, 0xbe83c745, 0x6961471d, 0xca37c1b4, + 0x1dd541ec, 0x6b8c9a3c, 0xbc6e1a64, 0x1f389ccd, 0xc8da1c95, + 0x82e497de, 0x55061786, 0xf650912f, 0x21b21177, 0x622d87b9, + 0xb5cf07e1, 0x16998148, 0xc17b0110, 0x8b458a5b, 0x5ca70a03, + 0xfff18caa, 0x28130cf2, 0x78cea136, 0xaf2c216e, 0x0c7aa7c7, + 0xdb98279f, 0x91a6acd4, 0x46442c8c, 0xe512aa25, 0x32f02a7d, + 0x716fbcb3, 0xa68d3ceb, 0x05dbba42, 0xd2393a1a, 0x9807b151, + 0x4fe53109, 0xecb3b7a0, 0x3b5137f8, 0x9a11d850, 0x4df35808, + 0xeea5dea1, 0x39475ef9, 0x7379d5b2, 0xa49b55ea, 0x07cdd343, + 0xd02f531b, 0x93b0c5d5, 0x4452458d, 0xe704c324, 0x30e6437c, + 0x7ad8c837, 0xad3a486f, 0x0e6ccec6, 0xd98e4e9e, 0x8953e35a, + 0x5eb16302, 0xfde7e5ab, 0x2a0565f3, 0x603beeb8, 0xb7d96ee0, + 0x148fe849, 0xc36d6811, 0x80f2fedf, 0x57107e87, 0xf446f82e, + 0x23a47876, 0x699af33d, 0xbe787365, 0x1d2ef5cc, 0xcacc7594, + 0xbc95ae44, 0x6b772e1c, 0xc821a8b5, 0x1fc328ed, 0x55fda3a6, + 0x821f23fe, 0x2149a557, 0xf6ab250f, 0xb534b3c1, 0x62d63399, + 0xc180b530, 0x16623568, 0x5c5cbe23, 0x8bbe3e7b, 0x28e8b8d2, + 0xff0a388a, 0xafd7954e, 0x78351516, 0xdb6393bf, 0x0c8113e7, + 0x46bf98ac, 0x915d18f4, 0x320b9e5d, 0xe5e91e05, 0xa67688cb, + 0x71940893, 0xd2c28e3a, 0x05200e62, 0x4f1e8529, 0x98fc0571, + 0x3baa83d8, 0xec480380, 0xd7193478, 0x00fbb420, 0xa3ad3289, + 0x744fb2d1, 0x3e71399a, 0xe993b9c2, 0x4ac53f6b, 0x9d27bf33, + 0xdeb829fd, 0x095aa9a5, 0xaa0c2f0c, 0x7deeaf54, 0x37d0241f, + 0xe032a447, 0x436422ee, 0x9486a2b6, 0xc45b0f72, 0x13b98f2a, + 0xb0ef0983, 0x670d89db, 0x2d330290, 0xfad182c8, 0x59870461, + 0x8e658439, 0xcdfa12f7, 0x1a1892af, 0xb94e1406, 0x6eac945e, + 0x24921f15, 0xf3709f4d, 0x502619e4, 0x87c499bc, 0xf19d426c, + 0x267fc234, 0x8529449d, 0x52cbc4c5, 0x18f54f8e, 0xcf17cfd6, + 0x6c41497f, 0xbba3c927, 0xf83c5fe9, 0x2fdedfb1, 0x8c885918, + 0x5b6ad940, 0x1154520b, 0xc6b6d253, 0x65e054fa, 0xb202d4a2, + 0xe2df7966, 0x353df93e, 0x966b7f97, 0x4189ffcf, 0x0bb77484, + 0xdc55f4dc, 0x7f037275, 0xa8e1f22d, 0xeb7e64e3, 0x3c9ce4bb, + 0x9fca6212, 0x4828e24a, 0x02166901, 0xd5f4e959, 0x76a26ff0, + 0xa140efa8}, + {0x00000000, 0xef52b6e1, 0x05d46b83, 0xea86dd62, 0x0ba8d706, + 0xe4fa61e7, 0x0e7cbc85, 0xe12e0a64, 0x1751ae0c, 0xf80318ed, + 0x1285c58f, 0xfdd7736e, 0x1cf9790a, 0xf3abcfeb, 0x192d1289, + 0xf67fa468, 0x2ea35c18, 0xc1f1eaf9, 0x2b77379b, 0xc425817a, + 0x250b8b1e, 0xca593dff, 0x20dfe09d, 0xcf8d567c, 0x39f2f214, + 0xd6a044f5, 0x3c269997, 0xd3742f76, 0x325a2512, 0xdd0893f3, + 0x378e4e91, 0xd8dcf870, 0x5d46b830, 0xb2140ed1, 0x5892d3b3, + 0xb7c06552, 0x56ee6f36, 0xb9bcd9d7, 0x533a04b5, 0xbc68b254, + 0x4a17163c, 0xa545a0dd, 0x4fc37dbf, 0xa091cb5e, 0x41bfc13a, + 0xaeed77db, 0x446baab9, 0xab391c58, 0x73e5e428, 0x9cb752c9, + 0x76318fab, 0x9963394a, 0x784d332e, 0x971f85cf, 0x7d9958ad, + 0x92cbee4c, 0x64b44a24, 0x8be6fcc5, 0x616021a7, 0x8e329746, + 0x6f1c9d22, 0x804e2bc3, 0x6ac8f6a1, 0x859a4040, 0xba8d7060, + 0x55dfc681, 0xbf591be3, 0x500bad02, 0xb125a766, 0x5e771187, + 0xb4f1cce5, 0x5ba37a04, 0xaddcde6c, 0x428e688d, 0xa808b5ef, + 0x475a030e, 0xa674096a, 0x4926bf8b, 0xa3a062e9, 0x4cf2d408, + 0x942e2c78, 0x7b7c9a99, 0x91fa47fb, 0x7ea8f11a, 0x9f86fb7e, + 0x70d44d9f, 0x9a5290fd, 0x7500261c, 0x837f8274, 0x6c2d3495, + 0x86abe9f7, 0x69f95f16, 0x88d75572, 0x6785e393, 0x8d033ef1, + 0x62518810, 0xe7cbc850, 0x08997eb1, 0xe21fa3d3, 0x0d4d1532, + 0xec631f56, 0x0331a9b7, 0xe9b774d5, 0x06e5c234, 0xf09a665c, + 0x1fc8d0bd, 0xf54e0ddf, 0x1a1cbb3e, 0xfb32b15a, 0x146007bb, + 0xfee6dad9, 0x11b46c38, 0xc9689448, 0x263a22a9, 0xccbcffcb, + 0x23ee492a, 0xc2c0434e, 0x2d92f5af, 0xc71428cd, 0x28469e2c, + 0xde393a44, 0x316b8ca5, 0xdbed51c7, 0x34bfe726, 0xd591ed42, + 0x3ac35ba3, 0xd04586c1, 0x3f173020, 0xae6be681, 0x41395060, + 0xabbf8d02, 0x44ed3be3, 0xa5c33187, 0x4a918766, 0xa0175a04, + 0x4f45ece5, 0xb93a488d, 0x5668fe6c, 0xbcee230e, 0x53bc95ef, + 0xb2929f8b, 0x5dc0296a, 0xb746f408, 0x581442e9, 0x80c8ba99, + 0x6f9a0c78, 0x851cd11a, 0x6a4e67fb, 0x8b606d9f, 0x6432db7e, + 0x8eb4061c, 0x61e6b0fd, 0x97991495, 0x78cba274, 0x924d7f16, + 0x7d1fc9f7, 0x9c31c393, 0x73637572, 0x99e5a810, 0x76b71ef1, + 0xf32d5eb1, 0x1c7fe850, 0xf6f93532, 0x19ab83d3, 0xf88589b7, + 0x17d73f56, 0xfd51e234, 0x120354d5, 0xe47cf0bd, 0x0b2e465c, + 0xe1a89b3e, 0x0efa2ddf, 0xefd427bb, 0x0086915a, 0xea004c38, + 0x0552fad9, 0xdd8e02a9, 0x32dcb448, 0xd85a692a, 0x3708dfcb, + 0xd626d5af, 0x3974634e, 0xd3f2be2c, 0x3ca008cd, 0xcadfaca5, + 0x258d1a44, 0xcf0bc726, 0x205971c7, 0xc1777ba3, 0x2e25cd42, + 0xc4a31020, 0x2bf1a6c1, 0x14e696e1, 0xfbb42000, 0x1132fd62, + 0xfe604b83, 0x1f4e41e7, 0xf01cf706, 0x1a9a2a64, 0xf5c89c85, + 0x03b738ed, 0xece58e0c, 0x0663536e, 0xe931e58f, 0x081fefeb, + 0xe74d590a, 0x0dcb8468, 0xe2993289, 0x3a45caf9, 0xd5177c18, + 0x3f91a17a, 0xd0c3179b, 0x31ed1dff, 0xdebfab1e, 0x3439767c, + 0xdb6bc09d, 0x2d1464f5, 0xc246d214, 0x28c00f76, 0xc792b997, + 0x26bcb3f3, 0xc9ee0512, 0x2368d870, 0xcc3a6e91, 0x49a02ed1, + 0xa6f29830, 0x4c744552, 0xa326f3b3, 0x4208f9d7, 0xad5a4f36, + 0x47dc9254, 0xa88e24b5, 0x5ef180dd, 0xb1a3363c, 0x5b25eb5e, + 0xb4775dbf, 0x555957db, 0xba0be13a, 0x508d3c58, 0xbfdf8ab9, + 0x670372c9, 0x8851c428, 0x62d7194a, 0x8d85afab, 0x6caba5cf, + 0x83f9132e, 0x697fce4c, 0x862d78ad, 0x7052dcc5, 0x9f006a24, + 0x7586b746, 0x9ad401a7, 0x7bfa0bc3, 0x94a8bd22, 0x7e2e6040, + 0x917cd6a1}, + {0x00000000, 0x87a6cb43, 0xd43c90c7, 0x539a5b84, 0x730827cf, + 0xf4aeec8c, 0xa734b708, 0x20927c4b, 0xe6104f9e, 0x61b684dd, + 0x322cdf59, 0xb58a141a, 0x95186851, 0x12bea312, 0x4124f896, + 0xc68233d5, 0x1751997d, 0x90f7523e, 0xc36d09ba, 0x44cbc2f9, + 0x6459beb2, 0xe3ff75f1, 0xb0652e75, 0x37c3e536, 0xf141d6e3, + 0x76e71da0, 0x257d4624, 0xa2db8d67, 0x8249f12c, 0x05ef3a6f, + 0x567561eb, 0xd1d3aaa8, 0x2ea332fa, 0xa905f9b9, 0xfa9fa23d, + 0x7d39697e, 0x5dab1535, 0xda0dde76, 0x899785f2, 0x0e314eb1, + 0xc8b37d64, 0x4f15b627, 0x1c8feda3, 0x9b2926e0, 0xbbbb5aab, + 0x3c1d91e8, 0x6f87ca6c, 0xe821012f, 0x39f2ab87, 0xbe5460c4, + 0xedce3b40, 0x6a68f003, 0x4afa8c48, 0xcd5c470b, 0x9ec61c8f, + 0x1960d7cc, 0xdfe2e419, 0x58442f5a, 0x0bde74de, 0x8c78bf9d, + 0xaceac3d6, 0x2b4c0895, 0x78d65311, 0xff709852, 0x5d4665f4, + 0xdae0aeb7, 0x897af533, 0x0edc3e70, 0x2e4e423b, 0xa9e88978, + 0xfa72d2fc, 0x7dd419bf, 0xbb562a6a, 0x3cf0e129, 0x6f6abaad, + 0xe8cc71ee, 0xc85e0da5, 0x4ff8c6e6, 0x1c629d62, 0x9bc45621, + 0x4a17fc89, 0xcdb137ca, 0x9e2b6c4e, 0x198da70d, 0x391fdb46, + 0xbeb91005, 0xed234b81, 0x6a8580c2, 0xac07b317, 0x2ba17854, + 0x783b23d0, 0xff9de893, 0xdf0f94d8, 0x58a95f9b, 0x0b33041f, + 0x8c95cf5c, 0x73e5570e, 0xf4439c4d, 0xa7d9c7c9, 0x207f0c8a, + 0x00ed70c1, 0x874bbb82, 0xd4d1e006, 0x53772b45, 0x95f51890, + 0x1253d3d3, 0x41c98857, 0xc66f4314, 0xe6fd3f5f, 0x615bf41c, + 0x32c1af98, 0xb56764db, 0x64b4ce73, 0xe3120530, 0xb0885eb4, + 0x372e95f7, 0x17bce9bc, 0x901a22ff, 0xc380797b, 0x4426b238, + 0x82a481ed, 0x05024aae, 0x5698112a, 0xd13eda69, 0xf1aca622, + 0x760a6d61, 0x259036e5, 0xa236fda6, 0xba8ccbe8, 0x3d2a00ab, + 0x6eb05b2f, 0xe916906c, 0xc984ec27, 0x4e222764, 0x1db87ce0, + 0x9a1eb7a3, 0x5c9c8476, 0xdb3a4f35, 0x88a014b1, 0x0f06dff2, + 0x2f94a3b9, 0xa83268fa, 0xfba8337e, 0x7c0ef83d, 0xaddd5295, + 0x2a7b99d6, 0x79e1c252, 0xfe470911, 0xded5755a, 0x5973be19, + 0x0ae9e59d, 0x8d4f2ede, 0x4bcd1d0b, 0xcc6bd648, 0x9ff18dcc, + 0x1857468f, 0x38c53ac4, 0xbf63f187, 0xecf9aa03, 0x6b5f6140, + 0x942ff912, 0x13893251, 0x401369d5, 0xc7b5a296, 0xe727dedd, + 0x6081159e, 0x331b4e1a, 0xb4bd8559, 0x723fb68c, 0xf5997dcf, + 0xa603264b, 0x21a5ed08, 0x01379143, 0x86915a00, 0xd50b0184, + 0x52adcac7, 0x837e606f, 0x04d8ab2c, 0x5742f0a8, 0xd0e43beb, + 0xf07647a0, 0x77d08ce3, 0x244ad767, 0xa3ec1c24, 0x656e2ff1, + 0xe2c8e4b2, 0xb152bf36, 0x36f47475, 0x1666083e, 0x91c0c37d, + 0xc25a98f9, 0x45fc53ba, 0xe7caae1c, 0x606c655f, 0x33f63edb, + 0xb450f598, 0x94c289d3, 0x13644290, 0x40fe1914, 0xc758d257, + 0x01dae182, 0x867c2ac1, 0xd5e67145, 0x5240ba06, 0x72d2c64d, + 0xf5740d0e, 0xa6ee568a, 0x21489dc9, 0xf09b3761, 0x773dfc22, + 0x24a7a7a6, 0xa3016ce5, 0x839310ae, 0x0435dbed, 0x57af8069, + 0xd0094b2a, 0x168b78ff, 0x912db3bc, 0xc2b7e838, 0x4511237b, + 0x65835f30, 0xe2259473, 0xb1bfcff7, 0x361904b4, 0xc9699ce6, + 0x4ecf57a5, 0x1d550c21, 0x9af3c762, 0xba61bb29, 0x3dc7706a, + 0x6e5d2bee, 0xe9fbe0ad, 0x2f79d378, 0xa8df183b, 0xfb4543bf, + 0x7ce388fc, 0x5c71f4b7, 0xdbd73ff4, 0x884d6470, 0x0febaf33, + 0xde38059b, 0x599eced8, 0x0a04955c, 0x8da25e1f, 0xad302254, + 0x2a96e917, 0x790cb293, 0xfeaa79d0, 0x38284a05, 0xbf8e8146, + 0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d, + 0x18ba364e}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0x43cba68700000000, 0xc7903cd400000000, + 0x845b9a5300000000, 0xcf27087300000000, 0x8cecaef400000000, + 0x08b734a700000000, 0x4b7c922000000000, 0x9e4f10e600000000, + 0xdd84b66100000000, 0x59df2c3200000000, 0x1a148ab500000000, + 0x5168189500000000, 0x12a3be1200000000, 0x96f8244100000000, + 0xd53382c600000000, 0x7d99511700000000, 0x3e52f79000000000, + 0xba096dc300000000, 0xf9c2cb4400000000, 0xb2be596400000000, + 0xf175ffe300000000, 0x752e65b000000000, 0x36e5c33700000000, + 0xe3d641f100000000, 0xa01de77600000000, 0x24467d2500000000, + 0x678ddba200000000, 0x2cf1498200000000, 0x6f3aef0500000000, + 0xeb61755600000000, 0xa8aad3d100000000, 0xfa32a32e00000000, + 0xb9f905a900000000, 0x3da29ffa00000000, 0x7e69397d00000000, + 0x3515ab5d00000000, 0x76de0dda00000000, 0xf285978900000000, + 0xb14e310e00000000, 0x647db3c800000000, 0x27b6154f00000000, + 0xa3ed8f1c00000000, 0xe026299b00000000, 0xab5abbbb00000000, + 0xe8911d3c00000000, 0x6cca876f00000000, 0x2f0121e800000000, + 0x87abf23900000000, 0xc46054be00000000, 0x403bceed00000000, + 0x03f0686a00000000, 0x488cfa4a00000000, 0x0b475ccd00000000, + 0x8f1cc69e00000000, 0xccd7601900000000, 0x19e4e2df00000000, + 0x5a2f445800000000, 0xde74de0b00000000, 0x9dbf788c00000000, + 0xd6c3eaac00000000, 0x95084c2b00000000, 0x1153d67800000000, + 0x529870ff00000000, 0xf465465d00000000, 0xb7aee0da00000000, + 0x33f57a8900000000, 0x703edc0e00000000, 0x3b424e2e00000000, + 0x7889e8a900000000, 0xfcd272fa00000000, 0xbf19d47d00000000, + 0x6a2a56bb00000000, 0x29e1f03c00000000, 0xadba6a6f00000000, + 0xee71cce800000000, 0xa50d5ec800000000, 0xe6c6f84f00000000, + 0x629d621c00000000, 0x2156c49b00000000, 0x89fc174a00000000, + 0xca37b1cd00000000, 0x4e6c2b9e00000000, 0x0da78d1900000000, + 0x46db1f3900000000, 0x0510b9be00000000, 0x814b23ed00000000, + 0xc280856a00000000, 0x17b307ac00000000, 0x5478a12b00000000, + 0xd0233b7800000000, 0x93e89dff00000000, 0xd8940fdf00000000, + 0x9b5fa95800000000, 0x1f04330b00000000, 0x5ccf958c00000000, + 0x0e57e57300000000, 0x4d9c43f400000000, 0xc9c7d9a700000000, + 0x8a0c7f2000000000, 0xc170ed0000000000, 0x82bb4b8700000000, + 0x06e0d1d400000000, 0x452b775300000000, 0x9018f59500000000, + 0xd3d3531200000000, 0x5788c94100000000, 0x14436fc600000000, + 0x5f3ffde600000000, 0x1cf45b6100000000, 0x98afc13200000000, + 0xdb6467b500000000, 0x73ceb46400000000, 0x300512e300000000, + 0xb45e88b000000000, 0xf7952e3700000000, 0xbce9bc1700000000, + 0xff221a9000000000, 0x7b7980c300000000, 0x38b2264400000000, + 0xed81a48200000000, 0xae4a020500000000, 0x2a11985600000000, + 0x69da3ed100000000, 0x22a6acf100000000, 0x616d0a7600000000, + 0xe536902500000000, 0xa6fd36a200000000, 0xe8cb8cba00000000, + 0xab002a3d00000000, 0x2f5bb06e00000000, 0x6c9016e900000000, + 0x27ec84c900000000, 0x6427224e00000000, 0xe07cb81d00000000, + 0xa3b71e9a00000000, 0x76849c5c00000000, 0x354f3adb00000000, + 0xb114a08800000000, 0xf2df060f00000000, 0xb9a3942f00000000, + 0xfa6832a800000000, 0x7e33a8fb00000000, 0x3df80e7c00000000, + 0x9552ddad00000000, 0xd6997b2a00000000, 0x52c2e17900000000, + 0x110947fe00000000, 0x5a75d5de00000000, 0x19be735900000000, + 0x9de5e90a00000000, 0xde2e4f8d00000000, 0x0b1dcd4b00000000, + 0x48d66bcc00000000, 0xcc8df19f00000000, 0x8f46571800000000, + 0xc43ac53800000000, 0x87f163bf00000000, 0x03aaf9ec00000000, + 0x40615f6b00000000, 0x12f92f9400000000, 0x5132891300000000, + 0xd569134000000000, 0x96a2b5c700000000, 0xddde27e700000000, + 0x9e15816000000000, 0x1a4e1b3300000000, 0x5985bdb400000000, + 0x8cb63f7200000000, 0xcf7d99f500000000, 0x4b2603a600000000, + 0x08eda52100000000, 0x4391370100000000, 0x005a918600000000, + 0x84010bd500000000, 0xc7caad5200000000, 0x6f607e8300000000, + 0x2cabd80400000000, 0xa8f0425700000000, 0xeb3be4d000000000, + 0xa04776f000000000, 0xe38cd07700000000, 0x67d74a2400000000, + 0x241ceca300000000, 0xf12f6e6500000000, 0xb2e4c8e200000000, + 0x36bf52b100000000, 0x7574f43600000000, 0x3e08661600000000, + 0x7dc3c09100000000, 0xf9985ac200000000, 0xba53fc4500000000, + 0x1caecae700000000, 0x5f656c6000000000, 0xdb3ef63300000000, + 0x98f550b400000000, 0xd389c29400000000, 0x9042641300000000, + 0x1419fe4000000000, 0x57d258c700000000, 0x82e1da0100000000, + 0xc12a7c8600000000, 0x4571e6d500000000, 0x06ba405200000000, + 0x4dc6d27200000000, 0x0e0d74f500000000, 0x8a56eea600000000, + 0xc99d482100000000, 0x61379bf000000000, 0x22fc3d7700000000, + 0xa6a7a72400000000, 0xe56c01a300000000, 0xae10938300000000, + 0xeddb350400000000, 0x6980af5700000000, 0x2a4b09d000000000, + 0xff788b1600000000, 0xbcb32d9100000000, 0x38e8b7c200000000, + 0x7b23114500000000, 0x305f836500000000, 0x739425e200000000, + 0xf7cfbfb100000000, 0xb404193600000000, 0xe69c69c900000000, + 0xa557cf4e00000000, 0x210c551d00000000, 0x62c7f39a00000000, + 0x29bb61ba00000000, 0x6a70c73d00000000, 0xee2b5d6e00000000, + 0xade0fbe900000000, 0x78d3792f00000000, 0x3b18dfa800000000, + 0xbf4345fb00000000, 0xfc88e37c00000000, 0xb7f4715c00000000, + 0xf43fd7db00000000, 0x70644d8800000000, 0x33afeb0f00000000, + 0x9b0538de00000000, 0xd8ce9e5900000000, 0x5c95040a00000000, + 0x1f5ea28d00000000, 0x542230ad00000000, 0x17e9962a00000000, + 0x93b20c7900000000, 0xd079aafe00000000, 0x054a283800000000, + 0x46818ebf00000000, 0xc2da14ec00000000, 0x8111b26b00000000, + 0xca6d204b00000000, 0x89a686cc00000000, 0x0dfd1c9f00000000, + 0x4e36ba1800000000}, + {0x0000000000000000, 0xe1b652ef00000000, 0x836bd40500000000, + 0x62dd86ea00000000, 0x06d7a80b00000000, 0xe761fae400000000, + 0x85bc7c0e00000000, 0x640a2ee100000000, 0x0cae511700000000, + 0xed1803f800000000, 0x8fc5851200000000, 0x6e73d7fd00000000, + 0x0a79f91c00000000, 0xebcfabf300000000, 0x89122d1900000000, + 0x68a47ff600000000, 0x185ca32e00000000, 0xf9eaf1c100000000, + 0x9b37772b00000000, 0x7a8125c400000000, 0x1e8b0b2500000000, + 0xff3d59ca00000000, 0x9de0df2000000000, 0x7c568dcf00000000, + 0x14f2f23900000000, 0xf544a0d600000000, 0x9799263c00000000, + 0x762f74d300000000, 0x12255a3200000000, 0xf39308dd00000000, + 0x914e8e3700000000, 0x70f8dcd800000000, 0x30b8465d00000000, + 0xd10e14b200000000, 0xb3d3925800000000, 0x5265c0b700000000, + 0x366fee5600000000, 0xd7d9bcb900000000, 0xb5043a5300000000, + 0x54b268bc00000000, 0x3c16174a00000000, 0xdda045a500000000, + 0xbf7dc34f00000000, 0x5ecb91a000000000, 0x3ac1bf4100000000, + 0xdb77edae00000000, 0xb9aa6b4400000000, 0x581c39ab00000000, + 0x28e4e57300000000, 0xc952b79c00000000, 0xab8f317600000000, + 0x4a39639900000000, 0x2e334d7800000000, 0xcf851f9700000000, + 0xad58997d00000000, 0x4ceecb9200000000, 0x244ab46400000000, + 0xc5fce68b00000000, 0xa721606100000000, 0x4697328e00000000, + 0x229d1c6f00000000, 0xc32b4e8000000000, 0xa1f6c86a00000000, + 0x40409a8500000000, 0x60708dba00000000, 0x81c6df5500000000, + 0xe31b59bf00000000, 0x02ad0b5000000000, 0x66a725b100000000, + 0x8711775e00000000, 0xe5ccf1b400000000, 0x047aa35b00000000, + 0x6cdedcad00000000, 0x8d688e4200000000, 0xefb508a800000000, + 0x0e035a4700000000, 0x6a0974a600000000, 0x8bbf264900000000, + 0xe962a0a300000000, 0x08d4f24c00000000, 0x782c2e9400000000, + 0x999a7c7b00000000, 0xfb47fa9100000000, 0x1af1a87e00000000, + 0x7efb869f00000000, 0x9f4dd47000000000, 0xfd90529a00000000, + 0x1c26007500000000, 0x74827f8300000000, 0x95342d6c00000000, + 0xf7e9ab8600000000, 0x165ff96900000000, 0x7255d78800000000, + 0x93e3856700000000, 0xf13e038d00000000, 0x1088516200000000, + 0x50c8cbe700000000, 0xb17e990800000000, 0xd3a31fe200000000, + 0x32154d0d00000000, 0x561f63ec00000000, 0xb7a9310300000000, + 0xd574b7e900000000, 0x34c2e50600000000, 0x5c669af000000000, + 0xbdd0c81f00000000, 0xdf0d4ef500000000, 0x3ebb1c1a00000000, + 0x5ab132fb00000000, 0xbb07601400000000, 0xd9dae6fe00000000, + 0x386cb41100000000, 0x489468c900000000, 0xa9223a2600000000, + 0xcbffbccc00000000, 0x2a49ee2300000000, 0x4e43c0c200000000, + 0xaff5922d00000000, 0xcd2814c700000000, 0x2c9e462800000000, + 0x443a39de00000000, 0xa58c6b3100000000, 0xc751eddb00000000, + 0x26e7bf3400000000, 0x42ed91d500000000, 0xa35bc33a00000000, + 0xc18645d000000000, 0x2030173f00000000, 0x81e66bae00000000, + 0x6050394100000000, 0x028dbfab00000000, 0xe33bed4400000000, + 0x8731c3a500000000, 0x6687914a00000000, 0x045a17a000000000, + 0xe5ec454f00000000, 0x8d483ab900000000, 0x6cfe685600000000, + 0x0e23eebc00000000, 0xef95bc5300000000, 0x8b9f92b200000000, + 0x6a29c05d00000000, 0x08f446b700000000, 0xe942145800000000, + 0x99bac88000000000, 0x780c9a6f00000000, 0x1ad11c8500000000, + 0xfb674e6a00000000, 0x9f6d608b00000000, 0x7edb326400000000, + 0x1c06b48e00000000, 0xfdb0e66100000000, 0x9514999700000000, + 0x74a2cb7800000000, 0x167f4d9200000000, 0xf7c91f7d00000000, + 0x93c3319c00000000, 0x7275637300000000, 0x10a8e59900000000, + 0xf11eb77600000000, 0xb15e2df300000000, 0x50e87f1c00000000, + 0x3235f9f600000000, 0xd383ab1900000000, 0xb78985f800000000, + 0x563fd71700000000, 0x34e251fd00000000, 0xd554031200000000, + 0xbdf07ce400000000, 0x5c462e0b00000000, 0x3e9ba8e100000000, + 0xdf2dfa0e00000000, 0xbb27d4ef00000000, 0x5a91860000000000, + 0x384c00ea00000000, 0xd9fa520500000000, 0xa9028edd00000000, + 0x48b4dc3200000000, 0x2a695ad800000000, 0xcbdf083700000000, + 0xafd526d600000000, 0x4e63743900000000, 0x2cbef2d300000000, + 0xcd08a03c00000000, 0xa5acdfca00000000, 0x441a8d2500000000, + 0x26c70bcf00000000, 0xc771592000000000, 0xa37b77c100000000, + 0x42cd252e00000000, 0x2010a3c400000000, 0xc1a6f12b00000000, + 0xe196e61400000000, 0x0020b4fb00000000, 0x62fd321100000000, + 0x834b60fe00000000, 0xe7414e1f00000000, 0x06f71cf000000000, + 0x642a9a1a00000000, 0x859cc8f500000000, 0xed38b70300000000, + 0x0c8ee5ec00000000, 0x6e53630600000000, 0x8fe531e900000000, + 0xebef1f0800000000, 0x0a594de700000000, 0x6884cb0d00000000, + 0x893299e200000000, 0xf9ca453a00000000, 0x187c17d500000000, + 0x7aa1913f00000000, 0x9b17c3d000000000, 0xff1ded3100000000, + 0x1eabbfde00000000, 0x7c76393400000000, 0x9dc06bdb00000000, + 0xf564142d00000000, 0x14d246c200000000, 0x760fc02800000000, + 0x97b992c700000000, 0xf3b3bc2600000000, 0x1205eec900000000, + 0x70d8682300000000, 0x916e3acc00000000, 0xd12ea04900000000, + 0x3098f2a600000000, 0x5245744c00000000, 0xb3f326a300000000, + 0xd7f9084200000000, 0x364f5aad00000000, 0x5492dc4700000000, + 0xb5248ea800000000, 0xdd80f15e00000000, 0x3c36a3b100000000, + 0x5eeb255b00000000, 0xbf5d77b400000000, 0xdb57595500000000, + 0x3ae10bba00000000, 0x583c8d5000000000, 0xb98adfbf00000000, + 0xc972036700000000, 0x28c4518800000000, 0x4a19d76200000000, + 0xabaf858d00000000, 0xcfa5ab6c00000000, 0x2e13f98300000000, + 0x4cce7f6900000000, 0xad782d8600000000, 0xc5dc527000000000, + 0x246a009f00000000, 0x46b7867500000000, 0xa701d49a00000000, + 0xc30bfa7b00000000, 0x22bda89400000000, 0x40602e7e00000000, + 0xa1d67c9100000000}, + {0x0000000000000000, 0x5880e2d700000000, 0xf106b47400000000, + 0xa98656a300000000, 0xe20d68e900000000, 0xba8d8a3e00000000, + 0x130bdc9d00000000, 0x4b8b3e4a00000000, 0x851da10900000000, + 0xdd9d43de00000000, 0x741b157d00000000, 0x2c9bf7aa00000000, + 0x6710c9e000000000, 0x3f902b3700000000, 0x96167d9400000000, + 0xce969f4300000000, 0x0a3b421300000000, 0x52bba0c400000000, + 0xfb3df66700000000, 0xa3bd14b000000000, 0xe8362afa00000000, + 0xb0b6c82d00000000, 0x19309e8e00000000, 0x41b07c5900000000, + 0x8f26e31a00000000, 0xd7a601cd00000000, 0x7e20576e00000000, + 0x26a0b5b900000000, 0x6d2b8bf300000000, 0x35ab692400000000, + 0x9c2d3f8700000000, 0xc4addd5000000000, 0x1476842600000000, + 0x4cf666f100000000, 0xe570305200000000, 0xbdf0d28500000000, + 0xf67beccf00000000, 0xaefb0e1800000000, 0x077d58bb00000000, + 0x5ffdba6c00000000, 0x916b252f00000000, 0xc9ebc7f800000000, + 0x606d915b00000000, 0x38ed738c00000000, 0x73664dc600000000, + 0x2be6af1100000000, 0x8260f9b200000000, 0xdae01b6500000000, + 0x1e4dc63500000000, 0x46cd24e200000000, 0xef4b724100000000, + 0xb7cb909600000000, 0xfc40aedc00000000, 0xa4c04c0b00000000, + 0x0d461aa800000000, 0x55c6f87f00000000, 0x9b50673c00000000, + 0xc3d085eb00000000, 0x6a56d34800000000, 0x32d6319f00000000, + 0x795d0fd500000000, 0x21dded0200000000, 0x885bbba100000000, + 0xd0db597600000000, 0x28ec084d00000000, 0x706cea9a00000000, + 0xd9eabc3900000000, 0x816a5eee00000000, 0xcae160a400000000, + 0x9261827300000000, 0x3be7d4d000000000, 0x6367360700000000, + 0xadf1a94400000000, 0xf5714b9300000000, 0x5cf71d3000000000, + 0x0477ffe700000000, 0x4ffcc1ad00000000, 0x177c237a00000000, + 0xbefa75d900000000, 0xe67a970e00000000, 0x22d74a5e00000000, + 0x7a57a88900000000, 0xd3d1fe2a00000000, 0x8b511cfd00000000, + 0xc0da22b700000000, 0x985ac06000000000, 0x31dc96c300000000, + 0x695c741400000000, 0xa7caeb5700000000, 0xff4a098000000000, + 0x56cc5f2300000000, 0x0e4cbdf400000000, 0x45c783be00000000, + 0x1d47616900000000, 0xb4c137ca00000000, 0xec41d51d00000000, + 0x3c9a8c6b00000000, 0x641a6ebc00000000, 0xcd9c381f00000000, + 0x951cdac800000000, 0xde97e48200000000, 0x8617065500000000, + 0x2f9150f600000000, 0x7711b22100000000, 0xb9872d6200000000, + 0xe107cfb500000000, 0x4881991600000000, 0x10017bc100000000, + 0x5b8a458b00000000, 0x030aa75c00000000, 0xaa8cf1ff00000000, + 0xf20c132800000000, 0x36a1ce7800000000, 0x6e212caf00000000, + 0xc7a77a0c00000000, 0x9f2798db00000000, 0xd4aca69100000000, + 0x8c2c444600000000, 0x25aa12e500000000, 0x7d2af03200000000, + 0xb3bc6f7100000000, 0xeb3c8da600000000, 0x42badb0500000000, + 0x1a3a39d200000000, 0x51b1079800000000, 0x0931e54f00000000, + 0xa0b7b3ec00000000, 0xf837513b00000000, 0x50d8119a00000000, + 0x0858f34d00000000, 0xa1dea5ee00000000, 0xf95e473900000000, + 0xb2d5797300000000, 0xea559ba400000000, 0x43d3cd0700000000, + 0x1b532fd000000000, 0xd5c5b09300000000, 0x8d45524400000000, + 0x24c304e700000000, 0x7c43e63000000000, 0x37c8d87a00000000, + 0x6f483aad00000000, 0xc6ce6c0e00000000, 0x9e4e8ed900000000, + 0x5ae3538900000000, 0x0263b15e00000000, 0xabe5e7fd00000000, + 0xf365052a00000000, 0xb8ee3b6000000000, 0xe06ed9b700000000, + 0x49e88f1400000000, 0x11686dc300000000, 0xdffef28000000000, + 0x877e105700000000, 0x2ef846f400000000, 0x7678a42300000000, + 0x3df39a6900000000, 0x657378be00000000, 0xccf52e1d00000000, + 0x9475ccca00000000, 0x44ae95bc00000000, 0x1c2e776b00000000, + 0xb5a821c800000000, 0xed28c31f00000000, 0xa6a3fd5500000000, + 0xfe231f8200000000, 0x57a5492100000000, 0x0f25abf600000000, + 0xc1b334b500000000, 0x9933d66200000000, 0x30b580c100000000, + 0x6835621600000000, 0x23be5c5c00000000, 0x7b3ebe8b00000000, + 0xd2b8e82800000000, 0x8a380aff00000000, 0x4e95d7af00000000, + 0x1615357800000000, 0xbf9363db00000000, 0xe713810c00000000, + 0xac98bf4600000000, 0xf4185d9100000000, 0x5d9e0b3200000000, + 0x051ee9e500000000, 0xcb8876a600000000, 0x9308947100000000, + 0x3a8ec2d200000000, 0x620e200500000000, 0x29851e4f00000000, + 0x7105fc9800000000, 0xd883aa3b00000000, 0x800348ec00000000, + 0x783419d700000000, 0x20b4fb0000000000, 0x8932ada300000000, + 0xd1b24f7400000000, 0x9a39713e00000000, 0xc2b993e900000000, + 0x6b3fc54a00000000, 0x33bf279d00000000, 0xfd29b8de00000000, + 0xa5a95a0900000000, 0x0c2f0caa00000000, 0x54afee7d00000000, + 0x1f24d03700000000, 0x47a432e000000000, 0xee22644300000000, + 0xb6a2869400000000, 0x720f5bc400000000, 0x2a8fb91300000000, + 0x8309efb000000000, 0xdb890d6700000000, 0x9002332d00000000, + 0xc882d1fa00000000, 0x6104875900000000, 0x3984658e00000000, + 0xf712facd00000000, 0xaf92181a00000000, 0x06144eb900000000, + 0x5e94ac6e00000000, 0x151f922400000000, 0x4d9f70f300000000, + 0xe419265000000000, 0xbc99c48700000000, 0x6c429df100000000, + 0x34c27f2600000000, 0x9d44298500000000, 0xc5c4cb5200000000, + 0x8e4ff51800000000, 0xd6cf17cf00000000, 0x7f49416c00000000, + 0x27c9a3bb00000000, 0xe95f3cf800000000, 0xb1dfde2f00000000, + 0x1859888c00000000, 0x40d96a5b00000000, 0x0b52541100000000, + 0x53d2b6c600000000, 0xfa54e06500000000, 0xa2d402b200000000, + 0x6679dfe200000000, 0x3ef93d3500000000, 0x977f6b9600000000, + 0xcfff894100000000, 0x8474b70b00000000, 0xdcf455dc00000000, + 0x7572037f00000000, 0x2df2e1a800000000, 0xe3647eeb00000000, + 0xbbe49c3c00000000, 0x1262ca9f00000000, 0x4ae2284800000000, + 0x0169160200000000, 0x59e9f4d500000000, 0xf06fa27600000000, + 0xa8ef40a100000000}, + {0x0000000000000000, 0x463b676500000000, 0x8c76ceca00000000, + 0xca4da9af00000000, 0x59ebed4e00000000, 0x1fd08a2b00000000, + 0xd59d238400000000, 0x93a644e100000000, 0xb2d6db9d00000000, + 0xf4edbcf800000000, 0x3ea0155700000000, 0x789b723200000000, + 0xeb3d36d300000000, 0xad0651b600000000, 0x674bf81900000000, + 0x21709f7c00000000, 0x25abc6e000000000, 0x6390a18500000000, + 0xa9dd082a00000000, 0xefe66f4f00000000, 0x7c402bae00000000, + 0x3a7b4ccb00000000, 0xf036e56400000000, 0xb60d820100000000, + 0x977d1d7d00000000, 0xd1467a1800000000, 0x1b0bd3b700000000, + 0x5d30b4d200000000, 0xce96f03300000000, 0x88ad975600000000, + 0x42e03ef900000000, 0x04db599c00000000, 0x0b50fc1a00000000, + 0x4d6b9b7f00000000, 0x872632d000000000, 0xc11d55b500000000, + 0x52bb115400000000, 0x1480763100000000, 0xdecddf9e00000000, + 0x98f6b8fb00000000, 0xb986278700000000, 0xffbd40e200000000, + 0x35f0e94d00000000, 0x73cb8e2800000000, 0xe06dcac900000000, + 0xa656adac00000000, 0x6c1b040300000000, 0x2a20636600000000, + 0x2efb3afa00000000, 0x68c05d9f00000000, 0xa28df43000000000, + 0xe4b6935500000000, 0x7710d7b400000000, 0x312bb0d100000000, + 0xfb66197e00000000, 0xbd5d7e1b00000000, 0x9c2de16700000000, + 0xda16860200000000, 0x105b2fad00000000, 0x566048c800000000, + 0xc5c60c2900000000, 0x83fd6b4c00000000, 0x49b0c2e300000000, + 0x0f8ba58600000000, 0x16a0f83500000000, 0x509b9f5000000000, + 0x9ad636ff00000000, 0xdced519a00000000, 0x4f4b157b00000000, + 0x0970721e00000000, 0xc33ddbb100000000, 0x8506bcd400000000, + 0xa47623a800000000, 0xe24d44cd00000000, 0x2800ed6200000000, + 0x6e3b8a0700000000, 0xfd9dcee600000000, 0xbba6a98300000000, + 0x71eb002c00000000, 0x37d0674900000000, 0x330b3ed500000000, + 0x753059b000000000, 0xbf7df01f00000000, 0xf946977a00000000, + 0x6ae0d39b00000000, 0x2cdbb4fe00000000, 0xe6961d5100000000, + 0xa0ad7a3400000000, 0x81dde54800000000, 0xc7e6822d00000000, + 0x0dab2b8200000000, 0x4b904ce700000000, 0xd836080600000000, + 0x9e0d6f6300000000, 0x5440c6cc00000000, 0x127ba1a900000000, + 0x1df0042f00000000, 0x5bcb634a00000000, 0x9186cae500000000, + 0xd7bdad8000000000, 0x441be96100000000, 0x02208e0400000000, + 0xc86d27ab00000000, 0x8e5640ce00000000, 0xaf26dfb200000000, + 0xe91db8d700000000, 0x2350117800000000, 0x656b761d00000000, + 0xf6cd32fc00000000, 0xb0f6559900000000, 0x7abbfc3600000000, + 0x3c809b5300000000, 0x385bc2cf00000000, 0x7e60a5aa00000000, + 0xb42d0c0500000000, 0xf2166b6000000000, 0x61b02f8100000000, + 0x278b48e400000000, 0xedc6e14b00000000, 0xabfd862e00000000, + 0x8a8d195200000000, 0xccb67e3700000000, 0x06fbd79800000000, + 0x40c0b0fd00000000, 0xd366f41c00000000, 0x955d937900000000, + 0x5f103ad600000000, 0x192b5db300000000, 0x2c40f16b00000000, + 0x6a7b960e00000000, 0xa0363fa100000000, 0xe60d58c400000000, + 0x75ab1c2500000000, 0x33907b4000000000, 0xf9ddd2ef00000000, + 0xbfe6b58a00000000, 0x9e962af600000000, 0xd8ad4d9300000000, + 0x12e0e43c00000000, 0x54db835900000000, 0xc77dc7b800000000, + 0x8146a0dd00000000, 0x4b0b097200000000, 0x0d306e1700000000, + 0x09eb378b00000000, 0x4fd050ee00000000, 0x859df94100000000, + 0xc3a69e2400000000, 0x5000dac500000000, 0x163bbda000000000, + 0xdc76140f00000000, 0x9a4d736a00000000, 0xbb3dec1600000000, + 0xfd068b7300000000, 0x374b22dc00000000, 0x717045b900000000, + 0xe2d6015800000000, 0xa4ed663d00000000, 0x6ea0cf9200000000, + 0x289ba8f700000000, 0x27100d7100000000, 0x612b6a1400000000, + 0xab66c3bb00000000, 0xed5da4de00000000, 0x7efbe03f00000000, + 0x38c0875a00000000, 0xf28d2ef500000000, 0xb4b6499000000000, + 0x95c6d6ec00000000, 0xd3fdb18900000000, 0x19b0182600000000, + 0x5f8b7f4300000000, 0xcc2d3ba200000000, 0x8a165cc700000000, + 0x405bf56800000000, 0x0660920d00000000, 0x02bbcb9100000000, + 0x4480acf400000000, 0x8ecd055b00000000, 0xc8f6623e00000000, + 0x5b5026df00000000, 0x1d6b41ba00000000, 0xd726e81500000000, + 0x911d8f7000000000, 0xb06d100c00000000, 0xf656776900000000, + 0x3c1bdec600000000, 0x7a20b9a300000000, 0xe986fd4200000000, + 0xafbd9a2700000000, 0x65f0338800000000, 0x23cb54ed00000000, + 0x3ae0095e00000000, 0x7cdb6e3b00000000, 0xb696c79400000000, + 0xf0ada0f100000000, 0x630be41000000000, 0x2530837500000000, + 0xef7d2ada00000000, 0xa9464dbf00000000, 0x8836d2c300000000, + 0xce0db5a600000000, 0x04401c0900000000, 0x427b7b6c00000000, + 0xd1dd3f8d00000000, 0x97e658e800000000, 0x5dabf14700000000, + 0x1b90962200000000, 0x1f4bcfbe00000000, 0x5970a8db00000000, + 0x933d017400000000, 0xd506661100000000, 0x46a022f000000000, + 0x009b459500000000, 0xcad6ec3a00000000, 0x8ced8b5f00000000, + 0xad9d142300000000, 0xeba6734600000000, 0x21ebdae900000000, + 0x67d0bd8c00000000, 0xf476f96d00000000, 0xb24d9e0800000000, + 0x780037a700000000, 0x3e3b50c200000000, 0x31b0f54400000000, + 0x778b922100000000, 0xbdc63b8e00000000, 0xfbfd5ceb00000000, + 0x685b180a00000000, 0x2e607f6f00000000, 0xe42dd6c000000000, + 0xa216b1a500000000, 0x83662ed900000000, 0xc55d49bc00000000, + 0x0f10e01300000000, 0x492b877600000000, 0xda8dc39700000000, + 0x9cb6a4f200000000, 0x56fb0d5d00000000, 0x10c06a3800000000, + 0x141b33a400000000, 0x522054c100000000, 0x986dfd6e00000000, + 0xde569a0b00000000, 0x4df0deea00000000, 0x0bcbb98f00000000, + 0xc186102000000000, 0x87bd774500000000, 0xa6cde83900000000, + 0xe0f68f5c00000000, 0x2abb26f300000000, 0x6c80419600000000, + 0xff26057700000000, 0xb91d621200000000, 0x7350cbbd00000000, + 0x356bacd800000000}, + {0x0000000000000000, 0x9e83da9f00000000, 0x7d01c4e400000000, + 0xe3821e7b00000000, 0xbb04f91200000000, 0x2587238d00000000, + 0xc6053df600000000, 0x5886e76900000000, 0x7609f22500000000, + 0xe88a28ba00000000, 0x0b0836c100000000, 0x958bec5e00000000, + 0xcd0d0b3700000000, 0x538ed1a800000000, 0xb00ccfd300000000, + 0x2e8f154c00000000, 0xec12e44b00000000, 0x72913ed400000000, + 0x911320af00000000, 0x0f90fa3000000000, 0x57161d5900000000, + 0xc995c7c600000000, 0x2a17d9bd00000000, 0xb494032200000000, + 0x9a1b166e00000000, 0x0498ccf100000000, 0xe71ad28a00000000, + 0x7999081500000000, 0x211fef7c00000000, 0xbf9c35e300000000, + 0x5c1e2b9800000000, 0xc29df10700000000, 0xd825c89700000000, + 0x46a6120800000000, 0xa5240c7300000000, 0x3ba7d6ec00000000, + 0x6321318500000000, 0xfda2eb1a00000000, 0x1e20f56100000000, + 0x80a32ffe00000000, 0xae2c3ab200000000, 0x30afe02d00000000, + 0xd32dfe5600000000, 0x4dae24c900000000, 0x1528c3a000000000, + 0x8bab193f00000000, 0x6829074400000000, 0xf6aadddb00000000, + 0x34372cdc00000000, 0xaab4f64300000000, 0x4936e83800000000, + 0xd7b532a700000000, 0x8f33d5ce00000000, 0x11b00f5100000000, + 0xf232112a00000000, 0x6cb1cbb500000000, 0x423edef900000000, + 0xdcbd046600000000, 0x3f3f1a1d00000000, 0xa1bcc08200000000, + 0xf93a27eb00000000, 0x67b9fd7400000000, 0x843be30f00000000, + 0x1ab8399000000000, 0xf14de1f400000000, 0x6fce3b6b00000000, + 0x8c4c251000000000, 0x12cfff8f00000000, 0x4a4918e600000000, + 0xd4cac27900000000, 0x3748dc0200000000, 0xa9cb069d00000000, + 0x874413d100000000, 0x19c7c94e00000000, 0xfa45d73500000000, + 0x64c60daa00000000, 0x3c40eac300000000, 0xa2c3305c00000000, + 0x41412e2700000000, 0xdfc2f4b800000000, 0x1d5f05bf00000000, + 0x83dcdf2000000000, 0x605ec15b00000000, 0xfedd1bc400000000, + 0xa65bfcad00000000, 0x38d8263200000000, 0xdb5a384900000000, + 0x45d9e2d600000000, 0x6b56f79a00000000, 0xf5d52d0500000000, + 0x1657337e00000000, 0x88d4e9e100000000, 0xd0520e8800000000, + 0x4ed1d41700000000, 0xad53ca6c00000000, 0x33d010f300000000, + 0x2968296300000000, 0xb7ebf3fc00000000, 0x5469ed8700000000, + 0xcaea371800000000, 0x926cd07100000000, 0x0cef0aee00000000, + 0xef6d149500000000, 0x71eece0a00000000, 0x5f61db4600000000, + 0xc1e201d900000000, 0x22601fa200000000, 0xbce3c53d00000000, + 0xe465225400000000, 0x7ae6f8cb00000000, 0x9964e6b000000000, + 0x07e73c2f00000000, 0xc57acd2800000000, 0x5bf917b700000000, + 0xb87b09cc00000000, 0x26f8d35300000000, 0x7e7e343a00000000, + 0xe0fdeea500000000, 0x037ff0de00000000, 0x9dfc2a4100000000, + 0xb3733f0d00000000, 0x2df0e59200000000, 0xce72fbe900000000, + 0x50f1217600000000, 0x0877c61f00000000, 0x96f41c8000000000, + 0x757602fb00000000, 0xebf5d86400000000, 0xa39db33200000000, + 0x3d1e69ad00000000, 0xde9c77d600000000, 0x401fad4900000000, + 0x18994a2000000000, 0x861a90bf00000000, 0x65988ec400000000, + 0xfb1b545b00000000, 0xd594411700000000, 0x4b179b8800000000, + 0xa89585f300000000, 0x36165f6c00000000, 0x6e90b80500000000, + 0xf013629a00000000, 0x13917ce100000000, 0x8d12a67e00000000, + 0x4f8f577900000000, 0xd10c8de600000000, 0x328e939d00000000, + 0xac0d490200000000, 0xf48bae6b00000000, 0x6a0874f400000000, + 0x898a6a8f00000000, 0x1709b01000000000, 0x3986a55c00000000, + 0xa7057fc300000000, 0x448761b800000000, 0xda04bb2700000000, + 0x82825c4e00000000, 0x1c0186d100000000, 0xff8398aa00000000, + 0x6100423500000000, 0x7bb87ba500000000, 0xe53ba13a00000000, + 0x06b9bf4100000000, 0x983a65de00000000, 0xc0bc82b700000000, + 0x5e3f582800000000, 0xbdbd465300000000, 0x233e9ccc00000000, + 0x0db1898000000000, 0x9332531f00000000, 0x70b04d6400000000, + 0xee3397fb00000000, 0xb6b5709200000000, 0x2836aa0d00000000, + 0xcbb4b47600000000, 0x55376ee900000000, 0x97aa9fee00000000, + 0x0929457100000000, 0xeaab5b0a00000000, 0x7428819500000000, + 0x2cae66fc00000000, 0xb22dbc6300000000, 0x51afa21800000000, + 0xcf2c788700000000, 0xe1a36dcb00000000, 0x7f20b75400000000, + 0x9ca2a92f00000000, 0x022173b000000000, 0x5aa794d900000000, + 0xc4244e4600000000, 0x27a6503d00000000, 0xb9258aa200000000, + 0x52d052c600000000, 0xcc53885900000000, 0x2fd1962200000000, + 0xb1524cbd00000000, 0xe9d4abd400000000, 0x7757714b00000000, + 0x94d56f3000000000, 0x0a56b5af00000000, 0x24d9a0e300000000, + 0xba5a7a7c00000000, 0x59d8640700000000, 0xc75bbe9800000000, + 0x9fdd59f100000000, 0x015e836e00000000, 0xe2dc9d1500000000, + 0x7c5f478a00000000, 0xbec2b68d00000000, 0x20416c1200000000, + 0xc3c3726900000000, 0x5d40a8f600000000, 0x05c64f9f00000000, + 0x9b45950000000000, 0x78c78b7b00000000, 0xe64451e400000000, + 0xc8cb44a800000000, 0x56489e3700000000, 0xb5ca804c00000000, + 0x2b495ad300000000, 0x73cfbdba00000000, 0xed4c672500000000, + 0x0ece795e00000000, 0x904da3c100000000, 0x8af59a5100000000, + 0x147640ce00000000, 0xf7f45eb500000000, 0x6977842a00000000, + 0x31f1634300000000, 0xaf72b9dc00000000, 0x4cf0a7a700000000, + 0xd2737d3800000000, 0xfcfc687400000000, 0x627fb2eb00000000, + 0x81fdac9000000000, 0x1f7e760f00000000, 0x47f8916600000000, + 0xd97b4bf900000000, 0x3af9558200000000, 0xa47a8f1d00000000, + 0x66e77e1a00000000, 0xf864a48500000000, 0x1be6bafe00000000, + 0x8565606100000000, 0xdde3870800000000, 0x43605d9700000000, + 0xa0e243ec00000000, 0x3e61997300000000, 0x10ee8c3f00000000, + 0x8e6d56a000000000, 0x6def48db00000000, 0xf36c924400000000, + 0xabea752d00000000, 0x3569afb200000000, 0xd6ebb1c900000000, + 0x48686b5600000000}, + {0x0000000000000000, 0xc064281700000000, 0x80c9502e00000000, + 0x40ad783900000000, 0x0093a15c00000000, 0xc0f7894b00000000, + 0x805af17200000000, 0x403ed96500000000, 0x002643b900000000, + 0xc0426bae00000000, 0x80ef139700000000, 0x408b3b8000000000, + 0x00b5e2e500000000, 0xc0d1caf200000000, 0x807cb2cb00000000, + 0x40189adc00000000, 0x414af7a900000000, 0x812edfbe00000000, + 0xc183a78700000000, 0x01e78f9000000000, 0x41d956f500000000, + 0x81bd7ee200000000, 0xc11006db00000000, 0x01742ecc00000000, + 0x416cb41000000000, 0x81089c0700000000, 0xc1a5e43e00000000, + 0x01c1cc2900000000, 0x41ff154c00000000, 0x819b3d5b00000000, + 0xc136456200000000, 0x01526d7500000000, 0xc3929f8800000000, + 0x03f6b79f00000000, 0x435bcfa600000000, 0x833fe7b100000000, + 0xc3013ed400000000, 0x036516c300000000, 0x43c86efa00000000, + 0x83ac46ed00000000, 0xc3b4dc3100000000, 0x03d0f42600000000, + 0x437d8c1f00000000, 0x8319a40800000000, 0xc3277d6d00000000, + 0x0343557a00000000, 0x43ee2d4300000000, 0x838a055400000000, + 0x82d8682100000000, 0x42bc403600000000, 0x0211380f00000000, + 0xc275101800000000, 0x824bc97d00000000, 0x422fe16a00000000, + 0x0282995300000000, 0xc2e6b14400000000, 0x82fe2b9800000000, + 0x429a038f00000000, 0x02377bb600000000, 0xc25353a100000000, + 0x826d8ac400000000, 0x4209a2d300000000, 0x02a4daea00000000, + 0xc2c0f2fd00000000, 0xc7234eca00000000, 0x074766dd00000000, + 0x47ea1ee400000000, 0x878e36f300000000, 0xc7b0ef9600000000, + 0x07d4c78100000000, 0x4779bfb800000000, 0x871d97af00000000, + 0xc7050d7300000000, 0x0761256400000000, 0x47cc5d5d00000000, + 0x87a8754a00000000, 0xc796ac2f00000000, 0x07f2843800000000, + 0x475ffc0100000000, 0x873bd41600000000, 0x8669b96300000000, + 0x460d917400000000, 0x06a0e94d00000000, 0xc6c4c15a00000000, + 0x86fa183f00000000, 0x469e302800000000, 0x0633481100000000, + 0xc657600600000000, 0x864ffada00000000, 0x462bd2cd00000000, + 0x0686aaf400000000, 0xc6e282e300000000, 0x86dc5b8600000000, + 0x46b8739100000000, 0x06150ba800000000, 0xc67123bf00000000, + 0x04b1d14200000000, 0xc4d5f95500000000, 0x8478816c00000000, + 0x441ca97b00000000, 0x0422701e00000000, 0xc446580900000000, + 0x84eb203000000000, 0x448f082700000000, 0x049792fb00000000, + 0xc4f3baec00000000, 0x845ec2d500000000, 0x443aeac200000000, + 0x040433a700000000, 0xc4601bb000000000, 0x84cd638900000000, + 0x44a94b9e00000000, 0x45fb26eb00000000, 0x859f0efc00000000, + 0xc53276c500000000, 0x05565ed200000000, 0x456887b700000000, + 0x850cafa000000000, 0xc5a1d79900000000, 0x05c5ff8e00000000, + 0x45dd655200000000, 0x85b94d4500000000, 0xc514357c00000000, + 0x05701d6b00000000, 0x454ec40e00000000, 0x852aec1900000000, + 0xc587942000000000, 0x05e3bc3700000000, 0xcf41ed4f00000000, + 0x0f25c55800000000, 0x4f88bd6100000000, 0x8fec957600000000, + 0xcfd24c1300000000, 0x0fb6640400000000, 0x4f1b1c3d00000000, + 0x8f7f342a00000000, 0xcf67aef600000000, 0x0f0386e100000000, + 0x4faefed800000000, 0x8fcad6cf00000000, 0xcff40faa00000000, + 0x0f9027bd00000000, 0x4f3d5f8400000000, 0x8f59779300000000, + 0x8e0b1ae600000000, 0x4e6f32f100000000, 0x0ec24ac800000000, + 0xcea662df00000000, 0x8e98bbba00000000, 0x4efc93ad00000000, + 0x0e51eb9400000000, 0xce35c38300000000, 0x8e2d595f00000000, + 0x4e49714800000000, 0x0ee4097100000000, 0xce80216600000000, + 0x8ebef80300000000, 0x4edad01400000000, 0x0e77a82d00000000, + 0xce13803a00000000, 0x0cd372c700000000, 0xccb75ad000000000, + 0x8c1a22e900000000, 0x4c7e0afe00000000, 0x0c40d39b00000000, + 0xcc24fb8c00000000, 0x8c8983b500000000, 0x4cedaba200000000, + 0x0cf5317e00000000, 0xcc91196900000000, 0x8c3c615000000000, + 0x4c58494700000000, 0x0c66902200000000, 0xcc02b83500000000, + 0x8cafc00c00000000, 0x4ccbe81b00000000, 0x4d99856e00000000, + 0x8dfdad7900000000, 0xcd50d54000000000, 0x0d34fd5700000000, + 0x4d0a243200000000, 0x8d6e0c2500000000, 0xcdc3741c00000000, + 0x0da75c0b00000000, 0x4dbfc6d700000000, 0x8ddbeec000000000, + 0xcd7696f900000000, 0x0d12beee00000000, 0x4d2c678b00000000, + 0x8d484f9c00000000, 0xcde537a500000000, 0x0d811fb200000000, + 0x0862a38500000000, 0xc8068b9200000000, 0x88abf3ab00000000, + 0x48cfdbbc00000000, 0x08f102d900000000, 0xc8952ace00000000, + 0x883852f700000000, 0x485c7ae000000000, 0x0844e03c00000000, + 0xc820c82b00000000, 0x888db01200000000, 0x48e9980500000000, + 0x08d7416000000000, 0xc8b3697700000000, 0x881e114e00000000, + 0x487a395900000000, 0x4928542c00000000, 0x894c7c3b00000000, + 0xc9e1040200000000, 0x09852c1500000000, 0x49bbf57000000000, + 0x89dfdd6700000000, 0xc972a55e00000000, 0x09168d4900000000, + 0x490e179500000000, 0x896a3f8200000000, 0xc9c747bb00000000, + 0x09a36fac00000000, 0x499db6c900000000, 0x89f99ede00000000, + 0xc954e6e700000000, 0x0930cef000000000, 0xcbf03c0d00000000, + 0x0b94141a00000000, 0x4b396c2300000000, 0x8b5d443400000000, + 0xcb639d5100000000, 0x0b07b54600000000, 0x4baacd7f00000000, + 0x8bcee56800000000, 0xcbd67fb400000000, 0x0bb257a300000000, + 0x4b1f2f9a00000000, 0x8b7b078d00000000, 0xcb45dee800000000, + 0x0b21f6ff00000000, 0x4b8c8ec600000000, 0x8be8a6d100000000, + 0x8abacba400000000, 0x4adee3b300000000, 0x0a739b8a00000000, + 0xca17b39d00000000, 0x8a296af800000000, 0x4a4d42ef00000000, + 0x0ae03ad600000000, 0xca8412c100000000, 0x8a9c881d00000000, + 0x4af8a00a00000000, 0x0a55d83300000000, 0xca31f02400000000, + 0x8a0f294100000000, 0x4a6b015600000000, 0x0ac6796f00000000, + 0xcaa2517800000000}, + {0x0000000000000000, 0xd4ea739b00000000, 0xe9d396ed00000000, + 0x3d39e57600000000, 0x93a15c0000000000, 0x474b2f9b00000000, + 0x7a72caed00000000, 0xae98b97600000000, 0x2643b90000000000, + 0xf2a9ca9b00000000, 0xcf902fed00000000, 0x1b7a5c7600000000, + 0xb5e2e50000000000, 0x6108969b00000000, 0x5c3173ed00000000, + 0x88db007600000000, 0x4c86720100000000, 0x986c019a00000000, + 0xa555e4ec00000000, 0x71bf977700000000, 0xdf272e0100000000, + 0x0bcd5d9a00000000, 0x36f4b8ec00000000, 0xe21ecb7700000000, + 0x6ac5cb0100000000, 0xbe2fb89a00000000, 0x83165dec00000000, + 0x57fc2e7700000000, 0xf964970100000000, 0x2d8ee49a00000000, + 0x10b701ec00000000, 0xc45d727700000000, 0x980ce50200000000, + 0x4ce6969900000000, 0x71df73ef00000000, 0xa535007400000000, + 0x0badb90200000000, 0xdf47ca9900000000, 0xe27e2fef00000000, + 0x36945c7400000000, 0xbe4f5c0200000000, 0x6aa52f9900000000, + 0x579ccaef00000000, 0x8376b97400000000, 0x2dee000200000000, + 0xf904739900000000, 0xc43d96ef00000000, 0x10d7e57400000000, + 0xd48a970300000000, 0x0060e49800000000, 0x3d5901ee00000000, + 0xe9b3727500000000, 0x472bcb0300000000, 0x93c1b89800000000, + 0xaef85dee00000000, 0x7a122e7500000000, 0xf2c92e0300000000, + 0x26235d9800000000, 0x1b1ab8ee00000000, 0xcff0cb7500000000, + 0x6168720300000000, 0xb582019800000000, 0x88bbe4ee00000000, + 0x5c51977500000000, 0x3019ca0500000000, 0xe4f3b99e00000000, + 0xd9ca5ce800000000, 0x0d202f7300000000, 0xa3b8960500000000, + 0x7752e59e00000000, 0x4a6b00e800000000, 0x9e81737300000000, + 0x165a730500000000, 0xc2b0009e00000000, 0xff89e5e800000000, + 0x2b63967300000000, 0x85fb2f0500000000, 0x51115c9e00000000, + 0x6c28b9e800000000, 0xb8c2ca7300000000, 0x7c9fb80400000000, + 0xa875cb9f00000000, 0x954c2ee900000000, 0x41a65d7200000000, + 0xef3ee40400000000, 0x3bd4979f00000000, 0x06ed72e900000000, + 0xd207017200000000, 0x5adc010400000000, 0x8e36729f00000000, + 0xb30f97e900000000, 0x67e5e47200000000, 0xc97d5d0400000000, + 0x1d972e9f00000000, 0x20aecbe900000000, 0xf444b87200000000, + 0xa8152f0700000000, 0x7cff5c9c00000000, 0x41c6b9ea00000000, + 0x952cca7100000000, 0x3bb4730700000000, 0xef5e009c00000000, + 0xd267e5ea00000000, 0x068d967100000000, 0x8e56960700000000, + 0x5abce59c00000000, 0x678500ea00000000, 0xb36f737100000000, + 0x1df7ca0700000000, 0xc91db99c00000000, 0xf4245cea00000000, + 0x20ce2f7100000000, 0xe4935d0600000000, 0x30792e9d00000000, + 0x0d40cbeb00000000, 0xd9aab87000000000, 0x7732010600000000, + 0xa3d8729d00000000, 0x9ee197eb00000000, 0x4a0be47000000000, + 0xc2d0e40600000000, 0x163a979d00000000, 0x2b0372eb00000000, + 0xffe9017000000000, 0x5171b80600000000, 0x859bcb9d00000000, + 0xb8a22eeb00000000, 0x6c485d7000000000, 0x6032940b00000000, + 0xb4d8e79000000000, 0x89e102e600000000, 0x5d0b717d00000000, + 0xf393c80b00000000, 0x2779bb9000000000, 0x1a405ee600000000, + 0xceaa2d7d00000000, 0x46712d0b00000000, 0x929b5e9000000000, + 0xafa2bbe600000000, 0x7b48c87d00000000, 0xd5d0710b00000000, + 0x013a029000000000, 0x3c03e7e600000000, 0xe8e9947d00000000, + 0x2cb4e60a00000000, 0xf85e959100000000, 0xc56770e700000000, + 0x118d037c00000000, 0xbf15ba0a00000000, 0x6bffc99100000000, + 0x56c62ce700000000, 0x822c5f7c00000000, 0x0af75f0a00000000, + 0xde1d2c9100000000, 0xe324c9e700000000, 0x37ceba7c00000000, + 0x9956030a00000000, 0x4dbc709100000000, 0x708595e700000000, + 0xa46fe67c00000000, 0xf83e710900000000, 0x2cd4029200000000, + 0x11ede7e400000000, 0xc507947f00000000, 0x6b9f2d0900000000, + 0xbf755e9200000000, 0x824cbbe400000000, 0x56a6c87f00000000, + 0xde7dc80900000000, 0x0a97bb9200000000, 0x37ae5ee400000000, + 0xe3442d7f00000000, 0x4ddc940900000000, 0x9936e79200000000, + 0xa40f02e400000000, 0x70e5717f00000000, 0xb4b8030800000000, + 0x6052709300000000, 0x5d6b95e500000000, 0x8981e67e00000000, + 0x27195f0800000000, 0xf3f32c9300000000, 0xcecac9e500000000, + 0x1a20ba7e00000000, 0x92fbba0800000000, 0x4611c99300000000, + 0x7b282ce500000000, 0xafc25f7e00000000, 0x015ae60800000000, + 0xd5b0959300000000, 0xe88970e500000000, 0x3c63037e00000000, + 0x502b5e0e00000000, 0x84c12d9500000000, 0xb9f8c8e300000000, + 0x6d12bb7800000000, 0xc38a020e00000000, 0x1760719500000000, + 0x2a5994e300000000, 0xfeb3e77800000000, 0x7668e70e00000000, + 0xa282949500000000, 0x9fbb71e300000000, 0x4b51027800000000, + 0xe5c9bb0e00000000, 0x3123c89500000000, 0x0c1a2de300000000, + 0xd8f05e7800000000, 0x1cad2c0f00000000, 0xc8475f9400000000, + 0xf57ebae200000000, 0x2194c97900000000, 0x8f0c700f00000000, + 0x5be6039400000000, 0x66dfe6e200000000, 0xb235957900000000, + 0x3aee950f00000000, 0xee04e69400000000, 0xd33d03e200000000, + 0x07d7707900000000, 0xa94fc90f00000000, 0x7da5ba9400000000, + 0x409c5fe200000000, 0x94762c7900000000, 0xc827bb0c00000000, + 0x1ccdc89700000000, 0x21f42de100000000, 0xf51e5e7a00000000, + 0x5b86e70c00000000, 0x8f6c949700000000, 0xb25571e100000000, + 0x66bf027a00000000, 0xee64020c00000000, 0x3a8e719700000000, + 0x07b794e100000000, 0xd35de77a00000000, 0x7dc55e0c00000000, + 0xa92f2d9700000000, 0x9416c8e100000000, 0x40fcbb7a00000000, + 0x84a1c90d00000000, 0x504bba9600000000, 0x6d725fe000000000, + 0xb9982c7b00000000, 0x1700950d00000000, 0xc3eae69600000000, + 0xfed303e000000000, 0x2a39707b00000000, 0xa2e2700d00000000, + 0x7608039600000000, 0x4b31e6e000000000, 0x9fdb957b00000000, + 0x31432c0d00000000, 0xe5a95f9600000000, 0xd890bae000000000, + 0x0c7ac97b00000000}, + {0x0000000000000000, 0x2765258100000000, 0x0fcc3bd900000000, + 0x28a91e5800000000, 0x5f9e066900000000, 0x78fb23e800000000, + 0x50523db000000000, 0x7737183100000000, 0xbe3c0dd200000000, + 0x9959285300000000, 0xb1f0360b00000000, 0x9695138a00000000, + 0xe1a20bbb00000000, 0xc6c72e3a00000000, 0xee6e306200000000, + 0xc90b15e300000000, 0x3d7f6b7f00000000, 0x1a1a4efe00000000, + 0x32b350a600000000, 0x15d6752700000000, 0x62e16d1600000000, + 0x4584489700000000, 0x6d2d56cf00000000, 0x4a48734e00000000, + 0x834366ad00000000, 0xa426432c00000000, 0x8c8f5d7400000000, + 0xabea78f500000000, 0xdcdd60c400000000, 0xfbb8454500000000, + 0xd3115b1d00000000, 0xf4747e9c00000000, 0x7afed6fe00000000, + 0x5d9bf37f00000000, 0x7532ed2700000000, 0x5257c8a600000000, + 0x2560d09700000000, 0x0205f51600000000, 0x2aaceb4e00000000, + 0x0dc9cecf00000000, 0xc4c2db2c00000000, 0xe3a7fead00000000, + 0xcb0ee0f500000000, 0xec6bc57400000000, 0x9b5cdd4500000000, + 0xbc39f8c400000000, 0x9490e69c00000000, 0xb3f5c31d00000000, + 0x4781bd8100000000, 0x60e4980000000000, 0x484d865800000000, + 0x6f28a3d900000000, 0x181fbbe800000000, 0x3f7a9e6900000000, + 0x17d3803100000000, 0x30b6a5b000000000, 0xf9bdb05300000000, + 0xded895d200000000, 0xf6718b8a00000000, 0xd114ae0b00000000, + 0xa623b63a00000000, 0x814693bb00000000, 0xa9ef8de300000000, + 0x8e8aa86200000000, 0xb5fadc2600000000, 0x929ff9a700000000, + 0xba36e7ff00000000, 0x9d53c27e00000000, 0xea64da4f00000000, + 0xcd01ffce00000000, 0xe5a8e19600000000, 0xc2cdc41700000000, + 0x0bc6d1f400000000, 0x2ca3f47500000000, 0x040aea2d00000000, + 0x236fcfac00000000, 0x5458d79d00000000, 0x733df21c00000000, + 0x5b94ec4400000000, 0x7cf1c9c500000000, 0x8885b75900000000, + 0xafe092d800000000, 0x87498c8000000000, 0xa02ca90100000000, + 0xd71bb13000000000, 0xf07e94b100000000, 0xd8d78ae900000000, + 0xffb2af6800000000, 0x36b9ba8b00000000, 0x11dc9f0a00000000, + 0x3975815200000000, 0x1e10a4d300000000, 0x6927bce200000000, + 0x4e42996300000000, 0x66eb873b00000000, 0x418ea2ba00000000, + 0xcf040ad800000000, 0xe8612f5900000000, 0xc0c8310100000000, + 0xe7ad148000000000, 0x909a0cb100000000, 0xb7ff293000000000, + 0x9f56376800000000, 0xb83312e900000000, 0x7138070a00000000, + 0x565d228b00000000, 0x7ef43cd300000000, 0x5991195200000000, + 0x2ea6016300000000, 0x09c324e200000000, 0x216a3aba00000000, + 0x060f1f3b00000000, 0xf27b61a700000000, 0xd51e442600000000, + 0xfdb75a7e00000000, 0xdad27fff00000000, 0xade567ce00000000, + 0x8a80424f00000000, 0xa2295c1700000000, 0x854c799600000000, + 0x4c476c7500000000, 0x6b2249f400000000, 0x438b57ac00000000, + 0x64ee722d00000000, 0x13d96a1c00000000, 0x34bc4f9d00000000, + 0x1c1551c500000000, 0x3b70744400000000, 0x6af5b94d00000000, + 0x4d909ccc00000000, 0x6539829400000000, 0x425ca71500000000, + 0x356bbf2400000000, 0x120e9aa500000000, 0x3aa784fd00000000, + 0x1dc2a17c00000000, 0xd4c9b49f00000000, 0xf3ac911e00000000, + 0xdb058f4600000000, 0xfc60aac700000000, 0x8b57b2f600000000, + 0xac32977700000000, 0x849b892f00000000, 0xa3feacae00000000, + 0x578ad23200000000, 0x70eff7b300000000, 0x5846e9eb00000000, + 0x7f23cc6a00000000, 0x0814d45b00000000, 0x2f71f1da00000000, + 0x07d8ef8200000000, 0x20bdca0300000000, 0xe9b6dfe000000000, + 0xced3fa6100000000, 0xe67ae43900000000, 0xc11fc1b800000000, + 0xb628d98900000000, 0x914dfc0800000000, 0xb9e4e25000000000, + 0x9e81c7d100000000, 0x100b6fb300000000, 0x376e4a3200000000, + 0x1fc7546a00000000, 0x38a271eb00000000, 0x4f9569da00000000, + 0x68f04c5b00000000, 0x4059520300000000, 0x673c778200000000, + 0xae37626100000000, 0x895247e000000000, 0xa1fb59b800000000, + 0x869e7c3900000000, 0xf1a9640800000000, 0xd6cc418900000000, + 0xfe655fd100000000, 0xd9007a5000000000, 0x2d7404cc00000000, + 0x0a11214d00000000, 0x22b83f1500000000, 0x05dd1a9400000000, + 0x72ea02a500000000, 0x558f272400000000, 0x7d26397c00000000, + 0x5a431cfd00000000, 0x9348091e00000000, 0xb42d2c9f00000000, + 0x9c8432c700000000, 0xbbe1174600000000, 0xccd60f7700000000, + 0xebb32af600000000, 0xc31a34ae00000000, 0xe47f112f00000000, + 0xdf0f656b00000000, 0xf86a40ea00000000, 0xd0c35eb200000000, + 0xf7a67b3300000000, 0x8091630200000000, 0xa7f4468300000000, + 0x8f5d58db00000000, 0xa8387d5a00000000, 0x613368b900000000, + 0x46564d3800000000, 0x6eff536000000000, 0x499a76e100000000, + 0x3ead6ed000000000, 0x19c84b5100000000, 0x3161550900000000, + 0x1604708800000000, 0xe2700e1400000000, 0xc5152b9500000000, + 0xedbc35cd00000000, 0xcad9104c00000000, 0xbdee087d00000000, + 0x9a8b2dfc00000000, 0xb22233a400000000, 0x9547162500000000, + 0x5c4c03c600000000, 0x7b29264700000000, 0x5380381f00000000, + 0x74e51d9e00000000, 0x03d205af00000000, 0x24b7202e00000000, + 0x0c1e3e7600000000, 0x2b7b1bf700000000, 0xa5f1b39500000000, + 0x8294961400000000, 0xaa3d884c00000000, 0x8d58adcd00000000, + 0xfa6fb5fc00000000, 0xdd0a907d00000000, 0xf5a38e2500000000, + 0xd2c6aba400000000, 0x1bcdbe4700000000, 0x3ca89bc600000000, + 0x1401859e00000000, 0x3364a01f00000000, 0x4453b82e00000000, + 0x63369daf00000000, 0x4b9f83f700000000, 0x6cfaa67600000000, + 0x988ed8ea00000000, 0xbfebfd6b00000000, 0x9742e33300000000, + 0xb027c6b200000000, 0xc710de8300000000, 0xe075fb0200000000, + 0xc8dce55a00000000, 0xefb9c0db00000000, 0x26b2d53800000000, + 0x01d7f0b900000000, 0x297eeee100000000, 0x0e1bcb6000000000, + 0x792cd35100000000, 0x5e49f6d000000000, 0x76e0e88800000000, + 0x5185cd0900000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f, + 0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91, + 0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e, + 0x72949f71, 0x0c18edfc, 0x97bda193, 0xe0237363, 0x7b863f0c, + 0x0f1ed683, 0x94bb9aec, 0xe325481c, 0x78800473, 0x0a149b02, + 0x91b1d76d, 0xe62f059d, 0x7d8a49f2, 0x0912a07d, 0x92b7ec12, + 0xe5293ee2, 0x7e8c728d, 0x1831dbf8, 0x83949797, 0xf40a4567, + 0x6faf0908, 0x1b37e087, 0x8092ace8, 0xf70c7e18, 0x6ca93277, + 0x1e3dad06, 0x8598e169, 0xf2063399, 0x69a37ff6, 0x1d3b9679, + 0x869eda16, 0xf10008e6, 0x6aa54489, 0x14293604, 0x8f8c7a6b, + 0xf812a89b, 0x63b7e4f4, 0x172f0d7b, 0x8c8a4114, 0xfb1493e4, + 0x60b1df8b, 0x122540fa, 0x89800c95, 0xfe1ede65, 0x65bb920a, + 0x11237b85, 0x8a8637ea, 0xfd18e51a, 0x66bda975, 0x3063b7f0, + 0xabc6fb9f, 0xdc58296f, 0x47fd6500, 0x33658c8f, 0xa8c0c0e0, + 0xdf5e1210, 0x44fb5e7f, 0x366fc10e, 0xadca8d61, 0xda545f91, + 0x41f113fe, 0x3569fa71, 0xaeccb61e, 0xd95264ee, 0x42f72881, + 0x3c7b5a0c, 0xa7de1663, 0xd040c493, 0x4be588fc, 0x3f7d6173, + 0xa4d82d1c, 0xd346ffec, 0x48e3b383, 0x3a772cf2, 0xa1d2609d, + 0xd64cb26d, 0x4de9fe02, 0x3971178d, 0xa2d45be2, 0xd54a8912, + 0x4eefc57d, 0x28526c08, 0xb3f72067, 0xc469f297, 0x5fccbef8, + 0x2b545777, 0xb0f11b18, 0xc76fc9e8, 0x5cca8587, 0x2e5e1af6, + 0xb5fb5699, 0xc2658469, 0x59c0c806, 0x2d582189, 0xb6fd6de6, + 0xc163bf16, 0x5ac6f379, 0x244a81f4, 0xbfefcd9b, 0xc8711f6b, + 0x53d45304, 0x274cba8b, 0xbce9f6e4, 0xcb772414, 0x50d2687b, + 0x2246f70a, 0xb9e3bb65, 0xce7d6995, 0x55d825fa, 0x2140cc75, + 0xbae5801a, 0xcd7b52ea, 0x56de1e85, 0x60c76fe0, 0xfb62238f, + 0x8cfcf17f, 0x1759bd10, 0x63c1549f, 0xf86418f0, 0x8ffaca00, + 0x145f866f, 0x66cb191e, 0xfd6e5571, 0x8af08781, 0x1155cbee, + 0x65cd2261, 0xfe686e0e, 0x89f6bcfe, 0x1253f091, 0x6cdf821c, + 0xf77ace73, 0x80e41c83, 0x1b4150ec, 0x6fd9b963, 0xf47cf50c, + 0x83e227fc, 0x18476b93, 0x6ad3f4e2, 0xf176b88d, 0x86e86a7d, + 0x1d4d2612, 0x69d5cf9d, 0xf27083f2, 0x85ee5102, 0x1e4b1d6d, + 0x78f6b418, 0xe353f877, 0x94cd2a87, 0x0f6866e8, 0x7bf08f67, + 0xe055c308, 0x97cb11f8, 0x0c6e5d97, 0x7efac2e6, 0xe55f8e89, + 0x92c15c79, 0x09641016, 0x7dfcf999, 0xe659b5f6, 0x91c76706, + 0x0a622b69, 0x74ee59e4, 0xef4b158b, 0x98d5c77b, 0x03708b14, + 0x77e8629b, 0xec4d2ef4, 0x9bd3fc04, 0x0076b06b, 0x72e22f1a, + 0xe9476375, 0x9ed9b185, 0x057cfdea, 0x71e41465, 0xea41580a, + 0x9ddf8afa, 0x067ac695, 0x50a4d810, 0xcb01947f, 0xbc9f468f, + 0x273a0ae0, 0x53a2e36f, 0xc807af00, 0xbf997df0, 0x243c319f, + 0x56a8aeee, 0xcd0de281, 0xba933071, 0x21367c1e, 0x55ae9591, + 0xce0bd9fe, 0xb9950b0e, 0x22304761, 0x5cbc35ec, 0xc7197983, + 0xb087ab73, 0x2b22e71c, 0x5fba0e93, 0xc41f42fc, 0xb381900c, + 0x2824dc63, 0x5ab04312, 0xc1150f7d, 0xb68bdd8d, 0x2d2e91e2, + 0x59b6786d, 0xc2133402, 0xb58de6f2, 0x2e28aa9d, 0x489503e8, + 0xd3304f87, 0xa4ae9d77, 0x3f0bd118, 0x4b933897, 0xd03674f8, + 0xa7a8a608, 0x3c0dea67, 0x4e997516, 0xd53c3979, 0xa2a2eb89, + 0x3907a7e6, 0x4d9f4e69, 0xd63a0206, 0xa1a4d0f6, 0x3a019c99, + 0x448dee14, 0xdf28a27b, 0xa8b6708b, 0x33133ce4, 0x478bd56b, + 0xdc2e9904, 0xabb04bf4, 0x3015079b, 0x428198ea, 0xd924d485, + 0xaeba0675, 0x351f4a1a, 0x4187a395, 0xda22effa, 0xadbc3d0a, + 0x36197165}, + {0x00000000, 0xc18edfc0, 0x586cb9c1, 0x99e26601, 0xb0d97382, + 0x7157ac42, 0xe8b5ca43, 0x293b1583, 0xbac3e145, 0x7b4d3e85, + 0xe2af5884, 0x23218744, 0x0a1a92c7, 0xcb944d07, 0x52762b06, + 0x93f8f4c6, 0xaef6c4cb, 0x6f781b0b, 0xf69a7d0a, 0x3714a2ca, + 0x1e2fb749, 0xdfa16889, 0x46430e88, 0x87cdd148, 0x1435258e, + 0xd5bbfa4e, 0x4c599c4f, 0x8dd7438f, 0xa4ec560c, 0x656289cc, + 0xfc80efcd, 0x3d0e300d, 0x869c8fd7, 0x47125017, 0xdef03616, + 0x1f7ee9d6, 0x3645fc55, 0xf7cb2395, 0x6e294594, 0xafa79a54, + 0x3c5f6e92, 0xfdd1b152, 0x6433d753, 0xa5bd0893, 0x8c861d10, + 0x4d08c2d0, 0xd4eaa4d1, 0x15647b11, 0x286a4b1c, 0xe9e494dc, + 0x7006f2dd, 0xb1882d1d, 0x98b3389e, 0x593de75e, 0xc0df815f, + 0x01515e9f, 0x92a9aa59, 0x53277599, 0xcac51398, 0x0b4bcc58, + 0x2270d9db, 0xe3fe061b, 0x7a1c601a, 0xbb92bfda, 0xd64819ef, + 0x17c6c62f, 0x8e24a02e, 0x4faa7fee, 0x66916a6d, 0xa71fb5ad, + 0x3efdd3ac, 0xff730c6c, 0x6c8bf8aa, 0xad05276a, 0x34e7416b, + 0xf5699eab, 0xdc528b28, 0x1ddc54e8, 0x843e32e9, 0x45b0ed29, + 0x78bedd24, 0xb93002e4, 0x20d264e5, 0xe15cbb25, 0xc867aea6, + 0x09e97166, 0x900b1767, 0x5185c8a7, 0xc27d3c61, 0x03f3e3a1, + 0x9a1185a0, 0x5b9f5a60, 0x72a44fe3, 0xb32a9023, 0x2ac8f622, + 0xeb4629e2, 0x50d49638, 0x915a49f8, 0x08b82ff9, 0xc936f039, + 0xe00de5ba, 0x21833a7a, 0xb8615c7b, 0x79ef83bb, 0xea17777d, + 0x2b99a8bd, 0xb27bcebc, 0x73f5117c, 0x5ace04ff, 0x9b40db3f, + 0x02a2bd3e, 0xc32c62fe, 0xfe2252f3, 0x3fac8d33, 0xa64eeb32, + 0x67c034f2, 0x4efb2171, 0x8f75feb1, 0x169798b0, 0xd7194770, + 0x44e1b3b6, 0x856f6c76, 0x1c8d0a77, 0xdd03d5b7, 0xf438c034, + 0x35b61ff4, 0xac5479f5, 0x6ddaa635, 0x77e1359f, 0xb66fea5f, + 0x2f8d8c5e, 0xee03539e, 0xc738461d, 0x06b699dd, 0x9f54ffdc, + 0x5eda201c, 0xcd22d4da, 0x0cac0b1a, 0x954e6d1b, 0x54c0b2db, + 0x7dfba758, 0xbc757898, 0x25971e99, 0xe419c159, 0xd917f154, + 0x18992e94, 0x817b4895, 0x40f59755, 0x69ce82d6, 0xa8405d16, + 0x31a23b17, 0xf02ce4d7, 0x63d41011, 0xa25acfd1, 0x3bb8a9d0, + 0xfa367610, 0xd30d6393, 0x1283bc53, 0x8b61da52, 0x4aef0592, + 0xf17dba48, 0x30f36588, 0xa9110389, 0x689fdc49, 0x41a4c9ca, + 0x802a160a, 0x19c8700b, 0xd846afcb, 0x4bbe5b0d, 0x8a3084cd, + 0x13d2e2cc, 0xd25c3d0c, 0xfb67288f, 0x3ae9f74f, 0xa30b914e, + 0x62854e8e, 0x5f8b7e83, 0x9e05a143, 0x07e7c742, 0xc6691882, + 0xef520d01, 0x2edcd2c1, 0xb73eb4c0, 0x76b06b00, 0xe5489fc6, + 0x24c64006, 0xbd242607, 0x7caaf9c7, 0x5591ec44, 0x941f3384, + 0x0dfd5585, 0xcc738a45, 0xa1a92c70, 0x6027f3b0, 0xf9c595b1, + 0x384b4a71, 0x11705ff2, 0xd0fe8032, 0x491ce633, 0x889239f3, + 0x1b6acd35, 0xdae412f5, 0x430674f4, 0x8288ab34, 0xabb3beb7, + 0x6a3d6177, 0xf3df0776, 0x3251d8b6, 0x0f5fe8bb, 0xced1377b, + 0x5733517a, 0x96bd8eba, 0xbf869b39, 0x7e0844f9, 0xe7ea22f8, + 0x2664fd38, 0xb59c09fe, 0x7412d63e, 0xedf0b03f, 0x2c7e6fff, + 0x05457a7c, 0xc4cba5bc, 0x5d29c3bd, 0x9ca71c7d, 0x2735a3a7, + 0xe6bb7c67, 0x7f591a66, 0xbed7c5a6, 0x97ecd025, 0x56620fe5, + 0xcf8069e4, 0x0e0eb624, 0x9df642e2, 0x5c789d22, 0xc59afb23, + 0x041424e3, 0x2d2f3160, 0xeca1eea0, 0x754388a1, 0xb4cd5761, + 0x89c3676c, 0x484db8ac, 0xd1afdead, 0x1021016d, 0x391a14ee, + 0xf894cb2e, 0x6176ad2f, 0xa0f872ef, 0x33008629, 0xf28e59e9, + 0x6b6c3fe8, 0xaae2e028, 0x83d9f5ab, 0x42572a6b, 0xdbb54c6a, + 0x1a3b93aa}, + {0x00000000, 0xefc26b3e, 0x04f5d03d, 0xeb37bb03, 0x09eba07a, + 0xe629cb44, 0x0d1e7047, 0xe2dc1b79, 0x13d740f4, 0xfc152bca, + 0x172290c9, 0xf8e0fbf7, 0x1a3ce08e, 0xf5fe8bb0, 0x1ec930b3, + 0xf10b5b8d, 0x27ae81e8, 0xc86cead6, 0x235b51d5, 0xcc993aeb, + 0x2e452192, 0xc1874aac, 0x2ab0f1af, 0xc5729a91, 0x3479c11c, + 0xdbbbaa22, 0x308c1121, 0xdf4e7a1f, 0x3d926166, 0xd2500a58, + 0x3967b15b, 0xd6a5da65, 0x4f5d03d0, 0xa09f68ee, 0x4ba8d3ed, + 0xa46ab8d3, 0x46b6a3aa, 0xa974c894, 0x42437397, 0xad8118a9, + 0x5c8a4324, 0xb348281a, 0x587f9319, 0xb7bdf827, 0x5561e35e, + 0xbaa38860, 0x51943363, 0xbe56585d, 0x68f38238, 0x8731e906, + 0x6c065205, 0x83c4393b, 0x61182242, 0x8eda497c, 0x65edf27f, + 0x8a2f9941, 0x7b24c2cc, 0x94e6a9f2, 0x7fd112f1, 0x901379cf, + 0x72cf62b6, 0x9d0d0988, 0x763ab28b, 0x99f8d9b5, 0x9eba07a0, + 0x71786c9e, 0x9a4fd79d, 0x758dbca3, 0x9751a7da, 0x7893cce4, + 0x93a477e7, 0x7c661cd9, 0x8d6d4754, 0x62af2c6a, 0x89989769, + 0x665afc57, 0x8486e72e, 0x6b448c10, 0x80733713, 0x6fb15c2d, + 0xb9148648, 0x56d6ed76, 0xbde15675, 0x52233d4b, 0xb0ff2632, + 0x5f3d4d0c, 0xb40af60f, 0x5bc89d31, 0xaac3c6bc, 0x4501ad82, + 0xae361681, 0x41f47dbf, 0xa32866c6, 0x4cea0df8, 0xa7ddb6fb, + 0x481fddc5, 0xd1e70470, 0x3e256f4e, 0xd512d44d, 0x3ad0bf73, + 0xd80ca40a, 0x37cecf34, 0xdcf97437, 0x333b1f09, 0xc2304484, + 0x2df22fba, 0xc6c594b9, 0x2907ff87, 0xcbdbe4fe, 0x24198fc0, + 0xcf2e34c3, 0x20ec5ffd, 0xf6498598, 0x198beea6, 0xf2bc55a5, + 0x1d7e3e9b, 0xffa225e2, 0x10604edc, 0xfb57f5df, 0x14959ee1, + 0xe59ec56c, 0x0a5cae52, 0xe16b1551, 0x0ea97e6f, 0xec756516, + 0x03b70e28, 0xe880b52b, 0x0742de15, 0xe6050901, 0x09c7623f, + 0xe2f0d93c, 0x0d32b202, 0xefeea97b, 0x002cc245, 0xeb1b7946, + 0x04d91278, 0xf5d249f5, 0x1a1022cb, 0xf12799c8, 0x1ee5f2f6, + 0xfc39e98f, 0x13fb82b1, 0xf8cc39b2, 0x170e528c, 0xc1ab88e9, + 0x2e69e3d7, 0xc55e58d4, 0x2a9c33ea, 0xc8402893, 0x278243ad, + 0xccb5f8ae, 0x23779390, 0xd27cc81d, 0x3dbea323, 0xd6891820, + 0x394b731e, 0xdb976867, 0x34550359, 0xdf62b85a, 0x30a0d364, + 0xa9580ad1, 0x469a61ef, 0xadaddaec, 0x426fb1d2, 0xa0b3aaab, + 0x4f71c195, 0xa4467a96, 0x4b8411a8, 0xba8f4a25, 0x554d211b, + 0xbe7a9a18, 0x51b8f126, 0xb364ea5f, 0x5ca68161, 0xb7913a62, + 0x5853515c, 0x8ef68b39, 0x6134e007, 0x8a035b04, 0x65c1303a, + 0x871d2b43, 0x68df407d, 0x83e8fb7e, 0x6c2a9040, 0x9d21cbcd, + 0x72e3a0f3, 0x99d41bf0, 0x761670ce, 0x94ca6bb7, 0x7b080089, + 0x903fbb8a, 0x7ffdd0b4, 0x78bf0ea1, 0x977d659f, 0x7c4ade9c, + 0x9388b5a2, 0x7154aedb, 0x9e96c5e5, 0x75a17ee6, 0x9a6315d8, + 0x6b684e55, 0x84aa256b, 0x6f9d9e68, 0x805ff556, 0x6283ee2f, + 0x8d418511, 0x66763e12, 0x89b4552c, 0x5f118f49, 0xb0d3e477, + 0x5be45f74, 0xb426344a, 0x56fa2f33, 0xb938440d, 0x520fff0e, + 0xbdcd9430, 0x4cc6cfbd, 0xa304a483, 0x48331f80, 0xa7f174be, + 0x452d6fc7, 0xaaef04f9, 0x41d8bffa, 0xae1ad4c4, 0x37e20d71, + 0xd820664f, 0x3317dd4c, 0xdcd5b672, 0x3e09ad0b, 0xd1cbc635, + 0x3afc7d36, 0xd53e1608, 0x24354d85, 0xcbf726bb, 0x20c09db8, + 0xcf02f686, 0x2ddeedff, 0xc21c86c1, 0x292b3dc2, 0xc6e956fc, + 0x104c8c99, 0xff8ee7a7, 0x14b95ca4, 0xfb7b379a, 0x19a72ce3, + 0xf66547dd, 0x1d52fcde, 0xf29097e0, 0x039bcc6d, 0xec59a753, + 0x076e1c50, 0xe8ac776e, 0x0a706c17, 0xe5b20729, 0x0e85bc2a, + 0xe147d714}, + {0x00000000, 0x177b1443, 0x2ef62886, 0x398d3cc5, 0x5dec510c, + 0x4a97454f, 0x731a798a, 0x64616dc9, 0xbbd8a218, 0xaca3b65b, + 0x952e8a9e, 0x82559edd, 0xe634f314, 0xf14fe757, 0xc8c2db92, + 0xdfb9cfd1, 0xacc04271, 0xbbbb5632, 0x82366af7, 0x954d7eb4, + 0xf12c137d, 0xe657073e, 0xdfda3bfb, 0xc8a12fb8, 0x1718e069, + 0x0063f42a, 0x39eec8ef, 0x2e95dcac, 0x4af4b165, 0x5d8fa526, + 0x640299e3, 0x73798da0, 0x82f182a3, 0x958a96e0, 0xac07aa25, + 0xbb7cbe66, 0xdf1dd3af, 0xc866c7ec, 0xf1ebfb29, 0xe690ef6a, + 0x392920bb, 0x2e5234f8, 0x17df083d, 0x00a41c7e, 0x64c571b7, + 0x73be65f4, 0x4a335931, 0x5d484d72, 0x2e31c0d2, 0x394ad491, + 0x00c7e854, 0x17bcfc17, 0x73dd91de, 0x64a6859d, 0x5d2bb958, + 0x4a50ad1b, 0x95e962ca, 0x82927689, 0xbb1f4a4c, 0xac645e0f, + 0xc80533c6, 0xdf7e2785, 0xe6f31b40, 0xf1880f03, 0xde920307, + 0xc9e91744, 0xf0642b81, 0xe71f3fc2, 0x837e520b, 0x94054648, + 0xad887a8d, 0xbaf36ece, 0x654aa11f, 0x7231b55c, 0x4bbc8999, + 0x5cc79dda, 0x38a6f013, 0x2fdde450, 0x1650d895, 0x012bccd6, + 0x72524176, 0x65295535, 0x5ca469f0, 0x4bdf7db3, 0x2fbe107a, + 0x38c50439, 0x014838fc, 0x16332cbf, 0xc98ae36e, 0xdef1f72d, + 0xe77ccbe8, 0xf007dfab, 0x9466b262, 0x831da621, 0xba909ae4, + 0xadeb8ea7, 0x5c6381a4, 0x4b1895e7, 0x7295a922, 0x65eebd61, + 0x018fd0a8, 0x16f4c4eb, 0x2f79f82e, 0x3802ec6d, 0xe7bb23bc, + 0xf0c037ff, 0xc94d0b3a, 0xde361f79, 0xba5772b0, 0xad2c66f3, + 0x94a15a36, 0x83da4e75, 0xf0a3c3d5, 0xe7d8d796, 0xde55eb53, + 0xc92eff10, 0xad4f92d9, 0xba34869a, 0x83b9ba5f, 0x94c2ae1c, + 0x4b7b61cd, 0x5c00758e, 0x658d494b, 0x72f65d08, 0x169730c1, + 0x01ec2482, 0x38611847, 0x2f1a0c04, 0x6655004f, 0x712e140c, + 0x48a328c9, 0x5fd83c8a, 0x3bb95143, 0x2cc24500, 0x154f79c5, + 0x02346d86, 0xdd8da257, 0xcaf6b614, 0xf37b8ad1, 0xe4009e92, + 0x8061f35b, 0x971ae718, 0xae97dbdd, 0xb9eccf9e, 0xca95423e, + 0xddee567d, 0xe4636ab8, 0xf3187efb, 0x97791332, 0x80020771, + 0xb98f3bb4, 0xaef42ff7, 0x714de026, 0x6636f465, 0x5fbbc8a0, + 0x48c0dce3, 0x2ca1b12a, 0x3bdaa569, 0x025799ac, 0x152c8def, + 0xe4a482ec, 0xf3df96af, 0xca52aa6a, 0xdd29be29, 0xb948d3e0, + 0xae33c7a3, 0x97befb66, 0x80c5ef25, 0x5f7c20f4, 0x480734b7, + 0x718a0872, 0x66f11c31, 0x029071f8, 0x15eb65bb, 0x2c66597e, + 0x3b1d4d3d, 0x4864c09d, 0x5f1fd4de, 0x6692e81b, 0x71e9fc58, + 0x15889191, 0x02f385d2, 0x3b7eb917, 0x2c05ad54, 0xf3bc6285, + 0xe4c776c6, 0xdd4a4a03, 0xca315e40, 0xae503389, 0xb92b27ca, + 0x80a61b0f, 0x97dd0f4c, 0xb8c70348, 0xafbc170b, 0x96312bce, + 0x814a3f8d, 0xe52b5244, 0xf2504607, 0xcbdd7ac2, 0xdca66e81, + 0x031fa150, 0x1464b513, 0x2de989d6, 0x3a929d95, 0x5ef3f05c, + 0x4988e41f, 0x7005d8da, 0x677ecc99, 0x14074139, 0x037c557a, + 0x3af169bf, 0x2d8a7dfc, 0x49eb1035, 0x5e900476, 0x671d38b3, + 0x70662cf0, 0xafdfe321, 0xb8a4f762, 0x8129cba7, 0x9652dfe4, + 0xf233b22d, 0xe548a66e, 0xdcc59aab, 0xcbbe8ee8, 0x3a3681eb, + 0x2d4d95a8, 0x14c0a96d, 0x03bbbd2e, 0x67dad0e7, 0x70a1c4a4, + 0x492cf861, 0x5e57ec22, 0x81ee23f3, 0x969537b0, 0xaf180b75, + 0xb8631f36, 0xdc0272ff, 0xcb7966bc, 0xf2f45a79, 0xe58f4e3a, + 0x96f6c39a, 0x818dd7d9, 0xb800eb1c, 0xaf7bff5f, 0xcb1a9296, + 0xdc6186d5, 0xe5ecba10, 0xf297ae53, 0x2d2e6182, 0x3a5575c1, + 0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808, + 0x494f0c4b}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x43147b17, 0x8628f62e, 0xc53c8d39, 0x0c51ec5d, + 0x4f45974a, 0x8a791a73, 0xc96d6164, 0x18a2d8bb, 0x5bb6a3ac, + 0x9e8a2e95, 0xdd9e5582, 0x14f334e6, 0x57e74ff1, 0x92dbc2c8, + 0xd1cfb9df, 0x7142c0ac, 0x3256bbbb, 0xf76a3682, 0xb47e4d95, + 0x7d132cf1, 0x3e0757e6, 0xfb3bdadf, 0xb82fa1c8, 0x69e01817, + 0x2af46300, 0xefc8ee39, 0xacdc952e, 0x65b1f44a, 0x26a58f5d, + 0xe3990264, 0xa08d7973, 0xa382f182, 0xe0968a95, 0x25aa07ac, + 0x66be7cbb, 0xafd31ddf, 0xecc766c8, 0x29fbebf1, 0x6aef90e6, + 0xbb202939, 0xf834522e, 0x3d08df17, 0x7e1ca400, 0xb771c564, + 0xf465be73, 0x3159334a, 0x724d485d, 0xd2c0312e, 0x91d44a39, + 0x54e8c700, 0x17fcbc17, 0xde91dd73, 0x9d85a664, 0x58b92b5d, + 0x1bad504a, 0xca62e995, 0x89769282, 0x4c4a1fbb, 0x0f5e64ac, + 0xc63305c8, 0x85277edf, 0x401bf3e6, 0x030f88f1, 0x070392de, + 0x4417e9c9, 0x812b64f0, 0xc23f1fe7, 0x0b527e83, 0x48460594, + 0x8d7a88ad, 0xce6ef3ba, 0x1fa14a65, 0x5cb53172, 0x9989bc4b, + 0xda9dc75c, 0x13f0a638, 0x50e4dd2f, 0x95d85016, 0xd6cc2b01, + 0x76415272, 0x35552965, 0xf069a45c, 0xb37ddf4b, 0x7a10be2f, + 0x3904c538, 0xfc384801, 0xbf2c3316, 0x6ee38ac9, 0x2df7f1de, + 0xe8cb7ce7, 0xabdf07f0, 0x62b26694, 0x21a61d83, 0xe49a90ba, + 0xa78eebad, 0xa481635c, 0xe795184b, 0x22a99572, 0x61bdee65, + 0xa8d08f01, 0xebc4f416, 0x2ef8792f, 0x6dec0238, 0xbc23bbe7, + 0xff37c0f0, 0x3a0b4dc9, 0x791f36de, 0xb07257ba, 0xf3662cad, + 0x365aa194, 0x754eda83, 0xd5c3a3f0, 0x96d7d8e7, 0x53eb55de, + 0x10ff2ec9, 0xd9924fad, 0x9a8634ba, 0x5fbab983, 0x1caec294, + 0xcd617b4b, 0x8e75005c, 0x4b498d65, 0x085df672, 0xc1309716, + 0x8224ec01, 0x47186138, 0x040c1a2f, 0x4f005566, 0x0c142e71, + 0xc928a348, 0x8a3cd85f, 0x4351b93b, 0x0045c22c, 0xc5794f15, + 0x866d3402, 0x57a28ddd, 0x14b6f6ca, 0xd18a7bf3, 0x929e00e4, + 0x5bf36180, 0x18e71a97, 0xdddb97ae, 0x9ecfecb9, 0x3e4295ca, + 0x7d56eedd, 0xb86a63e4, 0xfb7e18f3, 0x32137997, 0x71070280, + 0xb43b8fb9, 0xf72ff4ae, 0x26e04d71, 0x65f43666, 0xa0c8bb5f, + 0xe3dcc048, 0x2ab1a12c, 0x69a5da3b, 0xac995702, 0xef8d2c15, + 0xec82a4e4, 0xaf96dff3, 0x6aaa52ca, 0x29be29dd, 0xe0d348b9, + 0xa3c733ae, 0x66fbbe97, 0x25efc580, 0xf4207c5f, 0xb7340748, + 0x72088a71, 0x311cf166, 0xf8719002, 0xbb65eb15, 0x7e59662c, + 0x3d4d1d3b, 0x9dc06448, 0xded41f5f, 0x1be89266, 0x58fce971, + 0x91918815, 0xd285f302, 0x17b97e3b, 0x54ad052c, 0x8562bcf3, + 0xc676c7e4, 0x034a4add, 0x405e31ca, 0x893350ae, 0xca272bb9, + 0x0f1ba680, 0x4c0fdd97, 0x4803c7b8, 0x0b17bcaf, 0xce2b3196, + 0x8d3f4a81, 0x44522be5, 0x074650f2, 0xc27addcb, 0x816ea6dc, + 0x50a11f03, 0x13b56414, 0xd689e92d, 0x959d923a, 0x5cf0f35e, + 0x1fe48849, 0xdad80570, 0x99cc7e67, 0x39410714, 0x7a557c03, + 0xbf69f13a, 0xfc7d8a2d, 0x3510eb49, 0x7604905e, 0xb3381d67, + 0xf02c6670, 0x21e3dfaf, 0x62f7a4b8, 0xa7cb2981, 0xe4df5296, + 0x2db233f2, 0x6ea648e5, 0xab9ac5dc, 0xe88ebecb, 0xeb81363a, + 0xa8954d2d, 0x6da9c014, 0x2ebdbb03, 0xe7d0da67, 0xa4c4a170, + 0x61f82c49, 0x22ec575e, 0xf323ee81, 0xb0379596, 0x750b18af, + 0x361f63b8, 0xff7202dc, 0xbc6679cb, 0x795af4f2, 0x3a4e8fe5, + 0x9ac3f696, 0xd9d78d81, 0x1ceb00b8, 0x5fff7baf, 0x96921acb, + 0xd58661dc, 0x10baece5, 0x53ae97f2, 0x82612e2d, 0xc175553a, + 0x0449d803, 0x475da314, 0x8e30c270, 0xcd24b967, 0x0818345e, + 0x4b0c4f49}, + {0x00000000, 0x3e6bc2ef, 0x3dd0f504, 0x03bb37eb, 0x7aa0eb09, + 0x44cb29e6, 0x47701e0d, 0x791bdce2, 0xf440d713, 0xca2b15fc, + 0xc9902217, 0xf7fbe0f8, 0x8ee03c1a, 0xb08bfef5, 0xb330c91e, + 0x8d5b0bf1, 0xe881ae27, 0xd6ea6cc8, 0xd5515b23, 0xeb3a99cc, + 0x9221452e, 0xac4a87c1, 0xaff1b02a, 0x919a72c5, 0x1cc17934, + 0x22aabbdb, 0x21118c30, 0x1f7a4edf, 0x6661923d, 0x580a50d2, + 0x5bb16739, 0x65daa5d6, 0xd0035d4f, 0xee689fa0, 0xedd3a84b, + 0xd3b86aa4, 0xaaa3b646, 0x94c874a9, 0x97734342, 0xa91881ad, + 0x24438a5c, 0x1a2848b3, 0x19937f58, 0x27f8bdb7, 0x5ee36155, + 0x6088a3ba, 0x63339451, 0x5d5856be, 0x3882f368, 0x06e93187, + 0x0552066c, 0x3b39c483, 0x42221861, 0x7c49da8e, 0x7ff2ed65, + 0x41992f8a, 0xccc2247b, 0xf2a9e694, 0xf112d17f, 0xcf791390, + 0xb662cf72, 0x88090d9d, 0x8bb23a76, 0xb5d9f899, 0xa007ba9e, + 0x9e6c7871, 0x9dd74f9a, 0xa3bc8d75, 0xdaa75197, 0xe4cc9378, + 0xe777a493, 0xd91c667c, 0x54476d8d, 0x6a2caf62, 0x69979889, + 0x57fc5a66, 0x2ee78684, 0x108c446b, 0x13377380, 0x2d5cb16f, + 0x488614b9, 0x76edd656, 0x7556e1bd, 0x4b3d2352, 0x3226ffb0, + 0x0c4d3d5f, 0x0ff60ab4, 0x319dc85b, 0xbcc6c3aa, 0x82ad0145, + 0x811636ae, 0xbf7df441, 0xc66628a3, 0xf80dea4c, 0xfbb6dda7, + 0xc5dd1f48, 0x7004e7d1, 0x4e6f253e, 0x4dd412d5, 0x73bfd03a, + 0x0aa40cd8, 0x34cfce37, 0x3774f9dc, 0x091f3b33, 0x844430c2, + 0xba2ff22d, 0xb994c5c6, 0x87ff0729, 0xfee4dbcb, 0xc08f1924, + 0xc3342ecf, 0xfd5fec20, 0x988549f6, 0xa6ee8b19, 0xa555bcf2, + 0x9b3e7e1d, 0xe225a2ff, 0xdc4e6010, 0xdff557fb, 0xe19e9514, + 0x6cc59ee5, 0x52ae5c0a, 0x51156be1, 0x6f7ea90e, 0x166575ec, + 0x280eb703, 0x2bb580e8, 0x15de4207, 0x010905e6, 0x3f62c709, + 0x3cd9f0e2, 0x02b2320d, 0x7ba9eeef, 0x45c22c00, 0x46791beb, + 0x7812d904, 0xf549d2f5, 0xcb22101a, 0xc89927f1, 0xf6f2e51e, + 0x8fe939fc, 0xb182fb13, 0xb239ccf8, 0x8c520e17, 0xe988abc1, + 0xd7e3692e, 0xd4585ec5, 0xea339c2a, 0x932840c8, 0xad438227, + 0xaef8b5cc, 0x90937723, 0x1dc87cd2, 0x23a3be3d, 0x201889d6, + 0x1e734b39, 0x676897db, 0x59035534, 0x5ab862df, 0x64d3a030, + 0xd10a58a9, 0xef619a46, 0xecdaadad, 0xd2b16f42, 0xabaab3a0, + 0x95c1714f, 0x967a46a4, 0xa811844b, 0x254a8fba, 0x1b214d55, + 0x189a7abe, 0x26f1b851, 0x5fea64b3, 0x6181a65c, 0x623a91b7, + 0x5c515358, 0x398bf68e, 0x07e03461, 0x045b038a, 0x3a30c165, + 0x432b1d87, 0x7d40df68, 0x7efbe883, 0x40902a6c, 0xcdcb219d, + 0xf3a0e372, 0xf01bd499, 0xce701676, 0xb76bca94, 0x8900087b, + 0x8abb3f90, 0xb4d0fd7f, 0xa10ebf78, 0x9f657d97, 0x9cde4a7c, + 0xa2b58893, 0xdbae5471, 0xe5c5969e, 0xe67ea175, 0xd815639a, + 0x554e686b, 0x6b25aa84, 0x689e9d6f, 0x56f55f80, 0x2fee8362, + 0x1185418d, 0x123e7666, 0x2c55b489, 0x498f115f, 0x77e4d3b0, + 0x745fe45b, 0x4a3426b4, 0x332ffa56, 0x0d4438b9, 0x0eff0f52, + 0x3094cdbd, 0xbdcfc64c, 0x83a404a3, 0x801f3348, 0xbe74f1a7, + 0xc76f2d45, 0xf904efaa, 0xfabfd841, 0xc4d41aae, 0x710de237, + 0x4f6620d8, 0x4cdd1733, 0x72b6d5dc, 0x0bad093e, 0x35c6cbd1, + 0x367dfc3a, 0x08163ed5, 0x854d3524, 0xbb26f7cb, 0xb89dc020, + 0x86f602cf, 0xffedde2d, 0xc1861cc2, 0xc23d2b29, 0xfc56e9c6, + 0x998c4c10, 0xa7e78eff, 0xa45cb914, 0x9a377bfb, 0xe32ca719, + 0xdd4765f6, 0xdefc521d, 0xe09790f2, 0x6dcc9b03, 0x53a759ec, + 0x501c6e07, 0x6e77ace8, 0x176c700a, 0x2907b2e5, 0x2abc850e, + 0x14d747e1}, + {0x00000000, 0xc0df8ec1, 0xc1b96c58, 0x0166e299, 0x8273d9b0, + 0x42ac5771, 0x43cab5e8, 0x83153b29, 0x45e1c3ba, 0x853e4d7b, + 0x8458afe2, 0x44872123, 0xc7921a0a, 0x074d94cb, 0x062b7652, + 0xc6f4f893, 0xcbc4f6ae, 0x0b1b786f, 0x0a7d9af6, 0xcaa21437, + 0x49b72f1e, 0x8968a1df, 0x880e4346, 0x48d1cd87, 0x8e253514, + 0x4efabbd5, 0x4f9c594c, 0x8f43d78d, 0x0c56eca4, 0xcc896265, + 0xcdef80fc, 0x0d300e3d, 0xd78f9c86, 0x17501247, 0x1636f0de, + 0xd6e97e1f, 0x55fc4536, 0x9523cbf7, 0x9445296e, 0x549aa7af, + 0x926e5f3c, 0x52b1d1fd, 0x53d73364, 0x9308bda5, 0x101d868c, + 0xd0c2084d, 0xd1a4ead4, 0x117b6415, 0x1c4b6a28, 0xdc94e4e9, + 0xddf20670, 0x1d2d88b1, 0x9e38b398, 0x5ee73d59, 0x5f81dfc0, + 0x9f5e5101, 0x59aaa992, 0x99752753, 0x9813c5ca, 0x58cc4b0b, + 0xdbd97022, 0x1b06fee3, 0x1a601c7a, 0xdabf92bb, 0xef1948d6, + 0x2fc6c617, 0x2ea0248e, 0xee7faa4f, 0x6d6a9166, 0xadb51fa7, + 0xacd3fd3e, 0x6c0c73ff, 0xaaf88b6c, 0x6a2705ad, 0x6b41e734, + 0xab9e69f5, 0x288b52dc, 0xe854dc1d, 0xe9323e84, 0x29edb045, + 0x24ddbe78, 0xe40230b9, 0xe564d220, 0x25bb5ce1, 0xa6ae67c8, + 0x6671e909, 0x67170b90, 0xa7c88551, 0x613c7dc2, 0xa1e3f303, + 0xa085119a, 0x605a9f5b, 0xe34fa472, 0x23902ab3, 0x22f6c82a, + 0xe22946eb, 0x3896d450, 0xf8495a91, 0xf92fb808, 0x39f036c9, + 0xbae50de0, 0x7a3a8321, 0x7b5c61b8, 0xbb83ef79, 0x7d7717ea, + 0xbda8992b, 0xbcce7bb2, 0x7c11f573, 0xff04ce5a, 0x3fdb409b, + 0x3ebda202, 0xfe622cc3, 0xf35222fe, 0x338dac3f, 0x32eb4ea6, + 0xf234c067, 0x7121fb4e, 0xb1fe758f, 0xb0989716, 0x704719d7, + 0xb6b3e144, 0x766c6f85, 0x770a8d1c, 0xb7d503dd, 0x34c038f4, + 0xf41fb635, 0xf57954ac, 0x35a6da6d, 0x9f35e177, 0x5fea6fb6, + 0x5e8c8d2f, 0x9e5303ee, 0x1d4638c7, 0xdd99b606, 0xdcff549f, + 0x1c20da5e, 0xdad422cd, 0x1a0bac0c, 0x1b6d4e95, 0xdbb2c054, + 0x58a7fb7d, 0x987875bc, 0x991e9725, 0x59c119e4, 0x54f117d9, + 0x942e9918, 0x95487b81, 0x5597f540, 0xd682ce69, 0x165d40a8, + 0x173ba231, 0xd7e42cf0, 0x1110d463, 0xd1cf5aa2, 0xd0a9b83b, + 0x107636fa, 0x93630dd3, 0x53bc8312, 0x52da618b, 0x9205ef4a, + 0x48ba7df1, 0x8865f330, 0x890311a9, 0x49dc9f68, 0xcac9a441, + 0x0a162a80, 0x0b70c819, 0xcbaf46d8, 0x0d5bbe4b, 0xcd84308a, + 0xcce2d213, 0x0c3d5cd2, 0x8f2867fb, 0x4ff7e93a, 0x4e910ba3, + 0x8e4e8562, 0x837e8b5f, 0x43a1059e, 0x42c7e707, 0x821869c6, + 0x010d52ef, 0xc1d2dc2e, 0xc0b43eb7, 0x006bb076, 0xc69f48e5, + 0x0640c624, 0x072624bd, 0xc7f9aa7c, 0x44ec9155, 0x84331f94, + 0x8555fd0d, 0x458a73cc, 0x702ca9a1, 0xb0f32760, 0xb195c5f9, + 0x714a4b38, 0xf25f7011, 0x3280fed0, 0x33e61c49, 0xf3399288, + 0x35cd6a1b, 0xf512e4da, 0xf4740643, 0x34ab8882, 0xb7beb3ab, + 0x77613d6a, 0x7607dff3, 0xb6d85132, 0xbbe85f0f, 0x7b37d1ce, + 0x7a513357, 0xba8ebd96, 0x399b86bf, 0xf944087e, 0xf822eae7, + 0x38fd6426, 0xfe099cb5, 0x3ed61274, 0x3fb0f0ed, 0xff6f7e2c, + 0x7c7a4505, 0xbca5cbc4, 0xbdc3295d, 0x7d1ca79c, 0xa7a33527, + 0x677cbbe6, 0x661a597f, 0xa6c5d7be, 0x25d0ec97, 0xe50f6256, + 0xe46980cf, 0x24b60e0e, 0xe242f69d, 0x229d785c, 0x23fb9ac5, + 0xe3241404, 0x60312f2d, 0xa0eea1ec, 0xa1884375, 0x6157cdb4, + 0x6c67c389, 0xacb84d48, 0xaddeafd1, 0x6d012110, 0xee141a39, + 0x2ecb94f8, 0x2fad7661, 0xef72f8a0, 0x29860033, 0xe9598ef2, + 0xe83f6c6b, 0x28e0e2aa, 0xabf5d983, 0x6b2a5742, 0x6a4cb5db, + 0xaa933b1a}, + {0x00000000, 0x6f4ca59b, 0x9f9e3bec, 0xf0d29e77, 0x7f3b0603, + 0x1077a398, 0xe0a53def, 0x8fe99874, 0xfe760c06, 0x913aa99d, + 0x61e837ea, 0x0ea49271, 0x814d0a05, 0xee01af9e, 0x1ed331e9, + 0x719f9472, 0xfced180c, 0x93a1bd97, 0x637323e0, 0x0c3f867b, + 0x83d61e0f, 0xec9abb94, 0x1c4825e3, 0x73048078, 0x029b140a, + 0x6dd7b191, 0x9d052fe6, 0xf2498a7d, 0x7da01209, 0x12ecb792, + 0xe23e29e5, 0x8d728c7e, 0xf8db3118, 0x97979483, 0x67450af4, + 0x0809af6f, 0x87e0371b, 0xe8ac9280, 0x187e0cf7, 0x7732a96c, + 0x06ad3d1e, 0x69e19885, 0x993306f2, 0xf67fa369, 0x79963b1d, + 0x16da9e86, 0xe60800f1, 0x8944a56a, 0x04362914, 0x6b7a8c8f, + 0x9ba812f8, 0xf4e4b763, 0x7b0d2f17, 0x14418a8c, 0xe49314fb, + 0x8bdfb160, 0xfa402512, 0x950c8089, 0x65de1efe, 0x0a92bb65, + 0x857b2311, 0xea37868a, 0x1ae518fd, 0x75a9bd66, 0xf0b76330, + 0x9ffbc6ab, 0x6f2958dc, 0x0065fd47, 0x8f8c6533, 0xe0c0c0a8, + 0x10125edf, 0x7f5efb44, 0x0ec16f36, 0x618dcaad, 0x915f54da, + 0xfe13f141, 0x71fa6935, 0x1eb6ccae, 0xee6452d9, 0x8128f742, + 0x0c5a7b3c, 0x6316dea7, 0x93c440d0, 0xfc88e54b, 0x73617d3f, + 0x1c2dd8a4, 0xecff46d3, 0x83b3e348, 0xf22c773a, 0x9d60d2a1, + 0x6db24cd6, 0x02fee94d, 0x8d177139, 0xe25bd4a2, 0x12894ad5, + 0x7dc5ef4e, 0x086c5228, 0x6720f7b3, 0x97f269c4, 0xf8becc5f, + 0x7757542b, 0x181bf1b0, 0xe8c96fc7, 0x8785ca5c, 0xf61a5e2e, + 0x9956fbb5, 0x698465c2, 0x06c8c059, 0x8921582d, 0xe66dfdb6, + 0x16bf63c1, 0x79f3c65a, 0xf4814a24, 0x9bcdefbf, 0x6b1f71c8, + 0x0453d453, 0x8bba4c27, 0xe4f6e9bc, 0x142477cb, 0x7b68d250, + 0x0af74622, 0x65bbe3b9, 0x95697dce, 0xfa25d855, 0x75cc4021, + 0x1a80e5ba, 0xea527bcd, 0x851ede56, 0xe06fc760, 0x8f2362fb, + 0x7ff1fc8c, 0x10bd5917, 0x9f54c163, 0xf01864f8, 0x00cafa8f, + 0x6f865f14, 0x1e19cb66, 0x71556efd, 0x8187f08a, 0xeecb5511, + 0x6122cd65, 0x0e6e68fe, 0xfebcf689, 0x91f05312, 0x1c82df6c, + 0x73ce7af7, 0x831ce480, 0xec50411b, 0x63b9d96f, 0x0cf57cf4, + 0xfc27e283, 0x936b4718, 0xe2f4d36a, 0x8db876f1, 0x7d6ae886, + 0x12264d1d, 0x9dcfd569, 0xf28370f2, 0x0251ee85, 0x6d1d4b1e, + 0x18b4f678, 0x77f853e3, 0x872acd94, 0xe866680f, 0x678ff07b, + 0x08c355e0, 0xf811cb97, 0x975d6e0c, 0xe6c2fa7e, 0x898e5fe5, + 0x795cc192, 0x16106409, 0x99f9fc7d, 0xf6b559e6, 0x0667c791, + 0x692b620a, 0xe459ee74, 0x8b154bef, 0x7bc7d598, 0x148b7003, + 0x9b62e877, 0xf42e4dec, 0x04fcd39b, 0x6bb07600, 0x1a2fe272, + 0x756347e9, 0x85b1d99e, 0xeafd7c05, 0x6514e471, 0x0a5841ea, + 0xfa8adf9d, 0x95c67a06, 0x10d8a450, 0x7f9401cb, 0x8f469fbc, + 0xe00a3a27, 0x6fe3a253, 0x00af07c8, 0xf07d99bf, 0x9f313c24, + 0xeeaea856, 0x81e20dcd, 0x713093ba, 0x1e7c3621, 0x9195ae55, + 0xfed90bce, 0x0e0b95b9, 0x61473022, 0xec35bc5c, 0x837919c7, + 0x73ab87b0, 0x1ce7222b, 0x930eba5f, 0xfc421fc4, 0x0c9081b3, + 0x63dc2428, 0x1243b05a, 0x7d0f15c1, 0x8ddd8bb6, 0xe2912e2d, + 0x6d78b659, 0x023413c2, 0xf2e68db5, 0x9daa282e, 0xe8039548, + 0x874f30d3, 0x779daea4, 0x18d10b3f, 0x9738934b, 0xf87436d0, + 0x08a6a8a7, 0x67ea0d3c, 0x1675994e, 0x79393cd5, 0x89eba2a2, + 0xe6a70739, 0x694e9f4d, 0x06023ad6, 0xf6d0a4a1, 0x999c013a, + 0x14ee8d44, 0x7ba228df, 0x8b70b6a8, 0xe43c1333, 0x6bd58b47, + 0x04992edc, 0xf44bb0ab, 0x9b071530, 0xea988142, 0x85d424d9, + 0x7506baae, 0x1a4a1f35, 0x95a38741, 0xfaef22da, 0x0a3dbcad, + 0x65711936}}; + +#endif + +#endif + +#if N == 4 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xf1da05aa, 0x38c50d15, 0xc91f08bf, 0x718a1a2a, + 0x80501f80, 0x494f173f, 0xb8951295, 0xe3143454, 0x12ce31fe, + 0xdbd13941, 0x2a0b3ceb, 0x929e2e7e, 0x63442bd4, 0xaa5b236b, + 0x5b8126c1, 0x1d596ee9, 0xec836b43, 0x259c63fc, 0xd4466656, + 0x6cd374c3, 0x9d097169, 0x541679d6, 0xa5cc7c7c, 0xfe4d5abd, + 0x0f975f17, 0xc68857a8, 0x37525202, 0x8fc74097, 0x7e1d453d, + 0xb7024d82, 0x46d84828, 0x3ab2ddd2, 0xcb68d878, 0x0277d0c7, + 0xf3add56d, 0x4b38c7f8, 0xbae2c252, 0x73fdcaed, 0x8227cf47, + 0xd9a6e986, 0x287cec2c, 0xe163e493, 0x10b9e139, 0xa82cf3ac, + 0x59f6f606, 0x90e9feb9, 0x6133fb13, 0x27ebb33b, 0xd631b691, + 0x1f2ebe2e, 0xeef4bb84, 0x5661a911, 0xa7bbacbb, 0x6ea4a404, + 0x9f7ea1ae, 0xc4ff876f, 0x352582c5, 0xfc3a8a7a, 0x0de08fd0, + 0xb5759d45, 0x44af98ef, 0x8db09050, 0x7c6a95fa, 0x7565bba4, + 0x84bfbe0e, 0x4da0b6b1, 0xbc7ab31b, 0x04efa18e, 0xf535a424, + 0x3c2aac9b, 0xcdf0a931, 0x96718ff0, 0x67ab8a5a, 0xaeb482e5, + 0x5f6e874f, 0xe7fb95da, 0x16219070, 0xdf3e98cf, 0x2ee49d65, + 0x683cd54d, 0x99e6d0e7, 0x50f9d858, 0xa123ddf2, 0x19b6cf67, + 0xe86ccacd, 0x2173c272, 0xd0a9c7d8, 0x8b28e119, 0x7af2e4b3, + 0xb3edec0c, 0x4237e9a6, 0xfaa2fb33, 0x0b78fe99, 0xc267f626, + 0x33bdf38c, 0x4fd76676, 0xbe0d63dc, 0x77126b63, 0x86c86ec9, + 0x3e5d7c5c, 0xcf8779f6, 0x06987149, 0xf74274e3, 0xacc35222, + 0x5d195788, 0x94065f37, 0x65dc5a9d, 0xdd494808, 0x2c934da2, + 0xe58c451d, 0x145640b7, 0x528e089f, 0xa3540d35, 0x6a4b058a, + 0x9b910020, 0x230412b5, 0xd2de171f, 0x1bc11fa0, 0xea1b1a0a, + 0xb19a3ccb, 0x40403961, 0x895f31de, 0x78853474, 0xc01026e1, + 0x31ca234b, 0xf8d52bf4, 0x090f2e5e, 0xeacb7748, 0x1b1172e2, + 0xd20e7a5d, 0x23d47ff7, 0x9b416d62, 0x6a9b68c8, 0xa3846077, + 0x525e65dd, 0x09df431c, 0xf80546b6, 0x311a4e09, 0xc0c04ba3, + 0x78555936, 0x898f5c9c, 0x40905423, 0xb14a5189, 0xf79219a1, + 0x06481c0b, 0xcf5714b4, 0x3e8d111e, 0x8618038b, 0x77c20621, + 0xbedd0e9e, 0x4f070b34, 0x14862df5, 0xe55c285f, 0x2c4320e0, + 0xdd99254a, 0x650c37df, 0x94d63275, 0x5dc93aca, 0xac133f60, + 0xd079aa9a, 0x21a3af30, 0xe8bca78f, 0x1966a225, 0xa1f3b0b0, + 0x5029b51a, 0x9936bda5, 0x68ecb80f, 0x336d9ece, 0xc2b79b64, + 0x0ba893db, 0xfa729671, 0x42e784e4, 0xb33d814e, 0x7a2289f1, + 0x8bf88c5b, 0xcd20c473, 0x3cfac1d9, 0xf5e5c966, 0x043fcccc, + 0xbcaade59, 0x4d70dbf3, 0x846fd34c, 0x75b5d6e6, 0x2e34f027, + 0xdfeef58d, 0x16f1fd32, 0xe72bf898, 0x5fbeea0d, 0xae64efa7, + 0x677be718, 0x96a1e2b2, 0x9faeccec, 0x6e74c946, 0xa76bc1f9, + 0x56b1c453, 0xee24d6c6, 0x1ffed36c, 0xd6e1dbd3, 0x273bde79, + 0x7cbaf8b8, 0x8d60fd12, 0x447ff5ad, 0xb5a5f007, 0x0d30e292, + 0xfceae738, 0x35f5ef87, 0xc42fea2d, 0x82f7a205, 0x732da7af, + 0xba32af10, 0x4be8aaba, 0xf37db82f, 0x02a7bd85, 0xcbb8b53a, + 0x3a62b090, 0x61e39651, 0x903993fb, 0x59269b44, 0xa8fc9eee, + 0x10698c7b, 0xe1b389d1, 0x28ac816e, 0xd97684c4, 0xa51c113e, + 0x54c61494, 0x9dd91c2b, 0x6c031981, 0xd4960b14, 0x254c0ebe, + 0xec530601, 0x1d8903ab, 0x4608256a, 0xb7d220c0, 0x7ecd287f, + 0x8f172dd5, 0x37823f40, 0xc6583aea, 0x0f473255, 0xfe9d37ff, + 0xb8457fd7, 0x499f7a7d, 0x808072c2, 0x715a7768, 0xc9cf65fd, + 0x38156057, 0xf10a68e8, 0x00d06d42, 0x5b514b83, 0xaa8b4e29, + 0x63944696, 0x924e433c, 0x2adb51a9, 0xdb015403, 0x121e5cbc, + 0xe3c45916}, + {0x00000000, 0x0ee7e8d1, 0x1dcfd1a2, 0x13283973, 0x3b9fa344, + 0x35784b95, 0x265072e6, 0x28b79a37, 0x773f4688, 0x79d8ae59, + 0x6af0972a, 0x64177ffb, 0x4ca0e5cc, 0x42470d1d, 0x516f346e, + 0x5f88dcbf, 0xee7e8d10, 0xe09965c1, 0xf3b15cb2, 0xfd56b463, + 0xd5e12e54, 0xdb06c685, 0xc82efff6, 0xc6c91727, 0x9941cb98, + 0x97a62349, 0x848e1a3a, 0x8a69f2eb, 0xa2de68dc, 0xac39800d, + 0xbf11b97e, 0xb1f651af, 0x078c1c61, 0x096bf4b0, 0x1a43cdc3, + 0x14a42512, 0x3c13bf25, 0x32f457f4, 0x21dc6e87, 0x2f3b8656, + 0x70b35ae9, 0x7e54b238, 0x6d7c8b4b, 0x639b639a, 0x4b2cf9ad, + 0x45cb117c, 0x56e3280f, 0x5804c0de, 0xe9f29171, 0xe71579a0, + 0xf43d40d3, 0xfadaa802, 0xd26d3235, 0xdc8adae4, 0xcfa2e397, + 0xc1450b46, 0x9ecdd7f9, 0x902a3f28, 0x8302065b, 0x8de5ee8a, + 0xa55274bd, 0xabb59c6c, 0xb89da51f, 0xb67a4dce, 0x0f1838c2, + 0x01ffd013, 0x12d7e960, 0x1c3001b1, 0x34879b86, 0x3a607357, + 0x29484a24, 0x27afa2f5, 0x78277e4a, 0x76c0969b, 0x65e8afe8, + 0x6b0f4739, 0x43b8dd0e, 0x4d5f35df, 0x5e770cac, 0x5090e47d, + 0xe166b5d2, 0xef815d03, 0xfca96470, 0xf24e8ca1, 0xdaf91696, + 0xd41efe47, 0xc736c734, 0xc9d12fe5, 0x9659f35a, 0x98be1b8b, + 0x8b9622f8, 0x8571ca29, 0xadc6501e, 0xa321b8cf, 0xb00981bc, + 0xbeee696d, 0x089424a3, 0x0673cc72, 0x155bf501, 0x1bbc1dd0, + 0x330b87e7, 0x3dec6f36, 0x2ec45645, 0x2023be94, 0x7fab622b, + 0x714c8afa, 0x6264b389, 0x6c835b58, 0x4434c16f, 0x4ad329be, + 0x59fb10cd, 0x571cf81c, 0xe6eaa9b3, 0xe80d4162, 0xfb257811, + 0xf5c290c0, 0xdd750af7, 0xd392e226, 0xc0badb55, 0xce5d3384, + 0x91d5ef3b, 0x9f3207ea, 0x8c1a3e99, 0x82fdd648, 0xaa4a4c7f, + 0xa4ada4ae, 0xb7859ddd, 0xb962750c, 0x1e307184, 0x10d79955, + 0x03ffa026, 0x0d1848f7, 0x25afd2c0, 0x2b483a11, 0x38600362, + 0x3687ebb3, 0x690f370c, 0x67e8dfdd, 0x74c0e6ae, 0x7a270e7f, + 0x52909448, 0x5c777c99, 0x4f5f45ea, 0x41b8ad3b, 0xf04efc94, + 0xfea91445, 0xed812d36, 0xe366c5e7, 0xcbd15fd0, 0xc536b701, + 0xd61e8e72, 0xd8f966a3, 0x8771ba1c, 0x899652cd, 0x9abe6bbe, + 0x9459836f, 0xbcee1958, 0xb209f189, 0xa121c8fa, 0xafc6202b, + 0x19bc6de5, 0x175b8534, 0x0473bc47, 0x0a945496, 0x2223cea1, + 0x2cc42670, 0x3fec1f03, 0x310bf7d2, 0x6e832b6d, 0x6064c3bc, + 0x734cfacf, 0x7dab121e, 0x551c8829, 0x5bfb60f8, 0x48d3598b, + 0x4634b15a, 0xf7c2e0f5, 0xf9250824, 0xea0d3157, 0xe4ead986, + 0xcc5d43b1, 0xc2baab60, 0xd1929213, 0xdf757ac2, 0x80fda67d, + 0x8e1a4eac, 0x9d3277df, 0x93d59f0e, 0xbb620539, 0xb585ede8, + 0xa6add49b, 0xa84a3c4a, 0x11284946, 0x1fcfa197, 0x0ce798e4, + 0x02007035, 0x2ab7ea02, 0x245002d3, 0x37783ba0, 0x399fd371, + 0x66170fce, 0x68f0e71f, 0x7bd8de6c, 0x753f36bd, 0x5d88ac8a, + 0x536f445b, 0x40477d28, 0x4ea095f9, 0xff56c456, 0xf1b12c87, + 0xe29915f4, 0xec7efd25, 0xc4c96712, 0xca2e8fc3, 0xd906b6b0, + 0xd7e15e61, 0x886982de, 0x868e6a0f, 0x95a6537c, 0x9b41bbad, + 0xb3f6219a, 0xbd11c94b, 0xae39f038, 0xa0de18e9, 0x16a45527, + 0x1843bdf6, 0x0b6b8485, 0x058c6c54, 0x2d3bf663, 0x23dc1eb2, + 0x30f427c1, 0x3e13cf10, 0x619b13af, 0x6f7cfb7e, 0x7c54c20d, + 0x72b32adc, 0x5a04b0eb, 0x54e3583a, 0x47cb6149, 0x492c8998, + 0xf8dad837, 0xf63d30e6, 0xe5150995, 0xebf2e144, 0xc3457b73, + 0xcda293a2, 0xde8aaad1, 0xd06d4200, 0x8fe59ebf, 0x8102766e, + 0x922a4f1d, 0x9ccda7cc, 0xb47a3dfb, 0xba9dd52a, 0xa9b5ec59, + 0xa7520488}, + {0x00000000, 0x3c60e308, 0x78c1c610, 0x44a12518, 0xf1838c20, + 0xcde36f28, 0x89424a30, 0xb522a938, 0x38761e01, 0x0416fd09, + 0x40b7d811, 0x7cd73b19, 0xc9f59221, 0xf5957129, 0xb1345431, + 0x8d54b739, 0x70ec3c02, 0x4c8cdf0a, 0x082dfa12, 0x344d191a, + 0x816fb022, 0xbd0f532a, 0xf9ae7632, 0xc5ce953a, 0x489a2203, + 0x74fac10b, 0x305be413, 0x0c3b071b, 0xb919ae23, 0x85794d2b, + 0xc1d86833, 0xfdb88b3b, 0xe1d87804, 0xddb89b0c, 0x9919be14, + 0xa5795d1c, 0x105bf424, 0x2c3b172c, 0x689a3234, 0x54fad13c, + 0xd9ae6605, 0xe5ce850d, 0xa16fa015, 0x9d0f431d, 0x282dea25, + 0x144d092d, 0x50ec2c35, 0x6c8ccf3d, 0x91344406, 0xad54a70e, + 0xe9f58216, 0xd595611e, 0x60b7c826, 0x5cd72b2e, 0x18760e36, + 0x2416ed3e, 0xa9425a07, 0x9522b90f, 0xd1839c17, 0xede37f1f, + 0x58c1d627, 0x64a1352f, 0x20001037, 0x1c60f33f, 0x18c1f649, + 0x24a11541, 0x60003059, 0x5c60d351, 0xe9427a69, 0xd5229961, + 0x9183bc79, 0xade35f71, 0x20b7e848, 0x1cd70b40, 0x58762e58, + 0x6416cd50, 0xd1346468, 0xed548760, 0xa9f5a278, 0x95954170, + 0x682dca4b, 0x544d2943, 0x10ec0c5b, 0x2c8cef53, 0x99ae466b, + 0xa5cea563, 0xe16f807b, 0xdd0f6373, 0x505bd44a, 0x6c3b3742, + 0x289a125a, 0x14faf152, 0xa1d8586a, 0x9db8bb62, 0xd9199e7a, + 0xe5797d72, 0xf9198e4d, 0xc5796d45, 0x81d8485d, 0xbdb8ab55, + 0x089a026d, 0x34fae165, 0x705bc47d, 0x4c3b2775, 0xc16f904c, + 0xfd0f7344, 0xb9ae565c, 0x85ceb554, 0x30ec1c6c, 0x0c8cff64, + 0x482dda7c, 0x744d3974, 0x89f5b24f, 0xb5955147, 0xf134745f, + 0xcd549757, 0x78763e6f, 0x4416dd67, 0x00b7f87f, 0x3cd71b77, + 0xb183ac4e, 0x8de34f46, 0xc9426a5e, 0xf5228956, 0x4000206e, + 0x7c60c366, 0x38c1e67e, 0x04a10576, 0x3183ec92, 0x0de30f9a, + 0x49422a82, 0x7522c98a, 0xc00060b2, 0xfc6083ba, 0xb8c1a6a2, + 0x84a145aa, 0x09f5f293, 0x3595119b, 0x71343483, 0x4d54d78b, + 0xf8767eb3, 0xc4169dbb, 0x80b7b8a3, 0xbcd75bab, 0x416fd090, + 0x7d0f3398, 0x39ae1680, 0x05cef588, 0xb0ec5cb0, 0x8c8cbfb8, + 0xc82d9aa0, 0xf44d79a8, 0x7919ce91, 0x45792d99, 0x01d80881, + 0x3db8eb89, 0x889a42b1, 0xb4faa1b9, 0xf05b84a1, 0xcc3b67a9, + 0xd05b9496, 0xec3b779e, 0xa89a5286, 0x94fab18e, 0x21d818b6, + 0x1db8fbbe, 0x5919dea6, 0x65793dae, 0xe82d8a97, 0xd44d699f, + 0x90ec4c87, 0xac8caf8f, 0x19ae06b7, 0x25cee5bf, 0x616fc0a7, + 0x5d0f23af, 0xa0b7a894, 0x9cd74b9c, 0xd8766e84, 0xe4168d8c, + 0x513424b4, 0x6d54c7bc, 0x29f5e2a4, 0x159501ac, 0x98c1b695, + 0xa4a1559d, 0xe0007085, 0xdc60938d, 0x69423ab5, 0x5522d9bd, + 0x1183fca5, 0x2de31fad, 0x29421adb, 0x1522f9d3, 0x5183dccb, + 0x6de33fc3, 0xd8c196fb, 0xe4a175f3, 0xa00050eb, 0x9c60b3e3, + 0x113404da, 0x2d54e7d2, 0x69f5c2ca, 0x559521c2, 0xe0b788fa, + 0xdcd76bf2, 0x98764eea, 0xa416ade2, 0x59ae26d9, 0x65cec5d1, + 0x216fe0c9, 0x1d0f03c1, 0xa82daaf9, 0x944d49f1, 0xd0ec6ce9, + 0xec8c8fe1, 0x61d838d8, 0x5db8dbd0, 0x1919fec8, 0x25791dc0, + 0x905bb4f8, 0xac3b57f0, 0xe89a72e8, 0xd4fa91e0, 0xc89a62df, + 0xf4fa81d7, 0xb05ba4cf, 0x8c3b47c7, 0x3919eeff, 0x05790df7, + 0x41d828ef, 0x7db8cbe7, 0xf0ec7cde, 0xcc8c9fd6, 0x882dbace, + 0xb44d59c6, 0x016ff0fe, 0x3d0f13f6, 0x79ae36ee, 0x45ced5e6, + 0xb8765edd, 0x8416bdd5, 0xc0b798cd, 0xfcd77bc5, 0x49f5d2fd, + 0x759531f5, 0x313414ed, 0x0d54f7e5, 0x800040dc, 0xbc60a3d4, + 0xf8c186cc, 0xc4a165c4, 0x7183ccfc, 0x4de32ff4, 0x09420aec, + 0x3522e9e4}, + {0x00000000, 0x6307d924, 0xc60fb248, 0xa5086b6c, 0x576e62d1, + 0x3469bbf5, 0x9161d099, 0xf26609bd, 0xaedcc5a2, 0xcddb1c86, + 0x68d377ea, 0x0bd4aece, 0xf9b2a773, 0x9ab57e57, 0x3fbd153b, + 0x5cbacc1f, 0x86c88d05, 0xe5cf5421, 0x40c73f4d, 0x23c0e669, + 0xd1a6efd4, 0xb2a136f0, 0x17a95d9c, 0x74ae84b8, 0x281448a7, + 0x4b139183, 0xee1bfaef, 0x8d1c23cb, 0x7f7a2a76, 0x1c7df352, + 0xb975983e, 0xda72411a, 0xd6e01c4b, 0xb5e7c56f, 0x10efae03, + 0x73e87727, 0x818e7e9a, 0xe289a7be, 0x4781ccd2, 0x248615f6, + 0x783cd9e9, 0x1b3b00cd, 0xbe336ba1, 0xdd34b285, 0x2f52bb38, + 0x4c55621c, 0xe95d0970, 0x8a5ad054, 0x5028914e, 0x332f486a, + 0x96272306, 0xf520fa22, 0x0746f39f, 0x64412abb, 0xc14941d7, + 0xa24e98f3, 0xfef454ec, 0x9df38dc8, 0x38fbe6a4, 0x5bfc3f80, + 0xa99a363d, 0xca9def19, 0x6f958475, 0x0c925d51, 0x76b13ed7, + 0x15b6e7f3, 0xb0be8c9f, 0xd3b955bb, 0x21df5c06, 0x42d88522, + 0xe7d0ee4e, 0x84d7376a, 0xd86dfb75, 0xbb6a2251, 0x1e62493d, + 0x7d659019, 0x8f0399a4, 0xec044080, 0x490c2bec, 0x2a0bf2c8, + 0xf079b3d2, 0x937e6af6, 0x3676019a, 0x5571d8be, 0xa717d103, + 0xc4100827, 0x6118634b, 0x021fba6f, 0x5ea57670, 0x3da2af54, + 0x98aac438, 0xfbad1d1c, 0x09cb14a1, 0x6acccd85, 0xcfc4a6e9, + 0xacc37fcd, 0xa051229c, 0xc356fbb8, 0x665e90d4, 0x055949f0, + 0xf73f404d, 0x94389969, 0x3130f205, 0x52372b21, 0x0e8de73e, + 0x6d8a3e1a, 0xc8825576, 0xab858c52, 0x59e385ef, 0x3ae45ccb, + 0x9fec37a7, 0xfcebee83, 0x2699af99, 0x459e76bd, 0xe0961dd1, + 0x8391c4f5, 0x71f7cd48, 0x12f0146c, 0xb7f87f00, 0xd4ffa624, + 0x88456a3b, 0xeb42b31f, 0x4e4ad873, 0x2d4d0157, 0xdf2b08ea, + 0xbc2cd1ce, 0x1924baa2, 0x7a236386, 0xed627dae, 0x8e65a48a, + 0x2b6dcfe6, 0x486a16c2, 0xba0c1f7f, 0xd90bc65b, 0x7c03ad37, + 0x1f047413, 0x43beb80c, 0x20b96128, 0x85b10a44, 0xe6b6d360, + 0x14d0dadd, 0x77d703f9, 0xd2df6895, 0xb1d8b1b1, 0x6baaf0ab, + 0x08ad298f, 0xada542e3, 0xcea29bc7, 0x3cc4927a, 0x5fc34b5e, + 0xfacb2032, 0x99ccf916, 0xc5763509, 0xa671ec2d, 0x03798741, + 0x607e5e65, 0x921857d8, 0xf11f8efc, 0x5417e590, 0x37103cb4, + 0x3b8261e5, 0x5885b8c1, 0xfd8dd3ad, 0x9e8a0a89, 0x6cec0334, + 0x0febda10, 0xaae3b17c, 0xc9e46858, 0x955ea447, 0xf6597d63, + 0x5351160f, 0x3056cf2b, 0xc230c696, 0xa1371fb2, 0x043f74de, + 0x6738adfa, 0xbd4aece0, 0xde4d35c4, 0x7b455ea8, 0x1842878c, + 0xea248e31, 0x89235715, 0x2c2b3c79, 0x4f2ce55d, 0x13962942, + 0x7091f066, 0xd5999b0a, 0xb69e422e, 0x44f84b93, 0x27ff92b7, + 0x82f7f9db, 0xe1f020ff, 0x9bd34379, 0xf8d49a5d, 0x5ddcf131, + 0x3edb2815, 0xccbd21a8, 0xafbaf88c, 0x0ab293e0, 0x69b54ac4, + 0x350f86db, 0x56085fff, 0xf3003493, 0x9007edb7, 0x6261e40a, + 0x01663d2e, 0xa46e5642, 0xc7698f66, 0x1d1bce7c, 0x7e1c1758, + 0xdb147c34, 0xb813a510, 0x4a75acad, 0x29727589, 0x8c7a1ee5, + 0xef7dc7c1, 0xb3c70bde, 0xd0c0d2fa, 0x75c8b996, 0x16cf60b2, + 0xe4a9690f, 0x87aeb02b, 0x22a6db47, 0x41a10263, 0x4d335f32, + 0x2e348616, 0x8b3ced7a, 0xe83b345e, 0x1a5d3de3, 0x795ae4c7, + 0xdc528fab, 0xbf55568f, 0xe3ef9a90, 0x80e843b4, 0x25e028d8, + 0x46e7f1fc, 0xb481f841, 0xd7862165, 0x728e4a09, 0x1189932d, + 0xcbfbd237, 0xa8fc0b13, 0x0df4607f, 0x6ef3b95b, 0x9c95b0e6, + 0xff9269c2, 0x5a9a02ae, 0x399ddb8a, 0x65271795, 0x0620ceb1, + 0xa328a5dd, 0xc02f7cf9, 0x32497544, 0x514eac60, 0xf446c70c, + 0x97411e28}, + {0x00000000, 0x01b5fd1d, 0x036bfa3a, 0x02de0727, 0x06d7f474, + 0x07620969, 0x05bc0e4e, 0x0409f353, 0x0dafe8e8, 0x0c1a15f5, + 0x0ec412d2, 0x0f71efcf, 0x0b781c9c, 0x0acde181, 0x0813e6a6, + 0x09a61bbb, 0x1b5fd1d0, 0x1aea2ccd, 0x18342bea, 0x1981d6f7, + 0x1d8825a4, 0x1c3dd8b9, 0x1ee3df9e, 0x1f562283, 0x16f03938, + 0x1745c425, 0x159bc302, 0x142e3e1f, 0x1027cd4c, 0x11923051, + 0x134c3776, 0x12f9ca6b, 0x36bfa3a0, 0x370a5ebd, 0x35d4599a, + 0x3461a487, 0x306857d4, 0x31ddaac9, 0x3303adee, 0x32b650f3, + 0x3b104b48, 0x3aa5b655, 0x387bb172, 0x39ce4c6f, 0x3dc7bf3c, + 0x3c724221, 0x3eac4506, 0x3f19b81b, 0x2de07270, 0x2c558f6d, + 0x2e8b884a, 0x2f3e7557, 0x2b378604, 0x2a827b19, 0x285c7c3e, + 0x29e98123, 0x204f9a98, 0x21fa6785, 0x232460a2, 0x22919dbf, + 0x26986eec, 0x272d93f1, 0x25f394d6, 0x244669cb, 0x6d7f4740, + 0x6ccaba5d, 0x6e14bd7a, 0x6fa14067, 0x6ba8b334, 0x6a1d4e29, + 0x68c3490e, 0x6976b413, 0x60d0afa8, 0x616552b5, 0x63bb5592, + 0x620ea88f, 0x66075bdc, 0x67b2a6c1, 0x656ca1e6, 0x64d95cfb, + 0x76209690, 0x77956b8d, 0x754b6caa, 0x74fe91b7, 0x70f762e4, + 0x71429ff9, 0x739c98de, 0x722965c3, 0x7b8f7e78, 0x7a3a8365, + 0x78e48442, 0x7951795f, 0x7d588a0c, 0x7ced7711, 0x7e337036, + 0x7f868d2b, 0x5bc0e4e0, 0x5a7519fd, 0x58ab1eda, 0x591ee3c7, + 0x5d171094, 0x5ca2ed89, 0x5e7ceaae, 0x5fc917b3, 0x566f0c08, + 0x57daf115, 0x5504f632, 0x54b10b2f, 0x50b8f87c, 0x510d0561, + 0x53d30246, 0x5266ff5b, 0x409f3530, 0x412ac82d, 0x43f4cf0a, + 0x42413217, 0x4648c144, 0x47fd3c59, 0x45233b7e, 0x4496c663, + 0x4d30ddd8, 0x4c8520c5, 0x4e5b27e2, 0x4feedaff, 0x4be729ac, + 0x4a52d4b1, 0x488cd396, 0x49392e8b, 0xdafe8e80, 0xdb4b739d, + 0xd99574ba, 0xd82089a7, 0xdc297af4, 0xdd9c87e9, 0xdf4280ce, + 0xdef77dd3, 0xd7516668, 0xd6e49b75, 0xd43a9c52, 0xd58f614f, + 0xd186921c, 0xd0336f01, 0xd2ed6826, 0xd358953b, 0xc1a15f50, + 0xc014a24d, 0xc2caa56a, 0xc37f5877, 0xc776ab24, 0xc6c35639, + 0xc41d511e, 0xc5a8ac03, 0xcc0eb7b8, 0xcdbb4aa5, 0xcf654d82, + 0xced0b09f, 0xcad943cc, 0xcb6cbed1, 0xc9b2b9f6, 0xc80744eb, + 0xec412d20, 0xedf4d03d, 0xef2ad71a, 0xee9f2a07, 0xea96d954, + 0xeb232449, 0xe9fd236e, 0xe848de73, 0xe1eec5c8, 0xe05b38d5, + 0xe2853ff2, 0xe330c2ef, 0xe73931bc, 0xe68ccca1, 0xe452cb86, + 0xe5e7369b, 0xf71efcf0, 0xf6ab01ed, 0xf47506ca, 0xf5c0fbd7, + 0xf1c90884, 0xf07cf599, 0xf2a2f2be, 0xf3170fa3, 0xfab11418, + 0xfb04e905, 0xf9daee22, 0xf86f133f, 0xfc66e06c, 0xfdd31d71, + 0xff0d1a56, 0xfeb8e74b, 0xb781c9c0, 0xb63434dd, 0xb4ea33fa, + 0xb55fcee7, 0xb1563db4, 0xb0e3c0a9, 0xb23dc78e, 0xb3883a93, + 0xba2e2128, 0xbb9bdc35, 0xb945db12, 0xb8f0260f, 0xbcf9d55c, + 0xbd4c2841, 0xbf922f66, 0xbe27d27b, 0xacde1810, 0xad6be50d, + 0xafb5e22a, 0xae001f37, 0xaa09ec64, 0xabbc1179, 0xa962165e, + 0xa8d7eb43, 0xa171f0f8, 0xa0c40de5, 0xa21a0ac2, 0xa3aff7df, + 0xa7a6048c, 0xa613f991, 0xa4cdfeb6, 0xa57803ab, 0x813e6a60, + 0x808b977d, 0x8255905a, 0x83e06d47, 0x87e99e14, 0x865c6309, + 0x8482642e, 0x85379933, 0x8c918288, 0x8d247f95, 0x8ffa78b2, + 0x8e4f85af, 0x8a4676fc, 0x8bf38be1, 0x892d8cc6, 0x889871db, + 0x9a61bbb0, 0x9bd446ad, 0x990a418a, 0x98bfbc97, 0x9cb64fc4, + 0x9d03b2d9, 0x9fddb5fe, 0x9e6848e3, 0x97ce5358, 0x967bae45, + 0x94a5a962, 0x9510547f, 0x9119a72c, 0x90ac5a31, 0x92725d16, + 0x93c7a00b}, + {0x00000000, 0x6e8c1b41, 0xdd183682, 0xb3942dc3, 0x61416b45, + 0x0fcd7004, 0xbc595dc7, 0xd2d54686, 0xc282d68a, 0xac0ecdcb, + 0x1f9ae008, 0x7116fb49, 0xa3c3bdcf, 0xcd4fa68e, 0x7edb8b4d, + 0x1057900c, 0x5e74ab55, 0x30f8b014, 0x836c9dd7, 0xede08696, + 0x3f35c010, 0x51b9db51, 0xe22df692, 0x8ca1edd3, 0x9cf67ddf, + 0xf27a669e, 0x41ee4b5d, 0x2f62501c, 0xfdb7169a, 0x933b0ddb, + 0x20af2018, 0x4e233b59, 0xbce956aa, 0xd2654deb, 0x61f16028, + 0x0f7d7b69, 0xdda83def, 0xb32426ae, 0x00b00b6d, 0x6e3c102c, + 0x7e6b8020, 0x10e79b61, 0xa373b6a2, 0xcdffade3, 0x1f2aeb65, + 0x71a6f024, 0xc232dde7, 0xacbec6a6, 0xe29dfdff, 0x8c11e6be, + 0x3f85cb7d, 0x5109d03c, 0x83dc96ba, 0xed508dfb, 0x5ec4a038, + 0x3048bb79, 0x201f2b75, 0x4e933034, 0xfd071df7, 0x938b06b6, + 0x415e4030, 0x2fd25b71, 0x9c4676b2, 0xf2ca6df3, 0xa2a3ab15, + 0xcc2fb054, 0x7fbb9d97, 0x113786d6, 0xc3e2c050, 0xad6edb11, + 0x1efaf6d2, 0x7076ed93, 0x60217d9f, 0x0ead66de, 0xbd394b1d, + 0xd3b5505c, 0x016016da, 0x6fec0d9b, 0xdc782058, 0xb2f43b19, + 0xfcd70040, 0x925b1b01, 0x21cf36c2, 0x4f432d83, 0x9d966b05, + 0xf31a7044, 0x408e5d87, 0x2e0246c6, 0x3e55d6ca, 0x50d9cd8b, + 0xe34de048, 0x8dc1fb09, 0x5f14bd8f, 0x3198a6ce, 0x820c8b0d, + 0xec80904c, 0x1e4afdbf, 0x70c6e6fe, 0xc352cb3d, 0xadded07c, + 0x7f0b96fa, 0x11878dbb, 0xa213a078, 0xcc9fbb39, 0xdcc82b35, + 0xb2443074, 0x01d01db7, 0x6f5c06f6, 0xbd894070, 0xd3055b31, + 0x609176f2, 0x0e1d6db3, 0x403e56ea, 0x2eb24dab, 0x9d266068, + 0xf3aa7b29, 0x217f3daf, 0x4ff326ee, 0xfc670b2d, 0x92eb106c, + 0x82bc8060, 0xec309b21, 0x5fa4b6e2, 0x3128ada3, 0xe3fdeb25, + 0x8d71f064, 0x3ee5dda7, 0x5069c6e6, 0x9e36506b, 0xf0ba4b2a, + 0x432e66e9, 0x2da27da8, 0xff773b2e, 0x91fb206f, 0x226f0dac, + 0x4ce316ed, 0x5cb486e1, 0x32389da0, 0x81acb063, 0xef20ab22, + 0x3df5eda4, 0x5379f6e5, 0xe0eddb26, 0x8e61c067, 0xc042fb3e, + 0xaecee07f, 0x1d5acdbc, 0x73d6d6fd, 0xa103907b, 0xcf8f8b3a, + 0x7c1ba6f9, 0x1297bdb8, 0x02c02db4, 0x6c4c36f5, 0xdfd81b36, + 0xb1540077, 0x638146f1, 0x0d0d5db0, 0xbe997073, 0xd0156b32, + 0x22df06c1, 0x4c531d80, 0xffc73043, 0x914b2b02, 0x439e6d84, + 0x2d1276c5, 0x9e865b06, 0xf00a4047, 0xe05dd04b, 0x8ed1cb0a, + 0x3d45e6c9, 0x53c9fd88, 0x811cbb0e, 0xef90a04f, 0x5c048d8c, + 0x328896cd, 0x7cabad94, 0x1227b6d5, 0xa1b39b16, 0xcf3f8057, + 0x1deac6d1, 0x7366dd90, 0xc0f2f053, 0xae7eeb12, 0xbe297b1e, + 0xd0a5605f, 0x63314d9c, 0x0dbd56dd, 0xdf68105b, 0xb1e40b1a, + 0x027026d9, 0x6cfc3d98, 0x3c95fb7e, 0x5219e03f, 0xe18dcdfc, + 0x8f01d6bd, 0x5dd4903b, 0x33588b7a, 0x80cca6b9, 0xee40bdf8, + 0xfe172df4, 0x909b36b5, 0x230f1b76, 0x4d830037, 0x9f5646b1, + 0xf1da5df0, 0x424e7033, 0x2cc26b72, 0x62e1502b, 0x0c6d4b6a, + 0xbff966a9, 0xd1757de8, 0x03a03b6e, 0x6d2c202f, 0xdeb80dec, + 0xb03416ad, 0xa06386a1, 0xceef9de0, 0x7d7bb023, 0x13f7ab62, + 0xc122ede4, 0xafaef6a5, 0x1c3adb66, 0x72b6c027, 0x807cadd4, + 0xeef0b695, 0x5d649b56, 0x33e88017, 0xe13dc691, 0x8fb1ddd0, + 0x3c25f013, 0x52a9eb52, 0x42fe7b5e, 0x2c72601f, 0x9fe64ddc, + 0xf16a569d, 0x23bf101b, 0x4d330b5a, 0xfea72699, 0x902b3dd8, + 0xde080681, 0xb0841dc0, 0x03103003, 0x6d9c2b42, 0xbf496dc4, + 0xd1c57685, 0x62515b46, 0x0cdd4007, 0x1c8ad00b, 0x7206cb4a, + 0xc192e689, 0xaf1efdc8, 0x7dcbbb4e, 0x1347a00f, 0xa0d38dcc, + 0xce5f968d}, + {0x00000000, 0xe71da697, 0x154a4b6f, 0xf257edf8, 0x2a9496de, + 0xcd893049, 0x3fdeddb1, 0xd8c37b26, 0x55292dbc, 0xb2348b2b, + 0x406366d3, 0xa77ec044, 0x7fbdbb62, 0x98a01df5, 0x6af7f00d, + 0x8dea569a, 0xaa525b78, 0x4d4ffdef, 0xbf181017, 0x5805b680, + 0x80c6cda6, 0x67db6b31, 0x958c86c9, 0x7291205e, 0xff7b76c4, + 0x1866d053, 0xea313dab, 0x0d2c9b3c, 0xd5efe01a, 0x32f2468d, + 0xc0a5ab75, 0x27b80de2, 0x8fd5b0b1, 0x68c81626, 0x9a9ffbde, + 0x7d825d49, 0xa541266f, 0x425c80f8, 0xb00b6d00, 0x5716cb97, + 0xdafc9d0d, 0x3de13b9a, 0xcfb6d662, 0x28ab70f5, 0xf0680bd3, + 0x1775ad44, 0xe52240bc, 0x023fe62b, 0x2587ebc9, 0xc29a4d5e, + 0x30cda0a6, 0xd7d00631, 0x0f137d17, 0xe80edb80, 0x1a593678, + 0xfd4490ef, 0x70aec675, 0x97b360e2, 0x65e48d1a, 0x82f92b8d, + 0x5a3a50ab, 0xbd27f63c, 0x4f701bc4, 0xa86dbd53, 0xc4da6723, + 0x23c7c1b4, 0xd1902c4c, 0x368d8adb, 0xee4ef1fd, 0x0953576a, + 0xfb04ba92, 0x1c191c05, 0x91f34a9f, 0x76eeec08, 0x84b901f0, + 0x63a4a767, 0xbb67dc41, 0x5c7a7ad6, 0xae2d972e, 0x493031b9, + 0x6e883c5b, 0x89959acc, 0x7bc27734, 0x9cdfd1a3, 0x441caa85, + 0xa3010c12, 0x5156e1ea, 0xb64b477d, 0x3ba111e7, 0xdcbcb770, + 0x2eeb5a88, 0xc9f6fc1f, 0x11358739, 0xf62821ae, 0x047fcc56, + 0xe3626ac1, 0x4b0fd792, 0xac127105, 0x5e459cfd, 0xb9583a6a, + 0x619b414c, 0x8686e7db, 0x74d10a23, 0x93ccacb4, 0x1e26fa2e, + 0xf93b5cb9, 0x0b6cb141, 0xec7117d6, 0x34b26cf0, 0xd3afca67, + 0x21f8279f, 0xc6e58108, 0xe15d8cea, 0x06402a7d, 0xf417c785, + 0x130a6112, 0xcbc91a34, 0x2cd4bca3, 0xde83515b, 0x399ef7cc, + 0xb474a156, 0x536907c1, 0xa13eea39, 0x46234cae, 0x9ee03788, + 0x79fd911f, 0x8baa7ce7, 0x6cb7da70, 0x52c5c807, 0xb5d86e90, + 0x478f8368, 0xa09225ff, 0x78515ed9, 0x9f4cf84e, 0x6d1b15b6, + 0x8a06b321, 0x07ece5bb, 0xe0f1432c, 0x12a6aed4, 0xf5bb0843, + 0x2d787365, 0xca65d5f2, 0x3832380a, 0xdf2f9e9d, 0xf897937f, + 0x1f8a35e8, 0xedddd810, 0x0ac07e87, 0xd20305a1, 0x351ea336, + 0xc7494ece, 0x2054e859, 0xadbebec3, 0x4aa31854, 0xb8f4f5ac, + 0x5fe9533b, 0x872a281d, 0x60378e8a, 0x92606372, 0x757dc5e5, + 0xdd1078b6, 0x3a0dde21, 0xc85a33d9, 0x2f47954e, 0xf784ee68, + 0x109948ff, 0xe2cea507, 0x05d30390, 0x8839550a, 0x6f24f39d, + 0x9d731e65, 0x7a6eb8f2, 0xa2adc3d4, 0x45b06543, 0xb7e788bb, + 0x50fa2e2c, 0x774223ce, 0x905f8559, 0x620868a1, 0x8515ce36, + 0x5dd6b510, 0xbacb1387, 0x489cfe7f, 0xaf8158e8, 0x226b0e72, + 0xc576a8e5, 0x3721451d, 0xd03ce38a, 0x08ff98ac, 0xefe23e3b, + 0x1db5d3c3, 0xfaa87554, 0x961faf24, 0x710209b3, 0x8355e44b, + 0x644842dc, 0xbc8b39fa, 0x5b969f6d, 0xa9c17295, 0x4edcd402, + 0xc3368298, 0x242b240f, 0xd67cc9f7, 0x31616f60, 0xe9a21446, + 0x0ebfb2d1, 0xfce85f29, 0x1bf5f9be, 0x3c4df45c, 0xdb5052cb, + 0x2907bf33, 0xce1a19a4, 0x16d96282, 0xf1c4c415, 0x039329ed, + 0xe48e8f7a, 0x6964d9e0, 0x8e797f77, 0x7c2e928f, 0x9b333418, + 0x43f04f3e, 0xa4ede9a9, 0x56ba0451, 0xb1a7a2c6, 0x19ca1f95, + 0xfed7b902, 0x0c8054fa, 0xeb9df26d, 0x335e894b, 0xd4432fdc, + 0x2614c224, 0xc10964b3, 0x4ce33229, 0xabfe94be, 0x59a97946, + 0xbeb4dfd1, 0x6677a4f7, 0x816a0260, 0x733def98, 0x9420490f, + 0xb39844ed, 0x5485e27a, 0xa6d20f82, 0x41cfa915, 0x990cd233, + 0x7e1174a4, 0x8c46995c, 0x6b5b3fcb, 0xe6b16951, 0x01accfc6, + 0xf3fb223e, 0x14e684a9, 0xcc25ff8f, 0x2b385918, 0xd96fb4e0, + 0x3e721277}, + {0x00000000, 0xa58b900e, 0x9066265d, 0x35edb653, 0xfbbd4afb, + 0x5e36daf5, 0x6bdb6ca6, 0xce50fca8, 0x2c0b93b7, 0x898003b9, + 0xbc6db5ea, 0x19e625e4, 0xd7b6d94c, 0x723d4942, 0x47d0ff11, + 0xe25b6f1f, 0x5817276e, 0xfd9cb760, 0xc8710133, 0x6dfa913d, + 0xa3aa6d95, 0x0621fd9b, 0x33cc4bc8, 0x9647dbc6, 0x741cb4d9, + 0xd19724d7, 0xe47a9284, 0x41f1028a, 0x8fa1fe22, 0x2a2a6e2c, + 0x1fc7d87f, 0xba4c4871, 0xb02e4edc, 0x15a5ded2, 0x20486881, + 0x85c3f88f, 0x4b930427, 0xee189429, 0xdbf5227a, 0x7e7eb274, + 0x9c25dd6b, 0x39ae4d65, 0x0c43fb36, 0xa9c86b38, 0x67989790, + 0xc213079e, 0xf7feb1cd, 0x527521c3, 0xe83969b2, 0x4db2f9bc, + 0x785f4fef, 0xddd4dfe1, 0x13842349, 0xb60fb347, 0x83e20514, + 0x2669951a, 0xc432fa05, 0x61b96a0b, 0x5454dc58, 0xf1df4c56, + 0x3f8fb0fe, 0x9a0420f0, 0xafe996a3, 0x0a6206ad, 0xbb2d9bf9, + 0x1ea60bf7, 0x2b4bbda4, 0x8ec02daa, 0x4090d102, 0xe51b410c, + 0xd0f6f75f, 0x757d6751, 0x9726084e, 0x32ad9840, 0x07402e13, + 0xa2cbbe1d, 0x6c9b42b5, 0xc910d2bb, 0xfcfd64e8, 0x5976f4e6, + 0xe33abc97, 0x46b12c99, 0x735c9aca, 0xd6d70ac4, 0x1887f66c, + 0xbd0c6662, 0x88e1d031, 0x2d6a403f, 0xcf312f20, 0x6ababf2e, + 0x5f57097d, 0xfadc9973, 0x348c65db, 0x9107f5d5, 0xa4ea4386, + 0x0161d388, 0x0b03d525, 0xae88452b, 0x9b65f378, 0x3eee6376, + 0xf0be9fde, 0x55350fd0, 0x60d8b983, 0xc553298d, 0x27084692, + 0x8283d69c, 0xb76e60cf, 0x12e5f0c1, 0xdcb50c69, 0x793e9c67, + 0x4cd32a34, 0xe958ba3a, 0x5314f24b, 0xf69f6245, 0xc372d416, + 0x66f94418, 0xa8a9b8b0, 0x0d2228be, 0x38cf9eed, 0x9d440ee3, + 0x7f1f61fc, 0xda94f1f2, 0xef7947a1, 0x4af2d7af, 0x84a22b07, + 0x2129bb09, 0x14c40d5a, 0xb14f9d54, 0xad2a31b3, 0x08a1a1bd, + 0x3d4c17ee, 0x98c787e0, 0x56977b48, 0xf31ceb46, 0xc6f15d15, + 0x637acd1b, 0x8121a204, 0x24aa320a, 0x11478459, 0xb4cc1457, + 0x7a9ce8ff, 0xdf1778f1, 0xeafacea2, 0x4f715eac, 0xf53d16dd, + 0x50b686d3, 0x655b3080, 0xc0d0a08e, 0x0e805c26, 0xab0bcc28, + 0x9ee67a7b, 0x3b6dea75, 0xd936856a, 0x7cbd1564, 0x4950a337, + 0xecdb3339, 0x228bcf91, 0x87005f9f, 0xb2ede9cc, 0x176679c2, + 0x1d047f6f, 0xb88fef61, 0x8d625932, 0x28e9c93c, 0xe6b93594, + 0x4332a59a, 0x76df13c9, 0xd35483c7, 0x310fecd8, 0x94847cd6, + 0xa169ca85, 0x04e25a8b, 0xcab2a623, 0x6f39362d, 0x5ad4807e, + 0xff5f1070, 0x45135801, 0xe098c80f, 0xd5757e5c, 0x70feee52, + 0xbeae12fa, 0x1b2582f4, 0x2ec834a7, 0x8b43a4a9, 0x6918cbb6, + 0xcc935bb8, 0xf97eedeb, 0x5cf57de5, 0x92a5814d, 0x372e1143, + 0x02c3a710, 0xa748371e, 0x1607aa4a, 0xb38c3a44, 0x86618c17, + 0x23ea1c19, 0xedbae0b1, 0x483170bf, 0x7ddcc6ec, 0xd85756e2, + 0x3a0c39fd, 0x9f87a9f3, 0xaa6a1fa0, 0x0fe18fae, 0xc1b17306, + 0x643ae308, 0x51d7555b, 0xf45cc555, 0x4e108d24, 0xeb9b1d2a, + 0xde76ab79, 0x7bfd3b77, 0xb5adc7df, 0x102657d1, 0x25cbe182, + 0x8040718c, 0x621b1e93, 0xc7908e9d, 0xf27d38ce, 0x57f6a8c0, + 0x99a65468, 0x3c2dc466, 0x09c07235, 0xac4be23b, 0xa629e496, + 0x03a27498, 0x364fc2cb, 0x93c452c5, 0x5d94ae6d, 0xf81f3e63, + 0xcdf28830, 0x6879183e, 0x8a227721, 0x2fa9e72f, 0x1a44517c, + 0xbfcfc172, 0x719f3dda, 0xd414add4, 0xe1f91b87, 0x44728b89, + 0xfe3ec3f8, 0x5bb553f6, 0x6e58e5a5, 0xcbd375ab, 0x05838903, + 0xa008190d, 0x95e5af5e, 0x306e3f50, 0xd235504f, 0x77bec041, + 0x42537612, 0xe7d8e61c, 0x29881ab4, 0x8c038aba, 0xb9ee3ce9, + 0x1c65ace7}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0x0e908ba500000000, 0x5d26669000000000, + 0x53b6ed3500000000, 0xfb4abdfb00000000, 0xf5da365e00000000, + 0xa66cdb6b00000000, 0xa8fc50ce00000000, 0xb7930b2c00000000, + 0xb903808900000000, 0xeab56dbc00000000, 0xe425e61900000000, + 0x4cd9b6d700000000, 0x42493d7200000000, 0x11ffd04700000000, + 0x1f6f5be200000000, 0x6e27175800000000, 0x60b79cfd00000000, + 0x330171c800000000, 0x3d91fa6d00000000, 0x956daaa300000000, + 0x9bfd210600000000, 0xc84bcc3300000000, 0xc6db479600000000, + 0xd9b41c7400000000, 0xd72497d100000000, 0x84927ae400000000, + 0x8a02f14100000000, 0x22fea18f00000000, 0x2c6e2a2a00000000, + 0x7fd8c71f00000000, 0x71484cba00000000, 0xdc4e2eb000000000, + 0xd2dea51500000000, 0x8168482000000000, 0x8ff8c38500000000, + 0x2704934b00000000, 0x299418ee00000000, 0x7a22f5db00000000, + 0x74b27e7e00000000, 0x6bdd259c00000000, 0x654dae3900000000, + 0x36fb430c00000000, 0x386bc8a900000000, 0x9097986700000000, + 0x9e0713c200000000, 0xcdb1fef700000000, 0xc321755200000000, + 0xb26939e800000000, 0xbcf9b24d00000000, 0xef4f5f7800000000, + 0xe1dfd4dd00000000, 0x4923841300000000, 0x47b30fb600000000, + 0x1405e28300000000, 0x1a95692600000000, 0x05fa32c400000000, + 0x0b6ab96100000000, 0x58dc545400000000, 0x564cdff100000000, + 0xfeb08f3f00000000, 0xf020049a00000000, 0xa396e9af00000000, + 0xad06620a00000000, 0xf99b2dbb00000000, 0xf70ba61e00000000, + 0xa4bd4b2b00000000, 0xaa2dc08e00000000, 0x02d1904000000000, + 0x0c411be500000000, 0x5ff7f6d000000000, 0x51677d7500000000, + 0x4e08269700000000, 0x4098ad3200000000, 0x132e400700000000, + 0x1dbecba200000000, 0xb5429b6c00000000, 0xbbd210c900000000, + 0xe864fdfc00000000, 0xe6f4765900000000, 0x97bc3ae300000000, + 0x992cb14600000000, 0xca9a5c7300000000, 0xc40ad7d600000000, + 0x6cf6871800000000, 0x62660cbd00000000, 0x31d0e18800000000, + 0x3f406a2d00000000, 0x202f31cf00000000, 0x2ebfba6a00000000, + 0x7d09575f00000000, 0x7399dcfa00000000, 0xdb658c3400000000, + 0xd5f5079100000000, 0x8643eaa400000000, 0x88d3610100000000, + 0x25d5030b00000000, 0x2b4588ae00000000, 0x78f3659b00000000, + 0x7663ee3e00000000, 0xde9fbef000000000, 0xd00f355500000000, + 0x83b9d86000000000, 0x8d2953c500000000, 0x9246082700000000, + 0x9cd6838200000000, 0xcf606eb700000000, 0xc1f0e51200000000, + 0x690cb5dc00000000, 0x679c3e7900000000, 0x342ad34c00000000, + 0x3aba58e900000000, 0x4bf2145300000000, 0x45629ff600000000, + 0x16d472c300000000, 0x1844f96600000000, 0xb0b8a9a800000000, + 0xbe28220d00000000, 0xed9ecf3800000000, 0xe30e449d00000000, + 0xfc611f7f00000000, 0xf2f194da00000000, 0xa14779ef00000000, + 0xafd7f24a00000000, 0x072ba28400000000, 0x09bb292100000000, + 0x5a0dc41400000000, 0x549d4fb100000000, 0xb3312aad00000000, + 0xbda1a10800000000, 0xee174c3d00000000, 0xe087c79800000000, + 0x487b975600000000, 0x46eb1cf300000000, 0x155df1c600000000, + 0x1bcd7a6300000000, 0x04a2218100000000, 0x0a32aa2400000000, + 0x5984471100000000, 0x5714ccb400000000, 0xffe89c7a00000000, + 0xf17817df00000000, 0xa2cefaea00000000, 0xac5e714f00000000, + 0xdd163df500000000, 0xd386b65000000000, 0x80305b6500000000, + 0x8ea0d0c000000000, 0x265c800e00000000, 0x28cc0bab00000000, + 0x7b7ae69e00000000, 0x75ea6d3b00000000, 0x6a8536d900000000, + 0x6415bd7c00000000, 0x37a3504900000000, 0x3933dbec00000000, + 0x91cf8b2200000000, 0x9f5f008700000000, 0xcce9edb200000000, + 0xc279661700000000, 0x6f7f041d00000000, 0x61ef8fb800000000, + 0x3259628d00000000, 0x3cc9e92800000000, 0x9435b9e600000000, + 0x9aa5324300000000, 0xc913df7600000000, 0xc78354d300000000, + 0xd8ec0f3100000000, 0xd67c849400000000, 0x85ca69a100000000, + 0x8b5ae20400000000, 0x23a6b2ca00000000, 0x2d36396f00000000, + 0x7e80d45a00000000, 0x70105fff00000000, 0x0158134500000000, + 0x0fc898e000000000, 0x5c7e75d500000000, 0x52eefe7000000000, + 0xfa12aebe00000000, 0xf482251b00000000, 0xa734c82e00000000, + 0xa9a4438b00000000, 0xb6cb186900000000, 0xb85b93cc00000000, + 0xebed7ef900000000, 0xe57df55c00000000, 0x4d81a59200000000, + 0x43112e3700000000, 0x10a7c30200000000, 0x1e3748a700000000, + 0x4aaa071600000000, 0x443a8cb300000000, 0x178c618600000000, + 0x191cea2300000000, 0xb1e0baed00000000, 0xbf70314800000000, + 0xecc6dc7d00000000, 0xe25657d800000000, 0xfd390c3a00000000, + 0xf3a9879f00000000, 0xa01f6aaa00000000, 0xae8fe10f00000000, + 0x0673b1c100000000, 0x08e33a6400000000, 0x5b55d75100000000, + 0x55c55cf400000000, 0x248d104e00000000, 0x2a1d9beb00000000, + 0x79ab76de00000000, 0x773bfd7b00000000, 0xdfc7adb500000000, + 0xd157261000000000, 0x82e1cb2500000000, 0x8c71408000000000, + 0x931e1b6200000000, 0x9d8e90c700000000, 0xce387df200000000, + 0xc0a8f65700000000, 0x6854a69900000000, 0x66c42d3c00000000, + 0x3572c00900000000, 0x3be24bac00000000, 0x96e429a600000000, + 0x9874a20300000000, 0xcbc24f3600000000, 0xc552c49300000000, + 0x6dae945d00000000, 0x633e1ff800000000, 0x3088f2cd00000000, + 0x3e18796800000000, 0x2177228a00000000, 0x2fe7a92f00000000, + 0x7c51441a00000000, 0x72c1cfbf00000000, 0xda3d9f7100000000, + 0xd4ad14d400000000, 0x871bf9e100000000, 0x898b724400000000, + 0xf8c33efe00000000, 0xf653b55b00000000, 0xa5e5586e00000000, + 0xab75d3cb00000000, 0x0389830500000000, 0x0d1908a000000000, + 0x5eafe59500000000, 0x503f6e3000000000, 0x4f5035d200000000, + 0x41c0be7700000000, 0x1276534200000000, 0x1ce6d8e700000000, + 0xb41a882900000000, 0xba8a038c00000000, 0xe93ceeb900000000, + 0xe7ac651c00000000}, + {0x0000000000000000, 0x97a61de700000000, 0x6f4b4a1500000000, + 0xf8ed57f200000000, 0xde96942a00000000, 0x493089cd00000000, + 0xb1ddde3f00000000, 0x267bc3d800000000, 0xbc2d295500000000, + 0x2b8b34b200000000, 0xd366634000000000, 0x44c07ea700000000, + 0x62bbbd7f00000000, 0xf51da09800000000, 0x0df0f76a00000000, + 0x9a56ea8d00000000, 0x785b52aa00000000, 0xeffd4f4d00000000, + 0x171018bf00000000, 0x80b6055800000000, 0xa6cdc68000000000, + 0x316bdb6700000000, 0xc9868c9500000000, 0x5e20917200000000, + 0xc4767bff00000000, 0x53d0661800000000, 0xab3d31ea00000000, + 0x3c9b2c0d00000000, 0x1ae0efd500000000, 0x8d46f23200000000, + 0x75aba5c000000000, 0xe20db82700000000, 0xb1b0d58f00000000, + 0x2616c86800000000, 0xdefb9f9a00000000, 0x495d827d00000000, + 0x6f2641a500000000, 0xf8805c4200000000, 0x006d0bb000000000, + 0x97cb165700000000, 0x0d9dfcda00000000, 0x9a3be13d00000000, + 0x62d6b6cf00000000, 0xf570ab2800000000, 0xd30b68f000000000, + 0x44ad751700000000, 0xbc4022e500000000, 0x2be63f0200000000, + 0xc9eb872500000000, 0x5e4d9ac200000000, 0xa6a0cd3000000000, + 0x3106d0d700000000, 0x177d130f00000000, 0x80db0ee800000000, + 0x7836591a00000000, 0xef9044fd00000000, 0x75c6ae7000000000, + 0xe260b39700000000, 0x1a8de46500000000, 0x8d2bf98200000000, + 0xab503a5a00000000, 0x3cf627bd00000000, 0xc41b704f00000000, + 0x53bd6da800000000, 0x2367dac400000000, 0xb4c1c72300000000, + 0x4c2c90d100000000, 0xdb8a8d3600000000, 0xfdf14eee00000000, + 0x6a57530900000000, 0x92ba04fb00000000, 0x051c191c00000000, + 0x9f4af39100000000, 0x08ecee7600000000, 0xf001b98400000000, + 0x67a7a46300000000, 0x41dc67bb00000000, 0xd67a7a5c00000000, + 0x2e972dae00000000, 0xb931304900000000, 0x5b3c886e00000000, + 0xcc9a958900000000, 0x3477c27b00000000, 0xa3d1df9c00000000, + 0x85aa1c4400000000, 0x120c01a300000000, 0xeae1565100000000, + 0x7d474bb600000000, 0xe711a13b00000000, 0x70b7bcdc00000000, + 0x885aeb2e00000000, 0x1ffcf6c900000000, 0x3987351100000000, + 0xae2128f600000000, 0x56cc7f0400000000, 0xc16a62e300000000, + 0x92d70f4b00000000, 0x057112ac00000000, 0xfd9c455e00000000, + 0x6a3a58b900000000, 0x4c419b6100000000, 0xdbe7868600000000, + 0x230ad17400000000, 0xb4accc9300000000, 0x2efa261e00000000, + 0xb95c3bf900000000, 0x41b16c0b00000000, 0xd61771ec00000000, + 0xf06cb23400000000, 0x67caafd300000000, 0x9f27f82100000000, + 0x0881e5c600000000, 0xea8c5de100000000, 0x7d2a400600000000, + 0x85c717f400000000, 0x12610a1300000000, 0x341ac9cb00000000, + 0xa3bcd42c00000000, 0x5b5183de00000000, 0xccf79e3900000000, + 0x56a174b400000000, 0xc107695300000000, 0x39ea3ea100000000, + 0xae4c234600000000, 0x8837e09e00000000, 0x1f91fd7900000000, + 0xe77caa8b00000000, 0x70dab76c00000000, 0x07c8c55200000000, + 0x906ed8b500000000, 0x68838f4700000000, 0xff2592a000000000, + 0xd95e517800000000, 0x4ef84c9f00000000, 0xb6151b6d00000000, + 0x21b3068a00000000, 0xbbe5ec0700000000, 0x2c43f1e000000000, + 0xd4aea61200000000, 0x4308bbf500000000, 0x6573782d00000000, + 0xf2d565ca00000000, 0x0a38323800000000, 0x9d9e2fdf00000000, + 0x7f9397f800000000, 0xe8358a1f00000000, 0x10d8dded00000000, + 0x877ec00a00000000, 0xa10503d200000000, 0x36a31e3500000000, + 0xce4e49c700000000, 0x59e8542000000000, 0xc3bebead00000000, + 0x5418a34a00000000, 0xacf5f4b800000000, 0x3b53e95f00000000, + 0x1d282a8700000000, 0x8a8e376000000000, 0x7263609200000000, + 0xe5c57d7500000000, 0xb67810dd00000000, 0x21de0d3a00000000, + 0xd9335ac800000000, 0x4e95472f00000000, 0x68ee84f700000000, + 0xff48991000000000, 0x07a5cee200000000, 0x9003d30500000000, + 0x0a55398800000000, 0x9df3246f00000000, 0x651e739d00000000, + 0xf2b86e7a00000000, 0xd4c3ada200000000, 0x4365b04500000000, + 0xbb88e7b700000000, 0x2c2efa5000000000, 0xce23427700000000, + 0x59855f9000000000, 0xa168086200000000, 0x36ce158500000000, + 0x10b5d65d00000000, 0x8713cbba00000000, 0x7ffe9c4800000000, + 0xe85881af00000000, 0x720e6b2200000000, 0xe5a876c500000000, + 0x1d45213700000000, 0x8ae33cd000000000, 0xac98ff0800000000, + 0x3b3ee2ef00000000, 0xc3d3b51d00000000, 0x5475a8fa00000000, + 0x24af1f9600000000, 0xb309027100000000, 0x4be4558300000000, + 0xdc42486400000000, 0xfa398bbc00000000, 0x6d9f965b00000000, + 0x9572c1a900000000, 0x02d4dc4e00000000, 0x988236c300000000, + 0x0f242b2400000000, 0xf7c97cd600000000, 0x606f613100000000, + 0x4614a2e900000000, 0xd1b2bf0e00000000, 0x295fe8fc00000000, + 0xbef9f51b00000000, 0x5cf44d3c00000000, 0xcb5250db00000000, + 0x33bf072900000000, 0xa4191ace00000000, 0x8262d91600000000, + 0x15c4c4f100000000, 0xed29930300000000, 0x7a8f8ee400000000, + 0xe0d9646900000000, 0x777f798e00000000, 0x8f922e7c00000000, + 0x1834339b00000000, 0x3e4ff04300000000, 0xa9e9eda400000000, + 0x5104ba5600000000, 0xc6a2a7b100000000, 0x951fca1900000000, + 0x02b9d7fe00000000, 0xfa54800c00000000, 0x6df29deb00000000, + 0x4b895e3300000000, 0xdc2f43d400000000, 0x24c2142600000000, + 0xb36409c100000000, 0x2932e34c00000000, 0xbe94feab00000000, + 0x4679a95900000000, 0xd1dfb4be00000000, 0xf7a4776600000000, + 0x60026a8100000000, 0x98ef3d7300000000, 0x0f49209400000000, + 0xed4498b300000000, 0x7ae2855400000000, 0x820fd2a600000000, + 0x15a9cf4100000000, 0x33d20c9900000000, 0xa474117e00000000, + 0x5c99468c00000000, 0xcb3f5b6b00000000, 0x5169b1e600000000, + 0xc6cfac0100000000, 0x3e22fbf300000000, 0xa984e61400000000, + 0x8fff25cc00000000, 0x1859382b00000000, 0xe0b46fd900000000, + 0x7712723e00000000}, + {0x0000000000000000, 0x411b8c6e00000000, 0x823618dd00000000, + 0xc32d94b300000000, 0x456b416100000000, 0x0470cd0f00000000, + 0xc75d59bc00000000, 0x8646d5d200000000, 0x8ad682c200000000, + 0xcbcd0eac00000000, 0x08e09a1f00000000, 0x49fb167100000000, + 0xcfbdc3a300000000, 0x8ea64fcd00000000, 0x4d8bdb7e00000000, + 0x0c90571000000000, 0x55ab745e00000000, 0x14b0f83000000000, + 0xd79d6c8300000000, 0x9686e0ed00000000, 0x10c0353f00000000, + 0x51dbb95100000000, 0x92f62de200000000, 0xd3eda18c00000000, + 0xdf7df69c00000000, 0x9e667af200000000, 0x5d4bee4100000000, + 0x1c50622f00000000, 0x9a16b7fd00000000, 0xdb0d3b9300000000, + 0x1820af2000000000, 0x593b234e00000000, 0xaa56e9bc00000000, + 0xeb4d65d200000000, 0x2860f16100000000, 0x697b7d0f00000000, + 0xef3da8dd00000000, 0xae2624b300000000, 0x6d0bb00000000000, + 0x2c103c6e00000000, 0x20806b7e00000000, 0x619be71000000000, + 0xa2b673a300000000, 0xe3adffcd00000000, 0x65eb2a1f00000000, + 0x24f0a67100000000, 0xe7dd32c200000000, 0xa6c6beac00000000, + 0xfffd9de200000000, 0xbee6118c00000000, 0x7dcb853f00000000, + 0x3cd0095100000000, 0xba96dc8300000000, 0xfb8d50ed00000000, + 0x38a0c45e00000000, 0x79bb483000000000, 0x752b1f2000000000, + 0x3430934e00000000, 0xf71d07fd00000000, 0xb6068b9300000000, + 0x30405e4100000000, 0x715bd22f00000000, 0xb276469c00000000, + 0xf36dcaf200000000, 0x15aba3a200000000, 0x54b02fcc00000000, + 0x979dbb7f00000000, 0xd686371100000000, 0x50c0e2c300000000, + 0x11db6ead00000000, 0xd2f6fa1e00000000, 0x93ed767000000000, + 0x9f7d216000000000, 0xde66ad0e00000000, 0x1d4b39bd00000000, + 0x5c50b5d300000000, 0xda16600100000000, 0x9b0dec6f00000000, + 0x582078dc00000000, 0x193bf4b200000000, 0x4000d7fc00000000, + 0x011b5b9200000000, 0xc236cf2100000000, 0x832d434f00000000, + 0x056b969d00000000, 0x44701af300000000, 0x875d8e4000000000, + 0xc646022e00000000, 0xcad6553e00000000, 0x8bcdd95000000000, + 0x48e04de300000000, 0x09fbc18d00000000, 0x8fbd145f00000000, + 0xcea6983100000000, 0x0d8b0c8200000000, 0x4c9080ec00000000, + 0xbffd4a1e00000000, 0xfee6c67000000000, 0x3dcb52c300000000, + 0x7cd0dead00000000, 0xfa960b7f00000000, 0xbb8d871100000000, + 0x78a013a200000000, 0x39bb9fcc00000000, 0x352bc8dc00000000, + 0x743044b200000000, 0xb71dd00100000000, 0xf6065c6f00000000, + 0x704089bd00000000, 0x315b05d300000000, 0xf276916000000000, + 0xb36d1d0e00000000, 0xea563e4000000000, 0xab4db22e00000000, + 0x6860269d00000000, 0x297baaf300000000, 0xaf3d7f2100000000, + 0xee26f34f00000000, 0x2d0b67fc00000000, 0x6c10eb9200000000, + 0x6080bc8200000000, 0x219b30ec00000000, 0xe2b6a45f00000000, + 0xa3ad283100000000, 0x25ebfde300000000, 0x64f0718d00000000, + 0xa7dde53e00000000, 0xe6c6695000000000, 0x6b50369e00000000, + 0x2a4bbaf000000000, 0xe9662e4300000000, 0xa87da22d00000000, + 0x2e3b77ff00000000, 0x6f20fb9100000000, 0xac0d6f2200000000, + 0xed16e34c00000000, 0xe186b45c00000000, 0xa09d383200000000, + 0x63b0ac8100000000, 0x22ab20ef00000000, 0xa4edf53d00000000, + 0xe5f6795300000000, 0x26dbede000000000, 0x67c0618e00000000, + 0x3efb42c000000000, 0x7fe0ceae00000000, 0xbccd5a1d00000000, + 0xfdd6d67300000000, 0x7b9003a100000000, 0x3a8b8fcf00000000, + 0xf9a61b7c00000000, 0xb8bd971200000000, 0xb42dc00200000000, + 0xf5364c6c00000000, 0x361bd8df00000000, 0x770054b100000000, + 0xf146816300000000, 0xb05d0d0d00000000, 0x737099be00000000, + 0x326b15d000000000, 0xc106df2200000000, 0x801d534c00000000, + 0x4330c7ff00000000, 0x022b4b9100000000, 0x846d9e4300000000, + 0xc576122d00000000, 0x065b869e00000000, 0x47400af000000000, + 0x4bd05de000000000, 0x0acbd18e00000000, 0xc9e6453d00000000, + 0x88fdc95300000000, 0x0ebb1c8100000000, 0x4fa090ef00000000, + 0x8c8d045c00000000, 0xcd96883200000000, 0x94adab7c00000000, + 0xd5b6271200000000, 0x169bb3a100000000, 0x57803fcf00000000, + 0xd1c6ea1d00000000, 0x90dd667300000000, 0x53f0f2c000000000, + 0x12eb7eae00000000, 0x1e7b29be00000000, 0x5f60a5d000000000, + 0x9c4d316300000000, 0xdd56bd0d00000000, 0x5b1068df00000000, + 0x1a0be4b100000000, 0xd926700200000000, 0x983dfc6c00000000, + 0x7efb953c00000000, 0x3fe0195200000000, 0xfccd8de100000000, + 0xbdd6018f00000000, 0x3b90d45d00000000, 0x7a8b583300000000, + 0xb9a6cc8000000000, 0xf8bd40ee00000000, 0xf42d17fe00000000, + 0xb5369b9000000000, 0x761b0f2300000000, 0x3700834d00000000, + 0xb146569f00000000, 0xf05ddaf100000000, 0x33704e4200000000, + 0x726bc22c00000000, 0x2b50e16200000000, 0x6a4b6d0c00000000, + 0xa966f9bf00000000, 0xe87d75d100000000, 0x6e3ba00300000000, + 0x2f202c6d00000000, 0xec0db8de00000000, 0xad1634b000000000, + 0xa18663a000000000, 0xe09defce00000000, 0x23b07b7d00000000, + 0x62abf71300000000, 0xe4ed22c100000000, 0xa5f6aeaf00000000, + 0x66db3a1c00000000, 0x27c0b67200000000, 0xd4ad7c8000000000, + 0x95b6f0ee00000000, 0x569b645d00000000, 0x1780e83300000000, + 0x91c63de100000000, 0xd0ddb18f00000000, 0x13f0253c00000000, + 0x52eba95200000000, 0x5e7bfe4200000000, 0x1f60722c00000000, + 0xdc4de69f00000000, 0x9d566af100000000, 0x1b10bf2300000000, + 0x5a0b334d00000000, 0x9926a7fe00000000, 0xd83d2b9000000000, + 0x810608de00000000, 0xc01d84b000000000, 0x0330100300000000, + 0x422b9c6d00000000, 0xc46d49bf00000000, 0x8576c5d100000000, + 0x465b516200000000, 0x0740dd0c00000000, 0x0bd08a1c00000000, + 0x4acb067200000000, 0x89e692c100000000, 0xc8fd1eaf00000000, + 0x4ebbcb7d00000000, 0x0fa0471300000000, 0xcc8dd3a000000000, + 0x8d965fce00000000}, + {0x0000000000000000, 0x1dfdb50100000000, 0x3afa6b0300000000, + 0x2707de0200000000, 0x74f4d70600000000, 0x6909620700000000, + 0x4e0ebc0500000000, 0x53f3090400000000, 0xe8e8af0d00000000, + 0xf5151a0c00000000, 0xd212c40e00000000, 0xcfef710f00000000, + 0x9c1c780b00000000, 0x81e1cd0a00000000, 0xa6e6130800000000, + 0xbb1ba60900000000, 0xd0d15f1b00000000, 0xcd2cea1a00000000, + 0xea2b341800000000, 0xf7d6811900000000, 0xa425881d00000000, + 0xb9d83d1c00000000, 0x9edfe31e00000000, 0x8322561f00000000, + 0x3839f01600000000, 0x25c4451700000000, 0x02c39b1500000000, + 0x1f3e2e1400000000, 0x4ccd271000000000, 0x5130921100000000, + 0x76374c1300000000, 0x6bcaf91200000000, 0xa0a3bf3600000000, + 0xbd5e0a3700000000, 0x9a59d43500000000, 0x87a4613400000000, + 0xd457683000000000, 0xc9aadd3100000000, 0xeead033300000000, + 0xf350b63200000000, 0x484b103b00000000, 0x55b6a53a00000000, + 0x72b17b3800000000, 0x6f4cce3900000000, 0x3cbfc73d00000000, + 0x2142723c00000000, 0x0645ac3e00000000, 0x1bb8193f00000000, + 0x7072e02d00000000, 0x6d8f552c00000000, 0x4a888b2e00000000, + 0x57753e2f00000000, 0x0486372b00000000, 0x197b822a00000000, + 0x3e7c5c2800000000, 0x2381e92900000000, 0x989a4f2000000000, + 0x8567fa2100000000, 0xa260242300000000, 0xbf9d912200000000, + 0xec6e982600000000, 0xf1932d2700000000, 0xd694f32500000000, + 0xcb69462400000000, 0x40477f6d00000000, 0x5dbaca6c00000000, + 0x7abd146e00000000, 0x6740a16f00000000, 0x34b3a86b00000000, + 0x294e1d6a00000000, 0x0e49c36800000000, 0x13b4766900000000, + 0xa8afd06000000000, 0xb552656100000000, 0x9255bb6300000000, + 0x8fa80e6200000000, 0xdc5b076600000000, 0xc1a6b26700000000, + 0xe6a16c6500000000, 0xfb5cd96400000000, 0x9096207600000000, + 0x8d6b957700000000, 0xaa6c4b7500000000, 0xb791fe7400000000, + 0xe462f77000000000, 0xf99f427100000000, 0xde989c7300000000, + 0xc365297200000000, 0x787e8f7b00000000, 0x65833a7a00000000, + 0x4284e47800000000, 0x5f79517900000000, 0x0c8a587d00000000, + 0x1177ed7c00000000, 0x3670337e00000000, 0x2b8d867f00000000, + 0xe0e4c05b00000000, 0xfd19755a00000000, 0xda1eab5800000000, + 0xc7e31e5900000000, 0x9410175d00000000, 0x89eda25c00000000, + 0xaeea7c5e00000000, 0xb317c95f00000000, 0x080c6f5600000000, + 0x15f1da5700000000, 0x32f6045500000000, 0x2f0bb15400000000, + 0x7cf8b85000000000, 0x61050d5100000000, 0x4602d35300000000, + 0x5bff665200000000, 0x30359f4000000000, 0x2dc82a4100000000, + 0x0acff44300000000, 0x1732414200000000, 0x44c1484600000000, + 0x593cfd4700000000, 0x7e3b234500000000, 0x63c6964400000000, + 0xd8dd304d00000000, 0xc520854c00000000, 0xe2275b4e00000000, + 0xffdaee4f00000000, 0xac29e74b00000000, 0xb1d4524a00000000, + 0x96d38c4800000000, 0x8b2e394900000000, 0x808efeda00000000, + 0x9d734bdb00000000, 0xba7495d900000000, 0xa78920d800000000, + 0xf47a29dc00000000, 0xe9879cdd00000000, 0xce8042df00000000, + 0xd37df7de00000000, 0x686651d700000000, 0x759be4d600000000, + 0x529c3ad400000000, 0x4f618fd500000000, 0x1c9286d100000000, + 0x016f33d000000000, 0x2668edd200000000, 0x3b9558d300000000, + 0x505fa1c100000000, 0x4da214c000000000, 0x6aa5cac200000000, + 0x77587fc300000000, 0x24ab76c700000000, 0x3956c3c600000000, + 0x1e511dc400000000, 0x03aca8c500000000, 0xb8b70ecc00000000, + 0xa54abbcd00000000, 0x824d65cf00000000, 0x9fb0d0ce00000000, + 0xcc43d9ca00000000, 0xd1be6ccb00000000, 0xf6b9b2c900000000, + 0xeb4407c800000000, 0x202d41ec00000000, 0x3dd0f4ed00000000, + 0x1ad72aef00000000, 0x072a9fee00000000, 0x54d996ea00000000, + 0x492423eb00000000, 0x6e23fde900000000, 0x73de48e800000000, + 0xc8c5eee100000000, 0xd5385be000000000, 0xf23f85e200000000, + 0xefc230e300000000, 0xbc3139e700000000, 0xa1cc8ce600000000, + 0x86cb52e400000000, 0x9b36e7e500000000, 0xf0fc1ef700000000, + 0xed01abf600000000, 0xca0675f400000000, 0xd7fbc0f500000000, + 0x8408c9f100000000, 0x99f57cf000000000, 0xbef2a2f200000000, + 0xa30f17f300000000, 0x1814b1fa00000000, 0x05e904fb00000000, + 0x22eedaf900000000, 0x3f136ff800000000, 0x6ce066fc00000000, + 0x711dd3fd00000000, 0x561a0dff00000000, 0x4be7b8fe00000000, + 0xc0c981b700000000, 0xdd3434b600000000, 0xfa33eab400000000, + 0xe7ce5fb500000000, 0xb43d56b100000000, 0xa9c0e3b000000000, + 0x8ec73db200000000, 0x933a88b300000000, 0x28212eba00000000, + 0x35dc9bbb00000000, 0x12db45b900000000, 0x0f26f0b800000000, + 0x5cd5f9bc00000000, 0x41284cbd00000000, 0x662f92bf00000000, + 0x7bd227be00000000, 0x1018deac00000000, 0x0de56bad00000000, + 0x2ae2b5af00000000, 0x371f00ae00000000, 0x64ec09aa00000000, + 0x7911bcab00000000, 0x5e1662a900000000, 0x43ebd7a800000000, + 0xf8f071a100000000, 0xe50dc4a000000000, 0xc20a1aa200000000, + 0xdff7afa300000000, 0x8c04a6a700000000, 0x91f913a600000000, + 0xb6fecda400000000, 0xab0378a500000000, 0x606a3e8100000000, + 0x7d978b8000000000, 0x5a90558200000000, 0x476de08300000000, + 0x149ee98700000000, 0x09635c8600000000, 0x2e64828400000000, + 0x3399378500000000, 0x8882918c00000000, 0x957f248d00000000, + 0xb278fa8f00000000, 0xaf854f8e00000000, 0xfc76468a00000000, + 0xe18bf38b00000000, 0xc68c2d8900000000, 0xdb71988800000000, + 0xb0bb619a00000000, 0xad46d49b00000000, 0x8a410a9900000000, + 0x97bcbf9800000000, 0xc44fb69c00000000, 0xd9b2039d00000000, + 0xfeb5dd9f00000000, 0xe348689e00000000, 0x5853ce9700000000, + 0x45ae7b9600000000, 0x62a9a59400000000, 0x7f54109500000000, + 0x2ca7199100000000, 0x315aac9000000000, 0x165d729200000000, + 0x0ba0c79300000000}, + {0x0000000000000000, 0x24d9076300000000, 0x48b20fc600000000, + 0x6c6b08a500000000, 0xd1626e5700000000, 0xf5bb693400000000, + 0x99d0619100000000, 0xbd0966f200000000, 0xa2c5dcae00000000, + 0x861cdbcd00000000, 0xea77d36800000000, 0xceaed40b00000000, + 0x73a7b2f900000000, 0x577eb59a00000000, 0x3b15bd3f00000000, + 0x1fccba5c00000000, 0x058dc88600000000, 0x2154cfe500000000, + 0x4d3fc74000000000, 0x69e6c02300000000, 0xd4efa6d100000000, + 0xf036a1b200000000, 0x9c5da91700000000, 0xb884ae7400000000, + 0xa748142800000000, 0x8391134b00000000, 0xeffa1bee00000000, + 0xcb231c8d00000000, 0x762a7a7f00000000, 0x52f37d1c00000000, + 0x3e9875b900000000, 0x1a4172da00000000, 0x4b1ce0d600000000, + 0x6fc5e7b500000000, 0x03aeef1000000000, 0x2777e87300000000, + 0x9a7e8e8100000000, 0xbea789e200000000, 0xd2cc814700000000, + 0xf615862400000000, 0xe9d93c7800000000, 0xcd003b1b00000000, + 0xa16b33be00000000, 0x85b234dd00000000, 0x38bb522f00000000, + 0x1c62554c00000000, 0x70095de900000000, 0x54d05a8a00000000, + 0x4e91285000000000, 0x6a482f3300000000, 0x0623279600000000, + 0x22fa20f500000000, 0x9ff3460700000000, 0xbb2a416400000000, + 0xd74149c100000000, 0xf3984ea200000000, 0xec54f4fe00000000, + 0xc88df39d00000000, 0xa4e6fb3800000000, 0x803ffc5b00000000, + 0x3d369aa900000000, 0x19ef9dca00000000, 0x7584956f00000000, + 0x515d920c00000000, 0xd73eb17600000000, 0xf3e7b61500000000, + 0x9f8cbeb000000000, 0xbb55b9d300000000, 0x065cdf2100000000, + 0x2285d84200000000, 0x4eeed0e700000000, 0x6a37d78400000000, + 0x75fb6dd800000000, 0x51226abb00000000, 0x3d49621e00000000, + 0x1990657d00000000, 0xa499038f00000000, 0x804004ec00000000, + 0xec2b0c4900000000, 0xc8f20b2a00000000, 0xd2b379f000000000, + 0xf66a7e9300000000, 0x9a01763600000000, 0xbed8715500000000, + 0x03d117a700000000, 0x270810c400000000, 0x4b63186100000000, + 0x6fba1f0200000000, 0x7076a55e00000000, 0x54afa23d00000000, + 0x38c4aa9800000000, 0x1c1dadfb00000000, 0xa114cb0900000000, + 0x85cdcc6a00000000, 0xe9a6c4cf00000000, 0xcd7fc3ac00000000, + 0x9c2251a000000000, 0xb8fb56c300000000, 0xd4905e6600000000, + 0xf049590500000000, 0x4d403ff700000000, 0x6999389400000000, + 0x05f2303100000000, 0x212b375200000000, 0x3ee78d0e00000000, + 0x1a3e8a6d00000000, 0x765582c800000000, 0x528c85ab00000000, + 0xef85e35900000000, 0xcb5ce43a00000000, 0xa737ec9f00000000, + 0x83eeebfc00000000, 0x99af992600000000, 0xbd769e4500000000, + 0xd11d96e000000000, 0xf5c4918300000000, 0x48cdf77100000000, + 0x6c14f01200000000, 0x007ff8b700000000, 0x24a6ffd400000000, + 0x3b6a458800000000, 0x1fb342eb00000000, 0x73d84a4e00000000, + 0x57014d2d00000000, 0xea082bdf00000000, 0xced12cbc00000000, + 0xa2ba241900000000, 0x8663237a00000000, 0xae7d62ed00000000, + 0x8aa4658e00000000, 0xe6cf6d2b00000000, 0xc2166a4800000000, + 0x7f1f0cba00000000, 0x5bc60bd900000000, 0x37ad037c00000000, + 0x1374041f00000000, 0x0cb8be4300000000, 0x2861b92000000000, + 0x440ab18500000000, 0x60d3b6e600000000, 0xdddad01400000000, + 0xf903d77700000000, 0x9568dfd200000000, 0xb1b1d8b100000000, + 0xabf0aa6b00000000, 0x8f29ad0800000000, 0xe342a5ad00000000, + 0xc79ba2ce00000000, 0x7a92c43c00000000, 0x5e4bc35f00000000, + 0x3220cbfa00000000, 0x16f9cc9900000000, 0x093576c500000000, + 0x2dec71a600000000, 0x4187790300000000, 0x655e7e6000000000, + 0xd857189200000000, 0xfc8e1ff100000000, 0x90e5175400000000, + 0xb43c103700000000, 0xe561823b00000000, 0xc1b8855800000000, + 0xadd38dfd00000000, 0x890a8a9e00000000, 0x3403ec6c00000000, + 0x10daeb0f00000000, 0x7cb1e3aa00000000, 0x5868e4c900000000, + 0x47a45e9500000000, 0x637d59f600000000, 0x0f16515300000000, + 0x2bcf563000000000, 0x96c630c200000000, 0xb21f37a100000000, + 0xde743f0400000000, 0xfaad386700000000, 0xe0ec4abd00000000, + 0xc4354dde00000000, 0xa85e457b00000000, 0x8c87421800000000, + 0x318e24ea00000000, 0x1557238900000000, 0x793c2b2c00000000, + 0x5de52c4f00000000, 0x4229961300000000, 0x66f0917000000000, + 0x0a9b99d500000000, 0x2e429eb600000000, 0x934bf84400000000, + 0xb792ff2700000000, 0xdbf9f78200000000, 0xff20f0e100000000, + 0x7943d39b00000000, 0x5d9ad4f800000000, 0x31f1dc5d00000000, + 0x1528db3e00000000, 0xa821bdcc00000000, 0x8cf8baaf00000000, + 0xe093b20a00000000, 0xc44ab56900000000, 0xdb860f3500000000, + 0xff5f085600000000, 0x933400f300000000, 0xb7ed079000000000, + 0x0ae4616200000000, 0x2e3d660100000000, 0x42566ea400000000, + 0x668f69c700000000, 0x7cce1b1d00000000, 0x58171c7e00000000, + 0x347c14db00000000, 0x10a513b800000000, 0xadac754a00000000, + 0x8975722900000000, 0xe51e7a8c00000000, 0xc1c77def00000000, + 0xde0bc7b300000000, 0xfad2c0d000000000, 0x96b9c87500000000, + 0xb260cf1600000000, 0x0f69a9e400000000, 0x2bb0ae8700000000, + 0x47dba62200000000, 0x6302a14100000000, 0x325f334d00000000, + 0x1686342e00000000, 0x7aed3c8b00000000, 0x5e343be800000000, + 0xe33d5d1a00000000, 0xc7e45a7900000000, 0xab8f52dc00000000, + 0x8f5655bf00000000, 0x909aefe300000000, 0xb443e88000000000, + 0xd828e02500000000, 0xfcf1e74600000000, 0x41f881b400000000, + 0x652186d700000000, 0x094a8e7200000000, 0x2d93891100000000, + 0x37d2fbcb00000000, 0x130bfca800000000, 0x7f60f40d00000000, + 0x5bb9f36e00000000, 0xe6b0959c00000000, 0xc26992ff00000000, + 0xae029a5a00000000, 0x8adb9d3900000000, 0x9517276500000000, + 0xb1ce200600000000, 0xdda528a300000000, 0xf97c2fc000000000, + 0x4475493200000000, 0x60ac4e5100000000, 0x0cc746f400000000, + 0x281e419700000000}, + {0x0000000000000000, 0x08e3603c00000000, 0x10c6c17800000000, + 0x1825a14400000000, 0x208c83f100000000, 0x286fe3cd00000000, + 0x304a428900000000, 0x38a922b500000000, 0x011e763800000000, + 0x09fd160400000000, 0x11d8b74000000000, 0x193bd77c00000000, + 0x2192f5c900000000, 0x297195f500000000, 0x315434b100000000, + 0x39b7548d00000000, 0x023cec7000000000, 0x0adf8c4c00000000, + 0x12fa2d0800000000, 0x1a194d3400000000, 0x22b06f8100000000, + 0x2a530fbd00000000, 0x3276aef900000000, 0x3a95cec500000000, + 0x03229a4800000000, 0x0bc1fa7400000000, 0x13e45b3000000000, + 0x1b073b0c00000000, 0x23ae19b900000000, 0x2b4d798500000000, + 0x3368d8c100000000, 0x3b8bb8fd00000000, 0x0478d8e100000000, + 0x0c9bb8dd00000000, 0x14be199900000000, 0x1c5d79a500000000, + 0x24f45b1000000000, 0x2c173b2c00000000, 0x34329a6800000000, + 0x3cd1fa5400000000, 0x0566aed900000000, 0x0d85cee500000000, + 0x15a06fa100000000, 0x1d430f9d00000000, 0x25ea2d2800000000, + 0x2d094d1400000000, 0x352cec5000000000, 0x3dcf8c6c00000000, + 0x0644349100000000, 0x0ea754ad00000000, 0x1682f5e900000000, + 0x1e6195d500000000, 0x26c8b76000000000, 0x2e2bd75c00000000, + 0x360e761800000000, 0x3eed162400000000, 0x075a42a900000000, + 0x0fb9229500000000, 0x179c83d100000000, 0x1f7fe3ed00000000, + 0x27d6c15800000000, 0x2f35a16400000000, 0x3710002000000000, + 0x3ff3601c00000000, 0x49f6c11800000000, 0x4115a12400000000, + 0x5930006000000000, 0x51d3605c00000000, 0x697a42e900000000, + 0x619922d500000000, 0x79bc839100000000, 0x715fe3ad00000000, + 0x48e8b72000000000, 0x400bd71c00000000, 0x582e765800000000, + 0x50cd166400000000, 0x686434d100000000, 0x608754ed00000000, + 0x78a2f5a900000000, 0x7041959500000000, 0x4bca2d6800000000, + 0x43294d5400000000, 0x5b0cec1000000000, 0x53ef8c2c00000000, + 0x6b46ae9900000000, 0x63a5cea500000000, 0x7b806fe100000000, + 0x73630fdd00000000, 0x4ad45b5000000000, 0x42373b6c00000000, + 0x5a129a2800000000, 0x52f1fa1400000000, 0x6a58d8a100000000, + 0x62bbb89d00000000, 0x7a9e19d900000000, 0x727d79e500000000, + 0x4d8e19f900000000, 0x456d79c500000000, 0x5d48d88100000000, + 0x55abb8bd00000000, 0x6d029a0800000000, 0x65e1fa3400000000, + 0x7dc45b7000000000, 0x75273b4c00000000, 0x4c906fc100000000, + 0x44730ffd00000000, 0x5c56aeb900000000, 0x54b5ce8500000000, + 0x6c1cec3000000000, 0x64ff8c0c00000000, 0x7cda2d4800000000, + 0x74394d7400000000, 0x4fb2f58900000000, 0x475195b500000000, + 0x5f7434f100000000, 0x579754cd00000000, 0x6f3e767800000000, + 0x67dd164400000000, 0x7ff8b70000000000, 0x771bd73c00000000, + 0x4eac83b100000000, 0x464fe38d00000000, 0x5e6a42c900000000, + 0x568922f500000000, 0x6e20004000000000, 0x66c3607c00000000, + 0x7ee6c13800000000, 0x7605a10400000000, 0x92ec833100000000, + 0x9a0fe30d00000000, 0x822a424900000000, 0x8ac9227500000000, + 0xb26000c000000000, 0xba8360fc00000000, 0xa2a6c1b800000000, + 0xaa45a18400000000, 0x93f2f50900000000, 0x9b11953500000000, + 0x8334347100000000, 0x8bd7544d00000000, 0xb37e76f800000000, + 0xbb9d16c400000000, 0xa3b8b78000000000, 0xab5bd7bc00000000, + 0x90d06f4100000000, 0x98330f7d00000000, 0x8016ae3900000000, + 0x88f5ce0500000000, 0xb05cecb000000000, 0xb8bf8c8c00000000, + 0xa09a2dc800000000, 0xa8794df400000000, 0x91ce197900000000, + 0x992d794500000000, 0x8108d80100000000, 0x89ebb83d00000000, + 0xb1429a8800000000, 0xb9a1fab400000000, 0xa1845bf000000000, + 0xa9673bcc00000000, 0x96945bd000000000, 0x9e773bec00000000, + 0x86529aa800000000, 0x8eb1fa9400000000, 0xb618d82100000000, + 0xbefbb81d00000000, 0xa6de195900000000, 0xae3d796500000000, + 0x978a2de800000000, 0x9f694dd400000000, 0x874cec9000000000, + 0x8faf8cac00000000, 0xb706ae1900000000, 0xbfe5ce2500000000, + 0xa7c06f6100000000, 0xaf230f5d00000000, 0x94a8b7a000000000, + 0x9c4bd79c00000000, 0x846e76d800000000, 0x8c8d16e400000000, + 0xb424345100000000, 0xbcc7546d00000000, 0xa4e2f52900000000, + 0xac01951500000000, 0x95b6c19800000000, 0x9d55a1a400000000, + 0x857000e000000000, 0x8d9360dc00000000, 0xb53a426900000000, + 0xbdd9225500000000, 0xa5fc831100000000, 0xad1fe32d00000000, + 0xdb1a422900000000, 0xd3f9221500000000, 0xcbdc835100000000, + 0xc33fe36d00000000, 0xfb96c1d800000000, 0xf375a1e400000000, + 0xeb5000a000000000, 0xe3b3609c00000000, 0xda04341100000000, + 0xd2e7542d00000000, 0xcac2f56900000000, 0xc221955500000000, + 0xfa88b7e000000000, 0xf26bd7dc00000000, 0xea4e769800000000, + 0xe2ad16a400000000, 0xd926ae5900000000, 0xd1c5ce6500000000, + 0xc9e06f2100000000, 0xc1030f1d00000000, 0xf9aa2da800000000, + 0xf1494d9400000000, 0xe96cecd000000000, 0xe18f8cec00000000, + 0xd838d86100000000, 0xd0dbb85d00000000, 0xc8fe191900000000, + 0xc01d792500000000, 0xf8b45b9000000000, 0xf0573bac00000000, + 0xe8729ae800000000, 0xe091fad400000000, 0xdf629ac800000000, + 0xd781faf400000000, 0xcfa45bb000000000, 0xc7473b8c00000000, + 0xffee193900000000, 0xf70d790500000000, 0xef28d84100000000, + 0xe7cbb87d00000000, 0xde7cecf000000000, 0xd69f8ccc00000000, + 0xceba2d8800000000, 0xc6594db400000000, 0xfef06f0100000000, + 0xf6130f3d00000000, 0xee36ae7900000000, 0xe6d5ce4500000000, + 0xdd5e76b800000000, 0xd5bd168400000000, 0xcd98b7c000000000, + 0xc57bd7fc00000000, 0xfdd2f54900000000, 0xf531957500000000, + 0xed14343100000000, 0xe5f7540d00000000, 0xdc40008000000000, + 0xd4a360bc00000000, 0xcc86c1f800000000, 0xc465a1c400000000, + 0xfccc837100000000, 0xf42fe34d00000000, 0xec0a420900000000, + 0xe4e9223500000000}, + {0x0000000000000000, 0xd1e8e70e00000000, 0xa2d1cf1d00000000, + 0x7339281300000000, 0x44a39f3b00000000, 0x954b783500000000, + 0xe672502600000000, 0x379ab72800000000, 0x88463f7700000000, + 0x59aed87900000000, 0x2a97f06a00000000, 0xfb7f176400000000, + 0xcce5a04c00000000, 0x1d0d474200000000, 0x6e346f5100000000, + 0xbfdc885f00000000, 0x108d7eee00000000, 0xc16599e000000000, + 0xb25cb1f300000000, 0x63b456fd00000000, 0x542ee1d500000000, + 0x85c606db00000000, 0xf6ff2ec800000000, 0x2717c9c600000000, + 0x98cb419900000000, 0x4923a69700000000, 0x3a1a8e8400000000, + 0xebf2698a00000000, 0xdc68dea200000000, 0x0d8039ac00000000, + 0x7eb911bf00000000, 0xaf51f6b100000000, 0x611c8c0700000000, + 0xb0f46b0900000000, 0xc3cd431a00000000, 0x1225a41400000000, + 0x25bf133c00000000, 0xf457f43200000000, 0x876edc2100000000, + 0x56863b2f00000000, 0xe95ab37000000000, 0x38b2547e00000000, + 0x4b8b7c6d00000000, 0x9a639b6300000000, 0xadf92c4b00000000, + 0x7c11cb4500000000, 0x0f28e35600000000, 0xdec0045800000000, + 0x7191f2e900000000, 0xa07915e700000000, 0xd3403df400000000, + 0x02a8dafa00000000, 0x35326dd200000000, 0xe4da8adc00000000, + 0x97e3a2cf00000000, 0x460b45c100000000, 0xf9d7cd9e00000000, + 0x283f2a9000000000, 0x5b06028300000000, 0x8aeee58d00000000, + 0xbd7452a500000000, 0x6c9cb5ab00000000, 0x1fa59db800000000, + 0xce4d7ab600000000, 0xc238180f00000000, 0x13d0ff0100000000, + 0x60e9d71200000000, 0xb101301c00000000, 0x869b873400000000, + 0x5773603a00000000, 0x244a482900000000, 0xf5a2af2700000000, + 0x4a7e277800000000, 0x9b96c07600000000, 0xe8afe86500000000, + 0x39470f6b00000000, 0x0eddb84300000000, 0xdf355f4d00000000, + 0xac0c775e00000000, 0x7de4905000000000, 0xd2b566e100000000, + 0x035d81ef00000000, 0x7064a9fc00000000, 0xa18c4ef200000000, + 0x9616f9da00000000, 0x47fe1ed400000000, 0x34c736c700000000, + 0xe52fd1c900000000, 0x5af3599600000000, 0x8b1bbe9800000000, + 0xf822968b00000000, 0x29ca718500000000, 0x1e50c6ad00000000, + 0xcfb821a300000000, 0xbc8109b000000000, 0x6d69eebe00000000, + 0xa324940800000000, 0x72cc730600000000, 0x01f55b1500000000, + 0xd01dbc1b00000000, 0xe7870b3300000000, 0x366fec3d00000000, + 0x4556c42e00000000, 0x94be232000000000, 0x2b62ab7f00000000, + 0xfa8a4c7100000000, 0x89b3646200000000, 0x585b836c00000000, + 0x6fc1344400000000, 0xbe29d34a00000000, 0xcd10fb5900000000, + 0x1cf81c5700000000, 0xb3a9eae600000000, 0x62410de800000000, + 0x117825fb00000000, 0xc090c2f500000000, 0xf70a75dd00000000, + 0x26e292d300000000, 0x55dbbac000000000, 0x84335dce00000000, + 0x3befd59100000000, 0xea07329f00000000, 0x993e1a8c00000000, + 0x48d6fd8200000000, 0x7f4c4aaa00000000, 0xaea4ada400000000, + 0xdd9d85b700000000, 0x0c7562b900000000, 0x8471301e00000000, + 0x5599d71000000000, 0x26a0ff0300000000, 0xf748180d00000000, + 0xc0d2af2500000000, 0x113a482b00000000, 0x6203603800000000, + 0xb3eb873600000000, 0x0c370f6900000000, 0xdddfe86700000000, + 0xaee6c07400000000, 0x7f0e277a00000000, 0x4894905200000000, + 0x997c775c00000000, 0xea455f4f00000000, 0x3badb84100000000, + 0x94fc4ef000000000, 0x4514a9fe00000000, 0x362d81ed00000000, + 0xe7c566e300000000, 0xd05fd1cb00000000, 0x01b736c500000000, + 0x728e1ed600000000, 0xa366f9d800000000, 0x1cba718700000000, + 0xcd52968900000000, 0xbe6bbe9a00000000, 0x6f83599400000000, + 0x5819eebc00000000, 0x89f109b200000000, 0xfac821a100000000, + 0x2b20c6af00000000, 0xe56dbc1900000000, 0x34855b1700000000, + 0x47bc730400000000, 0x9654940a00000000, 0xa1ce232200000000, + 0x7026c42c00000000, 0x031fec3f00000000, 0xd2f70b3100000000, + 0x6d2b836e00000000, 0xbcc3646000000000, 0xcffa4c7300000000, + 0x1e12ab7d00000000, 0x29881c5500000000, 0xf860fb5b00000000, + 0x8b59d34800000000, 0x5ab1344600000000, 0xf5e0c2f700000000, + 0x240825f900000000, 0x57310dea00000000, 0x86d9eae400000000, + 0xb1435dcc00000000, 0x60abbac200000000, 0x139292d100000000, + 0xc27a75df00000000, 0x7da6fd8000000000, 0xac4e1a8e00000000, + 0xdf77329d00000000, 0x0e9fd59300000000, 0x390562bb00000000, + 0xe8ed85b500000000, 0x9bd4ada600000000, 0x4a3c4aa800000000, + 0x4649281100000000, 0x97a1cf1f00000000, 0xe498e70c00000000, + 0x3570000200000000, 0x02eab72a00000000, 0xd302502400000000, + 0xa03b783700000000, 0x71d39f3900000000, 0xce0f176600000000, + 0x1fe7f06800000000, 0x6cded87b00000000, 0xbd363f7500000000, + 0x8aac885d00000000, 0x5b446f5300000000, 0x287d474000000000, + 0xf995a04e00000000, 0x56c456ff00000000, 0x872cb1f100000000, + 0xf41599e200000000, 0x25fd7eec00000000, 0x1267c9c400000000, + 0xc38f2eca00000000, 0xb0b606d900000000, 0x615ee1d700000000, + 0xde82698800000000, 0x0f6a8e8600000000, 0x7c53a69500000000, + 0xadbb419b00000000, 0x9a21f6b300000000, 0x4bc911bd00000000, + 0x38f039ae00000000, 0xe918dea000000000, 0x2755a41600000000, + 0xf6bd431800000000, 0x85846b0b00000000, 0x546c8c0500000000, + 0x63f63b2d00000000, 0xb21edc2300000000, 0xc127f43000000000, + 0x10cf133e00000000, 0xaf139b6100000000, 0x7efb7c6f00000000, + 0x0dc2547c00000000, 0xdc2ab37200000000, 0xebb0045a00000000, + 0x3a58e35400000000, 0x4961cb4700000000, 0x98892c4900000000, + 0x37d8daf800000000, 0xe6303df600000000, 0x950915e500000000, + 0x44e1f2eb00000000, 0x737b45c300000000, 0xa293a2cd00000000, + 0xd1aa8ade00000000, 0x00426dd000000000, 0xbf9ee58f00000000, + 0x6e76028100000000, 0x1d4f2a9200000000, 0xcca7cd9c00000000, + 0xfb3d7ab400000000, 0x2ad59dba00000000, 0x59ecb5a900000000, + 0x880452a700000000}, + {0x0000000000000000, 0xaa05daf100000000, 0x150dc53800000000, + 0xbf081fc900000000, 0x2a1a8a7100000000, 0x801f508000000000, + 0x3f174f4900000000, 0x951295b800000000, 0x543414e300000000, + 0xfe31ce1200000000, 0x4139d1db00000000, 0xeb3c0b2a00000000, + 0x7e2e9e9200000000, 0xd42b446300000000, 0x6b235baa00000000, + 0xc126815b00000000, 0xe96e591d00000000, 0x436b83ec00000000, + 0xfc639c2500000000, 0x566646d400000000, 0xc374d36c00000000, + 0x6971099d00000000, 0xd679165400000000, 0x7c7ccca500000000, + 0xbd5a4dfe00000000, 0x175f970f00000000, 0xa85788c600000000, + 0x0252523700000000, 0x9740c78f00000000, 0x3d451d7e00000000, + 0x824d02b700000000, 0x2848d84600000000, 0xd2ddb23a00000000, + 0x78d868cb00000000, 0xc7d0770200000000, 0x6dd5adf300000000, + 0xf8c7384b00000000, 0x52c2e2ba00000000, 0xedcafd7300000000, + 0x47cf278200000000, 0x86e9a6d900000000, 0x2cec7c2800000000, + 0x93e463e100000000, 0x39e1b91000000000, 0xacf32ca800000000, + 0x06f6f65900000000, 0xb9fee99000000000, 0x13fb336100000000, + 0x3bb3eb2700000000, 0x91b631d600000000, 0x2ebe2e1f00000000, + 0x84bbf4ee00000000, 0x11a9615600000000, 0xbbacbba700000000, + 0x04a4a46e00000000, 0xaea17e9f00000000, 0x6f87ffc400000000, + 0xc582253500000000, 0x7a8a3afc00000000, 0xd08fe00d00000000, + 0x459d75b500000000, 0xef98af4400000000, 0x5090b08d00000000, + 0xfa956a7c00000000, 0xa4bb657500000000, 0x0ebebf8400000000, + 0xb1b6a04d00000000, 0x1bb37abc00000000, 0x8ea1ef0400000000, + 0x24a435f500000000, 0x9bac2a3c00000000, 0x31a9f0cd00000000, + 0xf08f719600000000, 0x5a8aab6700000000, 0xe582b4ae00000000, + 0x4f876e5f00000000, 0xda95fbe700000000, 0x7090211600000000, + 0xcf983edf00000000, 0x659de42e00000000, 0x4dd53c6800000000, + 0xe7d0e69900000000, 0x58d8f95000000000, 0xf2dd23a100000000, + 0x67cfb61900000000, 0xcdca6ce800000000, 0x72c2732100000000, + 0xd8c7a9d000000000, 0x19e1288b00000000, 0xb3e4f27a00000000, + 0x0cecedb300000000, 0xa6e9374200000000, 0x33fba2fa00000000, + 0x99fe780b00000000, 0x26f667c200000000, 0x8cf3bd3300000000, + 0x7666d74f00000000, 0xdc630dbe00000000, 0x636b127700000000, + 0xc96ec88600000000, 0x5c7c5d3e00000000, 0xf67987cf00000000, + 0x4971980600000000, 0xe37442f700000000, 0x2252c3ac00000000, + 0x8857195d00000000, 0x375f069400000000, 0x9d5adc6500000000, + 0x084849dd00000000, 0xa24d932c00000000, 0x1d458ce500000000, + 0xb740561400000000, 0x9f088e5200000000, 0x350d54a300000000, + 0x8a054b6a00000000, 0x2000919b00000000, 0xb512042300000000, + 0x1f17ded200000000, 0xa01fc11b00000000, 0x0a1a1bea00000000, + 0xcb3c9ab100000000, 0x6139404000000000, 0xde315f8900000000, + 0x7434857800000000, 0xe12610c000000000, 0x4b23ca3100000000, + 0xf42bd5f800000000, 0x5e2e0f0900000000, 0x4877cbea00000000, + 0xe272111b00000000, 0x5d7a0ed200000000, 0xf77fd42300000000, + 0x626d419b00000000, 0xc8689b6a00000000, 0x776084a300000000, + 0xdd655e5200000000, 0x1c43df0900000000, 0xb64605f800000000, + 0x094e1a3100000000, 0xa34bc0c000000000, 0x3659557800000000, + 0x9c5c8f8900000000, 0x2354904000000000, 0x89514ab100000000, + 0xa11992f700000000, 0x0b1c480600000000, 0xb41457cf00000000, + 0x1e118d3e00000000, 0x8b03188600000000, 0x2106c27700000000, + 0x9e0eddbe00000000, 0x340b074f00000000, 0xf52d861400000000, + 0x5f285ce500000000, 0xe020432c00000000, 0x4a2599dd00000000, + 0xdf370c6500000000, 0x7532d69400000000, 0xca3ac95d00000000, + 0x603f13ac00000000, 0x9aaa79d000000000, 0x30afa32100000000, + 0x8fa7bce800000000, 0x25a2661900000000, 0xb0b0f3a100000000, + 0x1ab5295000000000, 0xa5bd369900000000, 0x0fb8ec6800000000, + 0xce9e6d3300000000, 0x649bb7c200000000, 0xdb93a80b00000000, + 0x719672fa00000000, 0xe484e74200000000, 0x4e813db300000000, + 0xf189227a00000000, 0x5b8cf88b00000000, 0x73c420cd00000000, + 0xd9c1fa3c00000000, 0x66c9e5f500000000, 0xcccc3f0400000000, + 0x59deaabc00000000, 0xf3db704d00000000, 0x4cd36f8400000000, + 0xe6d6b57500000000, 0x27f0342e00000000, 0x8df5eedf00000000, + 0x32fdf11600000000, 0x98f82be700000000, 0x0deabe5f00000000, + 0xa7ef64ae00000000, 0x18e77b6700000000, 0xb2e2a19600000000, + 0xecccae9f00000000, 0x46c9746e00000000, 0xf9c16ba700000000, + 0x53c4b15600000000, 0xc6d624ee00000000, 0x6cd3fe1f00000000, + 0xd3dbe1d600000000, 0x79de3b2700000000, 0xb8f8ba7c00000000, + 0x12fd608d00000000, 0xadf57f4400000000, 0x07f0a5b500000000, + 0x92e2300d00000000, 0x38e7eafc00000000, 0x87eff53500000000, + 0x2dea2fc400000000, 0x05a2f78200000000, 0xafa72d7300000000, + 0x10af32ba00000000, 0xbaaae84b00000000, 0x2fb87df300000000, + 0x85bda70200000000, 0x3ab5b8cb00000000, 0x90b0623a00000000, + 0x5196e36100000000, 0xfb93399000000000, 0x449b265900000000, + 0xee9efca800000000, 0x7b8c691000000000, 0xd189b3e100000000, + 0x6e81ac2800000000, 0xc48476d900000000, 0x3e111ca500000000, + 0x9414c65400000000, 0x2b1cd99d00000000, 0x8119036c00000000, + 0x140b96d400000000, 0xbe0e4c2500000000, 0x010653ec00000000, + 0xab03891d00000000, 0x6a25084600000000, 0xc020d2b700000000, + 0x7f28cd7e00000000, 0xd52d178f00000000, 0x403f823700000000, + 0xea3a58c600000000, 0x5532470f00000000, 0xff379dfe00000000, + 0xd77f45b800000000, 0x7d7a9f4900000000, 0xc272808000000000, + 0x68775a7100000000, 0xfd65cfc900000000, 0x5760153800000000, + 0xe8680af100000000, 0x426dd00000000000, 0x834b515b00000000, + 0x294e8baa00000000, 0x9646946300000000, 0x3c434e9200000000, + 0xa951db2a00000000, 0x035401db00000000, 0xbc5c1e1200000000, + 0x1659c4e300000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87, + 0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede, + 0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab, + 0x8eea673a, 0xe6273e9e, 0x484faf0f, 0x61871bfd, 0xcfef8a6c, + 0x32167219, 0x9c7ee388, 0xb5b6577a, 0x1bdec6eb, 0x9534a1d1, + 0x3b5c3040, 0x129484b2, 0xbcfc1523, 0x4105ed56, 0xef6d7cc7, + 0xc6a5c835, 0x68cd59a4, 0x173f7b7d, 0xb957eaec, 0x909f5e1e, + 0x3ef7cf8f, 0xc30e37fa, 0x6d66a66b, 0x44ae1299, 0xeac68308, + 0x642ce432, 0xca4475a3, 0xe38cc151, 0x4de450c0, 0xb01da8b5, + 0x1e753924, 0x37bd8dd6, 0x99d51c47, 0xf11845e3, 0x5f70d472, + 0x76b86080, 0xd8d0f111, 0x25290964, 0x8b4198f5, 0xa2892c07, + 0x0ce1bd96, 0x820bdaac, 0x2c634b3d, 0x05abffcf, 0xabc36e5e, + 0x563a962b, 0xf85207ba, 0xd19ab348, 0x7ff222d9, 0x2e7ef6fa, + 0x8016676b, 0xa9ded399, 0x07b64208, 0xfa4fba7d, 0x54272bec, + 0x7def9f1e, 0xd3870e8f, 0x5d6d69b5, 0xf305f824, 0xdacd4cd6, + 0x74a5dd47, 0x895c2532, 0x2734b4a3, 0x0efc0051, 0xa09491c0, + 0xc859c864, 0x663159f5, 0x4ff9ed07, 0xe1917c96, 0x1c6884e3, + 0xb2001572, 0x9bc8a180, 0x35a03011, 0xbb4a572b, 0x1522c6ba, + 0x3cea7248, 0x9282e3d9, 0x6f7b1bac, 0xc1138a3d, 0xe8db3ecf, + 0x46b3af5e, 0x39418d87, 0x97291c16, 0xbee1a8e4, 0x10893975, + 0xed70c100, 0x43185091, 0x6ad0e463, 0xc4b875f2, 0x4a5212c8, + 0xe43a8359, 0xcdf237ab, 0x639aa63a, 0x9e635e4f, 0x300bcfde, + 0x19c37b2c, 0xb7abeabd, 0xdf66b319, 0x710e2288, 0x58c6967a, + 0xf6ae07eb, 0x0b57ff9e, 0xa53f6e0f, 0x8cf7dafd, 0x229f4b6c, + 0xac752c56, 0x021dbdc7, 0x2bd50935, 0x85bd98a4, 0x784460d1, + 0xd62cf140, 0xffe445b2, 0x518cd423, 0x5cfdedf4, 0xf2957c65, + 0xdb5dc897, 0x75355906, 0x88cca173, 0x26a430e2, 0x0f6c8410, + 0xa1041581, 0x2fee72bb, 0x8186e32a, 0xa84e57d8, 0x0626c649, + 0xfbdf3e3c, 0x55b7afad, 0x7c7f1b5f, 0xd2178ace, 0xbadad36a, + 0x14b242fb, 0x3d7af609, 0x93126798, 0x6eeb9fed, 0xc0830e7c, + 0xe94bba8e, 0x47232b1f, 0xc9c94c25, 0x67a1ddb4, 0x4e696946, + 0xe001f8d7, 0x1df800a2, 0xb3909133, 0x9a5825c1, 0x3430b450, + 0x4bc29689, 0xe5aa0718, 0xcc62b3ea, 0x620a227b, 0x9ff3da0e, + 0x319b4b9f, 0x1853ff6d, 0xb63b6efc, 0x38d109c6, 0x96b99857, + 0xbf712ca5, 0x1119bd34, 0xece04541, 0x4288d4d0, 0x6b406022, + 0xc528f1b3, 0xade5a817, 0x038d3986, 0x2a458d74, 0x842d1ce5, + 0x79d4e490, 0xd7bc7501, 0xfe74c1f3, 0x501c5062, 0xdef63758, + 0x709ea6c9, 0x5956123b, 0xf73e83aa, 0x0ac77bdf, 0xa4afea4e, + 0x8d675ebc, 0x230fcf2d, 0x72831b0e, 0xdceb8a9f, 0xf5233e6d, + 0x5b4baffc, 0xa6b25789, 0x08dac618, 0x211272ea, 0x8f7ae37b, + 0x01908441, 0xaff815d0, 0x8630a122, 0x285830b3, 0xd5a1c8c6, + 0x7bc95957, 0x5201eda5, 0xfc697c34, 0x94a42590, 0x3accb401, + 0x130400f3, 0xbd6c9162, 0x40956917, 0xeefdf886, 0xc7354c74, + 0x695ddde5, 0xe7b7badf, 0x49df2b4e, 0x60179fbc, 0xce7f0e2d, + 0x3386f658, 0x9dee67c9, 0xb426d33b, 0x1a4e42aa, 0x65bc6073, + 0xcbd4f1e2, 0xe21c4510, 0x4c74d481, 0xb18d2cf4, 0x1fe5bd65, + 0x362d0997, 0x98459806, 0x16afff3c, 0xb8c76ead, 0x910fda5f, + 0x3f674bce, 0xc29eb3bb, 0x6cf6222a, 0x453e96d8, 0xeb560749, + 0x839b5eed, 0x2df3cf7c, 0x043b7b8e, 0xaa53ea1f, 0x57aa126a, + 0xf9c283fb, 0xd00a3709, 0x7e62a698, 0xf088c1a2, 0x5ee05033, + 0x7728e4c1, 0xd9407550, 0x24b98d25, 0x8ad11cb4, 0xa319a846, + 0x0d7139d7}, + {0x00000000, 0xb9fbdbe8, 0xa886b191, 0x117d6a79, 0x8a7c6563, + 0x3387be8b, 0x22fad4f2, 0x9b010f1a, 0xcf89cc87, 0x7672176f, + 0x670f7d16, 0xdef4a6fe, 0x45f5a9e4, 0xfc0e720c, 0xed731875, + 0x5488c39d, 0x44629f4f, 0xfd9944a7, 0xece42ede, 0x551ff536, + 0xce1efa2c, 0x77e521c4, 0x66984bbd, 0xdf639055, 0x8beb53c8, + 0x32108820, 0x236de259, 0x9a9639b1, 0x019736ab, 0xb86ced43, + 0xa911873a, 0x10ea5cd2, 0x88c53e9e, 0x313ee576, 0x20438f0f, + 0x99b854e7, 0x02b95bfd, 0xbb428015, 0xaa3fea6c, 0x13c43184, + 0x474cf219, 0xfeb729f1, 0xefca4388, 0x56319860, 0xcd30977a, + 0x74cb4c92, 0x65b626eb, 0xdc4dfd03, 0xcca7a1d1, 0x755c7a39, + 0x64211040, 0xdddacba8, 0x46dbc4b2, 0xff201f5a, 0xee5d7523, + 0x57a6aecb, 0x032e6d56, 0xbad5b6be, 0xaba8dcc7, 0x1253072f, + 0x89520835, 0x30a9d3dd, 0x21d4b9a4, 0x982f624c, 0xcafb7b7d, + 0x7300a095, 0x627dcaec, 0xdb861104, 0x40871e1e, 0xf97cc5f6, + 0xe801af8f, 0x51fa7467, 0x0572b7fa, 0xbc896c12, 0xadf4066b, + 0x140fdd83, 0x8f0ed299, 0x36f50971, 0x27886308, 0x9e73b8e0, + 0x8e99e432, 0x37623fda, 0x261f55a3, 0x9fe48e4b, 0x04e58151, + 0xbd1e5ab9, 0xac6330c0, 0x1598eb28, 0x411028b5, 0xf8ebf35d, + 0xe9969924, 0x506d42cc, 0xcb6c4dd6, 0x7297963e, 0x63eafc47, + 0xda1127af, 0x423e45e3, 0xfbc59e0b, 0xeab8f472, 0x53432f9a, + 0xc8422080, 0x71b9fb68, 0x60c49111, 0xd93f4af9, 0x8db78964, + 0x344c528c, 0x253138f5, 0x9ccae31d, 0x07cbec07, 0xbe3037ef, + 0xaf4d5d96, 0x16b6867e, 0x065cdaac, 0xbfa70144, 0xaeda6b3d, + 0x1721b0d5, 0x8c20bfcf, 0x35db6427, 0x24a60e5e, 0x9d5dd5b6, + 0xc9d5162b, 0x702ecdc3, 0x6153a7ba, 0xd8a87c52, 0x43a97348, + 0xfa52a8a0, 0xeb2fc2d9, 0x52d41931, 0x4e87f0bb, 0xf77c2b53, + 0xe601412a, 0x5ffa9ac2, 0xc4fb95d8, 0x7d004e30, 0x6c7d2449, + 0xd586ffa1, 0x810e3c3c, 0x38f5e7d4, 0x29888dad, 0x90735645, + 0x0b72595f, 0xb28982b7, 0xa3f4e8ce, 0x1a0f3326, 0x0ae56ff4, + 0xb31eb41c, 0xa263de65, 0x1b98058d, 0x80990a97, 0x3962d17f, + 0x281fbb06, 0x91e460ee, 0xc56ca373, 0x7c97789b, 0x6dea12e2, + 0xd411c90a, 0x4f10c610, 0xf6eb1df8, 0xe7967781, 0x5e6dac69, + 0xc642ce25, 0x7fb915cd, 0x6ec47fb4, 0xd73fa45c, 0x4c3eab46, + 0xf5c570ae, 0xe4b81ad7, 0x5d43c13f, 0x09cb02a2, 0xb030d94a, + 0xa14db333, 0x18b668db, 0x83b767c1, 0x3a4cbc29, 0x2b31d650, + 0x92ca0db8, 0x8220516a, 0x3bdb8a82, 0x2aa6e0fb, 0x935d3b13, + 0x085c3409, 0xb1a7efe1, 0xa0da8598, 0x19215e70, 0x4da99ded, + 0xf4524605, 0xe52f2c7c, 0x5cd4f794, 0xc7d5f88e, 0x7e2e2366, + 0x6f53491f, 0xd6a892f7, 0x847c8bc6, 0x3d87502e, 0x2cfa3a57, + 0x9501e1bf, 0x0e00eea5, 0xb7fb354d, 0xa6865f34, 0x1f7d84dc, + 0x4bf54741, 0xf20e9ca9, 0xe373f6d0, 0x5a882d38, 0xc1892222, + 0x7872f9ca, 0x690f93b3, 0xd0f4485b, 0xc01e1489, 0x79e5cf61, + 0x6898a518, 0xd1637ef0, 0x4a6271ea, 0xf399aa02, 0xe2e4c07b, + 0x5b1f1b93, 0x0f97d80e, 0xb66c03e6, 0xa711699f, 0x1eeab277, + 0x85ebbd6d, 0x3c106685, 0x2d6d0cfc, 0x9496d714, 0x0cb9b558, + 0xb5426eb0, 0xa43f04c9, 0x1dc4df21, 0x86c5d03b, 0x3f3e0bd3, + 0x2e4361aa, 0x97b8ba42, 0xc33079df, 0x7acba237, 0x6bb6c84e, + 0xd24d13a6, 0x494c1cbc, 0xf0b7c754, 0xe1caad2d, 0x583176c5, + 0x48db2a17, 0xf120f1ff, 0xe05d9b86, 0x59a6406e, 0xc2a74f74, + 0x7b5c949c, 0x6a21fee5, 0xd3da250d, 0x8752e690, 0x3ea93d78, + 0x2fd45701, 0x962f8ce9, 0x0d2e83f3, 0xb4d5581b, 0xa5a83262, + 0x1c53e98a}, + {0x00000000, 0x9d0fe176, 0xe16ec4ad, 0x7c6125db, 0x19ac8f1b, + 0x84a36e6d, 0xf8c24bb6, 0x65cdaac0, 0x33591e36, 0xae56ff40, + 0xd237da9b, 0x4f383bed, 0x2af5912d, 0xb7fa705b, 0xcb9b5580, + 0x5694b4f6, 0x66b23c6c, 0xfbbddd1a, 0x87dcf8c1, 0x1ad319b7, + 0x7f1eb377, 0xe2115201, 0x9e7077da, 0x037f96ac, 0x55eb225a, + 0xc8e4c32c, 0xb485e6f7, 0x298a0781, 0x4c47ad41, 0xd1484c37, + 0xad2969ec, 0x3026889a, 0xcd6478d8, 0x506b99ae, 0x2c0abc75, + 0xb1055d03, 0xd4c8f7c3, 0x49c716b5, 0x35a6336e, 0xa8a9d218, + 0xfe3d66ee, 0x63328798, 0x1f53a243, 0x825c4335, 0xe791e9f5, + 0x7a9e0883, 0x06ff2d58, 0x9bf0cc2e, 0xabd644b4, 0x36d9a5c2, + 0x4ab88019, 0xd7b7616f, 0xb27acbaf, 0x2f752ad9, 0x53140f02, + 0xce1bee74, 0x988f5a82, 0x0580bbf4, 0x79e19e2f, 0xe4ee7f59, + 0x8123d599, 0x1c2c34ef, 0x604d1134, 0xfd42f042, 0x41b9f7f1, + 0xdcb61687, 0xa0d7335c, 0x3dd8d22a, 0x581578ea, 0xc51a999c, + 0xb97bbc47, 0x24745d31, 0x72e0e9c7, 0xefef08b1, 0x938e2d6a, + 0x0e81cc1c, 0x6b4c66dc, 0xf64387aa, 0x8a22a271, 0x172d4307, + 0x270bcb9d, 0xba042aeb, 0xc6650f30, 0x5b6aee46, 0x3ea74486, + 0xa3a8a5f0, 0xdfc9802b, 0x42c6615d, 0x1452d5ab, 0x895d34dd, + 0xf53c1106, 0x6833f070, 0x0dfe5ab0, 0x90f1bbc6, 0xec909e1d, + 0x719f7f6b, 0x8cdd8f29, 0x11d26e5f, 0x6db34b84, 0xf0bcaaf2, + 0x95710032, 0x087ee144, 0x741fc49f, 0xe91025e9, 0xbf84911f, + 0x228b7069, 0x5eea55b2, 0xc3e5b4c4, 0xa6281e04, 0x3b27ff72, + 0x4746daa9, 0xda493bdf, 0xea6fb345, 0x77605233, 0x0b0177e8, + 0x960e969e, 0xf3c33c5e, 0x6eccdd28, 0x12adf8f3, 0x8fa21985, + 0xd936ad73, 0x44394c05, 0x385869de, 0xa55788a8, 0xc09a2268, + 0x5d95c31e, 0x21f4e6c5, 0xbcfb07b3, 0x8373efe2, 0x1e7c0e94, + 0x621d2b4f, 0xff12ca39, 0x9adf60f9, 0x07d0818f, 0x7bb1a454, + 0xe6be4522, 0xb02af1d4, 0x2d2510a2, 0x51443579, 0xcc4bd40f, + 0xa9867ecf, 0x34899fb9, 0x48e8ba62, 0xd5e75b14, 0xe5c1d38e, + 0x78ce32f8, 0x04af1723, 0x99a0f655, 0xfc6d5c95, 0x6162bde3, + 0x1d039838, 0x800c794e, 0xd698cdb8, 0x4b972cce, 0x37f60915, + 0xaaf9e863, 0xcf3442a3, 0x523ba3d5, 0x2e5a860e, 0xb3556778, + 0x4e17973a, 0xd318764c, 0xaf795397, 0x3276b2e1, 0x57bb1821, + 0xcab4f957, 0xb6d5dc8c, 0x2bda3dfa, 0x7d4e890c, 0xe041687a, + 0x9c204da1, 0x012facd7, 0x64e20617, 0xf9ede761, 0x858cc2ba, + 0x188323cc, 0x28a5ab56, 0xb5aa4a20, 0xc9cb6ffb, 0x54c48e8d, + 0x3109244d, 0xac06c53b, 0xd067e0e0, 0x4d680196, 0x1bfcb560, + 0x86f35416, 0xfa9271cd, 0x679d90bb, 0x02503a7b, 0x9f5fdb0d, + 0xe33efed6, 0x7e311fa0, 0xc2ca1813, 0x5fc5f965, 0x23a4dcbe, + 0xbeab3dc8, 0xdb669708, 0x4669767e, 0x3a0853a5, 0xa707b2d3, + 0xf1930625, 0x6c9ce753, 0x10fdc288, 0x8df223fe, 0xe83f893e, + 0x75306848, 0x09514d93, 0x945eace5, 0xa478247f, 0x3977c509, + 0x4516e0d2, 0xd81901a4, 0xbdd4ab64, 0x20db4a12, 0x5cba6fc9, + 0xc1b58ebf, 0x97213a49, 0x0a2edb3f, 0x764ffee4, 0xeb401f92, + 0x8e8db552, 0x13825424, 0x6fe371ff, 0xf2ec9089, 0x0fae60cb, + 0x92a181bd, 0xeec0a466, 0x73cf4510, 0x1602efd0, 0x8b0d0ea6, + 0xf76c2b7d, 0x6a63ca0b, 0x3cf77efd, 0xa1f89f8b, 0xdd99ba50, + 0x40965b26, 0x255bf1e6, 0xb8541090, 0xc435354b, 0x593ad43d, + 0x691c5ca7, 0xf413bdd1, 0x8872980a, 0x157d797c, 0x70b0d3bc, + 0xedbf32ca, 0x91de1711, 0x0cd1f667, 0x5a454291, 0xc74aa3e7, + 0xbb2b863c, 0x2624674a, 0x43e9cd8a, 0xdee62cfc, 0xa2870927, + 0x3f88e851}, + {0x00000000, 0xdd96d985, 0x605cb54b, 0xbdca6cce, 0xc0b96a96, + 0x1d2fb313, 0xa0e5dfdd, 0x7d730658, 0x5a03d36d, 0x87950ae8, + 0x3a5f6626, 0xe7c9bfa3, 0x9abab9fb, 0x472c607e, 0xfae60cb0, + 0x2770d535, 0xb407a6da, 0x69917f5f, 0xd45b1391, 0x09cdca14, + 0x74becc4c, 0xa92815c9, 0x14e27907, 0xc974a082, 0xee0475b7, + 0x3392ac32, 0x8e58c0fc, 0x53ce1979, 0x2ebd1f21, 0xf32bc6a4, + 0x4ee1aa6a, 0x937773ef, 0xb37e4bf5, 0x6ee89270, 0xd322febe, + 0x0eb4273b, 0x73c72163, 0xae51f8e6, 0x139b9428, 0xce0d4dad, + 0xe97d9898, 0x34eb411d, 0x89212dd3, 0x54b7f456, 0x29c4f20e, + 0xf4522b8b, 0x49984745, 0x940e9ec0, 0x0779ed2f, 0xdaef34aa, + 0x67255864, 0xbab381e1, 0xc7c087b9, 0x1a565e3c, 0xa79c32f2, + 0x7a0aeb77, 0x5d7a3e42, 0x80ece7c7, 0x3d268b09, 0xe0b0528c, + 0x9dc354d4, 0x40558d51, 0xfd9fe19f, 0x2009381a, 0xbd8d91ab, + 0x601b482e, 0xddd124e0, 0x0047fd65, 0x7d34fb3d, 0xa0a222b8, + 0x1d684e76, 0xc0fe97f3, 0xe78e42c6, 0x3a189b43, 0x87d2f78d, + 0x5a442e08, 0x27372850, 0xfaa1f1d5, 0x476b9d1b, 0x9afd449e, + 0x098a3771, 0xd41ceef4, 0x69d6823a, 0xb4405bbf, 0xc9335de7, + 0x14a58462, 0xa96fe8ac, 0x74f93129, 0x5389e41c, 0x8e1f3d99, + 0x33d55157, 0xee4388d2, 0x93308e8a, 0x4ea6570f, 0xf36c3bc1, + 0x2efae244, 0x0ef3da5e, 0xd36503db, 0x6eaf6f15, 0xb339b690, + 0xce4ab0c8, 0x13dc694d, 0xae160583, 0x7380dc06, 0x54f00933, + 0x8966d0b6, 0x34acbc78, 0xe93a65fd, 0x944963a5, 0x49dfba20, + 0xf415d6ee, 0x29830f6b, 0xbaf47c84, 0x6762a501, 0xdaa8c9cf, + 0x073e104a, 0x7a4d1612, 0xa7dbcf97, 0x1a11a359, 0xc7877adc, + 0xe0f7afe9, 0x3d61766c, 0x80ab1aa2, 0x5d3dc327, 0x204ec57f, + 0xfdd81cfa, 0x40127034, 0x9d84a9b1, 0xa06a2517, 0x7dfcfc92, + 0xc036905c, 0x1da049d9, 0x60d34f81, 0xbd459604, 0x008ffaca, + 0xdd19234f, 0xfa69f67a, 0x27ff2fff, 0x9a354331, 0x47a39ab4, + 0x3ad09cec, 0xe7464569, 0x5a8c29a7, 0x871af022, 0x146d83cd, + 0xc9fb5a48, 0x74313686, 0xa9a7ef03, 0xd4d4e95b, 0x094230de, + 0xb4885c10, 0x691e8595, 0x4e6e50a0, 0x93f88925, 0x2e32e5eb, + 0xf3a43c6e, 0x8ed73a36, 0x5341e3b3, 0xee8b8f7d, 0x331d56f8, + 0x13146ee2, 0xce82b767, 0x7348dba9, 0xaede022c, 0xd3ad0474, + 0x0e3bddf1, 0xb3f1b13f, 0x6e6768ba, 0x4917bd8f, 0x9481640a, + 0x294b08c4, 0xf4ddd141, 0x89aed719, 0x54380e9c, 0xe9f26252, + 0x3464bbd7, 0xa713c838, 0x7a8511bd, 0xc74f7d73, 0x1ad9a4f6, + 0x67aaa2ae, 0xba3c7b2b, 0x07f617e5, 0xda60ce60, 0xfd101b55, + 0x2086c2d0, 0x9d4cae1e, 0x40da779b, 0x3da971c3, 0xe03fa846, + 0x5df5c488, 0x80631d0d, 0x1de7b4bc, 0xc0716d39, 0x7dbb01f7, + 0xa02dd872, 0xdd5ede2a, 0x00c807af, 0xbd026b61, 0x6094b2e4, + 0x47e467d1, 0x9a72be54, 0x27b8d29a, 0xfa2e0b1f, 0x875d0d47, + 0x5acbd4c2, 0xe701b80c, 0x3a976189, 0xa9e01266, 0x7476cbe3, + 0xc9bca72d, 0x142a7ea8, 0x695978f0, 0xb4cfa175, 0x0905cdbb, + 0xd493143e, 0xf3e3c10b, 0x2e75188e, 0x93bf7440, 0x4e29adc5, + 0x335aab9d, 0xeecc7218, 0x53061ed6, 0x8e90c753, 0xae99ff49, + 0x730f26cc, 0xcec54a02, 0x13539387, 0x6e2095df, 0xb3b64c5a, + 0x0e7c2094, 0xd3eaf911, 0xf49a2c24, 0x290cf5a1, 0x94c6996f, + 0x495040ea, 0x342346b2, 0xe9b59f37, 0x547ff3f9, 0x89e92a7c, + 0x1a9e5993, 0xc7088016, 0x7ac2ecd8, 0xa754355d, 0xda273305, + 0x07b1ea80, 0xba7b864e, 0x67ed5fcb, 0x409d8afe, 0x9d0b537b, + 0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523, + 0x3dee8ca6}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x85d996dd, 0x4bb55c60, 0xce6ccabd, 0x966ab9c0, + 0x13b32f1d, 0xdddfe5a0, 0x5806737d, 0x6dd3035a, 0xe80a9587, + 0x26665f3a, 0xa3bfc9e7, 0xfbb9ba9a, 0x7e602c47, 0xb00ce6fa, + 0x35d57027, 0xdaa607b4, 0x5f7f9169, 0x91135bd4, 0x14cacd09, + 0x4cccbe74, 0xc91528a9, 0x0779e214, 0x82a074c9, 0xb77504ee, + 0x32ac9233, 0xfcc0588e, 0x7919ce53, 0x211fbd2e, 0xa4c62bf3, + 0x6aaae14e, 0xef737793, 0xf54b7eb3, 0x7092e86e, 0xbefe22d3, + 0x3b27b40e, 0x6321c773, 0xe6f851ae, 0x28949b13, 0xad4d0dce, + 0x98987de9, 0x1d41eb34, 0xd32d2189, 0x56f4b754, 0x0ef2c429, + 0x8b2b52f4, 0x45479849, 0xc09e0e94, 0x2fed7907, 0xaa34efda, + 0x64582567, 0xe181b3ba, 0xb987c0c7, 0x3c5e561a, 0xf2329ca7, + 0x77eb0a7a, 0x423e7a5d, 0xc7e7ec80, 0x098b263d, 0x8c52b0e0, + 0xd454c39d, 0x518d5540, 0x9fe19ffd, 0x1a380920, 0xab918dbd, + 0x2e481b60, 0xe024d1dd, 0x65fd4700, 0x3dfb347d, 0xb822a2a0, + 0x764e681d, 0xf397fec0, 0xc6428ee7, 0x439b183a, 0x8df7d287, + 0x082e445a, 0x50283727, 0xd5f1a1fa, 0x1b9d6b47, 0x9e44fd9a, + 0x71378a09, 0xf4ee1cd4, 0x3a82d669, 0xbf5b40b4, 0xe75d33c9, + 0x6284a514, 0xace86fa9, 0x2931f974, 0x1ce48953, 0x993d1f8e, + 0x5751d533, 0xd28843ee, 0x8a8e3093, 0x0f57a64e, 0xc13b6cf3, + 0x44e2fa2e, 0x5edaf30e, 0xdb0365d3, 0x156faf6e, 0x90b639b3, + 0xc8b04ace, 0x4d69dc13, 0x830516ae, 0x06dc8073, 0x3309f054, + 0xb6d06689, 0x78bcac34, 0xfd653ae9, 0xa5634994, 0x20badf49, + 0xeed615f4, 0x6b0f8329, 0x847cf4ba, 0x01a56267, 0xcfc9a8da, + 0x4a103e07, 0x12164d7a, 0x97cfdba7, 0x59a3111a, 0xdc7a87c7, + 0xe9aff7e0, 0x6c76613d, 0xa21aab80, 0x27c33d5d, 0x7fc54e20, + 0xfa1cd8fd, 0x34701240, 0xb1a9849d, 0x17256aa0, 0x92fcfc7d, + 0x5c9036c0, 0xd949a01d, 0x814fd360, 0x049645bd, 0xcafa8f00, + 0x4f2319dd, 0x7af669fa, 0xff2fff27, 0x3143359a, 0xb49aa347, + 0xec9cd03a, 0x694546e7, 0xa7298c5a, 0x22f01a87, 0xcd836d14, + 0x485afbc9, 0x86363174, 0x03efa7a9, 0x5be9d4d4, 0xde304209, + 0x105c88b4, 0x95851e69, 0xa0506e4e, 0x2589f893, 0xebe5322e, + 0x6e3ca4f3, 0x363ad78e, 0xb3e34153, 0x7d8f8bee, 0xf8561d33, + 0xe26e1413, 0x67b782ce, 0xa9db4873, 0x2c02deae, 0x7404add3, + 0xf1dd3b0e, 0x3fb1f1b3, 0xba68676e, 0x8fbd1749, 0x0a648194, + 0xc4084b29, 0x41d1ddf4, 0x19d7ae89, 0x9c0e3854, 0x5262f2e9, + 0xd7bb6434, 0x38c813a7, 0xbd11857a, 0x737d4fc7, 0xf6a4d91a, + 0xaea2aa67, 0x2b7b3cba, 0xe517f607, 0x60ce60da, 0x551b10fd, + 0xd0c28620, 0x1eae4c9d, 0x9b77da40, 0xc371a93d, 0x46a83fe0, + 0x88c4f55d, 0x0d1d6380, 0xbcb4e71d, 0x396d71c0, 0xf701bb7d, + 0x72d82da0, 0x2ade5edd, 0xaf07c800, 0x616b02bd, 0xe4b29460, + 0xd167e447, 0x54be729a, 0x9ad2b827, 0x1f0b2efa, 0x470d5d87, + 0xc2d4cb5a, 0x0cb801e7, 0x8961973a, 0x6612e0a9, 0xe3cb7674, + 0x2da7bcc9, 0xa87e2a14, 0xf0785969, 0x75a1cfb4, 0xbbcd0509, + 0x3e1493d4, 0x0bc1e3f3, 0x8e18752e, 0x4074bf93, 0xc5ad294e, + 0x9dab5a33, 0x1872ccee, 0xd61e0653, 0x53c7908e, 0x49ff99ae, + 0xcc260f73, 0x024ac5ce, 0x87935313, 0xdf95206e, 0x5a4cb6b3, + 0x94207c0e, 0x11f9ead3, 0x242c9af4, 0xa1f50c29, 0x6f99c694, + 0xea405049, 0xb2462334, 0x379fb5e9, 0xf9f37f54, 0x7c2ae989, + 0x93599e1a, 0x168008c7, 0xd8ecc27a, 0x5d3554a7, 0x053327da, + 0x80eab107, 0x4e867bba, 0xcb5fed67, 0xfe8a9d40, 0x7b530b9d, + 0xb53fc120, 0x30e657fd, 0x68e02480, 0xed39b25d, 0x235578e0, + 0xa68cee3d}, + {0x00000000, 0x76e10f9d, 0xadc46ee1, 0xdb25617c, 0x1b8fac19, + 0x6d6ea384, 0xb64bc2f8, 0xc0aacd65, 0x361e5933, 0x40ff56ae, + 0x9bda37d2, 0xed3b384f, 0x2d91f52a, 0x5b70fab7, 0x80559bcb, + 0xf6b49456, 0x6c3cb266, 0x1addbdfb, 0xc1f8dc87, 0xb719d31a, + 0x77b31e7f, 0x015211e2, 0xda77709e, 0xac967f03, 0x5a22eb55, + 0x2cc3e4c8, 0xf7e685b4, 0x81078a29, 0x41ad474c, 0x374c48d1, + 0xec6929ad, 0x9a882630, 0xd87864cd, 0xae996b50, 0x75bc0a2c, + 0x035d05b1, 0xc3f7c8d4, 0xb516c749, 0x6e33a635, 0x18d2a9a8, + 0xee663dfe, 0x98873263, 0x43a2531f, 0x35435c82, 0xf5e991e7, + 0x83089e7a, 0x582dff06, 0x2eccf09b, 0xb444d6ab, 0xc2a5d936, + 0x1980b84a, 0x6f61b7d7, 0xafcb7ab2, 0xd92a752f, 0x020f1453, + 0x74ee1bce, 0x825a8f98, 0xf4bb8005, 0x2f9ee179, 0x597feee4, + 0x99d52381, 0xef342c1c, 0x34114d60, 0x42f042fd, 0xf1f7b941, + 0x8716b6dc, 0x5c33d7a0, 0x2ad2d83d, 0xea781558, 0x9c991ac5, + 0x47bc7bb9, 0x315d7424, 0xc7e9e072, 0xb108efef, 0x6a2d8e93, + 0x1ccc810e, 0xdc664c6b, 0xaa8743f6, 0x71a2228a, 0x07432d17, + 0x9dcb0b27, 0xeb2a04ba, 0x300f65c6, 0x46ee6a5b, 0x8644a73e, + 0xf0a5a8a3, 0x2b80c9df, 0x5d61c642, 0xabd55214, 0xdd345d89, + 0x06113cf5, 0x70f03368, 0xb05afe0d, 0xc6bbf190, 0x1d9e90ec, + 0x6b7f9f71, 0x298fdd8c, 0x5f6ed211, 0x844bb36d, 0xf2aabcf0, + 0x32007195, 0x44e17e08, 0x9fc41f74, 0xe92510e9, 0x1f9184bf, + 0x69708b22, 0xb255ea5e, 0xc4b4e5c3, 0x041e28a6, 0x72ff273b, + 0xa9da4647, 0xdf3b49da, 0x45b36fea, 0x33526077, 0xe877010b, + 0x9e960e96, 0x5e3cc3f3, 0x28ddcc6e, 0xf3f8ad12, 0x8519a28f, + 0x73ad36d9, 0x054c3944, 0xde695838, 0xa88857a5, 0x68229ac0, + 0x1ec3955d, 0xc5e6f421, 0xb307fbbc, 0xe2ef7383, 0x940e7c1e, + 0x4f2b1d62, 0x39ca12ff, 0xf960df9a, 0x8f81d007, 0x54a4b17b, + 0x2245bee6, 0xd4f12ab0, 0xa210252d, 0x79354451, 0x0fd44bcc, + 0xcf7e86a9, 0xb99f8934, 0x62bae848, 0x145be7d5, 0x8ed3c1e5, + 0xf832ce78, 0x2317af04, 0x55f6a099, 0x955c6dfc, 0xe3bd6261, + 0x3898031d, 0x4e790c80, 0xb8cd98d6, 0xce2c974b, 0x1509f637, + 0x63e8f9aa, 0xa34234cf, 0xd5a33b52, 0x0e865a2e, 0x786755b3, + 0x3a97174e, 0x4c7618d3, 0x975379af, 0xe1b27632, 0x2118bb57, + 0x57f9b4ca, 0x8cdcd5b6, 0xfa3dda2b, 0x0c894e7d, 0x7a6841e0, + 0xa14d209c, 0xd7ac2f01, 0x1706e264, 0x61e7edf9, 0xbac28c85, + 0xcc238318, 0x56aba528, 0x204aaab5, 0xfb6fcbc9, 0x8d8ec454, + 0x4d240931, 0x3bc506ac, 0xe0e067d0, 0x9601684d, 0x60b5fc1b, + 0x1654f386, 0xcd7192fa, 0xbb909d67, 0x7b3a5002, 0x0ddb5f9f, + 0xd6fe3ee3, 0xa01f317e, 0x1318cac2, 0x65f9c55f, 0xbedca423, + 0xc83dabbe, 0x089766db, 0x7e766946, 0xa553083a, 0xd3b207a7, + 0x250693f1, 0x53e79c6c, 0x88c2fd10, 0xfe23f28d, 0x3e893fe8, + 0x48683075, 0x934d5109, 0xe5ac5e94, 0x7f2478a4, 0x09c57739, + 0xd2e01645, 0xa40119d8, 0x64abd4bd, 0x124adb20, 0xc96fba5c, + 0xbf8eb5c1, 0x493a2197, 0x3fdb2e0a, 0xe4fe4f76, 0x921f40eb, + 0x52b58d8e, 0x24548213, 0xff71e36f, 0x8990ecf2, 0xcb60ae0f, + 0xbd81a192, 0x66a4c0ee, 0x1045cf73, 0xd0ef0216, 0xa60e0d8b, + 0x7d2b6cf7, 0x0bca636a, 0xfd7ef73c, 0x8b9ff8a1, 0x50ba99dd, + 0x265b9640, 0xe6f15b25, 0x901054b8, 0x4b3535c4, 0x3dd43a59, + 0xa75c1c69, 0xd1bd13f4, 0x0a987288, 0x7c797d15, 0xbcd3b070, + 0xca32bfed, 0x1117de91, 0x67f6d10c, 0x9142455a, 0xe7a34ac7, + 0x3c862bbb, 0x4a672426, 0x8acde943, 0xfc2ce6de, 0x270987a2, + 0x51e8883f}, + {0x00000000, 0xe8dbfbb9, 0x91b186a8, 0x796a7d11, 0x63657c8a, + 0x8bbe8733, 0xf2d4fa22, 0x1a0f019b, 0x87cc89cf, 0x6f177276, + 0x167d0f67, 0xfea6f4de, 0xe4a9f545, 0x0c720efc, 0x751873ed, + 0x9dc38854, 0x4f9f6244, 0xa74499fd, 0xde2ee4ec, 0x36f51f55, + 0x2cfa1ece, 0xc421e577, 0xbd4b9866, 0x559063df, 0xc853eb8b, + 0x20881032, 0x59e26d23, 0xb139969a, 0xab369701, 0x43ed6cb8, + 0x3a8711a9, 0xd25cea10, 0x9e3ec588, 0x76e53e31, 0x0f8f4320, + 0xe754b899, 0xfd5bb902, 0x158042bb, 0x6cea3faa, 0x8431c413, + 0x19f24c47, 0xf129b7fe, 0x8843caef, 0x60983156, 0x7a9730cd, + 0x924ccb74, 0xeb26b665, 0x03fd4ddc, 0xd1a1a7cc, 0x397a5c75, + 0x40102164, 0xa8cbdadd, 0xb2c4db46, 0x5a1f20ff, 0x23755dee, + 0xcbaea657, 0x566d2e03, 0xbeb6d5ba, 0xc7dca8ab, 0x2f075312, + 0x35085289, 0xddd3a930, 0xa4b9d421, 0x4c622f98, 0x7d7bfbca, + 0x95a00073, 0xecca7d62, 0x041186db, 0x1e1e8740, 0xf6c57cf9, + 0x8faf01e8, 0x6774fa51, 0xfab77205, 0x126c89bc, 0x6b06f4ad, + 0x83dd0f14, 0x99d20e8f, 0x7109f536, 0x08638827, 0xe0b8739e, + 0x32e4998e, 0xda3f6237, 0xa3551f26, 0x4b8ee49f, 0x5181e504, + 0xb95a1ebd, 0xc03063ac, 0x28eb9815, 0xb5281041, 0x5df3ebf8, + 0x249996e9, 0xcc426d50, 0xd64d6ccb, 0x3e969772, 0x47fcea63, + 0xaf2711da, 0xe3453e42, 0x0b9ec5fb, 0x72f4b8ea, 0x9a2f4353, + 0x802042c8, 0x68fbb971, 0x1191c460, 0xf94a3fd9, 0x6489b78d, + 0x8c524c34, 0xf5383125, 0x1de3ca9c, 0x07eccb07, 0xef3730be, + 0x965d4daf, 0x7e86b616, 0xacda5c06, 0x4401a7bf, 0x3d6bdaae, + 0xd5b02117, 0xcfbf208c, 0x2764db35, 0x5e0ea624, 0xb6d55d9d, + 0x2b16d5c9, 0xc3cd2e70, 0xbaa75361, 0x527ca8d8, 0x4873a943, + 0xa0a852fa, 0xd9c22feb, 0x3119d452, 0xbbf0874e, 0x532b7cf7, + 0x2a4101e6, 0xc29afa5f, 0xd895fbc4, 0x304e007d, 0x49247d6c, + 0xa1ff86d5, 0x3c3c0e81, 0xd4e7f538, 0xad8d8829, 0x45567390, + 0x5f59720b, 0xb78289b2, 0xcee8f4a3, 0x26330f1a, 0xf46fe50a, + 0x1cb41eb3, 0x65de63a2, 0x8d05981b, 0x970a9980, 0x7fd16239, + 0x06bb1f28, 0xee60e491, 0x73a36cc5, 0x9b78977c, 0xe212ea6d, + 0x0ac911d4, 0x10c6104f, 0xf81debf6, 0x817796e7, 0x69ac6d5e, + 0x25ce42c6, 0xcd15b97f, 0xb47fc46e, 0x5ca43fd7, 0x46ab3e4c, + 0xae70c5f5, 0xd71ab8e4, 0x3fc1435d, 0xa202cb09, 0x4ad930b0, + 0x33b34da1, 0xdb68b618, 0xc167b783, 0x29bc4c3a, 0x50d6312b, + 0xb80dca92, 0x6a512082, 0x828adb3b, 0xfbe0a62a, 0x133b5d93, + 0x09345c08, 0xe1efa7b1, 0x9885daa0, 0x705e2119, 0xed9da94d, + 0x054652f4, 0x7c2c2fe5, 0x94f7d45c, 0x8ef8d5c7, 0x66232e7e, + 0x1f49536f, 0xf792a8d6, 0xc68b7c84, 0x2e50873d, 0x573afa2c, + 0xbfe10195, 0xa5ee000e, 0x4d35fbb7, 0x345f86a6, 0xdc847d1f, + 0x4147f54b, 0xa99c0ef2, 0xd0f673e3, 0x382d885a, 0x222289c1, + 0xcaf97278, 0xb3930f69, 0x5b48f4d0, 0x89141ec0, 0x61cfe579, + 0x18a59868, 0xf07e63d1, 0xea71624a, 0x02aa99f3, 0x7bc0e4e2, + 0x931b1f5b, 0x0ed8970f, 0xe6036cb6, 0x9f6911a7, 0x77b2ea1e, + 0x6dbdeb85, 0x8566103c, 0xfc0c6d2d, 0x14d79694, 0x58b5b90c, + 0xb06e42b5, 0xc9043fa4, 0x21dfc41d, 0x3bd0c586, 0xd30b3e3f, + 0xaa61432e, 0x42bab897, 0xdf7930c3, 0x37a2cb7a, 0x4ec8b66b, + 0xa6134dd2, 0xbc1c4c49, 0x54c7b7f0, 0x2dadcae1, 0xc5763158, + 0x172adb48, 0xfff120f1, 0x869b5de0, 0x6e40a659, 0x744fa7c2, + 0x9c945c7b, 0xe5fe216a, 0x0d25dad3, 0x90e65287, 0x783da93e, + 0x0157d42f, 0xe98c2f96, 0xf3832e0d, 0x1b58d5b4, 0x6232a8a5, + 0x8ae9531c}, + {0x00000000, 0x919168ae, 0x6325a087, 0xf2b4c829, 0x874c31d4, + 0x16dd597a, 0xe4699153, 0x75f8f9fd, 0x4f9f1373, 0xde0e7bdd, + 0x2cbab3f4, 0xbd2bdb5a, 0xc8d322a7, 0x59424a09, 0xabf68220, + 0x3a67ea8e, 0x9e3e27e6, 0x0faf4f48, 0xfd1b8761, 0x6c8aefcf, + 0x19721632, 0x88e37e9c, 0x7a57b6b5, 0xebc6de1b, 0xd1a13495, + 0x40305c3b, 0xb2849412, 0x2315fcbc, 0x56ed0541, 0xc77c6def, + 0x35c8a5c6, 0xa459cd68, 0x7d7b3f17, 0xecea57b9, 0x1e5e9f90, + 0x8fcff73e, 0xfa370ec3, 0x6ba6666d, 0x9912ae44, 0x0883c6ea, + 0x32e42c64, 0xa37544ca, 0x51c18ce3, 0xc050e44d, 0xb5a81db0, + 0x2439751e, 0xd68dbd37, 0x471cd599, 0xe34518f1, 0x72d4705f, + 0x8060b876, 0x11f1d0d8, 0x64092925, 0xf598418b, 0x072c89a2, + 0x96bde10c, 0xacda0b82, 0x3d4b632c, 0xcfffab05, 0x5e6ec3ab, + 0x2b963a56, 0xba0752f8, 0x48b39ad1, 0xd922f27f, 0xfaf67e2e, + 0x6b671680, 0x99d3dea9, 0x0842b607, 0x7dba4ffa, 0xec2b2754, + 0x1e9fef7d, 0x8f0e87d3, 0xb5696d5d, 0x24f805f3, 0xd64ccdda, + 0x47dda574, 0x32255c89, 0xa3b43427, 0x5100fc0e, 0xc09194a0, + 0x64c859c8, 0xf5593166, 0x07edf94f, 0x967c91e1, 0xe384681c, + 0x721500b2, 0x80a1c89b, 0x1130a035, 0x2b574abb, 0xbac62215, + 0x4872ea3c, 0xd9e38292, 0xac1b7b6f, 0x3d8a13c1, 0xcf3edbe8, + 0x5eafb346, 0x878d4139, 0x161c2997, 0xe4a8e1be, 0x75398910, + 0x00c170ed, 0x91501843, 0x63e4d06a, 0xf275b8c4, 0xc812524a, + 0x59833ae4, 0xab37f2cd, 0x3aa69a63, 0x4f5e639e, 0xdecf0b30, + 0x2c7bc319, 0xbdeaabb7, 0x19b366df, 0x88220e71, 0x7a96c658, + 0xeb07aef6, 0x9eff570b, 0x0f6e3fa5, 0xfddaf78c, 0x6c4b9f22, + 0x562c75ac, 0xc7bd1d02, 0x3509d52b, 0xa498bd85, 0xd1604478, + 0x40f12cd6, 0xb245e4ff, 0x23d48c51, 0xf4edfd5c, 0x657c95f2, + 0x97c85ddb, 0x06593575, 0x73a1cc88, 0xe230a426, 0x10846c0f, + 0x811504a1, 0xbb72ee2f, 0x2ae38681, 0xd8574ea8, 0x49c62606, + 0x3c3edffb, 0xadafb755, 0x5f1b7f7c, 0xce8a17d2, 0x6ad3daba, + 0xfb42b214, 0x09f67a3d, 0x98671293, 0xed9feb6e, 0x7c0e83c0, + 0x8eba4be9, 0x1f2b2347, 0x254cc9c9, 0xb4dda167, 0x4669694e, + 0xd7f801e0, 0xa200f81d, 0x339190b3, 0xc125589a, 0x50b43034, + 0x8996c24b, 0x1807aae5, 0xeab362cc, 0x7b220a62, 0x0edaf39f, + 0x9f4b9b31, 0x6dff5318, 0xfc6e3bb6, 0xc609d138, 0x5798b996, + 0xa52c71bf, 0x34bd1911, 0x4145e0ec, 0xd0d48842, 0x2260406b, + 0xb3f128c5, 0x17a8e5ad, 0x86398d03, 0x748d452a, 0xe51c2d84, + 0x90e4d479, 0x0175bcd7, 0xf3c174fe, 0x62501c50, 0x5837f6de, + 0xc9a69e70, 0x3b125659, 0xaa833ef7, 0xdf7bc70a, 0x4eeaafa4, + 0xbc5e678d, 0x2dcf0f23, 0x0e1b8372, 0x9f8aebdc, 0x6d3e23f5, + 0xfcaf4b5b, 0x8957b2a6, 0x18c6da08, 0xea721221, 0x7be37a8f, + 0x41849001, 0xd015f8af, 0x22a13086, 0xb3305828, 0xc6c8a1d5, + 0x5759c97b, 0xa5ed0152, 0x347c69fc, 0x9025a494, 0x01b4cc3a, + 0xf3000413, 0x62916cbd, 0x17699540, 0x86f8fdee, 0x744c35c7, + 0xe5dd5d69, 0xdfbab7e7, 0x4e2bdf49, 0xbc9f1760, 0x2d0e7fce, + 0x58f68633, 0xc967ee9d, 0x3bd326b4, 0xaa424e1a, 0x7360bc65, + 0xe2f1d4cb, 0x10451ce2, 0x81d4744c, 0xf42c8db1, 0x65bde51f, + 0x97092d36, 0x06984598, 0x3cffaf16, 0xad6ec7b8, 0x5fda0f91, + 0xce4b673f, 0xbbb39ec2, 0x2a22f66c, 0xd8963e45, 0x490756eb, + 0xed5e9b83, 0x7ccff32d, 0x8e7b3b04, 0x1fea53aa, 0x6a12aa57, + 0xfb83c2f9, 0x09370ad0, 0x98a6627e, 0xa2c188f0, 0x3350e05e, + 0xc1e42877, 0x507540d9, 0x258db924, 0xb41cd18a, 0x46a819a3, + 0xd739710d}}; + +#endif + +#endif + +#if N == 5 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xaf449247, 0x85f822cf, 0x2abcb088, 0xd08143df, + 0x7fc5d198, 0x55796110, 0xfa3df357, 0x7a7381ff, 0xd53713b8, + 0xff8ba330, 0x50cf3177, 0xaaf2c220, 0x05b65067, 0x2f0ae0ef, + 0x804e72a8, 0xf4e703fe, 0x5ba391b9, 0x711f2131, 0xde5bb376, + 0x24664021, 0x8b22d266, 0xa19e62ee, 0x0edaf0a9, 0x8e948201, + 0x21d01046, 0x0b6ca0ce, 0xa4283289, 0x5e15c1de, 0xf1515399, + 0xdbede311, 0x74a97156, 0x32bf01bd, 0x9dfb93fa, 0xb7472372, + 0x1803b135, 0xe23e4262, 0x4d7ad025, 0x67c660ad, 0xc882f2ea, + 0x48cc8042, 0xe7881205, 0xcd34a28d, 0x627030ca, 0x984dc39d, + 0x370951da, 0x1db5e152, 0xb2f17315, 0xc6580243, 0x691c9004, + 0x43a0208c, 0xece4b2cb, 0x16d9419c, 0xb99dd3db, 0x93216353, + 0x3c65f114, 0xbc2b83bc, 0x136f11fb, 0x39d3a173, 0x96973334, + 0x6caac063, 0xc3ee5224, 0xe952e2ac, 0x461670eb, 0x657e037a, + 0xca3a913d, 0xe08621b5, 0x4fc2b3f2, 0xb5ff40a5, 0x1abbd2e2, + 0x3007626a, 0x9f43f02d, 0x1f0d8285, 0xb04910c2, 0x9af5a04a, + 0x35b1320d, 0xcf8cc15a, 0x60c8531d, 0x4a74e395, 0xe53071d2, + 0x91990084, 0x3edd92c3, 0x1461224b, 0xbb25b00c, 0x4118435b, + 0xee5cd11c, 0xc4e06194, 0x6ba4f3d3, 0xebea817b, 0x44ae133c, + 0x6e12a3b4, 0xc15631f3, 0x3b6bc2a4, 0x942f50e3, 0xbe93e06b, + 0x11d7722c, 0x57c102c7, 0xf8859080, 0xd2392008, 0x7d7db24f, + 0x87404118, 0x2804d35f, 0x02b863d7, 0xadfcf190, 0x2db28338, + 0x82f6117f, 0xa84aa1f7, 0x070e33b0, 0xfd33c0e7, 0x527752a0, + 0x78cbe228, 0xd78f706f, 0xa3260139, 0x0c62937e, 0x26de23f6, + 0x899ab1b1, 0x73a742e6, 0xdce3d0a1, 0xf65f6029, 0x591bf26e, + 0xd95580c6, 0x76111281, 0x5cada209, 0xf3e9304e, 0x09d4c319, + 0xa690515e, 0x8c2ce1d6, 0x23687391, 0xcafc06f4, 0x65b894b3, + 0x4f04243b, 0xe040b67c, 0x1a7d452b, 0xb539d76c, 0x9f8567e4, + 0x30c1f5a3, 0xb08f870b, 0x1fcb154c, 0x3577a5c4, 0x9a333783, + 0x600ec4d4, 0xcf4a5693, 0xe5f6e61b, 0x4ab2745c, 0x3e1b050a, + 0x915f974d, 0xbbe327c5, 0x14a7b582, 0xee9a46d5, 0x41ded492, + 0x6b62641a, 0xc426f65d, 0x446884f5, 0xeb2c16b2, 0xc190a63a, + 0x6ed4347d, 0x94e9c72a, 0x3bad556d, 0x1111e5e5, 0xbe5577a2, + 0xf8430749, 0x5707950e, 0x7dbb2586, 0xd2ffb7c1, 0x28c24496, + 0x8786d6d1, 0xad3a6659, 0x027ef41e, 0x823086b6, 0x2d7414f1, + 0x07c8a479, 0xa88c363e, 0x52b1c569, 0xfdf5572e, 0xd749e7a6, + 0x780d75e1, 0x0ca404b7, 0xa3e096f0, 0x895c2678, 0x2618b43f, + 0xdc254768, 0x7361d52f, 0x59dd65a7, 0xf699f7e0, 0x76d78548, + 0xd993170f, 0xf32fa787, 0x5c6b35c0, 0xa656c697, 0x091254d0, + 0x23aee458, 0x8cea761f, 0xaf82058e, 0x00c697c9, 0x2a7a2741, + 0x853eb506, 0x7f034651, 0xd047d416, 0xfafb649e, 0x55bff6d9, + 0xd5f18471, 0x7ab51636, 0x5009a6be, 0xff4d34f9, 0x0570c7ae, + 0xaa3455e9, 0x8088e561, 0x2fcc7726, 0x5b650670, 0xf4219437, + 0xde9d24bf, 0x71d9b6f8, 0x8be445af, 0x24a0d7e8, 0x0e1c6760, + 0xa158f527, 0x2116878f, 0x8e5215c8, 0xa4eea540, 0x0baa3707, + 0xf197c450, 0x5ed35617, 0x746fe69f, 0xdb2b74d8, 0x9d3d0433, + 0x32799674, 0x18c526fc, 0xb781b4bb, 0x4dbc47ec, 0xe2f8d5ab, + 0xc8446523, 0x6700f764, 0xe74e85cc, 0x480a178b, 0x62b6a703, + 0xcdf23544, 0x37cfc613, 0x988b5454, 0xb237e4dc, 0x1d73769b, + 0x69da07cd, 0xc69e958a, 0xec222502, 0x4366b745, 0xb95b4412, + 0x161fd655, 0x3ca366dd, 0x93e7f49a, 0x13a98632, 0xbced1475, + 0x9651a4fd, 0x391536ba, 0xc328c5ed, 0x6c6c57aa, 0x46d0e722, + 0xe9947565}, + {0x00000000, 0x4e890ba9, 0x9d121752, 0xd39b1cfb, 0xe15528e5, + 0xafdc234c, 0x7c473fb7, 0x32ce341e, 0x19db578b, 0x57525c22, + 0x84c940d9, 0xca404b70, 0xf88e7f6e, 0xb60774c7, 0x659c683c, + 0x2b156395, 0x33b6af16, 0x7d3fa4bf, 0xaea4b844, 0xe02db3ed, + 0xd2e387f3, 0x9c6a8c5a, 0x4ff190a1, 0x01789b08, 0x2a6df89d, + 0x64e4f334, 0xb77fefcf, 0xf9f6e466, 0xcb38d078, 0x85b1dbd1, + 0x562ac72a, 0x18a3cc83, 0x676d5e2c, 0x29e45585, 0xfa7f497e, + 0xb4f642d7, 0x863876c9, 0xc8b17d60, 0x1b2a619b, 0x55a36a32, + 0x7eb609a7, 0x303f020e, 0xe3a41ef5, 0xad2d155c, 0x9fe32142, + 0xd16a2aeb, 0x02f13610, 0x4c783db9, 0x54dbf13a, 0x1a52fa93, + 0xc9c9e668, 0x8740edc1, 0xb58ed9df, 0xfb07d276, 0x289cce8d, + 0x6615c524, 0x4d00a6b1, 0x0389ad18, 0xd012b1e3, 0x9e9bba4a, + 0xac558e54, 0xe2dc85fd, 0x31479906, 0x7fce92af, 0xcedabc58, + 0x8053b7f1, 0x53c8ab0a, 0x1d41a0a3, 0x2f8f94bd, 0x61069f14, + 0xb29d83ef, 0xfc148846, 0xd701ebd3, 0x9988e07a, 0x4a13fc81, + 0x049af728, 0x3654c336, 0x78ddc89f, 0xab46d464, 0xe5cfdfcd, + 0xfd6c134e, 0xb3e518e7, 0x607e041c, 0x2ef70fb5, 0x1c393bab, + 0x52b03002, 0x812b2cf9, 0xcfa22750, 0xe4b744c5, 0xaa3e4f6c, + 0x79a55397, 0x372c583e, 0x05e26c20, 0x4b6b6789, 0x98f07b72, + 0xd67970db, 0xa9b7e274, 0xe73ee9dd, 0x34a5f526, 0x7a2cfe8f, + 0x48e2ca91, 0x066bc138, 0xd5f0ddc3, 0x9b79d66a, 0xb06cb5ff, + 0xfee5be56, 0x2d7ea2ad, 0x63f7a904, 0x51399d1a, 0x1fb096b3, + 0xcc2b8a48, 0x82a281e1, 0x9a014d62, 0xd48846cb, 0x07135a30, + 0x499a5199, 0x7b546587, 0x35dd6e2e, 0xe64672d5, 0xa8cf797c, + 0x83da1ae9, 0xcd531140, 0x1ec80dbb, 0x50410612, 0x628f320c, + 0x2c0639a5, 0xff9d255e, 0xb1142ef7, 0x46c47ef1, 0x084d7558, + 0xdbd669a3, 0x955f620a, 0xa7915614, 0xe9185dbd, 0x3a834146, + 0x740a4aef, 0x5f1f297a, 0x119622d3, 0xc20d3e28, 0x8c843581, + 0xbe4a019f, 0xf0c30a36, 0x235816cd, 0x6dd11d64, 0x7572d1e7, + 0x3bfbda4e, 0xe860c6b5, 0xa6e9cd1c, 0x9427f902, 0xdaaef2ab, + 0x0935ee50, 0x47bce5f9, 0x6ca9866c, 0x22208dc5, 0xf1bb913e, + 0xbf329a97, 0x8dfcae89, 0xc375a520, 0x10eeb9db, 0x5e67b272, + 0x21a920dd, 0x6f202b74, 0xbcbb378f, 0xf2323c26, 0xc0fc0838, + 0x8e750391, 0x5dee1f6a, 0x136714c3, 0x38727756, 0x76fb7cff, + 0xa5606004, 0xebe96bad, 0xd9275fb3, 0x97ae541a, 0x443548e1, + 0x0abc4348, 0x121f8fcb, 0x5c968462, 0x8f0d9899, 0xc1849330, + 0xf34aa72e, 0xbdc3ac87, 0x6e58b07c, 0x20d1bbd5, 0x0bc4d840, + 0x454dd3e9, 0x96d6cf12, 0xd85fc4bb, 0xea91f0a5, 0xa418fb0c, + 0x7783e7f7, 0x390aec5e, 0x881ec2a9, 0xc697c900, 0x150cd5fb, + 0x5b85de52, 0x694bea4c, 0x27c2e1e5, 0xf459fd1e, 0xbad0f6b7, + 0x91c59522, 0xdf4c9e8b, 0x0cd78270, 0x425e89d9, 0x7090bdc7, + 0x3e19b66e, 0xed82aa95, 0xa30ba13c, 0xbba86dbf, 0xf5216616, + 0x26ba7aed, 0x68337144, 0x5afd455a, 0x14744ef3, 0xc7ef5208, + 0x896659a1, 0xa2733a34, 0xecfa319d, 0x3f612d66, 0x71e826cf, + 0x432612d1, 0x0daf1978, 0xde340583, 0x90bd0e2a, 0xef739c85, + 0xa1fa972c, 0x72618bd7, 0x3ce8807e, 0x0e26b460, 0x40afbfc9, + 0x9334a332, 0xddbda89b, 0xf6a8cb0e, 0xb821c0a7, 0x6bbadc5c, + 0x2533d7f5, 0x17fde3eb, 0x5974e842, 0x8aeff4b9, 0xc466ff10, + 0xdcc53393, 0x924c383a, 0x41d724c1, 0x0f5e2f68, 0x3d901b76, + 0x731910df, 0xa0820c24, 0xee0b078d, 0xc51e6418, 0x8b976fb1, + 0x580c734a, 0x168578e3, 0x244b4cfd, 0x6ac24754, 0xb9595baf, + 0xf7d05006}, + {0x00000000, 0x8d88fde2, 0xc060fd85, 0x4de80067, 0x5bb0fd4b, + 0xd63800a9, 0x9bd000ce, 0x1658fd2c, 0xb761fa96, 0x3ae90774, + 0x77010713, 0xfa89faf1, 0xecd107dd, 0x6159fa3f, 0x2cb1fa58, + 0xa13907ba, 0xb5b2f36d, 0x383a0e8f, 0x75d20ee8, 0xf85af30a, + 0xee020e26, 0x638af3c4, 0x2e62f3a3, 0xa3ea0e41, 0x02d309fb, + 0x8f5bf419, 0xc2b3f47e, 0x4f3b099c, 0x5963f4b0, 0xd4eb0952, + 0x99030935, 0x148bf4d7, 0xb014e09b, 0x3d9c1d79, 0x70741d1e, + 0xfdfce0fc, 0xeba41dd0, 0x662ce032, 0x2bc4e055, 0xa64c1db7, + 0x07751a0d, 0x8afde7ef, 0xc715e788, 0x4a9d1a6a, 0x5cc5e746, + 0xd14d1aa4, 0x9ca51ac3, 0x112de721, 0x05a613f6, 0x882eee14, + 0xc5c6ee73, 0x484e1391, 0x5e16eebd, 0xd39e135f, 0x9e761338, + 0x13feeeda, 0xb2c7e960, 0x3f4f1482, 0x72a714e5, 0xff2fe907, + 0xe977142b, 0x64ffe9c9, 0x2917e9ae, 0xa49f144c, 0xbb58c777, + 0x36d03a95, 0x7b383af2, 0xf6b0c710, 0xe0e83a3c, 0x6d60c7de, + 0x2088c7b9, 0xad003a5b, 0x0c393de1, 0x81b1c003, 0xcc59c064, + 0x41d13d86, 0x5789c0aa, 0xda013d48, 0x97e93d2f, 0x1a61c0cd, + 0x0eea341a, 0x8362c9f8, 0xce8ac99f, 0x4302347d, 0x555ac951, + 0xd8d234b3, 0x953a34d4, 0x18b2c936, 0xb98bce8c, 0x3403336e, + 0x79eb3309, 0xf463ceeb, 0xe23b33c7, 0x6fb3ce25, 0x225bce42, + 0xafd333a0, 0x0b4c27ec, 0x86c4da0e, 0xcb2cda69, 0x46a4278b, + 0x50fcdaa7, 0xdd742745, 0x909c2722, 0x1d14dac0, 0xbc2ddd7a, + 0x31a52098, 0x7c4d20ff, 0xf1c5dd1d, 0xe79d2031, 0x6a15ddd3, + 0x27fdddb4, 0xaa752056, 0xbefed481, 0x33762963, 0x7e9e2904, + 0xf316d4e6, 0xe54e29ca, 0x68c6d428, 0x252ed44f, 0xa8a629ad, + 0x099f2e17, 0x8417d3f5, 0xc9ffd392, 0x44772e70, 0x522fd35c, + 0xdfa72ebe, 0x924f2ed9, 0x1fc7d33b, 0xadc088af, 0x2048754d, + 0x6da0752a, 0xe02888c8, 0xf67075e4, 0x7bf88806, 0x36108861, + 0xbb987583, 0x1aa17239, 0x97298fdb, 0xdac18fbc, 0x5749725e, + 0x41118f72, 0xcc997290, 0x817172f7, 0x0cf98f15, 0x18727bc2, + 0x95fa8620, 0xd8128647, 0x559a7ba5, 0x43c28689, 0xce4a7b6b, + 0x83a27b0c, 0x0e2a86ee, 0xaf138154, 0x229b7cb6, 0x6f737cd1, + 0xe2fb8133, 0xf4a37c1f, 0x792b81fd, 0x34c3819a, 0xb94b7c78, + 0x1dd46834, 0x905c95d6, 0xddb495b1, 0x503c6853, 0x4664957f, + 0xcbec689d, 0x860468fa, 0x0b8c9518, 0xaab592a2, 0x273d6f40, + 0x6ad56f27, 0xe75d92c5, 0xf1056fe9, 0x7c8d920b, 0x3165926c, + 0xbced6f8e, 0xa8669b59, 0x25ee66bb, 0x680666dc, 0xe58e9b3e, + 0xf3d66612, 0x7e5e9bf0, 0x33b69b97, 0xbe3e6675, 0x1f0761cf, + 0x928f9c2d, 0xdf679c4a, 0x52ef61a8, 0x44b79c84, 0xc93f6166, + 0x84d76101, 0x095f9ce3, 0x16984fd8, 0x9b10b23a, 0xd6f8b25d, + 0x5b704fbf, 0x4d28b293, 0xc0a04f71, 0x8d484f16, 0x00c0b2f4, + 0xa1f9b54e, 0x2c7148ac, 0x619948cb, 0xec11b529, 0xfa494805, + 0x77c1b5e7, 0x3a29b580, 0xb7a14862, 0xa32abcb5, 0x2ea24157, + 0x634a4130, 0xeec2bcd2, 0xf89a41fe, 0x7512bc1c, 0x38fabc7b, + 0xb5724199, 0x144b4623, 0x99c3bbc1, 0xd42bbba6, 0x59a34644, + 0x4ffbbb68, 0xc273468a, 0x8f9b46ed, 0x0213bb0f, 0xa68caf43, + 0x2b0452a1, 0x66ec52c6, 0xeb64af24, 0xfd3c5208, 0x70b4afea, + 0x3d5caf8d, 0xb0d4526f, 0x11ed55d5, 0x9c65a837, 0xd18da850, + 0x5c0555b2, 0x4a5da89e, 0xc7d5557c, 0x8a3d551b, 0x07b5a8f9, + 0x133e5c2e, 0x9eb6a1cc, 0xd35ea1ab, 0x5ed65c49, 0x488ea165, + 0xc5065c87, 0x88ee5ce0, 0x0566a102, 0xa45fa6b8, 0x29d75b5a, + 0x643f5b3d, 0xe9b7a6df, 0xffef5bf3, 0x7267a611, 0x3f8fa676, + 0xb2075b94}, + {0x00000000, 0x80f0171f, 0xda91287f, 0x5a613f60, 0x6e5356bf, + 0xeea341a0, 0xb4c27ec0, 0x343269df, 0xdca6ad7e, 0x5c56ba61, + 0x06378501, 0x86c7921e, 0xb2f5fbc1, 0x3205ecde, 0x6864d3be, + 0xe894c4a1, 0x623c5cbd, 0xe2cc4ba2, 0xb8ad74c2, 0x385d63dd, + 0x0c6f0a02, 0x8c9f1d1d, 0xd6fe227d, 0x560e3562, 0xbe9af1c3, + 0x3e6ae6dc, 0x640bd9bc, 0xe4fbcea3, 0xd0c9a77c, 0x5039b063, + 0x0a588f03, 0x8aa8981c, 0xc478b97a, 0x4488ae65, 0x1ee99105, + 0x9e19861a, 0xaa2befc5, 0x2adbf8da, 0x70bac7ba, 0xf04ad0a5, + 0x18de1404, 0x982e031b, 0xc24f3c7b, 0x42bf2b64, 0x768d42bb, + 0xf67d55a4, 0xac1c6ac4, 0x2cec7ddb, 0xa644e5c7, 0x26b4f2d8, + 0x7cd5cdb8, 0xfc25daa7, 0xc817b378, 0x48e7a467, 0x12869b07, + 0x92768c18, 0x7ae248b9, 0xfa125fa6, 0xa07360c6, 0x208377d9, + 0x14b11e06, 0x94410919, 0xce203679, 0x4ed02166, 0x538074b5, + 0xd37063aa, 0x89115cca, 0x09e14bd5, 0x3dd3220a, 0xbd233515, + 0xe7420a75, 0x67b21d6a, 0x8f26d9cb, 0x0fd6ced4, 0x55b7f1b4, + 0xd547e6ab, 0xe1758f74, 0x6185986b, 0x3be4a70b, 0xbb14b014, + 0x31bc2808, 0xb14c3f17, 0xeb2d0077, 0x6bdd1768, 0x5fef7eb7, + 0xdf1f69a8, 0x857e56c8, 0x058e41d7, 0xed1a8576, 0x6dea9269, + 0x378bad09, 0xb77bba16, 0x8349d3c9, 0x03b9c4d6, 0x59d8fbb6, + 0xd928eca9, 0x97f8cdcf, 0x1708dad0, 0x4d69e5b0, 0xcd99f2af, + 0xf9ab9b70, 0x795b8c6f, 0x233ab30f, 0xa3caa410, 0x4b5e60b1, + 0xcbae77ae, 0x91cf48ce, 0x113f5fd1, 0x250d360e, 0xa5fd2111, + 0xff9c1e71, 0x7f6c096e, 0xf5c49172, 0x7534866d, 0x2f55b90d, + 0xafa5ae12, 0x9b97c7cd, 0x1b67d0d2, 0x4106efb2, 0xc1f6f8ad, + 0x29623c0c, 0xa9922b13, 0xf3f31473, 0x7303036c, 0x47316ab3, + 0xc7c17dac, 0x9da042cc, 0x1d5055d3, 0xa700e96a, 0x27f0fe75, + 0x7d91c115, 0xfd61d60a, 0xc953bfd5, 0x49a3a8ca, 0x13c297aa, + 0x933280b5, 0x7ba64414, 0xfb56530b, 0xa1376c6b, 0x21c77b74, + 0x15f512ab, 0x950505b4, 0xcf643ad4, 0x4f942dcb, 0xc53cb5d7, + 0x45cca2c8, 0x1fad9da8, 0x9f5d8ab7, 0xab6fe368, 0x2b9ff477, + 0x71fecb17, 0xf10edc08, 0x199a18a9, 0x996a0fb6, 0xc30b30d6, + 0x43fb27c9, 0x77c94e16, 0xf7395909, 0xad586669, 0x2da87176, + 0x63785010, 0xe388470f, 0xb9e9786f, 0x39196f70, 0x0d2b06af, + 0x8ddb11b0, 0xd7ba2ed0, 0x574a39cf, 0xbfdefd6e, 0x3f2eea71, + 0x654fd511, 0xe5bfc20e, 0xd18dabd1, 0x517dbcce, 0x0b1c83ae, + 0x8bec94b1, 0x01440cad, 0x81b41bb2, 0xdbd524d2, 0x5b2533cd, + 0x6f175a12, 0xefe74d0d, 0xb586726d, 0x35766572, 0xdde2a1d3, + 0x5d12b6cc, 0x077389ac, 0x87839eb3, 0xb3b1f76c, 0x3341e073, + 0x6920df13, 0xe9d0c80c, 0xf4809ddf, 0x74708ac0, 0x2e11b5a0, + 0xaee1a2bf, 0x9ad3cb60, 0x1a23dc7f, 0x4042e31f, 0xc0b2f400, + 0x282630a1, 0xa8d627be, 0xf2b718de, 0x72470fc1, 0x4675661e, + 0xc6857101, 0x9ce44e61, 0x1c14597e, 0x96bcc162, 0x164cd67d, + 0x4c2de91d, 0xccddfe02, 0xf8ef97dd, 0x781f80c2, 0x227ebfa2, + 0xa28ea8bd, 0x4a1a6c1c, 0xcaea7b03, 0x908b4463, 0x107b537c, + 0x24493aa3, 0xa4b92dbc, 0xfed812dc, 0x7e2805c3, 0x30f824a5, + 0xb00833ba, 0xea690cda, 0x6a991bc5, 0x5eab721a, 0xde5b6505, + 0x843a5a65, 0x04ca4d7a, 0xec5e89db, 0x6cae9ec4, 0x36cfa1a4, + 0xb63fb6bb, 0x820ddf64, 0x02fdc87b, 0x589cf71b, 0xd86ce004, + 0x52c47818, 0xd2346f07, 0x88555067, 0x08a54778, 0x3c972ea7, + 0xbc6739b8, 0xe60606d8, 0x66f611c7, 0x8e62d566, 0x0e92c279, + 0x54f3fd19, 0xd403ea06, 0xe03183d9, 0x60c194c6, 0x3aa0aba6, + 0xba50bcb9}, + {0x00000000, 0x9570d495, 0xf190af6b, 0x64e07bfe, 0x38505897, + 0xad208c02, 0xc9c0f7fc, 0x5cb02369, 0x70a0b12e, 0xe5d065bb, + 0x81301e45, 0x1440cad0, 0x48f0e9b9, 0xdd803d2c, 0xb96046d2, + 0x2c109247, 0xe141625c, 0x7431b6c9, 0x10d1cd37, 0x85a119a2, + 0xd9113acb, 0x4c61ee5e, 0x288195a0, 0xbdf14135, 0x91e1d372, + 0x049107e7, 0x60717c19, 0xf501a88c, 0xa9b18be5, 0x3cc15f70, + 0x5821248e, 0xcd51f01b, 0x19f3c2f9, 0x8c83166c, 0xe8636d92, + 0x7d13b907, 0x21a39a6e, 0xb4d34efb, 0xd0333505, 0x4543e190, + 0x695373d7, 0xfc23a742, 0x98c3dcbc, 0x0db30829, 0x51032b40, + 0xc473ffd5, 0xa093842b, 0x35e350be, 0xf8b2a0a5, 0x6dc27430, + 0x09220fce, 0x9c52db5b, 0xc0e2f832, 0x55922ca7, 0x31725759, + 0xa40283cc, 0x8812118b, 0x1d62c51e, 0x7982bee0, 0xecf26a75, + 0xb042491c, 0x25329d89, 0x41d2e677, 0xd4a232e2, 0x33e785f2, + 0xa6975167, 0xc2772a99, 0x5707fe0c, 0x0bb7dd65, 0x9ec709f0, + 0xfa27720e, 0x6f57a69b, 0x434734dc, 0xd637e049, 0xb2d79bb7, + 0x27a74f22, 0x7b176c4b, 0xee67b8de, 0x8a87c320, 0x1ff717b5, + 0xd2a6e7ae, 0x47d6333b, 0x233648c5, 0xb6469c50, 0xeaf6bf39, + 0x7f866bac, 0x1b661052, 0x8e16c4c7, 0xa2065680, 0x37768215, + 0x5396f9eb, 0xc6e62d7e, 0x9a560e17, 0x0f26da82, 0x6bc6a17c, + 0xfeb675e9, 0x2a14470b, 0xbf64939e, 0xdb84e860, 0x4ef43cf5, + 0x12441f9c, 0x8734cb09, 0xe3d4b0f7, 0x76a46462, 0x5ab4f625, + 0xcfc422b0, 0xab24594e, 0x3e548ddb, 0x62e4aeb2, 0xf7947a27, + 0x937401d9, 0x0604d54c, 0xcb552557, 0x5e25f1c2, 0x3ac58a3c, + 0xafb55ea9, 0xf3057dc0, 0x6675a955, 0x0295d2ab, 0x97e5063e, + 0xbbf59479, 0x2e8540ec, 0x4a653b12, 0xdf15ef87, 0x83a5ccee, + 0x16d5187b, 0x72356385, 0xe745b710, 0x67cf0be4, 0xf2bfdf71, + 0x965fa48f, 0x032f701a, 0x5f9f5373, 0xcaef87e6, 0xae0ffc18, + 0x3b7f288d, 0x176fbaca, 0x821f6e5f, 0xe6ff15a1, 0x738fc134, + 0x2f3fe25d, 0xba4f36c8, 0xdeaf4d36, 0x4bdf99a3, 0x868e69b8, + 0x13febd2d, 0x771ec6d3, 0xe26e1246, 0xbede312f, 0x2baee5ba, + 0x4f4e9e44, 0xda3e4ad1, 0xf62ed896, 0x635e0c03, 0x07be77fd, + 0x92cea368, 0xce7e8001, 0x5b0e5494, 0x3fee2f6a, 0xaa9efbff, + 0x7e3cc91d, 0xeb4c1d88, 0x8fac6676, 0x1adcb2e3, 0x466c918a, + 0xd31c451f, 0xb7fc3ee1, 0x228cea74, 0x0e9c7833, 0x9becaca6, + 0xff0cd758, 0x6a7c03cd, 0x36cc20a4, 0xa3bcf431, 0xc75c8fcf, + 0x522c5b5a, 0x9f7dab41, 0x0a0d7fd4, 0x6eed042a, 0xfb9dd0bf, + 0xa72df3d6, 0x325d2743, 0x56bd5cbd, 0xc3cd8828, 0xefdd1a6f, + 0x7aadcefa, 0x1e4db504, 0x8b3d6191, 0xd78d42f8, 0x42fd966d, + 0x261ded93, 0xb36d3906, 0x54288e16, 0xc1585a83, 0xa5b8217d, + 0x30c8f5e8, 0x6c78d681, 0xf9080214, 0x9de879ea, 0x0898ad7f, + 0x24883f38, 0xb1f8ebad, 0xd5189053, 0x406844c6, 0x1cd867af, + 0x89a8b33a, 0xed48c8c4, 0x78381c51, 0xb569ec4a, 0x201938df, + 0x44f94321, 0xd18997b4, 0x8d39b4dd, 0x18496048, 0x7ca91bb6, + 0xe9d9cf23, 0xc5c95d64, 0x50b989f1, 0x3459f20f, 0xa129269a, + 0xfd9905f3, 0x68e9d166, 0x0c09aa98, 0x99797e0d, 0x4ddb4cef, + 0xd8ab987a, 0xbc4be384, 0x293b3711, 0x758b1478, 0xe0fbc0ed, + 0x841bbb13, 0x116b6f86, 0x3d7bfdc1, 0xa80b2954, 0xcceb52aa, + 0x599b863f, 0x052ba556, 0x905b71c3, 0xf4bb0a3d, 0x61cbdea8, + 0xac9a2eb3, 0x39eafa26, 0x5d0a81d8, 0xc87a554d, 0x94ca7624, + 0x01baa2b1, 0x655ad94f, 0xf02a0dda, 0xdc3a9f9d, 0x494a4b08, + 0x2daa30f6, 0xb8dae463, 0xe46ac70a, 0x711a139f, 0x15fa6861, + 0x808abcf4}, + {0x00000000, 0xcf9e17c8, 0x444d29d1, 0x8bd33e19, 0x889a53a2, + 0x4704446a, 0xccd77a73, 0x03496dbb, 0xca45a105, 0x05dbb6cd, + 0x8e0888d4, 0x41969f1c, 0x42dff2a7, 0x8d41e56f, 0x0692db76, + 0xc90cccbe, 0x4ffa444b, 0x80645383, 0x0bb76d9a, 0xc4297a52, + 0xc76017e9, 0x08fe0021, 0x832d3e38, 0x4cb329f0, 0x85bfe54e, + 0x4a21f286, 0xc1f2cc9f, 0x0e6cdb57, 0x0d25b6ec, 0xc2bba124, + 0x49689f3d, 0x86f688f5, 0x9ff48896, 0x506a9f5e, 0xdbb9a147, + 0x1427b68f, 0x176edb34, 0xd8f0ccfc, 0x5323f2e5, 0x9cbde52d, + 0x55b12993, 0x9a2f3e5b, 0x11fc0042, 0xde62178a, 0xdd2b7a31, + 0x12b56df9, 0x996653e0, 0x56f84428, 0xd00eccdd, 0x1f90db15, + 0x9443e50c, 0x5bddf2c4, 0x58949f7f, 0x970a88b7, 0x1cd9b6ae, + 0xd347a166, 0x1a4b6dd8, 0xd5d57a10, 0x5e064409, 0x919853c1, + 0x92d13e7a, 0x5d4f29b2, 0xd69c17ab, 0x19020063, 0xe498176d, + 0x2b0600a5, 0xa0d53ebc, 0x6f4b2974, 0x6c0244cf, 0xa39c5307, + 0x284f6d1e, 0xe7d17ad6, 0x2eddb668, 0xe143a1a0, 0x6a909fb9, + 0xa50e8871, 0xa647e5ca, 0x69d9f202, 0xe20acc1b, 0x2d94dbd3, + 0xab625326, 0x64fc44ee, 0xef2f7af7, 0x20b16d3f, 0x23f80084, + 0xec66174c, 0x67b52955, 0xa82b3e9d, 0x6127f223, 0xaeb9e5eb, + 0x256adbf2, 0xeaf4cc3a, 0xe9bda181, 0x2623b649, 0xadf08850, + 0x626e9f98, 0x7b6c9ffb, 0xb4f28833, 0x3f21b62a, 0xf0bfa1e2, + 0xf3f6cc59, 0x3c68db91, 0xb7bbe588, 0x7825f240, 0xb1293efe, + 0x7eb72936, 0xf564172f, 0x3afa00e7, 0x39b36d5c, 0xf62d7a94, + 0x7dfe448d, 0xb2605345, 0x3496dbb0, 0xfb08cc78, 0x70dbf261, + 0xbf45e5a9, 0xbc0c8812, 0x73929fda, 0xf841a1c3, 0x37dfb60b, + 0xfed37ab5, 0x314d6d7d, 0xba9e5364, 0x750044ac, 0x76492917, + 0xb9d73edf, 0x320400c6, 0xfd9a170e, 0x1241289b, 0xdddf3f53, + 0x560c014a, 0x99921682, 0x9adb7b39, 0x55456cf1, 0xde9652e8, + 0x11084520, 0xd804899e, 0x179a9e56, 0x9c49a04f, 0x53d7b787, + 0x509eda3c, 0x9f00cdf4, 0x14d3f3ed, 0xdb4de425, 0x5dbb6cd0, + 0x92257b18, 0x19f64501, 0xd66852c9, 0xd5213f72, 0x1abf28ba, + 0x916c16a3, 0x5ef2016b, 0x97fecdd5, 0x5860da1d, 0xd3b3e404, + 0x1c2df3cc, 0x1f649e77, 0xd0fa89bf, 0x5b29b7a6, 0x94b7a06e, + 0x8db5a00d, 0x422bb7c5, 0xc9f889dc, 0x06669e14, 0x052ff3af, + 0xcab1e467, 0x4162da7e, 0x8efccdb6, 0x47f00108, 0x886e16c0, + 0x03bd28d9, 0xcc233f11, 0xcf6a52aa, 0x00f44562, 0x8b277b7b, + 0x44b96cb3, 0xc24fe446, 0x0dd1f38e, 0x8602cd97, 0x499cda5f, + 0x4ad5b7e4, 0x854ba02c, 0x0e989e35, 0xc10689fd, 0x080a4543, + 0xc794528b, 0x4c476c92, 0x83d97b5a, 0x809016e1, 0x4f0e0129, + 0xc4dd3f30, 0x0b4328f8, 0xf6d93ff6, 0x3947283e, 0xb2941627, + 0x7d0a01ef, 0x7e436c54, 0xb1dd7b9c, 0x3a0e4585, 0xf590524d, + 0x3c9c9ef3, 0xf302893b, 0x78d1b722, 0xb74fa0ea, 0xb406cd51, + 0x7b98da99, 0xf04be480, 0x3fd5f348, 0xb9237bbd, 0x76bd6c75, + 0xfd6e526c, 0x32f045a4, 0x31b9281f, 0xfe273fd7, 0x75f401ce, + 0xba6a1606, 0x7366dab8, 0xbcf8cd70, 0x372bf369, 0xf8b5e4a1, + 0xfbfc891a, 0x34629ed2, 0xbfb1a0cb, 0x702fb703, 0x692db760, + 0xa6b3a0a8, 0x2d609eb1, 0xe2fe8979, 0xe1b7e4c2, 0x2e29f30a, + 0xa5facd13, 0x6a64dadb, 0xa3681665, 0x6cf601ad, 0xe7253fb4, + 0x28bb287c, 0x2bf245c7, 0xe46c520f, 0x6fbf6c16, 0xa0217bde, + 0x26d7f32b, 0xe949e4e3, 0x629adafa, 0xad04cd32, 0xae4da089, + 0x61d3b741, 0xea008958, 0x259e9e90, 0xec92522e, 0x230c45e6, + 0xa8df7bff, 0x67416c37, 0x6408018c, 0xab961644, 0x2045285d, + 0xefdb3f95}, + {0x00000000, 0x24825136, 0x4904a26c, 0x6d86f35a, 0x920944d8, + 0xb68b15ee, 0xdb0de6b4, 0xff8fb782, 0xff638ff1, 0xdbe1dec7, + 0xb6672d9d, 0x92e57cab, 0x6d6acb29, 0x49e89a1f, 0x246e6945, + 0x00ec3873, 0x25b619a3, 0x01344895, 0x6cb2bbcf, 0x4830eaf9, + 0xb7bf5d7b, 0x933d0c4d, 0xfebbff17, 0xda39ae21, 0xdad59652, + 0xfe57c764, 0x93d1343e, 0xb7536508, 0x48dcd28a, 0x6c5e83bc, + 0x01d870e6, 0x255a21d0, 0x4b6c3346, 0x6fee6270, 0x0268912a, + 0x26eac01c, 0xd965779e, 0xfde726a8, 0x9061d5f2, 0xb4e384c4, + 0xb40fbcb7, 0x908ded81, 0xfd0b1edb, 0xd9894fed, 0x2606f86f, + 0x0284a959, 0x6f025a03, 0x4b800b35, 0x6eda2ae5, 0x4a587bd3, + 0x27de8889, 0x035cd9bf, 0xfcd36e3d, 0xd8513f0b, 0xb5d7cc51, + 0x91559d67, 0x91b9a514, 0xb53bf422, 0xd8bd0778, 0xfc3f564e, + 0x03b0e1cc, 0x2732b0fa, 0x4ab443a0, 0x6e361296, 0x96d8668c, + 0xb25a37ba, 0xdfdcc4e0, 0xfb5e95d6, 0x04d12254, 0x20537362, + 0x4dd58038, 0x6957d10e, 0x69bbe97d, 0x4d39b84b, 0x20bf4b11, + 0x043d1a27, 0xfbb2ada5, 0xdf30fc93, 0xb2b60fc9, 0x96345eff, + 0xb36e7f2f, 0x97ec2e19, 0xfa6add43, 0xdee88c75, 0x21673bf7, + 0x05e56ac1, 0x6863999b, 0x4ce1c8ad, 0x4c0df0de, 0x688fa1e8, + 0x050952b2, 0x218b0384, 0xde04b406, 0xfa86e530, 0x9700166a, + 0xb382475c, 0xddb455ca, 0xf93604fc, 0x94b0f7a6, 0xb032a690, + 0x4fbd1112, 0x6b3f4024, 0x06b9b37e, 0x223be248, 0x22d7da3b, + 0x06558b0d, 0x6bd37857, 0x4f512961, 0xb0de9ee3, 0x945ccfd5, + 0xf9da3c8f, 0xdd586db9, 0xf8024c69, 0xdc801d5f, 0xb106ee05, + 0x9584bf33, 0x6a0b08b1, 0x4e895987, 0x230faadd, 0x078dfbeb, + 0x0761c398, 0x23e392ae, 0x4e6561f4, 0x6ae730c2, 0x95688740, + 0xb1ead676, 0xdc6c252c, 0xf8ee741a, 0xf6c1cb59, 0xd2439a6f, + 0xbfc56935, 0x9b473803, 0x64c88f81, 0x404adeb7, 0x2dcc2ded, + 0x094e7cdb, 0x09a244a8, 0x2d20159e, 0x40a6e6c4, 0x6424b7f2, + 0x9bab0070, 0xbf295146, 0xd2afa21c, 0xf62df32a, 0xd377d2fa, + 0xf7f583cc, 0x9a737096, 0xbef121a0, 0x417e9622, 0x65fcc714, + 0x087a344e, 0x2cf86578, 0x2c145d0b, 0x08960c3d, 0x6510ff67, + 0x4192ae51, 0xbe1d19d3, 0x9a9f48e5, 0xf719bbbf, 0xd39bea89, + 0xbdadf81f, 0x992fa929, 0xf4a95a73, 0xd02b0b45, 0x2fa4bcc7, + 0x0b26edf1, 0x66a01eab, 0x42224f9d, 0x42ce77ee, 0x664c26d8, + 0x0bcad582, 0x2f4884b4, 0xd0c73336, 0xf4456200, 0x99c3915a, + 0xbd41c06c, 0x981be1bc, 0xbc99b08a, 0xd11f43d0, 0xf59d12e6, + 0x0a12a564, 0x2e90f452, 0x43160708, 0x6794563e, 0x67786e4d, + 0x43fa3f7b, 0x2e7ccc21, 0x0afe9d17, 0xf5712a95, 0xd1f37ba3, + 0xbc7588f9, 0x98f7d9cf, 0x6019add5, 0x449bfce3, 0x291d0fb9, + 0x0d9f5e8f, 0xf210e90d, 0xd692b83b, 0xbb144b61, 0x9f961a57, + 0x9f7a2224, 0xbbf87312, 0xd67e8048, 0xf2fcd17e, 0x0d7366fc, + 0x29f137ca, 0x4477c490, 0x60f595a6, 0x45afb476, 0x612de540, + 0x0cab161a, 0x2829472c, 0xd7a6f0ae, 0xf324a198, 0x9ea252c2, + 0xba2003f4, 0xbacc3b87, 0x9e4e6ab1, 0xf3c899eb, 0xd74ac8dd, + 0x28c57f5f, 0x0c472e69, 0x61c1dd33, 0x45438c05, 0x2b759e93, + 0x0ff7cfa5, 0x62713cff, 0x46f36dc9, 0xb97cda4b, 0x9dfe8b7d, + 0xf0787827, 0xd4fa2911, 0xd4161162, 0xf0944054, 0x9d12b30e, + 0xb990e238, 0x461f55ba, 0x629d048c, 0x0f1bf7d6, 0x2b99a6e0, + 0x0ec38730, 0x2a41d606, 0x47c7255c, 0x6345746a, 0x9ccac3e8, + 0xb84892de, 0xd5ce6184, 0xf14c30b2, 0xf1a008c1, 0xd52259f7, + 0xb8a4aaad, 0x9c26fb9b, 0x63a94c19, 0x472b1d2f, 0x2aadee75, + 0x0e2fbf43}, + {0x00000000, 0x36f290f3, 0x6de521e6, 0x5b17b115, 0xdbca43cc, + 0xed38d33f, 0xb62f622a, 0x80ddf2d9, 0x6ce581d9, 0x5a17112a, + 0x0100a03f, 0x37f230cc, 0xb72fc215, 0x81dd52e6, 0xdacae3f3, + 0xec387300, 0xd9cb03b2, 0xef399341, 0xb42e2254, 0x82dcb2a7, + 0x0201407e, 0x34f3d08d, 0x6fe46198, 0x5916f16b, 0xb52e826b, + 0x83dc1298, 0xd8cba38d, 0xee39337e, 0x6ee4c1a7, 0x58165154, + 0x0301e041, 0x35f370b2, 0x68e70125, 0x5e1591d6, 0x050220c3, + 0x33f0b030, 0xb32d42e9, 0x85dfd21a, 0xdec8630f, 0xe83af3fc, + 0x040280fc, 0x32f0100f, 0x69e7a11a, 0x5f1531e9, 0xdfc8c330, + 0xe93a53c3, 0xb22de2d6, 0x84df7225, 0xb12c0297, 0x87de9264, + 0xdcc92371, 0xea3bb382, 0x6ae6415b, 0x5c14d1a8, 0x070360bd, + 0x31f1f04e, 0xddc9834e, 0xeb3b13bd, 0xb02ca2a8, 0x86de325b, + 0x0603c082, 0x30f15071, 0x6be6e164, 0x5d147197, 0xd1ce024a, + 0xe73c92b9, 0xbc2b23ac, 0x8ad9b35f, 0x0a044186, 0x3cf6d175, + 0x67e16060, 0x5113f093, 0xbd2b8393, 0x8bd91360, 0xd0cea275, + 0xe63c3286, 0x66e1c05f, 0x501350ac, 0x0b04e1b9, 0x3df6714a, + 0x080501f8, 0x3ef7910b, 0x65e0201e, 0x5312b0ed, 0xd3cf4234, + 0xe53dd2c7, 0xbe2a63d2, 0x88d8f321, 0x64e08021, 0x521210d2, + 0x0905a1c7, 0x3ff73134, 0xbf2ac3ed, 0x89d8531e, 0xd2cfe20b, + 0xe43d72f8, 0xb929036f, 0x8fdb939c, 0xd4cc2289, 0xe23eb27a, + 0x62e340a3, 0x5411d050, 0x0f066145, 0x39f4f1b6, 0xd5cc82b6, + 0xe33e1245, 0xb829a350, 0x8edb33a3, 0x0e06c17a, 0x38f45189, + 0x63e3e09c, 0x5511706f, 0x60e200dd, 0x5610902e, 0x0d07213b, + 0x3bf5b1c8, 0xbb284311, 0x8ddad3e2, 0xd6cd62f7, 0xe03ff204, + 0x0c078104, 0x3af511f7, 0x61e2a0e2, 0x57103011, 0xd7cdc2c8, + 0xe13f523b, 0xba28e32e, 0x8cda73dd, 0x78ed02d5, 0x4e1f9226, + 0x15082333, 0x23fab3c0, 0xa3274119, 0x95d5d1ea, 0xcec260ff, + 0xf830f00c, 0x1408830c, 0x22fa13ff, 0x79eda2ea, 0x4f1f3219, + 0xcfc2c0c0, 0xf9305033, 0xa227e126, 0x94d571d5, 0xa1260167, + 0x97d49194, 0xccc32081, 0xfa31b072, 0x7aec42ab, 0x4c1ed258, + 0x1709634d, 0x21fbf3be, 0xcdc380be, 0xfb31104d, 0xa026a158, + 0x96d431ab, 0x1609c372, 0x20fb5381, 0x7bece294, 0x4d1e7267, + 0x100a03f0, 0x26f89303, 0x7def2216, 0x4b1db2e5, 0xcbc0403c, + 0xfd32d0cf, 0xa62561da, 0x90d7f129, 0x7cef8229, 0x4a1d12da, + 0x110aa3cf, 0x27f8333c, 0xa725c1e5, 0x91d75116, 0xcac0e003, + 0xfc3270f0, 0xc9c10042, 0xff3390b1, 0xa42421a4, 0x92d6b157, + 0x120b438e, 0x24f9d37d, 0x7fee6268, 0x491cf29b, 0xa524819b, + 0x93d61168, 0xc8c1a07d, 0xfe33308e, 0x7eeec257, 0x481c52a4, + 0x130be3b1, 0x25f97342, 0xa923009f, 0x9fd1906c, 0xc4c62179, + 0xf234b18a, 0x72e94353, 0x441bd3a0, 0x1f0c62b5, 0x29fef246, + 0xc5c68146, 0xf33411b5, 0xa823a0a0, 0x9ed13053, 0x1e0cc28a, + 0x28fe5279, 0x73e9e36c, 0x451b739f, 0x70e8032d, 0x461a93de, + 0x1d0d22cb, 0x2bffb238, 0xab2240e1, 0x9dd0d012, 0xc6c76107, + 0xf035f1f4, 0x1c0d82f4, 0x2aff1207, 0x71e8a312, 0x471a33e1, + 0xc7c7c138, 0xf13551cb, 0xaa22e0de, 0x9cd0702d, 0xc1c401ba, + 0xf7369149, 0xac21205c, 0x9ad3b0af, 0x1a0e4276, 0x2cfcd285, + 0x77eb6390, 0x4119f363, 0xad218063, 0x9bd31090, 0xc0c4a185, + 0xf6363176, 0x76ebc3af, 0x4019535c, 0x1b0ee249, 0x2dfc72ba, + 0x180f0208, 0x2efd92fb, 0x75ea23ee, 0x4318b31d, 0xc3c541c4, + 0xf537d137, 0xae206022, 0x98d2f0d1, 0x74ea83d1, 0x42181322, + 0x190fa237, 0x2ffd32c4, 0xaf20c01d, 0x99d250ee, 0xc2c5e1fb, + 0xf4377108}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0xf390f23600000000, 0xe621e56d00000000, + 0x15b1175b00000000, 0xcc43cadb00000000, 0x3fd338ed00000000, + 0x2a622fb600000000, 0xd9f2dd8000000000, 0xd981e56c00000000, + 0x2a11175a00000000, 0x3fa0000100000000, 0xcc30f23700000000, + 0x15c22fb700000000, 0xe652dd8100000000, 0xf3e3cada00000000, + 0x007338ec00000000, 0xb203cbd900000000, 0x419339ef00000000, + 0x54222eb400000000, 0xa7b2dc8200000000, 0x7e40010200000000, + 0x8dd0f33400000000, 0x9861e46f00000000, 0x6bf1165900000000, + 0x6b822eb500000000, 0x9812dc8300000000, 0x8da3cbd800000000, + 0x7e3339ee00000000, 0xa7c1e46e00000000, 0x5451165800000000, + 0x41e0010300000000, 0xb270f33500000000, 0x2501e76800000000, + 0xd691155e00000000, 0xc320020500000000, 0x30b0f03300000000, + 0xe9422db300000000, 0x1ad2df8500000000, 0x0f63c8de00000000, + 0xfcf33ae800000000, 0xfc80020400000000, 0x0f10f03200000000, + 0x1aa1e76900000000, 0xe931155f00000000, 0x30c3c8df00000000, + 0xc3533ae900000000, 0xd6e22db200000000, 0x2572df8400000000, + 0x97022cb100000000, 0x6492de8700000000, 0x7123c9dc00000000, + 0x82b33bea00000000, 0x5b41e66a00000000, 0xa8d1145c00000000, + 0xbd60030700000000, 0x4ef0f13100000000, 0x4e83c9dd00000000, + 0xbd133beb00000000, 0xa8a22cb000000000, 0x5b32de8600000000, + 0x82c0030600000000, 0x7150f13000000000, 0x64e1e66b00000000, + 0x9771145d00000000, 0x4a02ced100000000, 0xb9923ce700000000, + 0xac232bbc00000000, 0x5fb3d98a00000000, 0x8641040a00000000, + 0x75d1f63c00000000, 0x6060e16700000000, 0x93f0135100000000, + 0x93832bbd00000000, 0x6013d98b00000000, 0x75a2ced000000000, + 0x86323ce600000000, 0x5fc0e16600000000, 0xac50135000000000, + 0xb9e1040b00000000, 0x4a71f63d00000000, 0xf801050800000000, + 0x0b91f73e00000000, 0x1e20e06500000000, 0xedb0125300000000, + 0x3442cfd300000000, 0xc7d23de500000000, 0xd2632abe00000000, + 0x21f3d88800000000, 0x2180e06400000000, 0xd210125200000000, + 0xc7a1050900000000, 0x3431f73f00000000, 0xedc32abf00000000, + 0x1e53d88900000000, 0x0be2cfd200000000, 0xf8723de400000000, + 0x6f0329b900000000, 0x9c93db8f00000000, 0x8922ccd400000000, + 0x7ab23ee200000000, 0xa340e36200000000, 0x50d0115400000000, + 0x4561060f00000000, 0xb6f1f43900000000, 0xb682ccd500000000, + 0x45123ee300000000, 0x50a329b800000000, 0xa333db8e00000000, + 0x7ac1060e00000000, 0x8951f43800000000, 0x9ce0e36300000000, + 0x6f70115500000000, 0xdd00e26000000000, 0x2e90105600000000, + 0x3b21070d00000000, 0xc8b1f53b00000000, 0x114328bb00000000, + 0xe2d3da8d00000000, 0xf762cdd600000000, 0x04f23fe000000000, + 0x0481070c00000000, 0xf711f53a00000000, 0xe2a0e26100000000, + 0x1130105700000000, 0xc8c2cdd700000000, 0x3b523fe100000000, + 0x2ee328ba00000000, 0xdd73da8c00000000, 0xd502ed7800000000, + 0x26921f4e00000000, 0x3323081500000000, 0xc0b3fa2300000000, + 0x194127a300000000, 0xead1d59500000000, 0xff60c2ce00000000, + 0x0cf030f800000000, 0x0c83081400000000, 0xff13fa2200000000, + 0xeaa2ed7900000000, 0x19321f4f00000000, 0xc0c0c2cf00000000, + 0x335030f900000000, 0x26e127a200000000, 0xd571d59400000000, + 0x670126a100000000, 0x9491d49700000000, 0x8120c3cc00000000, + 0x72b031fa00000000, 0xab42ec7a00000000, 0x58d21e4c00000000, + 0x4d63091700000000, 0xbef3fb2100000000, 0xbe80c3cd00000000, + 0x4d1031fb00000000, 0x58a126a000000000, 0xab31d49600000000, + 0x72c3091600000000, 0x8153fb2000000000, 0x94e2ec7b00000000, + 0x67721e4d00000000, 0xf0030a1000000000, 0x0393f82600000000, + 0x1622ef7d00000000, 0xe5b21d4b00000000, 0x3c40c0cb00000000, + 0xcfd032fd00000000, 0xda6125a600000000, 0x29f1d79000000000, + 0x2982ef7c00000000, 0xda121d4a00000000, 0xcfa30a1100000000, + 0x3c33f82700000000, 0xe5c125a700000000, 0x1651d79100000000, + 0x03e0c0ca00000000, 0xf07032fc00000000, 0x4200c1c900000000, + 0xb19033ff00000000, 0xa42124a400000000, 0x57b1d69200000000, + 0x8e430b1200000000, 0x7dd3f92400000000, 0x6862ee7f00000000, + 0x9bf21c4900000000, 0x9b8124a500000000, 0x6811d69300000000, + 0x7da0c1c800000000, 0x8e3033fe00000000, 0x57c2ee7e00000000, + 0xa4521c4800000000, 0xb1e30b1300000000, 0x4273f92500000000, + 0x9f0023a900000000, 0x6c90d19f00000000, 0x7921c6c400000000, + 0x8ab134f200000000, 0x5343e97200000000, 0xa0d31b4400000000, + 0xb5620c1f00000000, 0x46f2fe2900000000, 0x4681c6c500000000, + 0xb51134f300000000, 0xa0a023a800000000, 0x5330d19e00000000, + 0x8ac20c1e00000000, 0x7952fe2800000000, 0x6ce3e97300000000, + 0x9f731b4500000000, 0x2d03e87000000000, 0xde931a4600000000, + 0xcb220d1d00000000, 0x38b2ff2b00000000, 0xe14022ab00000000, + 0x12d0d09d00000000, 0x0761c7c600000000, 0xf4f135f000000000, + 0xf4820d1c00000000, 0x0712ff2a00000000, 0x12a3e87100000000, + 0xe1331a4700000000, 0x38c1c7c700000000, 0xcb5135f100000000, + 0xdee022aa00000000, 0x2d70d09c00000000, 0xba01c4c100000000, + 0x499136f700000000, 0x5c2021ac00000000, 0xafb0d39a00000000, + 0x76420e1a00000000, 0x85d2fc2c00000000, 0x9063eb7700000000, + 0x63f3194100000000, 0x638021ad00000000, 0x9010d39b00000000, + 0x85a1c4c000000000, 0x763136f600000000, 0xafc3eb7600000000, + 0x5c53194000000000, 0x49e20e1b00000000, 0xba72fc2d00000000, + 0x08020f1800000000, 0xfb92fd2e00000000, 0xee23ea7500000000, + 0x1db3184300000000, 0xc441c5c300000000, 0x37d137f500000000, + 0x226020ae00000000, 0xd1f0d29800000000, 0xd183ea7400000000, + 0x2213184200000000, 0x37a20f1900000000, 0xc432fd2f00000000, + 0x1dc020af00000000, 0xee50d29900000000, 0xfbe1c5c200000000, + 0x087137f400000000}, + {0x0000000000000000, 0x3651822400000000, 0x6ca2044900000000, + 0x5af3866d00000000, 0xd844099200000000, 0xee158bb600000000, + 0xb4e60ddb00000000, 0x82b78fff00000000, 0xf18f63ff00000000, + 0xc7dee1db00000000, 0x9d2d67b600000000, 0xab7ce59200000000, + 0x29cb6a6d00000000, 0x1f9ae84900000000, 0x45696e2400000000, + 0x7338ec0000000000, 0xa319b62500000000, 0x9548340100000000, + 0xcfbbb26c00000000, 0xf9ea304800000000, 0x7b5dbfb700000000, + 0x4d0c3d9300000000, 0x17ffbbfe00000000, 0x21ae39da00000000, + 0x5296d5da00000000, 0x64c757fe00000000, 0x3e34d19300000000, + 0x086553b700000000, 0x8ad2dc4800000000, 0xbc835e6c00000000, + 0xe670d80100000000, 0xd0215a2500000000, 0x46336c4b00000000, + 0x7062ee6f00000000, 0x2a91680200000000, 0x1cc0ea2600000000, + 0x9e7765d900000000, 0xa826e7fd00000000, 0xf2d5619000000000, + 0xc484e3b400000000, 0xb7bc0fb400000000, 0x81ed8d9000000000, + 0xdb1e0bfd00000000, 0xed4f89d900000000, 0x6ff8062600000000, + 0x59a9840200000000, 0x035a026f00000000, 0x350b804b00000000, + 0xe52ada6e00000000, 0xd37b584a00000000, 0x8988de2700000000, + 0xbfd95c0300000000, 0x3d6ed3fc00000000, 0x0b3f51d800000000, + 0x51ccd7b500000000, 0x679d559100000000, 0x14a5b99100000000, + 0x22f43bb500000000, 0x7807bdd800000000, 0x4e563ffc00000000, + 0xcce1b00300000000, 0xfab0322700000000, 0xa043b44a00000000, + 0x9612366e00000000, 0x8c66d89600000000, 0xba375ab200000000, + 0xe0c4dcdf00000000, 0xd6955efb00000000, 0x5422d10400000000, + 0x6273532000000000, 0x3880d54d00000000, 0x0ed1576900000000, + 0x7de9bb6900000000, 0x4bb8394d00000000, 0x114bbf2000000000, + 0x271a3d0400000000, 0xa5adb2fb00000000, 0x93fc30df00000000, + 0xc90fb6b200000000, 0xff5e349600000000, 0x2f7f6eb300000000, + 0x192eec9700000000, 0x43dd6afa00000000, 0x758ce8de00000000, + 0xf73b672100000000, 0xc16ae50500000000, 0x9b99636800000000, + 0xadc8e14c00000000, 0xdef00d4c00000000, 0xe8a18f6800000000, + 0xb252090500000000, 0x84038b2100000000, 0x06b404de00000000, + 0x30e586fa00000000, 0x6a16009700000000, 0x5c4782b300000000, + 0xca55b4dd00000000, 0xfc0436f900000000, 0xa6f7b09400000000, + 0x90a632b000000000, 0x1211bd4f00000000, 0x24403f6b00000000, + 0x7eb3b90600000000, 0x48e23b2200000000, 0x3bdad72200000000, + 0x0d8b550600000000, 0x5778d36b00000000, 0x6129514f00000000, + 0xe39edeb000000000, 0xd5cf5c9400000000, 0x8f3cdaf900000000, + 0xb96d58dd00000000, 0x694c02f800000000, 0x5f1d80dc00000000, + 0x05ee06b100000000, 0x33bf849500000000, 0xb1080b6a00000000, + 0x8759894e00000000, 0xddaa0f2300000000, 0xebfb8d0700000000, + 0x98c3610700000000, 0xae92e32300000000, 0xf461654e00000000, + 0xc230e76a00000000, 0x4087689500000000, 0x76d6eab100000000, + 0x2c256cdc00000000, 0x1a74eef800000000, 0x59cbc1f600000000, + 0x6f9a43d200000000, 0x3569c5bf00000000, 0x0338479b00000000, + 0x818fc86400000000, 0xb7de4a4000000000, 0xed2dcc2d00000000, + 0xdb7c4e0900000000, 0xa844a20900000000, 0x9e15202d00000000, + 0xc4e6a64000000000, 0xf2b7246400000000, 0x7000ab9b00000000, + 0x465129bf00000000, 0x1ca2afd200000000, 0x2af32df600000000, + 0xfad277d300000000, 0xcc83f5f700000000, 0x9670739a00000000, + 0xa021f1be00000000, 0x22967e4100000000, 0x14c7fc6500000000, + 0x4e347a0800000000, 0x7865f82c00000000, 0x0b5d142c00000000, + 0x3d0c960800000000, 0x67ff106500000000, 0x51ae924100000000, + 0xd3191dbe00000000, 0xe5489f9a00000000, 0xbfbb19f700000000, + 0x89ea9bd300000000, 0x1ff8adbd00000000, 0x29a92f9900000000, + 0x735aa9f400000000, 0x450b2bd000000000, 0xc7bca42f00000000, + 0xf1ed260b00000000, 0xab1ea06600000000, 0x9d4f224200000000, + 0xee77ce4200000000, 0xd8264c6600000000, 0x82d5ca0b00000000, + 0xb484482f00000000, 0x3633c7d000000000, 0x006245f400000000, + 0x5a91c39900000000, 0x6cc041bd00000000, 0xbce11b9800000000, + 0x8ab099bc00000000, 0xd0431fd100000000, 0xe6129df500000000, + 0x64a5120a00000000, 0x52f4902e00000000, 0x0807164300000000, + 0x3e56946700000000, 0x4d6e786700000000, 0x7b3ffa4300000000, + 0x21cc7c2e00000000, 0x179dfe0a00000000, 0x952a71f500000000, + 0xa37bf3d100000000, 0xf98875bc00000000, 0xcfd9f79800000000, + 0xd5ad196000000000, 0xe3fc9b4400000000, 0xb90f1d2900000000, + 0x8f5e9f0d00000000, 0x0de910f200000000, 0x3bb892d600000000, + 0x614b14bb00000000, 0x571a969f00000000, 0x24227a9f00000000, + 0x1273f8bb00000000, 0x48807ed600000000, 0x7ed1fcf200000000, + 0xfc66730d00000000, 0xca37f12900000000, 0x90c4774400000000, + 0xa695f56000000000, 0x76b4af4500000000, 0x40e52d6100000000, + 0x1a16ab0c00000000, 0x2c47292800000000, 0xaef0a6d700000000, + 0x98a124f300000000, 0xc252a29e00000000, 0xf40320ba00000000, + 0x873bccba00000000, 0xb16a4e9e00000000, 0xeb99c8f300000000, + 0xddc84ad700000000, 0x5f7fc52800000000, 0x692e470c00000000, + 0x33ddc16100000000, 0x058c434500000000, 0x939e752b00000000, + 0xa5cff70f00000000, 0xff3c716200000000, 0xc96df34600000000, + 0x4bda7cb900000000, 0x7d8bfe9d00000000, 0x277878f000000000, + 0x1129fad400000000, 0x621116d400000000, 0x544094f000000000, + 0x0eb3129d00000000, 0x38e290b900000000, 0xba551f4600000000, + 0x8c049d6200000000, 0xd6f71b0f00000000, 0xe0a6992b00000000, + 0x3087c30e00000000, 0x06d6412a00000000, 0x5c25c74700000000, + 0x6a74456300000000, 0xe8c3ca9c00000000, 0xde9248b800000000, + 0x8461ced500000000, 0xb2304cf100000000, 0xc108a0f100000000, + 0xf75922d500000000, 0xadaaa4b800000000, 0x9bfb269c00000000, + 0x194ca96300000000, 0x2f1d2b4700000000, 0x75eead2a00000000, + 0x43bf2f0e00000000}, + {0x0000000000000000, 0xc8179ecf00000000, 0xd1294d4400000000, + 0x193ed38b00000000, 0xa2539a8800000000, 0x6a44044700000000, + 0x737ad7cc00000000, 0xbb6d490300000000, 0x05a145ca00000000, + 0xcdb6db0500000000, 0xd488088e00000000, 0x1c9f964100000000, + 0xa7f2df4200000000, 0x6fe5418d00000000, 0x76db920600000000, + 0xbecc0cc900000000, 0x4b44fa4f00000000, 0x8353648000000000, + 0x9a6db70b00000000, 0x527a29c400000000, 0xe91760c700000000, + 0x2100fe0800000000, 0x383e2d8300000000, 0xf029b34c00000000, + 0x4ee5bf8500000000, 0x86f2214a00000000, 0x9fccf2c100000000, + 0x57db6c0e00000000, 0xecb6250d00000000, 0x24a1bbc200000000, + 0x3d9f684900000000, 0xf588f68600000000, 0x9688f49f00000000, + 0x5e9f6a5000000000, 0x47a1b9db00000000, 0x8fb6271400000000, + 0x34db6e1700000000, 0xfcccf0d800000000, 0xe5f2235300000000, + 0x2de5bd9c00000000, 0x9329b15500000000, 0x5b3e2f9a00000000, + 0x4200fc1100000000, 0x8a1762de00000000, 0x317a2bdd00000000, + 0xf96db51200000000, 0xe053669900000000, 0x2844f85600000000, + 0xddcc0ed000000000, 0x15db901f00000000, 0x0ce5439400000000, + 0xc4f2dd5b00000000, 0x7f9f945800000000, 0xb7880a9700000000, + 0xaeb6d91c00000000, 0x66a147d300000000, 0xd86d4b1a00000000, + 0x107ad5d500000000, 0x0944065e00000000, 0xc153989100000000, + 0x7a3ed19200000000, 0xb2294f5d00000000, 0xab179cd600000000, + 0x6300021900000000, 0x6d1798e400000000, 0xa500062b00000000, + 0xbc3ed5a000000000, 0x74294b6f00000000, 0xcf44026c00000000, + 0x07539ca300000000, 0x1e6d4f2800000000, 0xd67ad1e700000000, + 0x68b6dd2e00000000, 0xa0a143e100000000, 0xb99f906a00000000, + 0x71880ea500000000, 0xcae547a600000000, 0x02f2d96900000000, + 0x1bcc0ae200000000, 0xd3db942d00000000, 0x265362ab00000000, + 0xee44fc6400000000, 0xf77a2fef00000000, 0x3f6db12000000000, + 0x8400f82300000000, 0x4c1766ec00000000, 0x5529b56700000000, + 0x9d3e2ba800000000, 0x23f2276100000000, 0xebe5b9ae00000000, + 0xf2db6a2500000000, 0x3accf4ea00000000, 0x81a1bde900000000, + 0x49b6232600000000, 0x5088f0ad00000000, 0x989f6e6200000000, + 0xfb9f6c7b00000000, 0x3388f2b400000000, 0x2ab6213f00000000, + 0xe2a1bff000000000, 0x59ccf6f300000000, 0x91db683c00000000, + 0x88e5bbb700000000, 0x40f2257800000000, 0xfe3e29b100000000, + 0x3629b77e00000000, 0x2f1764f500000000, 0xe700fa3a00000000, + 0x5c6db33900000000, 0x947a2df600000000, 0x8d44fe7d00000000, + 0x455360b200000000, 0xb0db963400000000, 0x78cc08fb00000000, + 0x61f2db7000000000, 0xa9e545bf00000000, 0x12880cbc00000000, + 0xda9f927300000000, 0xc3a141f800000000, 0x0bb6df3700000000, + 0xb57ad3fe00000000, 0x7d6d4d3100000000, 0x64539eba00000000, + 0xac44007500000000, 0x1729497600000000, 0xdf3ed7b900000000, + 0xc600043200000000, 0x0e179afd00000000, 0x9b28411200000000, + 0x533fdfdd00000000, 0x4a010c5600000000, 0x8216929900000000, + 0x397bdb9a00000000, 0xf16c455500000000, 0xe85296de00000000, + 0x2045081100000000, 0x9e8904d800000000, 0x569e9a1700000000, + 0x4fa0499c00000000, 0x87b7d75300000000, 0x3cda9e5000000000, + 0xf4cd009f00000000, 0xedf3d31400000000, 0x25e44ddb00000000, + 0xd06cbb5d00000000, 0x187b259200000000, 0x0145f61900000000, + 0xc95268d600000000, 0x723f21d500000000, 0xba28bf1a00000000, + 0xa3166c9100000000, 0x6b01f25e00000000, 0xd5cdfe9700000000, + 0x1dda605800000000, 0x04e4b3d300000000, 0xccf32d1c00000000, + 0x779e641f00000000, 0xbf89fad000000000, 0xa6b7295b00000000, + 0x6ea0b79400000000, 0x0da0b58d00000000, 0xc5b72b4200000000, + 0xdc89f8c900000000, 0x149e660600000000, 0xaff32f0500000000, + 0x67e4b1ca00000000, 0x7eda624100000000, 0xb6cdfc8e00000000, + 0x0801f04700000000, 0xc0166e8800000000, 0xd928bd0300000000, + 0x113f23cc00000000, 0xaa526acf00000000, 0x6245f40000000000, + 0x7b7b278b00000000, 0xb36cb94400000000, 0x46e44fc200000000, + 0x8ef3d10d00000000, 0x97cd028600000000, 0x5fda9c4900000000, + 0xe4b7d54a00000000, 0x2ca04b8500000000, 0x359e980e00000000, + 0xfd8906c100000000, 0x43450a0800000000, 0x8b5294c700000000, + 0x926c474c00000000, 0x5a7bd98300000000, 0xe116908000000000, + 0x29010e4f00000000, 0x303fddc400000000, 0xf828430b00000000, + 0xf63fd9f600000000, 0x3e28473900000000, 0x271694b200000000, + 0xef010a7d00000000, 0x546c437e00000000, 0x9c7bddb100000000, + 0x85450e3a00000000, 0x4d5290f500000000, 0xf39e9c3c00000000, + 0x3b8902f300000000, 0x22b7d17800000000, 0xeaa04fb700000000, + 0x51cd06b400000000, 0x99da987b00000000, 0x80e44bf000000000, + 0x48f3d53f00000000, 0xbd7b23b900000000, 0x756cbd7600000000, + 0x6c526efd00000000, 0xa445f03200000000, 0x1f28b93100000000, + 0xd73f27fe00000000, 0xce01f47500000000, 0x06166aba00000000, + 0xb8da667300000000, 0x70cdf8bc00000000, 0x69f32b3700000000, + 0xa1e4b5f800000000, 0x1a89fcfb00000000, 0xd29e623400000000, + 0xcba0b1bf00000000, 0x03b72f7000000000, 0x60b72d6900000000, + 0xa8a0b3a600000000, 0xb19e602d00000000, 0x7989fee200000000, + 0xc2e4b7e100000000, 0x0af3292e00000000, 0x13cdfaa500000000, + 0xdbda646a00000000, 0x651668a300000000, 0xad01f66c00000000, + 0xb43f25e700000000, 0x7c28bb2800000000, 0xc745f22b00000000, + 0x0f526ce400000000, 0x166cbf6f00000000, 0xde7b21a000000000, + 0x2bf3d72600000000, 0xe3e449e900000000, 0xfada9a6200000000, + 0x32cd04ad00000000, 0x89a04dae00000000, 0x41b7d36100000000, + 0x588900ea00000000, 0x909e9e2500000000, 0x2e5292ec00000000, + 0xe6450c2300000000, 0xff7bdfa800000000, 0x376c416700000000, + 0x8c01086400000000, 0x441696ab00000000, 0x5d28452000000000, + 0x953fdbef00000000}, + {0x0000000000000000, 0x95d4709500000000, 0x6baf90f100000000, + 0xfe7be06400000000, 0x9758503800000000, 0x028c20ad00000000, + 0xfcf7c0c900000000, 0x6923b05c00000000, 0x2eb1a07000000000, + 0xbb65d0e500000000, 0x451e308100000000, 0xd0ca401400000000, + 0xb9e9f04800000000, 0x2c3d80dd00000000, 0xd24660b900000000, + 0x4792102c00000000, 0x5c6241e100000000, 0xc9b6317400000000, + 0x37cdd11000000000, 0xa219a18500000000, 0xcb3a11d900000000, + 0x5eee614c00000000, 0xa095812800000000, 0x3541f1bd00000000, + 0x72d3e19100000000, 0xe707910400000000, 0x197c716000000000, + 0x8ca801f500000000, 0xe58bb1a900000000, 0x705fc13c00000000, + 0x8e24215800000000, 0x1bf051cd00000000, 0xf9c2f31900000000, + 0x6c16838c00000000, 0x926d63e800000000, 0x07b9137d00000000, + 0x6e9aa32100000000, 0xfb4ed3b400000000, 0x053533d000000000, + 0x90e1434500000000, 0xd773536900000000, 0x42a723fc00000000, + 0xbcdcc39800000000, 0x2908b30d00000000, 0x402b035100000000, + 0xd5ff73c400000000, 0x2b8493a000000000, 0xbe50e33500000000, + 0xa5a0b2f800000000, 0x3074c26d00000000, 0xce0f220900000000, + 0x5bdb529c00000000, 0x32f8e2c000000000, 0xa72c925500000000, + 0x5957723100000000, 0xcc8302a400000000, 0x8b11128800000000, + 0x1ec5621d00000000, 0xe0be827900000000, 0x756af2ec00000000, + 0x1c4942b000000000, 0x899d322500000000, 0x77e6d24100000000, + 0xe232a2d400000000, 0xf285e73300000000, 0x675197a600000000, + 0x992a77c200000000, 0x0cfe075700000000, 0x65ddb70b00000000, + 0xf009c79e00000000, 0x0e7227fa00000000, 0x9ba6576f00000000, + 0xdc34474300000000, 0x49e037d600000000, 0xb79bd7b200000000, + 0x224fa72700000000, 0x4b6c177b00000000, 0xdeb867ee00000000, + 0x20c3878a00000000, 0xb517f71f00000000, 0xaee7a6d200000000, + 0x3b33d64700000000, 0xc548362300000000, 0x509c46b600000000, + 0x39bff6ea00000000, 0xac6b867f00000000, 0x5210661b00000000, + 0xc7c4168e00000000, 0x805606a200000000, 0x1582763700000000, + 0xebf9965300000000, 0x7e2de6c600000000, 0x170e569a00000000, + 0x82da260f00000000, 0x7ca1c66b00000000, 0xe975b6fe00000000, + 0x0b47142a00000000, 0x9e9364bf00000000, 0x60e884db00000000, + 0xf53cf44e00000000, 0x9c1f441200000000, 0x09cb348700000000, + 0xf7b0d4e300000000, 0x6264a47600000000, 0x25f6b45a00000000, + 0xb022c4cf00000000, 0x4e5924ab00000000, 0xdb8d543e00000000, + 0xb2aee46200000000, 0x277a94f700000000, 0xd901749300000000, + 0x4cd5040600000000, 0x572555cb00000000, 0xc2f1255e00000000, + 0x3c8ac53a00000000, 0xa95eb5af00000000, 0xc07d05f300000000, + 0x55a9756600000000, 0xabd2950200000000, 0x3e06e59700000000, + 0x7994f5bb00000000, 0xec40852e00000000, 0x123b654a00000000, + 0x87ef15df00000000, 0xeecca58300000000, 0x7b18d51600000000, + 0x8563357200000000, 0x10b745e700000000, 0xe40bcf6700000000, + 0x71dfbff200000000, 0x8fa45f9600000000, 0x1a702f0300000000, + 0x73539f5f00000000, 0xe687efca00000000, 0x18fc0fae00000000, + 0x8d287f3b00000000, 0xcaba6f1700000000, 0x5f6e1f8200000000, + 0xa115ffe600000000, 0x34c18f7300000000, 0x5de23f2f00000000, + 0xc8364fba00000000, 0x364dafde00000000, 0xa399df4b00000000, + 0xb8698e8600000000, 0x2dbdfe1300000000, 0xd3c61e7700000000, + 0x46126ee200000000, 0x2f31debe00000000, 0xbae5ae2b00000000, + 0x449e4e4f00000000, 0xd14a3eda00000000, 0x96d82ef600000000, + 0x030c5e6300000000, 0xfd77be0700000000, 0x68a3ce9200000000, + 0x01807ece00000000, 0x94540e5b00000000, 0x6a2fee3f00000000, + 0xfffb9eaa00000000, 0x1dc93c7e00000000, 0x881d4ceb00000000, + 0x7666ac8f00000000, 0xe3b2dc1a00000000, 0x8a916c4600000000, + 0x1f451cd300000000, 0xe13efcb700000000, 0x74ea8c2200000000, + 0x33789c0e00000000, 0xa6acec9b00000000, 0x58d70cff00000000, + 0xcd037c6a00000000, 0xa420cc3600000000, 0x31f4bca300000000, + 0xcf8f5cc700000000, 0x5a5b2c5200000000, 0x41ab7d9f00000000, + 0xd47f0d0a00000000, 0x2a04ed6e00000000, 0xbfd09dfb00000000, + 0xd6f32da700000000, 0x43275d3200000000, 0xbd5cbd5600000000, + 0x2888cdc300000000, 0x6f1addef00000000, 0xfacead7a00000000, + 0x04b54d1e00000000, 0x91613d8b00000000, 0xf8428dd700000000, + 0x6d96fd4200000000, 0x93ed1d2600000000, 0x06396db300000000, + 0x168e285400000000, 0x835a58c100000000, 0x7d21b8a500000000, + 0xe8f5c83000000000, 0x81d6786c00000000, 0x140208f900000000, + 0xea79e89d00000000, 0x7fad980800000000, 0x383f882400000000, + 0xadebf8b100000000, 0x539018d500000000, 0xc644684000000000, + 0xaf67d81c00000000, 0x3ab3a88900000000, 0xc4c848ed00000000, + 0x511c387800000000, 0x4aec69b500000000, 0xdf38192000000000, + 0x2143f94400000000, 0xb49789d100000000, 0xddb4398d00000000, + 0x4860491800000000, 0xb61ba97c00000000, 0x23cfd9e900000000, + 0x645dc9c500000000, 0xf189b95000000000, 0x0ff2593400000000, + 0x9a2629a100000000, 0xf30599fd00000000, 0x66d1e96800000000, + 0x98aa090c00000000, 0x0d7e799900000000, 0xef4cdb4d00000000, + 0x7a98abd800000000, 0x84e34bbc00000000, 0x11373b2900000000, + 0x78148b7500000000, 0xedc0fbe000000000, 0x13bb1b8400000000, + 0x866f6b1100000000, 0xc1fd7b3d00000000, 0x54290ba800000000, + 0xaa52ebcc00000000, 0x3f869b5900000000, 0x56a52b0500000000, + 0xc3715b9000000000, 0x3d0abbf400000000, 0xa8decb6100000000, + 0xb32e9aac00000000, 0x26faea3900000000, 0xd8810a5d00000000, + 0x4d557ac800000000, 0x2476ca9400000000, 0xb1a2ba0100000000, + 0x4fd95a6500000000, 0xda0d2af000000000, 0x9d9f3adc00000000, + 0x084b4a4900000000, 0xf630aa2d00000000, 0x63e4dab800000000, + 0x0ac76ae400000000, 0x9f131a7100000000, 0x6168fa1500000000, + 0xf4bc8a8000000000}, + {0x0000000000000000, 0x1f17f08000000000, 0x7f2891da00000000, + 0x603f615a00000000, 0xbf56536e00000000, 0xa041a3ee00000000, + 0xc07ec2b400000000, 0xdf69323400000000, 0x7eada6dc00000000, + 0x61ba565c00000000, 0x0185370600000000, 0x1e92c78600000000, + 0xc1fbf5b200000000, 0xdeec053200000000, 0xbed3646800000000, + 0xa1c494e800000000, 0xbd5c3c6200000000, 0xa24bcce200000000, + 0xc274adb800000000, 0xdd635d3800000000, 0x020a6f0c00000000, + 0x1d1d9f8c00000000, 0x7d22fed600000000, 0x62350e5600000000, + 0xc3f19abe00000000, 0xdce66a3e00000000, 0xbcd90b6400000000, + 0xa3cefbe400000000, 0x7ca7c9d000000000, 0x63b0395000000000, + 0x038f580a00000000, 0x1c98a88a00000000, 0x7ab978c400000000, + 0x65ae884400000000, 0x0591e91e00000000, 0x1a86199e00000000, + 0xc5ef2baa00000000, 0xdaf8db2a00000000, 0xbac7ba7000000000, + 0xa5d04af000000000, 0x0414de1800000000, 0x1b032e9800000000, + 0x7b3c4fc200000000, 0x642bbf4200000000, 0xbb428d7600000000, + 0xa4557df600000000, 0xc46a1cac00000000, 0xdb7dec2c00000000, + 0xc7e544a600000000, 0xd8f2b42600000000, 0xb8cdd57c00000000, + 0xa7da25fc00000000, 0x78b317c800000000, 0x67a4e74800000000, + 0x079b861200000000, 0x188c769200000000, 0xb948e27a00000000, + 0xa65f12fa00000000, 0xc66073a000000000, 0xd977832000000000, + 0x061eb11400000000, 0x1909419400000000, 0x793620ce00000000, + 0x6621d04e00000000, 0xb574805300000000, 0xaa6370d300000000, + 0xca5c118900000000, 0xd54be10900000000, 0x0a22d33d00000000, + 0x153523bd00000000, 0x750a42e700000000, 0x6a1db26700000000, + 0xcbd9268f00000000, 0xd4ced60f00000000, 0xb4f1b75500000000, + 0xabe647d500000000, 0x748f75e100000000, 0x6b98856100000000, + 0x0ba7e43b00000000, 0x14b014bb00000000, 0x0828bc3100000000, + 0x173f4cb100000000, 0x77002deb00000000, 0x6817dd6b00000000, + 0xb77eef5f00000000, 0xa8691fdf00000000, 0xc8567e8500000000, + 0xd7418e0500000000, 0x76851aed00000000, 0x6992ea6d00000000, + 0x09ad8b3700000000, 0x16ba7bb700000000, 0xc9d3498300000000, + 0xd6c4b90300000000, 0xb6fbd85900000000, 0xa9ec28d900000000, + 0xcfcdf89700000000, 0xd0da081700000000, 0xb0e5694d00000000, + 0xaff299cd00000000, 0x709babf900000000, 0x6f8c5b7900000000, + 0x0fb33a2300000000, 0x10a4caa300000000, 0xb1605e4b00000000, + 0xae77aecb00000000, 0xce48cf9100000000, 0xd15f3f1100000000, + 0x0e360d2500000000, 0x1121fda500000000, 0x711e9cff00000000, + 0x6e096c7f00000000, 0x7291c4f500000000, 0x6d86347500000000, + 0x0db9552f00000000, 0x12aea5af00000000, 0xcdc7979b00000000, + 0xd2d0671b00000000, 0xb2ef064100000000, 0xadf8f6c100000000, + 0x0c3c622900000000, 0x132b92a900000000, 0x7314f3f300000000, + 0x6c03037300000000, 0xb36a314700000000, 0xac7dc1c700000000, + 0xcc42a09d00000000, 0xd355501d00000000, 0x6ae900a700000000, + 0x75fef02700000000, 0x15c1917d00000000, 0x0ad661fd00000000, + 0xd5bf53c900000000, 0xcaa8a34900000000, 0xaa97c21300000000, + 0xb580329300000000, 0x1444a67b00000000, 0x0b5356fb00000000, + 0x6b6c37a100000000, 0x747bc72100000000, 0xab12f51500000000, + 0xb405059500000000, 0xd43a64cf00000000, 0xcb2d944f00000000, + 0xd7b53cc500000000, 0xc8a2cc4500000000, 0xa89dad1f00000000, + 0xb78a5d9f00000000, 0x68e36fab00000000, 0x77f49f2b00000000, + 0x17cbfe7100000000, 0x08dc0ef100000000, 0xa9189a1900000000, + 0xb60f6a9900000000, 0xd6300bc300000000, 0xc927fb4300000000, + 0x164ec97700000000, 0x095939f700000000, 0x696658ad00000000, + 0x7671a82d00000000, 0x1050786300000000, 0x0f4788e300000000, + 0x6f78e9b900000000, 0x706f193900000000, 0xaf062b0d00000000, + 0xb011db8d00000000, 0xd02ebad700000000, 0xcf394a5700000000, + 0x6efddebf00000000, 0x71ea2e3f00000000, 0x11d54f6500000000, + 0x0ec2bfe500000000, 0xd1ab8dd100000000, 0xcebc7d5100000000, + 0xae831c0b00000000, 0xb194ec8b00000000, 0xad0c440100000000, + 0xb21bb48100000000, 0xd224d5db00000000, 0xcd33255b00000000, + 0x125a176f00000000, 0x0d4de7ef00000000, 0x6d7286b500000000, + 0x7265763500000000, 0xd3a1e2dd00000000, 0xccb6125d00000000, + 0xac89730700000000, 0xb39e838700000000, 0x6cf7b1b300000000, + 0x73e0413300000000, 0x13df206900000000, 0x0cc8d0e900000000, + 0xdf9d80f400000000, 0xc08a707400000000, 0xa0b5112e00000000, + 0xbfa2e1ae00000000, 0x60cbd39a00000000, 0x7fdc231a00000000, + 0x1fe3424000000000, 0x00f4b2c000000000, 0xa130262800000000, + 0xbe27d6a800000000, 0xde18b7f200000000, 0xc10f477200000000, + 0x1e66754600000000, 0x017185c600000000, 0x614ee49c00000000, + 0x7e59141c00000000, 0x62c1bc9600000000, 0x7dd64c1600000000, + 0x1de92d4c00000000, 0x02feddcc00000000, 0xdd97eff800000000, + 0xc2801f7800000000, 0xa2bf7e2200000000, 0xbda88ea200000000, + 0x1c6c1a4a00000000, 0x037beaca00000000, 0x63448b9000000000, + 0x7c537b1000000000, 0xa33a492400000000, 0xbc2db9a400000000, + 0xdc12d8fe00000000, 0xc305287e00000000, 0xa524f83000000000, + 0xba3308b000000000, 0xda0c69ea00000000, 0xc51b996a00000000, + 0x1a72ab5e00000000, 0x05655bde00000000, 0x655a3a8400000000, + 0x7a4dca0400000000, 0xdb895eec00000000, 0xc49eae6c00000000, + 0xa4a1cf3600000000, 0xbbb63fb600000000, 0x64df0d8200000000, + 0x7bc8fd0200000000, 0x1bf79c5800000000, 0x04e06cd800000000, + 0x1878c45200000000, 0x076f34d200000000, 0x6750558800000000, + 0x7847a50800000000, 0xa72e973c00000000, 0xb83967bc00000000, + 0xd80606e600000000, 0xc711f66600000000, 0x66d5628e00000000, + 0x79c2920e00000000, 0x19fdf35400000000, 0x06ea03d400000000, + 0xd98331e000000000, 0xc694c16000000000, 0xa6aba03a00000000, + 0xb9bc50ba00000000}, + {0x0000000000000000, 0xe2fd888d00000000, 0x85fd60c000000000, + 0x6700e84d00000000, 0x4bfdb05b00000000, 0xa90038d600000000, + 0xce00d09b00000000, 0x2cfd581600000000, 0x96fa61b700000000, + 0x7407e93a00000000, 0x1307017700000000, 0xf1fa89fa00000000, + 0xdd07d1ec00000000, 0x3ffa596100000000, 0x58fab12c00000000, + 0xba0739a100000000, 0x6df3b2b500000000, 0x8f0e3a3800000000, + 0xe80ed27500000000, 0x0af35af800000000, 0x260e02ee00000000, + 0xc4f38a6300000000, 0xa3f3622e00000000, 0x410eeaa300000000, + 0xfb09d30200000000, 0x19f45b8f00000000, 0x7ef4b3c200000000, + 0x9c093b4f00000000, 0xb0f4635900000000, 0x5209ebd400000000, + 0x3509039900000000, 0xd7f48b1400000000, 0x9be014b000000000, + 0x791d9c3d00000000, 0x1e1d747000000000, 0xfce0fcfd00000000, + 0xd01da4eb00000000, 0x32e02c6600000000, 0x55e0c42b00000000, + 0xb71d4ca600000000, 0x0d1a750700000000, 0xefe7fd8a00000000, + 0x88e715c700000000, 0x6a1a9d4a00000000, 0x46e7c55c00000000, + 0xa41a4dd100000000, 0xc31aa59c00000000, 0x21e72d1100000000, + 0xf613a60500000000, 0x14ee2e8800000000, 0x73eec6c500000000, + 0x91134e4800000000, 0xbdee165e00000000, 0x5f139ed300000000, + 0x3813769e00000000, 0xdaeefe1300000000, 0x60e9c7b200000000, + 0x82144f3f00000000, 0xe514a77200000000, 0x07e92fff00000000, + 0x2b1477e900000000, 0xc9e9ff6400000000, 0xaee9172900000000, + 0x4c149fa400000000, 0x77c758bb00000000, 0x953ad03600000000, + 0xf23a387b00000000, 0x10c7b0f600000000, 0x3c3ae8e000000000, + 0xdec7606d00000000, 0xb9c7882000000000, 0x5b3a00ad00000000, + 0xe13d390c00000000, 0x03c0b18100000000, 0x64c059cc00000000, + 0x863dd14100000000, 0xaac0895700000000, 0x483d01da00000000, + 0x2f3de99700000000, 0xcdc0611a00000000, 0x1a34ea0e00000000, + 0xf8c9628300000000, 0x9fc98ace00000000, 0x7d34024300000000, + 0x51c95a5500000000, 0xb334d2d800000000, 0xd4343a9500000000, + 0x36c9b21800000000, 0x8cce8bb900000000, 0x6e33033400000000, + 0x0933eb7900000000, 0xebce63f400000000, 0xc7333be200000000, + 0x25ceb36f00000000, 0x42ce5b2200000000, 0xa033d3af00000000, + 0xec274c0b00000000, 0x0edac48600000000, 0x69da2ccb00000000, + 0x8b27a44600000000, 0xa7dafc5000000000, 0x452774dd00000000, + 0x22279c9000000000, 0xc0da141d00000000, 0x7add2dbc00000000, + 0x9820a53100000000, 0xff204d7c00000000, 0x1dddc5f100000000, + 0x31209de700000000, 0xd3dd156a00000000, 0xb4ddfd2700000000, + 0x562075aa00000000, 0x81d4febe00000000, 0x6329763300000000, + 0x04299e7e00000000, 0xe6d416f300000000, 0xca294ee500000000, + 0x28d4c66800000000, 0x4fd42e2500000000, 0xad29a6a800000000, + 0x172e9f0900000000, 0xf5d3178400000000, 0x92d3ffc900000000, + 0x702e774400000000, 0x5cd32f5200000000, 0xbe2ea7df00000000, + 0xd92e4f9200000000, 0x3bd3c71f00000000, 0xaf88c0ad00000000, + 0x4d75482000000000, 0x2a75a06d00000000, 0xc88828e000000000, + 0xe47570f600000000, 0x0688f87b00000000, 0x6188103600000000, + 0x837598bb00000000, 0x3972a11a00000000, 0xdb8f299700000000, + 0xbc8fc1da00000000, 0x5e72495700000000, 0x728f114100000000, + 0x907299cc00000000, 0xf772718100000000, 0x158ff90c00000000, + 0xc27b721800000000, 0x2086fa9500000000, 0x478612d800000000, + 0xa57b9a5500000000, 0x8986c24300000000, 0x6b7b4ace00000000, + 0x0c7ba28300000000, 0xee862a0e00000000, 0x548113af00000000, + 0xb67c9b2200000000, 0xd17c736f00000000, 0x3381fbe200000000, + 0x1f7ca3f400000000, 0xfd812b7900000000, 0x9a81c33400000000, + 0x787c4bb900000000, 0x3468d41d00000000, 0xd6955c9000000000, + 0xb195b4dd00000000, 0x53683c5000000000, 0x7f95644600000000, + 0x9d68eccb00000000, 0xfa68048600000000, 0x18958c0b00000000, + 0xa292b5aa00000000, 0x406f3d2700000000, 0x276fd56a00000000, + 0xc5925de700000000, 0xe96f05f100000000, 0x0b928d7c00000000, + 0x6c92653100000000, 0x8e6fedbc00000000, 0x599b66a800000000, + 0xbb66ee2500000000, 0xdc66066800000000, 0x3e9b8ee500000000, + 0x1266d6f300000000, 0xf09b5e7e00000000, 0x979bb63300000000, + 0x75663ebe00000000, 0xcf61071f00000000, 0x2d9c8f9200000000, + 0x4a9c67df00000000, 0xa861ef5200000000, 0x849cb74400000000, + 0x66613fc900000000, 0x0161d78400000000, 0xe39c5f0900000000, + 0xd84f981600000000, 0x3ab2109b00000000, 0x5db2f8d600000000, + 0xbf4f705b00000000, 0x93b2284d00000000, 0x714fa0c000000000, + 0x164f488d00000000, 0xf4b2c00000000000, 0x4eb5f9a100000000, + 0xac48712c00000000, 0xcb48996100000000, 0x29b511ec00000000, + 0x054849fa00000000, 0xe7b5c17700000000, 0x80b5293a00000000, + 0x6248a1b700000000, 0xb5bc2aa300000000, 0x5741a22e00000000, + 0x30414a6300000000, 0xd2bcc2ee00000000, 0xfe419af800000000, + 0x1cbc127500000000, 0x7bbcfa3800000000, 0x994172b500000000, + 0x23464b1400000000, 0xc1bbc39900000000, 0xa6bb2bd400000000, + 0x4446a35900000000, 0x68bbfb4f00000000, 0x8a4673c200000000, + 0xed469b8f00000000, 0x0fbb130200000000, 0x43af8ca600000000, + 0xa152042b00000000, 0xc652ec6600000000, 0x24af64eb00000000, + 0x08523cfd00000000, 0xeaafb47000000000, 0x8daf5c3d00000000, + 0x6f52d4b000000000, 0xd555ed1100000000, 0x37a8659c00000000, + 0x50a88dd100000000, 0xb255055c00000000, 0x9ea85d4a00000000, + 0x7c55d5c700000000, 0x1b553d8a00000000, 0xf9a8b50700000000, + 0x2e5c3e1300000000, 0xcca1b69e00000000, 0xaba15ed300000000, + 0x495cd65e00000000, 0x65a18e4800000000, 0x875c06c500000000, + 0xe05cee8800000000, 0x02a1660500000000, 0xb8a65fa400000000, + 0x5a5bd72900000000, 0x3d5b3f6400000000, 0xdfa6b7e900000000, + 0xf35befff00000000, 0x11a6677200000000, 0x76a68f3f00000000, + 0x945b07b200000000}, + {0x0000000000000000, 0xa90b894e00000000, 0x5217129d00000000, + 0xfb1c9bd300000000, 0xe52855e100000000, 0x4c23dcaf00000000, + 0xb73f477c00000000, 0x1e34ce3200000000, 0x8b57db1900000000, + 0x225c525700000000, 0xd940c98400000000, 0x704b40ca00000000, + 0x6e7f8ef800000000, 0xc77407b600000000, 0x3c689c6500000000, + 0x9563152b00000000, 0x16afb63300000000, 0xbfa43f7d00000000, + 0x44b8a4ae00000000, 0xedb32de000000000, 0xf387e3d200000000, + 0x5a8c6a9c00000000, 0xa190f14f00000000, 0x089b780100000000, + 0x9df86d2a00000000, 0x34f3e46400000000, 0xcfef7fb700000000, + 0x66e4f6f900000000, 0x78d038cb00000000, 0xd1dbb18500000000, + 0x2ac72a5600000000, 0x83cca31800000000, 0x2c5e6d6700000000, + 0x8555e42900000000, 0x7e497ffa00000000, 0xd742f6b400000000, + 0xc976388600000000, 0x607db1c800000000, 0x9b612a1b00000000, + 0x326aa35500000000, 0xa709b67e00000000, 0x0e023f3000000000, + 0xf51ea4e300000000, 0x5c152dad00000000, 0x4221e39f00000000, + 0xeb2a6ad100000000, 0x1036f10200000000, 0xb93d784c00000000, + 0x3af1db5400000000, 0x93fa521a00000000, 0x68e6c9c900000000, + 0xc1ed408700000000, 0xdfd98eb500000000, 0x76d207fb00000000, + 0x8dce9c2800000000, 0x24c5156600000000, 0xb1a6004d00000000, + 0x18ad890300000000, 0xe3b112d000000000, 0x4aba9b9e00000000, + 0x548e55ac00000000, 0xfd85dce200000000, 0x0699473100000000, + 0xaf92ce7f00000000, 0x58bcdace00000000, 0xf1b7538000000000, + 0x0aabc85300000000, 0xa3a0411d00000000, 0xbd948f2f00000000, + 0x149f066100000000, 0xef839db200000000, 0x468814fc00000000, + 0xd3eb01d700000000, 0x7ae0889900000000, 0x81fc134a00000000, + 0x28f79a0400000000, 0x36c3543600000000, 0x9fc8dd7800000000, + 0x64d446ab00000000, 0xcddfcfe500000000, 0x4e136cfd00000000, + 0xe718e5b300000000, 0x1c047e6000000000, 0xb50ff72e00000000, + 0xab3b391c00000000, 0x0230b05200000000, 0xf92c2b8100000000, + 0x5027a2cf00000000, 0xc544b7e400000000, 0x6c4f3eaa00000000, + 0x9753a57900000000, 0x3e582c3700000000, 0x206ce20500000000, + 0x89676b4b00000000, 0x727bf09800000000, 0xdb7079d600000000, + 0x74e2b7a900000000, 0xdde93ee700000000, 0x26f5a53400000000, + 0x8ffe2c7a00000000, 0x91cae24800000000, 0x38c16b0600000000, + 0xc3ddf0d500000000, 0x6ad6799b00000000, 0xffb56cb000000000, + 0x56bee5fe00000000, 0xada27e2d00000000, 0x04a9f76300000000, + 0x1a9d395100000000, 0xb396b01f00000000, 0x488a2bcc00000000, + 0xe181a28200000000, 0x624d019a00000000, 0xcb4688d400000000, + 0x305a130700000000, 0x99519a4900000000, 0x8765547b00000000, + 0x2e6edd3500000000, 0xd57246e600000000, 0x7c79cfa800000000, + 0xe91ada8300000000, 0x401153cd00000000, 0xbb0dc81e00000000, + 0x1206415000000000, 0x0c328f6200000000, 0xa539062c00000000, + 0x5e259dff00000000, 0xf72e14b100000000, 0xf17ec44600000000, + 0x58754d0800000000, 0xa369d6db00000000, 0x0a625f9500000000, + 0x145691a700000000, 0xbd5d18e900000000, 0x4641833a00000000, + 0xef4a0a7400000000, 0x7a291f5f00000000, 0xd322961100000000, + 0x283e0dc200000000, 0x8135848c00000000, 0x9f014abe00000000, + 0x360ac3f000000000, 0xcd16582300000000, 0x641dd16d00000000, + 0xe7d1727500000000, 0x4edafb3b00000000, 0xb5c660e800000000, + 0x1ccde9a600000000, 0x02f9279400000000, 0xabf2aeda00000000, + 0x50ee350900000000, 0xf9e5bc4700000000, 0x6c86a96c00000000, + 0xc58d202200000000, 0x3e91bbf100000000, 0x979a32bf00000000, + 0x89aefc8d00000000, 0x20a575c300000000, 0xdbb9ee1000000000, + 0x72b2675e00000000, 0xdd20a92100000000, 0x742b206f00000000, + 0x8f37bbbc00000000, 0x263c32f200000000, 0x3808fcc000000000, + 0x9103758e00000000, 0x6a1fee5d00000000, 0xc314671300000000, + 0x5677723800000000, 0xff7cfb7600000000, 0x046060a500000000, + 0xad6be9eb00000000, 0xb35f27d900000000, 0x1a54ae9700000000, + 0xe148354400000000, 0x4843bc0a00000000, 0xcb8f1f1200000000, + 0x6284965c00000000, 0x99980d8f00000000, 0x309384c100000000, + 0x2ea74af300000000, 0x87acc3bd00000000, 0x7cb0586e00000000, + 0xd5bbd12000000000, 0x40d8c40b00000000, 0xe9d34d4500000000, + 0x12cfd69600000000, 0xbbc45fd800000000, 0xa5f091ea00000000, + 0x0cfb18a400000000, 0xf7e7837700000000, 0x5eec0a3900000000, + 0xa9c21e8800000000, 0x00c997c600000000, 0xfbd50c1500000000, + 0x52de855b00000000, 0x4cea4b6900000000, 0xe5e1c22700000000, + 0x1efd59f400000000, 0xb7f6d0ba00000000, 0x2295c59100000000, + 0x8b9e4cdf00000000, 0x7082d70c00000000, 0xd9895e4200000000, + 0xc7bd907000000000, 0x6eb6193e00000000, 0x95aa82ed00000000, + 0x3ca10ba300000000, 0xbf6da8bb00000000, 0x166621f500000000, + 0xed7aba2600000000, 0x4471336800000000, 0x5a45fd5a00000000, + 0xf34e741400000000, 0x0852efc700000000, 0xa159668900000000, + 0x343a73a200000000, 0x9d31faec00000000, 0x662d613f00000000, + 0xcf26e87100000000, 0xd112264300000000, 0x7819af0d00000000, + 0x830534de00000000, 0x2a0ebd9000000000, 0x859c73ef00000000, + 0x2c97faa100000000, 0xd78b617200000000, 0x7e80e83c00000000, + 0x60b4260e00000000, 0xc9bfaf4000000000, 0x32a3349300000000, + 0x9ba8bddd00000000, 0x0ecba8f600000000, 0xa7c021b800000000, + 0x5cdcba6b00000000, 0xf5d7332500000000, 0xebe3fd1700000000, + 0x42e8745900000000, 0xb9f4ef8a00000000, 0x10ff66c400000000, + 0x9333c5dc00000000, 0x3a384c9200000000, 0xc124d74100000000, + 0x682f5e0f00000000, 0x761b903d00000000, 0xdf10197300000000, + 0x240c82a000000000, 0x8d070bee00000000, 0x18641ec500000000, + 0xb16f978b00000000, 0x4a730c5800000000, 0xe378851600000000, + 0xfd4c4b2400000000, 0x5447c26a00000000, 0xaf5b59b900000000, + 0x0650d0f700000000}, + {0x0000000000000000, 0x479244af00000000, 0xcf22f88500000000, + 0x88b0bc2a00000000, 0xdf4381d000000000, 0x98d1c57f00000000, + 0x1061795500000000, 0x57f33dfa00000000, 0xff81737a00000000, + 0xb81337d500000000, 0x30a38bff00000000, 0x7731cf5000000000, + 0x20c2f2aa00000000, 0x6750b60500000000, 0xefe00a2f00000000, + 0xa8724e8000000000, 0xfe03e7f400000000, 0xb991a35b00000000, + 0x31211f7100000000, 0x76b35bde00000000, 0x2140662400000000, + 0x66d2228b00000000, 0xee629ea100000000, 0xa9f0da0e00000000, + 0x0182948e00000000, 0x4610d02100000000, 0xcea06c0b00000000, + 0x893228a400000000, 0xdec1155e00000000, 0x995351f100000000, + 0x11e3eddb00000000, 0x5671a97400000000, 0xbd01bf3200000000, + 0xfa93fb9d00000000, 0x722347b700000000, 0x35b1031800000000, + 0x62423ee200000000, 0x25d07a4d00000000, 0xad60c66700000000, + 0xeaf282c800000000, 0x4280cc4800000000, 0x051288e700000000, + 0x8da234cd00000000, 0xca30706200000000, 0x9dc34d9800000000, + 0xda51093700000000, 0x52e1b51d00000000, 0x1573f1b200000000, + 0x430258c600000000, 0x04901c6900000000, 0x8c20a04300000000, + 0xcbb2e4ec00000000, 0x9c41d91600000000, 0xdbd39db900000000, + 0x5363219300000000, 0x14f1653c00000000, 0xbc832bbc00000000, + 0xfb116f1300000000, 0x73a1d33900000000, 0x3433979600000000, + 0x63c0aa6c00000000, 0x2452eec300000000, 0xace252e900000000, + 0xeb70164600000000, 0x7a037e6500000000, 0x3d913aca00000000, + 0xb52186e000000000, 0xf2b3c24f00000000, 0xa540ffb500000000, + 0xe2d2bb1a00000000, 0x6a62073000000000, 0x2df0439f00000000, + 0x85820d1f00000000, 0xc21049b000000000, 0x4aa0f59a00000000, + 0x0d32b13500000000, 0x5ac18ccf00000000, 0x1d53c86000000000, + 0x95e3744a00000000, 0xd27130e500000000, 0x8400999100000000, + 0xc392dd3e00000000, 0x4b22611400000000, 0x0cb025bb00000000, + 0x5b43184100000000, 0x1cd15cee00000000, 0x9461e0c400000000, + 0xd3f3a46b00000000, 0x7b81eaeb00000000, 0x3c13ae4400000000, + 0xb4a3126e00000000, 0xf33156c100000000, 0xa4c26b3b00000000, + 0xe3502f9400000000, 0x6be093be00000000, 0x2c72d71100000000, + 0xc702c15700000000, 0x809085f800000000, 0x082039d200000000, + 0x4fb27d7d00000000, 0x1841408700000000, 0x5fd3042800000000, + 0xd763b80200000000, 0x90f1fcad00000000, 0x3883b22d00000000, + 0x7f11f68200000000, 0xf7a14aa800000000, 0xb0330e0700000000, + 0xe7c033fd00000000, 0xa052775200000000, 0x28e2cb7800000000, + 0x6f708fd700000000, 0x390126a300000000, 0x7e93620c00000000, + 0xf623de2600000000, 0xb1b19a8900000000, 0xe642a77300000000, + 0xa1d0e3dc00000000, 0x29605ff600000000, 0x6ef21b5900000000, + 0xc68055d900000000, 0x8112117600000000, 0x09a2ad5c00000000, + 0x4e30e9f300000000, 0x19c3d40900000000, 0x5e5190a600000000, + 0xd6e12c8c00000000, 0x9173682300000000, 0xf406fcca00000000, + 0xb394b86500000000, 0x3b24044f00000000, 0x7cb640e000000000, + 0x2b457d1a00000000, 0x6cd739b500000000, 0xe467859f00000000, + 0xa3f5c13000000000, 0x0b878fb000000000, 0x4c15cb1f00000000, + 0xc4a5773500000000, 0x8337339a00000000, 0xd4c40e6000000000, + 0x93564acf00000000, 0x1be6f6e500000000, 0x5c74b24a00000000, + 0x0a051b3e00000000, 0x4d975f9100000000, 0xc527e3bb00000000, + 0x82b5a71400000000, 0xd5469aee00000000, 0x92d4de4100000000, + 0x1a64626b00000000, 0x5df626c400000000, 0xf584684400000000, + 0xb2162ceb00000000, 0x3aa690c100000000, 0x7d34d46e00000000, + 0x2ac7e99400000000, 0x6d55ad3b00000000, 0xe5e5111100000000, + 0xa27755be00000000, 0x490743f800000000, 0x0e95075700000000, + 0x8625bb7d00000000, 0xc1b7ffd200000000, 0x9644c22800000000, + 0xd1d6868700000000, 0x59663aad00000000, 0x1ef47e0200000000, + 0xb686308200000000, 0xf114742d00000000, 0x79a4c80700000000, + 0x3e368ca800000000, 0x69c5b15200000000, 0x2e57f5fd00000000, + 0xa6e749d700000000, 0xe1750d7800000000, 0xb704a40c00000000, + 0xf096e0a300000000, 0x78265c8900000000, 0x3fb4182600000000, + 0x684725dc00000000, 0x2fd5617300000000, 0xa765dd5900000000, + 0xe0f799f600000000, 0x4885d77600000000, 0x0f1793d900000000, + 0x87a72ff300000000, 0xc0356b5c00000000, 0x97c656a600000000, + 0xd054120900000000, 0x58e4ae2300000000, 0x1f76ea8c00000000, + 0x8e0582af00000000, 0xc997c60000000000, 0x41277a2a00000000, + 0x06b53e8500000000, 0x5146037f00000000, 0x16d447d000000000, + 0x9e64fbfa00000000, 0xd9f6bf5500000000, 0x7184f1d500000000, + 0x3616b57a00000000, 0xbea6095000000000, 0xf9344dff00000000, + 0xaec7700500000000, 0xe95534aa00000000, 0x61e5888000000000, + 0x2677cc2f00000000, 0x7006655b00000000, 0x379421f400000000, + 0xbf249dde00000000, 0xf8b6d97100000000, 0xaf45e48b00000000, + 0xe8d7a02400000000, 0x60671c0e00000000, 0x27f558a100000000, + 0x8f87162100000000, 0xc815528e00000000, 0x40a5eea400000000, + 0x0737aa0b00000000, 0x50c497f100000000, 0x1756d35e00000000, + 0x9fe66f7400000000, 0xd8742bdb00000000, 0x33043d9d00000000, + 0x7496793200000000, 0xfc26c51800000000, 0xbbb481b700000000, + 0xec47bc4d00000000, 0xabd5f8e200000000, 0x236544c800000000, + 0x64f7006700000000, 0xcc854ee700000000, 0x8b170a4800000000, + 0x03a7b66200000000, 0x4435f2cd00000000, 0x13c6cf3700000000, + 0x54548b9800000000, 0xdce437b200000000, 0x9b76731d00000000, + 0xcd07da6900000000, 0x8a959ec600000000, 0x022522ec00000000, + 0x45b7664300000000, 0x12445bb900000000, 0x55d61f1600000000, + 0xdd66a33c00000000, 0x9af4e79300000000, 0x3286a91300000000, + 0x7514edbc00000000, 0xfda4519600000000, 0xba36153900000000, + 0xedc528c300000000, 0xaa576c6c00000000, 0x22e7d04600000000, + 0x657594e900000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59, + 0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4, + 0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67, + 0x7c9f7021, 0xe0c6ab25, 0x85a19063, 0x2a08dda9, 0x4f6fe6ef, + 0xae2b407c, 0xcb4c7b3a, 0x64e536f0, 0x01820db6, 0x7d1d7d97, + 0x187a46d1, 0xb7d30b1b, 0xd2b4305d, 0x33f096ce, 0x5697ad88, + 0xf93ee042, 0x9c59db04, 0x1afc500b, 0x7f9b6b4d, 0xd0322687, + 0xb5551dc1, 0x5411bb52, 0x31768014, 0x9edfcdde, 0xfbb8f698, + 0x872786b9, 0xe240bdff, 0x4de9f035, 0x288ecb73, 0xc9ca6de0, + 0xacad56a6, 0x03041b6c, 0x6663202a, 0xfa3afb2e, 0x9f5dc068, + 0x30f48da2, 0x5593b6e4, 0xb4d71077, 0xd1b02b31, 0x7e1966fb, + 0x1b7e5dbd, 0x67e12d9c, 0x028616da, 0xad2f5b10, 0xc8486056, + 0x290cc6c5, 0x4c6bfd83, 0xe3c2b049, 0x86a58b0f, 0x35f8a016, + 0x509f9b50, 0xff36d69a, 0x9a51eddc, 0x7b154b4f, 0x1e727009, + 0xb1db3dc3, 0xd4bc0685, 0xa82376a4, 0xcd444de2, 0x62ed0028, + 0x078a3b6e, 0xe6ce9dfd, 0x83a9a6bb, 0x2c00eb71, 0x4967d037, + 0xd53e0b33, 0xb0593075, 0x1ff07dbf, 0x7a9746f9, 0x9bd3e06a, + 0xfeb4db2c, 0x511d96e6, 0x347aada0, 0x48e5dd81, 0x2d82e6c7, + 0x822bab0d, 0xe74c904b, 0x060836d8, 0x636f0d9e, 0xccc64054, + 0xa9a17b12, 0x2f04f01d, 0x4a63cb5b, 0xe5ca8691, 0x80adbdd7, + 0x61e91b44, 0x048e2002, 0xab276dc8, 0xce40568e, 0xb2df26af, + 0xd7b81de9, 0x78115023, 0x1d766b65, 0xfc32cdf6, 0x9955f6b0, + 0x36fcbb7a, 0x539b803c, 0xcfc25b38, 0xaaa5607e, 0x050c2db4, + 0x606b16f2, 0x812fb061, 0xe4488b27, 0x4be1c6ed, 0x2e86fdab, + 0x52198d8a, 0x377eb6cc, 0x98d7fb06, 0xfdb0c040, 0x1cf466d3, + 0x79935d95, 0xd63a105f, 0xb35d2b19, 0x6bf1402c, 0x0e967b6a, + 0xa13f36a0, 0xc4580de6, 0x251cab75, 0x407b9033, 0xefd2ddf9, + 0x8ab5e6bf, 0xf62a969e, 0x934dadd8, 0x3ce4e012, 0x5983db54, + 0xb8c77dc7, 0xdda04681, 0x72090b4b, 0x176e300d, 0x8b37eb09, + 0xee50d04f, 0x41f99d85, 0x249ea6c3, 0xc5da0050, 0xa0bd3b16, + 0x0f1476dc, 0x6a734d9a, 0x16ec3dbb, 0x738b06fd, 0xdc224b37, + 0xb9457071, 0x5801d6e2, 0x3d66eda4, 0x92cfa06e, 0xf7a89b28, + 0x710d1027, 0x146a2b61, 0xbbc366ab, 0xdea45ded, 0x3fe0fb7e, + 0x5a87c038, 0xf52e8df2, 0x9049b6b4, 0xecd6c695, 0x89b1fdd3, + 0x2618b019, 0x437f8b5f, 0xa23b2dcc, 0xc75c168a, 0x68f55b40, + 0x0d926006, 0x91cbbb02, 0xf4ac8044, 0x5b05cd8e, 0x3e62f6c8, + 0xdf26505b, 0xba416b1d, 0x15e826d7, 0x708f1d91, 0x0c106db0, + 0x697756f6, 0xc6de1b3c, 0xa3b9207a, 0x42fd86e9, 0x279abdaf, + 0x8833f065, 0xed54cb23, 0x5e09e03a, 0x3b6edb7c, 0x94c796b6, + 0xf1a0adf0, 0x10e40b63, 0x75833025, 0xda2a7def, 0xbf4d46a9, + 0xc3d23688, 0xa6b50dce, 0x091c4004, 0x6c7b7b42, 0x8d3fddd1, + 0xe858e697, 0x47f1ab5d, 0x2296901b, 0xbecf4b1f, 0xdba87059, + 0x74013d93, 0x116606d5, 0xf022a046, 0x95459b00, 0x3aecd6ca, + 0x5f8bed8c, 0x23149dad, 0x4673a6eb, 0xe9daeb21, 0x8cbdd067, + 0x6df976f4, 0x089e4db2, 0xa7370078, 0xc2503b3e, 0x44f5b031, + 0x21928b77, 0x8e3bc6bd, 0xeb5cfdfb, 0x0a185b68, 0x6f7f602e, + 0xc0d62de4, 0xa5b116a2, 0xd92e6683, 0xbc495dc5, 0x13e0100f, + 0x76872b49, 0x97c38dda, 0xf2a4b69c, 0x5d0dfb56, 0x386ac010, + 0xa4331b14, 0xc1542052, 0x6efd6d98, 0x0b9a56de, 0xeadef04d, + 0x8fb9cb0b, 0x201086c1, 0x4577bd87, 0x39e8cda6, 0x5c8ff6e0, + 0xf326bb2a, 0x9641806c, 0x770526ff, 0x12621db9, 0xbdcb5073, + 0xd8ac6b35}, + {0x00000000, 0xd7e28058, 0x74b406f1, 0xa35686a9, 0xe9680de2, + 0x3e8a8dba, 0x9ddc0b13, 0x4a3e8b4b, 0x09a11d85, 0xde439ddd, + 0x7d151b74, 0xaaf79b2c, 0xe0c91067, 0x372b903f, 0x947d1696, + 0x439f96ce, 0x13423b0a, 0xc4a0bb52, 0x67f63dfb, 0xb014bda3, + 0xfa2a36e8, 0x2dc8b6b0, 0x8e9e3019, 0x597cb041, 0x1ae3268f, + 0xcd01a6d7, 0x6e57207e, 0xb9b5a026, 0xf38b2b6d, 0x2469ab35, + 0x873f2d9c, 0x50ddadc4, 0x26847614, 0xf166f64c, 0x523070e5, + 0x85d2f0bd, 0xcfec7bf6, 0x180efbae, 0xbb587d07, 0x6cbafd5f, + 0x2f256b91, 0xf8c7ebc9, 0x5b916d60, 0x8c73ed38, 0xc64d6673, + 0x11afe62b, 0xb2f96082, 0x651be0da, 0x35c64d1e, 0xe224cd46, + 0x41724bef, 0x9690cbb7, 0xdcae40fc, 0x0b4cc0a4, 0xa81a460d, + 0x7ff8c655, 0x3c67509b, 0xeb85d0c3, 0x48d3566a, 0x9f31d632, + 0xd50f5d79, 0x02eddd21, 0xa1bb5b88, 0x7659dbd0, 0x4d08ec28, + 0x9aea6c70, 0x39bcead9, 0xee5e6a81, 0xa460e1ca, 0x73826192, + 0xd0d4e73b, 0x07366763, 0x44a9f1ad, 0x934b71f5, 0x301df75c, + 0xe7ff7704, 0xadc1fc4f, 0x7a237c17, 0xd975fabe, 0x0e977ae6, + 0x5e4ad722, 0x89a8577a, 0x2afed1d3, 0xfd1c518b, 0xb722dac0, + 0x60c05a98, 0xc396dc31, 0x14745c69, 0x57ebcaa7, 0x80094aff, + 0x235fcc56, 0xf4bd4c0e, 0xbe83c745, 0x6961471d, 0xca37c1b4, + 0x1dd541ec, 0x6b8c9a3c, 0xbc6e1a64, 0x1f389ccd, 0xc8da1c95, + 0x82e497de, 0x55061786, 0xf650912f, 0x21b21177, 0x622d87b9, + 0xb5cf07e1, 0x16998148, 0xc17b0110, 0x8b458a5b, 0x5ca70a03, + 0xfff18caa, 0x28130cf2, 0x78cea136, 0xaf2c216e, 0x0c7aa7c7, + 0xdb98279f, 0x91a6acd4, 0x46442c8c, 0xe512aa25, 0x32f02a7d, + 0x716fbcb3, 0xa68d3ceb, 0x05dbba42, 0xd2393a1a, 0x9807b151, + 0x4fe53109, 0xecb3b7a0, 0x3b5137f8, 0x9a11d850, 0x4df35808, + 0xeea5dea1, 0x39475ef9, 0x7379d5b2, 0xa49b55ea, 0x07cdd343, + 0xd02f531b, 0x93b0c5d5, 0x4452458d, 0xe704c324, 0x30e6437c, + 0x7ad8c837, 0xad3a486f, 0x0e6ccec6, 0xd98e4e9e, 0x8953e35a, + 0x5eb16302, 0xfde7e5ab, 0x2a0565f3, 0x603beeb8, 0xb7d96ee0, + 0x148fe849, 0xc36d6811, 0x80f2fedf, 0x57107e87, 0xf446f82e, + 0x23a47876, 0x699af33d, 0xbe787365, 0x1d2ef5cc, 0xcacc7594, + 0xbc95ae44, 0x6b772e1c, 0xc821a8b5, 0x1fc328ed, 0x55fda3a6, + 0x821f23fe, 0x2149a557, 0xf6ab250f, 0xb534b3c1, 0x62d63399, + 0xc180b530, 0x16623568, 0x5c5cbe23, 0x8bbe3e7b, 0x28e8b8d2, + 0xff0a388a, 0xafd7954e, 0x78351516, 0xdb6393bf, 0x0c8113e7, + 0x46bf98ac, 0x915d18f4, 0x320b9e5d, 0xe5e91e05, 0xa67688cb, + 0x71940893, 0xd2c28e3a, 0x05200e62, 0x4f1e8529, 0x98fc0571, + 0x3baa83d8, 0xec480380, 0xd7193478, 0x00fbb420, 0xa3ad3289, + 0x744fb2d1, 0x3e71399a, 0xe993b9c2, 0x4ac53f6b, 0x9d27bf33, + 0xdeb829fd, 0x095aa9a5, 0xaa0c2f0c, 0x7deeaf54, 0x37d0241f, + 0xe032a447, 0x436422ee, 0x9486a2b6, 0xc45b0f72, 0x13b98f2a, + 0xb0ef0983, 0x670d89db, 0x2d330290, 0xfad182c8, 0x59870461, + 0x8e658439, 0xcdfa12f7, 0x1a1892af, 0xb94e1406, 0x6eac945e, + 0x24921f15, 0xf3709f4d, 0x502619e4, 0x87c499bc, 0xf19d426c, + 0x267fc234, 0x8529449d, 0x52cbc4c5, 0x18f54f8e, 0xcf17cfd6, + 0x6c41497f, 0xbba3c927, 0xf83c5fe9, 0x2fdedfb1, 0x8c885918, + 0x5b6ad940, 0x1154520b, 0xc6b6d253, 0x65e054fa, 0xb202d4a2, + 0xe2df7966, 0x353df93e, 0x966b7f97, 0x4189ffcf, 0x0bb77484, + 0xdc55f4dc, 0x7f037275, 0xa8e1f22d, 0xeb7e64e3, 0x3c9ce4bb, + 0x9fca6212, 0x4828e24a, 0x02166901, 0xd5f4e959, 0x76a26ff0, + 0xa140efa8}, + {0x00000000, 0xef52b6e1, 0x05d46b83, 0xea86dd62, 0x0ba8d706, + 0xe4fa61e7, 0x0e7cbc85, 0xe12e0a64, 0x1751ae0c, 0xf80318ed, + 0x1285c58f, 0xfdd7736e, 0x1cf9790a, 0xf3abcfeb, 0x192d1289, + 0xf67fa468, 0x2ea35c18, 0xc1f1eaf9, 0x2b77379b, 0xc425817a, + 0x250b8b1e, 0xca593dff, 0x20dfe09d, 0xcf8d567c, 0x39f2f214, + 0xd6a044f5, 0x3c269997, 0xd3742f76, 0x325a2512, 0xdd0893f3, + 0x378e4e91, 0xd8dcf870, 0x5d46b830, 0xb2140ed1, 0x5892d3b3, + 0xb7c06552, 0x56ee6f36, 0xb9bcd9d7, 0x533a04b5, 0xbc68b254, + 0x4a17163c, 0xa545a0dd, 0x4fc37dbf, 0xa091cb5e, 0x41bfc13a, + 0xaeed77db, 0x446baab9, 0xab391c58, 0x73e5e428, 0x9cb752c9, + 0x76318fab, 0x9963394a, 0x784d332e, 0x971f85cf, 0x7d9958ad, + 0x92cbee4c, 0x64b44a24, 0x8be6fcc5, 0x616021a7, 0x8e329746, + 0x6f1c9d22, 0x804e2bc3, 0x6ac8f6a1, 0x859a4040, 0xba8d7060, + 0x55dfc681, 0xbf591be3, 0x500bad02, 0xb125a766, 0x5e771187, + 0xb4f1cce5, 0x5ba37a04, 0xaddcde6c, 0x428e688d, 0xa808b5ef, + 0x475a030e, 0xa674096a, 0x4926bf8b, 0xa3a062e9, 0x4cf2d408, + 0x942e2c78, 0x7b7c9a99, 0x91fa47fb, 0x7ea8f11a, 0x9f86fb7e, + 0x70d44d9f, 0x9a5290fd, 0x7500261c, 0x837f8274, 0x6c2d3495, + 0x86abe9f7, 0x69f95f16, 0x88d75572, 0x6785e393, 0x8d033ef1, + 0x62518810, 0xe7cbc850, 0x08997eb1, 0xe21fa3d3, 0x0d4d1532, + 0xec631f56, 0x0331a9b7, 0xe9b774d5, 0x06e5c234, 0xf09a665c, + 0x1fc8d0bd, 0xf54e0ddf, 0x1a1cbb3e, 0xfb32b15a, 0x146007bb, + 0xfee6dad9, 0x11b46c38, 0xc9689448, 0x263a22a9, 0xccbcffcb, + 0x23ee492a, 0xc2c0434e, 0x2d92f5af, 0xc71428cd, 0x28469e2c, + 0xde393a44, 0x316b8ca5, 0xdbed51c7, 0x34bfe726, 0xd591ed42, + 0x3ac35ba3, 0xd04586c1, 0x3f173020, 0xae6be681, 0x41395060, + 0xabbf8d02, 0x44ed3be3, 0xa5c33187, 0x4a918766, 0xa0175a04, + 0x4f45ece5, 0xb93a488d, 0x5668fe6c, 0xbcee230e, 0x53bc95ef, + 0xb2929f8b, 0x5dc0296a, 0xb746f408, 0x581442e9, 0x80c8ba99, + 0x6f9a0c78, 0x851cd11a, 0x6a4e67fb, 0x8b606d9f, 0x6432db7e, + 0x8eb4061c, 0x61e6b0fd, 0x97991495, 0x78cba274, 0x924d7f16, + 0x7d1fc9f7, 0x9c31c393, 0x73637572, 0x99e5a810, 0x76b71ef1, + 0xf32d5eb1, 0x1c7fe850, 0xf6f93532, 0x19ab83d3, 0xf88589b7, + 0x17d73f56, 0xfd51e234, 0x120354d5, 0xe47cf0bd, 0x0b2e465c, + 0xe1a89b3e, 0x0efa2ddf, 0xefd427bb, 0x0086915a, 0xea004c38, + 0x0552fad9, 0xdd8e02a9, 0x32dcb448, 0xd85a692a, 0x3708dfcb, + 0xd626d5af, 0x3974634e, 0xd3f2be2c, 0x3ca008cd, 0xcadfaca5, + 0x258d1a44, 0xcf0bc726, 0x205971c7, 0xc1777ba3, 0x2e25cd42, + 0xc4a31020, 0x2bf1a6c1, 0x14e696e1, 0xfbb42000, 0x1132fd62, + 0xfe604b83, 0x1f4e41e7, 0xf01cf706, 0x1a9a2a64, 0xf5c89c85, + 0x03b738ed, 0xece58e0c, 0x0663536e, 0xe931e58f, 0x081fefeb, + 0xe74d590a, 0x0dcb8468, 0xe2993289, 0x3a45caf9, 0xd5177c18, + 0x3f91a17a, 0xd0c3179b, 0x31ed1dff, 0xdebfab1e, 0x3439767c, + 0xdb6bc09d, 0x2d1464f5, 0xc246d214, 0x28c00f76, 0xc792b997, + 0x26bcb3f3, 0xc9ee0512, 0x2368d870, 0xcc3a6e91, 0x49a02ed1, + 0xa6f29830, 0x4c744552, 0xa326f3b3, 0x4208f9d7, 0xad5a4f36, + 0x47dc9254, 0xa88e24b5, 0x5ef180dd, 0xb1a3363c, 0x5b25eb5e, + 0xb4775dbf, 0x555957db, 0xba0be13a, 0x508d3c58, 0xbfdf8ab9, + 0x670372c9, 0x8851c428, 0x62d7194a, 0x8d85afab, 0x6caba5cf, + 0x83f9132e, 0x697fce4c, 0x862d78ad, 0x7052dcc5, 0x9f006a24, + 0x7586b746, 0x9ad401a7, 0x7bfa0bc3, 0x94a8bd22, 0x7e2e6040, + 0x917cd6a1}, + {0x00000000, 0x87a6cb43, 0xd43c90c7, 0x539a5b84, 0x730827cf, + 0xf4aeec8c, 0xa734b708, 0x20927c4b, 0xe6104f9e, 0x61b684dd, + 0x322cdf59, 0xb58a141a, 0x95186851, 0x12bea312, 0x4124f896, + 0xc68233d5, 0x1751997d, 0x90f7523e, 0xc36d09ba, 0x44cbc2f9, + 0x6459beb2, 0xe3ff75f1, 0xb0652e75, 0x37c3e536, 0xf141d6e3, + 0x76e71da0, 0x257d4624, 0xa2db8d67, 0x8249f12c, 0x05ef3a6f, + 0x567561eb, 0xd1d3aaa8, 0x2ea332fa, 0xa905f9b9, 0xfa9fa23d, + 0x7d39697e, 0x5dab1535, 0xda0dde76, 0x899785f2, 0x0e314eb1, + 0xc8b37d64, 0x4f15b627, 0x1c8feda3, 0x9b2926e0, 0xbbbb5aab, + 0x3c1d91e8, 0x6f87ca6c, 0xe821012f, 0x39f2ab87, 0xbe5460c4, + 0xedce3b40, 0x6a68f003, 0x4afa8c48, 0xcd5c470b, 0x9ec61c8f, + 0x1960d7cc, 0xdfe2e419, 0x58442f5a, 0x0bde74de, 0x8c78bf9d, + 0xaceac3d6, 0x2b4c0895, 0x78d65311, 0xff709852, 0x5d4665f4, + 0xdae0aeb7, 0x897af533, 0x0edc3e70, 0x2e4e423b, 0xa9e88978, + 0xfa72d2fc, 0x7dd419bf, 0xbb562a6a, 0x3cf0e129, 0x6f6abaad, + 0xe8cc71ee, 0xc85e0da5, 0x4ff8c6e6, 0x1c629d62, 0x9bc45621, + 0x4a17fc89, 0xcdb137ca, 0x9e2b6c4e, 0x198da70d, 0x391fdb46, + 0xbeb91005, 0xed234b81, 0x6a8580c2, 0xac07b317, 0x2ba17854, + 0x783b23d0, 0xff9de893, 0xdf0f94d8, 0x58a95f9b, 0x0b33041f, + 0x8c95cf5c, 0x73e5570e, 0xf4439c4d, 0xa7d9c7c9, 0x207f0c8a, + 0x00ed70c1, 0x874bbb82, 0xd4d1e006, 0x53772b45, 0x95f51890, + 0x1253d3d3, 0x41c98857, 0xc66f4314, 0xe6fd3f5f, 0x615bf41c, + 0x32c1af98, 0xb56764db, 0x64b4ce73, 0xe3120530, 0xb0885eb4, + 0x372e95f7, 0x17bce9bc, 0x901a22ff, 0xc380797b, 0x4426b238, + 0x82a481ed, 0x05024aae, 0x5698112a, 0xd13eda69, 0xf1aca622, + 0x760a6d61, 0x259036e5, 0xa236fda6, 0xba8ccbe8, 0x3d2a00ab, + 0x6eb05b2f, 0xe916906c, 0xc984ec27, 0x4e222764, 0x1db87ce0, + 0x9a1eb7a3, 0x5c9c8476, 0xdb3a4f35, 0x88a014b1, 0x0f06dff2, + 0x2f94a3b9, 0xa83268fa, 0xfba8337e, 0x7c0ef83d, 0xaddd5295, + 0x2a7b99d6, 0x79e1c252, 0xfe470911, 0xded5755a, 0x5973be19, + 0x0ae9e59d, 0x8d4f2ede, 0x4bcd1d0b, 0xcc6bd648, 0x9ff18dcc, + 0x1857468f, 0x38c53ac4, 0xbf63f187, 0xecf9aa03, 0x6b5f6140, + 0x942ff912, 0x13893251, 0x401369d5, 0xc7b5a296, 0xe727dedd, + 0x6081159e, 0x331b4e1a, 0xb4bd8559, 0x723fb68c, 0xf5997dcf, + 0xa603264b, 0x21a5ed08, 0x01379143, 0x86915a00, 0xd50b0184, + 0x52adcac7, 0x837e606f, 0x04d8ab2c, 0x5742f0a8, 0xd0e43beb, + 0xf07647a0, 0x77d08ce3, 0x244ad767, 0xa3ec1c24, 0x656e2ff1, + 0xe2c8e4b2, 0xb152bf36, 0x36f47475, 0x1666083e, 0x91c0c37d, + 0xc25a98f9, 0x45fc53ba, 0xe7caae1c, 0x606c655f, 0x33f63edb, + 0xb450f598, 0x94c289d3, 0x13644290, 0x40fe1914, 0xc758d257, + 0x01dae182, 0x867c2ac1, 0xd5e67145, 0x5240ba06, 0x72d2c64d, + 0xf5740d0e, 0xa6ee568a, 0x21489dc9, 0xf09b3761, 0x773dfc22, + 0x24a7a7a6, 0xa3016ce5, 0x839310ae, 0x0435dbed, 0x57af8069, + 0xd0094b2a, 0x168b78ff, 0x912db3bc, 0xc2b7e838, 0x4511237b, + 0x65835f30, 0xe2259473, 0xb1bfcff7, 0x361904b4, 0xc9699ce6, + 0x4ecf57a5, 0x1d550c21, 0x9af3c762, 0xba61bb29, 0x3dc7706a, + 0x6e5d2bee, 0xe9fbe0ad, 0x2f79d378, 0xa8df183b, 0xfb4543bf, + 0x7ce388fc, 0x5c71f4b7, 0xdbd73ff4, 0x884d6470, 0x0febaf33, + 0xde38059b, 0x599eced8, 0x0a04955c, 0x8da25e1f, 0xad302254, + 0x2a96e917, 0x790cb293, 0xfeaa79d0, 0x38284a05, 0xbf8e8146, + 0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d, + 0x18ba364e}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x43cba687, 0xc7903cd4, 0x845b9a53, 0xcf270873, + 0x8cecaef4, 0x08b734a7, 0x4b7c9220, 0x9e4f10e6, 0xdd84b661, + 0x59df2c32, 0x1a148ab5, 0x51681895, 0x12a3be12, 0x96f82441, + 0xd53382c6, 0x7d995117, 0x3e52f790, 0xba096dc3, 0xf9c2cb44, + 0xb2be5964, 0xf175ffe3, 0x752e65b0, 0x36e5c337, 0xe3d641f1, + 0xa01de776, 0x24467d25, 0x678ddba2, 0x2cf14982, 0x6f3aef05, + 0xeb617556, 0xa8aad3d1, 0xfa32a32e, 0xb9f905a9, 0x3da29ffa, + 0x7e69397d, 0x3515ab5d, 0x76de0dda, 0xf2859789, 0xb14e310e, + 0x647db3c8, 0x27b6154f, 0xa3ed8f1c, 0xe026299b, 0xab5abbbb, + 0xe8911d3c, 0x6cca876f, 0x2f0121e8, 0x87abf239, 0xc46054be, + 0x403bceed, 0x03f0686a, 0x488cfa4a, 0x0b475ccd, 0x8f1cc69e, + 0xccd76019, 0x19e4e2df, 0x5a2f4458, 0xde74de0b, 0x9dbf788c, + 0xd6c3eaac, 0x95084c2b, 0x1153d678, 0x529870ff, 0xf465465d, + 0xb7aee0da, 0x33f57a89, 0x703edc0e, 0x3b424e2e, 0x7889e8a9, + 0xfcd272fa, 0xbf19d47d, 0x6a2a56bb, 0x29e1f03c, 0xadba6a6f, + 0xee71cce8, 0xa50d5ec8, 0xe6c6f84f, 0x629d621c, 0x2156c49b, + 0x89fc174a, 0xca37b1cd, 0x4e6c2b9e, 0x0da78d19, 0x46db1f39, + 0x0510b9be, 0x814b23ed, 0xc280856a, 0x17b307ac, 0x5478a12b, + 0xd0233b78, 0x93e89dff, 0xd8940fdf, 0x9b5fa958, 0x1f04330b, + 0x5ccf958c, 0x0e57e573, 0x4d9c43f4, 0xc9c7d9a7, 0x8a0c7f20, + 0xc170ed00, 0x82bb4b87, 0x06e0d1d4, 0x452b7753, 0x9018f595, + 0xd3d35312, 0x5788c941, 0x14436fc6, 0x5f3ffde6, 0x1cf45b61, + 0x98afc132, 0xdb6467b5, 0x73ceb464, 0x300512e3, 0xb45e88b0, + 0xf7952e37, 0xbce9bc17, 0xff221a90, 0x7b7980c3, 0x38b22644, + 0xed81a482, 0xae4a0205, 0x2a119856, 0x69da3ed1, 0x22a6acf1, + 0x616d0a76, 0xe5369025, 0xa6fd36a2, 0xe8cb8cba, 0xab002a3d, + 0x2f5bb06e, 0x6c9016e9, 0x27ec84c9, 0x6427224e, 0xe07cb81d, + 0xa3b71e9a, 0x76849c5c, 0x354f3adb, 0xb114a088, 0xf2df060f, + 0xb9a3942f, 0xfa6832a8, 0x7e33a8fb, 0x3df80e7c, 0x9552ddad, + 0xd6997b2a, 0x52c2e179, 0x110947fe, 0x5a75d5de, 0x19be7359, + 0x9de5e90a, 0xde2e4f8d, 0x0b1dcd4b, 0x48d66bcc, 0xcc8df19f, + 0x8f465718, 0xc43ac538, 0x87f163bf, 0x03aaf9ec, 0x40615f6b, + 0x12f92f94, 0x51328913, 0xd5691340, 0x96a2b5c7, 0xddde27e7, + 0x9e158160, 0x1a4e1b33, 0x5985bdb4, 0x8cb63f72, 0xcf7d99f5, + 0x4b2603a6, 0x08eda521, 0x43913701, 0x005a9186, 0x84010bd5, + 0xc7caad52, 0x6f607e83, 0x2cabd804, 0xa8f04257, 0xeb3be4d0, + 0xa04776f0, 0xe38cd077, 0x67d74a24, 0x241ceca3, 0xf12f6e65, + 0xb2e4c8e2, 0x36bf52b1, 0x7574f436, 0x3e086616, 0x7dc3c091, + 0xf9985ac2, 0xba53fc45, 0x1caecae7, 0x5f656c60, 0xdb3ef633, + 0x98f550b4, 0xd389c294, 0x90426413, 0x1419fe40, 0x57d258c7, + 0x82e1da01, 0xc12a7c86, 0x4571e6d5, 0x06ba4052, 0x4dc6d272, + 0x0e0d74f5, 0x8a56eea6, 0xc99d4821, 0x61379bf0, 0x22fc3d77, + 0xa6a7a724, 0xe56c01a3, 0xae109383, 0xeddb3504, 0x6980af57, + 0x2a4b09d0, 0xff788b16, 0xbcb32d91, 0x38e8b7c2, 0x7b231145, + 0x305f8365, 0x739425e2, 0xf7cfbfb1, 0xb4041936, 0xe69c69c9, + 0xa557cf4e, 0x210c551d, 0x62c7f39a, 0x29bb61ba, 0x6a70c73d, + 0xee2b5d6e, 0xade0fbe9, 0x78d3792f, 0x3b18dfa8, 0xbf4345fb, + 0xfc88e37c, 0xb7f4715c, 0xf43fd7db, 0x70644d88, 0x33afeb0f, + 0x9b0538de, 0xd8ce9e59, 0x5c95040a, 0x1f5ea28d, 0x542230ad, + 0x17e9962a, 0x93b20c79, 0xd079aafe, 0x054a2838, 0x46818ebf, + 0xc2da14ec, 0x8111b26b, 0xca6d204b, 0x89a686cc, 0x0dfd1c9f, + 0x4e36ba18}, + {0x00000000, 0xe1b652ef, 0x836bd405, 0x62dd86ea, 0x06d7a80b, + 0xe761fae4, 0x85bc7c0e, 0x640a2ee1, 0x0cae5117, 0xed1803f8, + 0x8fc58512, 0x6e73d7fd, 0x0a79f91c, 0xebcfabf3, 0x89122d19, + 0x68a47ff6, 0x185ca32e, 0xf9eaf1c1, 0x9b37772b, 0x7a8125c4, + 0x1e8b0b25, 0xff3d59ca, 0x9de0df20, 0x7c568dcf, 0x14f2f239, + 0xf544a0d6, 0x9799263c, 0x762f74d3, 0x12255a32, 0xf39308dd, + 0x914e8e37, 0x70f8dcd8, 0x30b8465d, 0xd10e14b2, 0xb3d39258, + 0x5265c0b7, 0x366fee56, 0xd7d9bcb9, 0xb5043a53, 0x54b268bc, + 0x3c16174a, 0xdda045a5, 0xbf7dc34f, 0x5ecb91a0, 0x3ac1bf41, + 0xdb77edae, 0xb9aa6b44, 0x581c39ab, 0x28e4e573, 0xc952b79c, + 0xab8f3176, 0x4a396399, 0x2e334d78, 0xcf851f97, 0xad58997d, + 0x4ceecb92, 0x244ab464, 0xc5fce68b, 0xa7216061, 0x4697328e, + 0x229d1c6f, 0xc32b4e80, 0xa1f6c86a, 0x40409a85, 0x60708dba, + 0x81c6df55, 0xe31b59bf, 0x02ad0b50, 0x66a725b1, 0x8711775e, + 0xe5ccf1b4, 0x047aa35b, 0x6cdedcad, 0x8d688e42, 0xefb508a8, + 0x0e035a47, 0x6a0974a6, 0x8bbf2649, 0xe962a0a3, 0x08d4f24c, + 0x782c2e94, 0x999a7c7b, 0xfb47fa91, 0x1af1a87e, 0x7efb869f, + 0x9f4dd470, 0xfd90529a, 0x1c260075, 0x74827f83, 0x95342d6c, + 0xf7e9ab86, 0x165ff969, 0x7255d788, 0x93e38567, 0xf13e038d, + 0x10885162, 0x50c8cbe7, 0xb17e9908, 0xd3a31fe2, 0x32154d0d, + 0x561f63ec, 0xb7a93103, 0xd574b7e9, 0x34c2e506, 0x5c669af0, + 0xbdd0c81f, 0xdf0d4ef5, 0x3ebb1c1a, 0x5ab132fb, 0xbb076014, + 0xd9dae6fe, 0x386cb411, 0x489468c9, 0xa9223a26, 0xcbffbccc, + 0x2a49ee23, 0x4e43c0c2, 0xaff5922d, 0xcd2814c7, 0x2c9e4628, + 0x443a39de, 0xa58c6b31, 0xc751eddb, 0x26e7bf34, 0x42ed91d5, + 0xa35bc33a, 0xc18645d0, 0x2030173f, 0x81e66bae, 0x60503941, + 0x028dbfab, 0xe33bed44, 0x8731c3a5, 0x6687914a, 0x045a17a0, + 0xe5ec454f, 0x8d483ab9, 0x6cfe6856, 0x0e23eebc, 0xef95bc53, + 0x8b9f92b2, 0x6a29c05d, 0x08f446b7, 0xe9421458, 0x99bac880, + 0x780c9a6f, 0x1ad11c85, 0xfb674e6a, 0x9f6d608b, 0x7edb3264, + 0x1c06b48e, 0xfdb0e661, 0x95149997, 0x74a2cb78, 0x167f4d92, + 0xf7c91f7d, 0x93c3319c, 0x72756373, 0x10a8e599, 0xf11eb776, + 0xb15e2df3, 0x50e87f1c, 0x3235f9f6, 0xd383ab19, 0xb78985f8, + 0x563fd717, 0x34e251fd, 0xd5540312, 0xbdf07ce4, 0x5c462e0b, + 0x3e9ba8e1, 0xdf2dfa0e, 0xbb27d4ef, 0x5a918600, 0x384c00ea, + 0xd9fa5205, 0xa9028edd, 0x48b4dc32, 0x2a695ad8, 0xcbdf0837, + 0xafd526d6, 0x4e637439, 0x2cbef2d3, 0xcd08a03c, 0xa5acdfca, + 0x441a8d25, 0x26c70bcf, 0xc7715920, 0xa37b77c1, 0x42cd252e, + 0x2010a3c4, 0xc1a6f12b, 0xe196e614, 0x0020b4fb, 0x62fd3211, + 0x834b60fe, 0xe7414e1f, 0x06f71cf0, 0x642a9a1a, 0x859cc8f5, + 0xed38b703, 0x0c8ee5ec, 0x6e536306, 0x8fe531e9, 0xebef1f08, + 0x0a594de7, 0x6884cb0d, 0x893299e2, 0xf9ca453a, 0x187c17d5, + 0x7aa1913f, 0x9b17c3d0, 0xff1ded31, 0x1eabbfde, 0x7c763934, + 0x9dc06bdb, 0xf564142d, 0x14d246c2, 0x760fc028, 0x97b992c7, + 0xf3b3bc26, 0x1205eec9, 0x70d86823, 0x916e3acc, 0xd12ea049, + 0x3098f2a6, 0x5245744c, 0xb3f326a3, 0xd7f90842, 0x364f5aad, + 0x5492dc47, 0xb5248ea8, 0xdd80f15e, 0x3c36a3b1, 0x5eeb255b, + 0xbf5d77b4, 0xdb575955, 0x3ae10bba, 0x583c8d50, 0xb98adfbf, + 0xc9720367, 0x28c45188, 0x4a19d762, 0xabaf858d, 0xcfa5ab6c, + 0x2e13f983, 0x4cce7f69, 0xad782d86, 0xc5dc5270, 0x246a009f, + 0x46b78675, 0xa701d49a, 0xc30bfa7b, 0x22bda894, 0x40602e7e, + 0xa1d67c91}, + {0x00000000, 0x5880e2d7, 0xf106b474, 0xa98656a3, 0xe20d68e9, + 0xba8d8a3e, 0x130bdc9d, 0x4b8b3e4a, 0x851da109, 0xdd9d43de, + 0x741b157d, 0x2c9bf7aa, 0x6710c9e0, 0x3f902b37, 0x96167d94, + 0xce969f43, 0x0a3b4213, 0x52bba0c4, 0xfb3df667, 0xa3bd14b0, + 0xe8362afa, 0xb0b6c82d, 0x19309e8e, 0x41b07c59, 0x8f26e31a, + 0xd7a601cd, 0x7e20576e, 0x26a0b5b9, 0x6d2b8bf3, 0x35ab6924, + 0x9c2d3f87, 0xc4addd50, 0x14768426, 0x4cf666f1, 0xe5703052, + 0xbdf0d285, 0xf67beccf, 0xaefb0e18, 0x077d58bb, 0x5ffdba6c, + 0x916b252f, 0xc9ebc7f8, 0x606d915b, 0x38ed738c, 0x73664dc6, + 0x2be6af11, 0x8260f9b2, 0xdae01b65, 0x1e4dc635, 0x46cd24e2, + 0xef4b7241, 0xb7cb9096, 0xfc40aedc, 0xa4c04c0b, 0x0d461aa8, + 0x55c6f87f, 0x9b50673c, 0xc3d085eb, 0x6a56d348, 0x32d6319f, + 0x795d0fd5, 0x21dded02, 0x885bbba1, 0xd0db5976, 0x28ec084d, + 0x706cea9a, 0xd9eabc39, 0x816a5eee, 0xcae160a4, 0x92618273, + 0x3be7d4d0, 0x63673607, 0xadf1a944, 0xf5714b93, 0x5cf71d30, + 0x0477ffe7, 0x4ffcc1ad, 0x177c237a, 0xbefa75d9, 0xe67a970e, + 0x22d74a5e, 0x7a57a889, 0xd3d1fe2a, 0x8b511cfd, 0xc0da22b7, + 0x985ac060, 0x31dc96c3, 0x695c7414, 0xa7caeb57, 0xff4a0980, + 0x56cc5f23, 0x0e4cbdf4, 0x45c783be, 0x1d476169, 0xb4c137ca, + 0xec41d51d, 0x3c9a8c6b, 0x641a6ebc, 0xcd9c381f, 0x951cdac8, + 0xde97e482, 0x86170655, 0x2f9150f6, 0x7711b221, 0xb9872d62, + 0xe107cfb5, 0x48819916, 0x10017bc1, 0x5b8a458b, 0x030aa75c, + 0xaa8cf1ff, 0xf20c1328, 0x36a1ce78, 0x6e212caf, 0xc7a77a0c, + 0x9f2798db, 0xd4aca691, 0x8c2c4446, 0x25aa12e5, 0x7d2af032, + 0xb3bc6f71, 0xeb3c8da6, 0x42badb05, 0x1a3a39d2, 0x51b10798, + 0x0931e54f, 0xa0b7b3ec, 0xf837513b, 0x50d8119a, 0x0858f34d, + 0xa1dea5ee, 0xf95e4739, 0xb2d57973, 0xea559ba4, 0x43d3cd07, + 0x1b532fd0, 0xd5c5b093, 0x8d455244, 0x24c304e7, 0x7c43e630, + 0x37c8d87a, 0x6f483aad, 0xc6ce6c0e, 0x9e4e8ed9, 0x5ae35389, + 0x0263b15e, 0xabe5e7fd, 0xf365052a, 0xb8ee3b60, 0xe06ed9b7, + 0x49e88f14, 0x11686dc3, 0xdffef280, 0x877e1057, 0x2ef846f4, + 0x7678a423, 0x3df39a69, 0x657378be, 0xccf52e1d, 0x9475ccca, + 0x44ae95bc, 0x1c2e776b, 0xb5a821c8, 0xed28c31f, 0xa6a3fd55, + 0xfe231f82, 0x57a54921, 0x0f25abf6, 0xc1b334b5, 0x9933d662, + 0x30b580c1, 0x68356216, 0x23be5c5c, 0x7b3ebe8b, 0xd2b8e828, + 0x8a380aff, 0x4e95d7af, 0x16153578, 0xbf9363db, 0xe713810c, + 0xac98bf46, 0xf4185d91, 0x5d9e0b32, 0x051ee9e5, 0xcb8876a6, + 0x93089471, 0x3a8ec2d2, 0x620e2005, 0x29851e4f, 0x7105fc98, + 0xd883aa3b, 0x800348ec, 0x783419d7, 0x20b4fb00, 0x8932ada3, + 0xd1b24f74, 0x9a39713e, 0xc2b993e9, 0x6b3fc54a, 0x33bf279d, + 0xfd29b8de, 0xa5a95a09, 0x0c2f0caa, 0x54afee7d, 0x1f24d037, + 0x47a432e0, 0xee226443, 0xb6a28694, 0x720f5bc4, 0x2a8fb913, + 0x8309efb0, 0xdb890d67, 0x9002332d, 0xc882d1fa, 0x61048759, + 0x3984658e, 0xf712facd, 0xaf92181a, 0x06144eb9, 0x5e94ac6e, + 0x151f9224, 0x4d9f70f3, 0xe4192650, 0xbc99c487, 0x6c429df1, + 0x34c27f26, 0x9d442985, 0xc5c4cb52, 0x8e4ff518, 0xd6cf17cf, + 0x7f49416c, 0x27c9a3bb, 0xe95f3cf8, 0xb1dfde2f, 0x1859888c, + 0x40d96a5b, 0x0b525411, 0x53d2b6c6, 0xfa54e065, 0xa2d402b2, + 0x6679dfe2, 0x3ef93d35, 0x977f6b96, 0xcfff8941, 0x8474b70b, + 0xdcf455dc, 0x7572037f, 0x2df2e1a8, 0xe3647eeb, 0xbbe49c3c, + 0x1262ca9f, 0x4ae22848, 0x01691602, 0x59e9f4d5, 0xf06fa276, + 0xa8ef40a1}, + {0x00000000, 0x463b6765, 0x8c76ceca, 0xca4da9af, 0x59ebed4e, + 0x1fd08a2b, 0xd59d2384, 0x93a644e1, 0xb2d6db9d, 0xf4edbcf8, + 0x3ea01557, 0x789b7232, 0xeb3d36d3, 0xad0651b6, 0x674bf819, + 0x21709f7c, 0x25abc6e0, 0x6390a185, 0xa9dd082a, 0xefe66f4f, + 0x7c402bae, 0x3a7b4ccb, 0xf036e564, 0xb60d8201, 0x977d1d7d, + 0xd1467a18, 0x1b0bd3b7, 0x5d30b4d2, 0xce96f033, 0x88ad9756, + 0x42e03ef9, 0x04db599c, 0x0b50fc1a, 0x4d6b9b7f, 0x872632d0, + 0xc11d55b5, 0x52bb1154, 0x14807631, 0xdecddf9e, 0x98f6b8fb, + 0xb9862787, 0xffbd40e2, 0x35f0e94d, 0x73cb8e28, 0xe06dcac9, + 0xa656adac, 0x6c1b0403, 0x2a206366, 0x2efb3afa, 0x68c05d9f, + 0xa28df430, 0xe4b69355, 0x7710d7b4, 0x312bb0d1, 0xfb66197e, + 0xbd5d7e1b, 0x9c2de167, 0xda168602, 0x105b2fad, 0x566048c8, + 0xc5c60c29, 0x83fd6b4c, 0x49b0c2e3, 0x0f8ba586, 0x16a0f835, + 0x509b9f50, 0x9ad636ff, 0xdced519a, 0x4f4b157b, 0x0970721e, + 0xc33ddbb1, 0x8506bcd4, 0xa47623a8, 0xe24d44cd, 0x2800ed62, + 0x6e3b8a07, 0xfd9dcee6, 0xbba6a983, 0x71eb002c, 0x37d06749, + 0x330b3ed5, 0x753059b0, 0xbf7df01f, 0xf946977a, 0x6ae0d39b, + 0x2cdbb4fe, 0xe6961d51, 0xa0ad7a34, 0x81dde548, 0xc7e6822d, + 0x0dab2b82, 0x4b904ce7, 0xd8360806, 0x9e0d6f63, 0x5440c6cc, + 0x127ba1a9, 0x1df0042f, 0x5bcb634a, 0x9186cae5, 0xd7bdad80, + 0x441be961, 0x02208e04, 0xc86d27ab, 0x8e5640ce, 0xaf26dfb2, + 0xe91db8d7, 0x23501178, 0x656b761d, 0xf6cd32fc, 0xb0f65599, + 0x7abbfc36, 0x3c809b53, 0x385bc2cf, 0x7e60a5aa, 0xb42d0c05, + 0xf2166b60, 0x61b02f81, 0x278b48e4, 0xedc6e14b, 0xabfd862e, + 0x8a8d1952, 0xccb67e37, 0x06fbd798, 0x40c0b0fd, 0xd366f41c, + 0x955d9379, 0x5f103ad6, 0x192b5db3, 0x2c40f16b, 0x6a7b960e, + 0xa0363fa1, 0xe60d58c4, 0x75ab1c25, 0x33907b40, 0xf9ddd2ef, + 0xbfe6b58a, 0x9e962af6, 0xd8ad4d93, 0x12e0e43c, 0x54db8359, + 0xc77dc7b8, 0x8146a0dd, 0x4b0b0972, 0x0d306e17, 0x09eb378b, + 0x4fd050ee, 0x859df941, 0xc3a69e24, 0x5000dac5, 0x163bbda0, + 0xdc76140f, 0x9a4d736a, 0xbb3dec16, 0xfd068b73, 0x374b22dc, + 0x717045b9, 0xe2d60158, 0xa4ed663d, 0x6ea0cf92, 0x289ba8f7, + 0x27100d71, 0x612b6a14, 0xab66c3bb, 0xed5da4de, 0x7efbe03f, + 0x38c0875a, 0xf28d2ef5, 0xb4b64990, 0x95c6d6ec, 0xd3fdb189, + 0x19b01826, 0x5f8b7f43, 0xcc2d3ba2, 0x8a165cc7, 0x405bf568, + 0x0660920d, 0x02bbcb91, 0x4480acf4, 0x8ecd055b, 0xc8f6623e, + 0x5b5026df, 0x1d6b41ba, 0xd726e815, 0x911d8f70, 0xb06d100c, + 0xf6567769, 0x3c1bdec6, 0x7a20b9a3, 0xe986fd42, 0xafbd9a27, + 0x65f03388, 0x23cb54ed, 0x3ae0095e, 0x7cdb6e3b, 0xb696c794, + 0xf0ada0f1, 0x630be410, 0x25308375, 0xef7d2ada, 0xa9464dbf, + 0x8836d2c3, 0xce0db5a6, 0x04401c09, 0x427b7b6c, 0xd1dd3f8d, + 0x97e658e8, 0x5dabf147, 0x1b909622, 0x1f4bcfbe, 0x5970a8db, + 0x933d0174, 0xd5066611, 0x46a022f0, 0x009b4595, 0xcad6ec3a, + 0x8ced8b5f, 0xad9d1423, 0xeba67346, 0x21ebdae9, 0x67d0bd8c, + 0xf476f96d, 0xb24d9e08, 0x780037a7, 0x3e3b50c2, 0x31b0f544, + 0x778b9221, 0xbdc63b8e, 0xfbfd5ceb, 0x685b180a, 0x2e607f6f, + 0xe42dd6c0, 0xa216b1a5, 0x83662ed9, 0xc55d49bc, 0x0f10e013, + 0x492b8776, 0xda8dc397, 0x9cb6a4f2, 0x56fb0d5d, 0x10c06a38, + 0x141b33a4, 0x522054c1, 0x986dfd6e, 0xde569a0b, 0x4df0deea, + 0x0bcbb98f, 0xc1861020, 0x87bd7745, 0xa6cde839, 0xe0f68f5c, + 0x2abb26f3, 0x6c804196, 0xff260577, 0xb91d6212, 0x7350cbbd, + 0x356bacd8}}; + +#endif + +#endif + +#if N == 6 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x3db1ecdc, 0x7b63d9b8, 0x46d23564, 0xf6c7b370, + 0xcb765fac, 0x8da46ac8, 0xb0158614, 0x36fe60a1, 0x0b4f8c7d, + 0x4d9db919, 0x702c55c5, 0xc039d3d1, 0xfd883f0d, 0xbb5a0a69, + 0x86ebe6b5, 0x6dfcc142, 0x504d2d9e, 0x169f18fa, 0x2b2ef426, + 0x9b3b7232, 0xa68a9eee, 0xe058ab8a, 0xdde94756, 0x5b02a1e3, + 0x66b34d3f, 0x2061785b, 0x1dd09487, 0xadc51293, 0x9074fe4f, + 0xd6a6cb2b, 0xeb1727f7, 0xdbf98284, 0xe6486e58, 0xa09a5b3c, + 0x9d2bb7e0, 0x2d3e31f4, 0x108fdd28, 0x565de84c, 0x6bec0490, + 0xed07e225, 0xd0b60ef9, 0x96643b9d, 0xabd5d741, 0x1bc05155, + 0x2671bd89, 0x60a388ed, 0x5d126431, 0xb60543c6, 0x8bb4af1a, + 0xcd669a7e, 0xf0d776a2, 0x40c2f0b6, 0x7d731c6a, 0x3ba1290e, + 0x0610c5d2, 0x80fb2367, 0xbd4acfbb, 0xfb98fadf, 0xc6291603, + 0x763c9017, 0x4b8d7ccb, 0x0d5f49af, 0x30eea573, 0x6c820349, + 0x5133ef95, 0x17e1daf1, 0x2a50362d, 0x9a45b039, 0xa7f45ce5, + 0xe1266981, 0xdc97855d, 0x5a7c63e8, 0x67cd8f34, 0x211fba50, + 0x1cae568c, 0xacbbd098, 0x910a3c44, 0xd7d80920, 0xea69e5fc, + 0x017ec20b, 0x3ccf2ed7, 0x7a1d1bb3, 0x47acf76f, 0xf7b9717b, + 0xca089da7, 0x8cdaa8c3, 0xb16b441f, 0x3780a2aa, 0x0a314e76, + 0x4ce37b12, 0x715297ce, 0xc14711da, 0xfcf6fd06, 0xba24c862, + 0x879524be, 0xb77b81cd, 0x8aca6d11, 0xcc185875, 0xf1a9b4a9, + 0x41bc32bd, 0x7c0dde61, 0x3adfeb05, 0x076e07d9, 0x8185e16c, + 0xbc340db0, 0xfae638d4, 0xc757d408, 0x7742521c, 0x4af3bec0, + 0x0c218ba4, 0x31906778, 0xda87408f, 0xe736ac53, 0xa1e49937, + 0x9c5575eb, 0x2c40f3ff, 0x11f11f23, 0x57232a47, 0x6a92c69b, + 0xec79202e, 0xd1c8ccf2, 0x971af996, 0xaaab154a, 0x1abe935e, + 0x270f7f82, 0x61dd4ae6, 0x5c6ca63a, 0xd9040692, 0xe4b5ea4e, + 0xa267df2a, 0x9fd633f6, 0x2fc3b5e2, 0x1272593e, 0x54a06c5a, + 0x69118086, 0xeffa6633, 0xd24b8aef, 0x9499bf8b, 0xa9285357, + 0x193dd543, 0x248c399f, 0x625e0cfb, 0x5fefe027, 0xb4f8c7d0, + 0x89492b0c, 0xcf9b1e68, 0xf22af2b4, 0x423f74a0, 0x7f8e987c, + 0x395cad18, 0x04ed41c4, 0x8206a771, 0xbfb74bad, 0xf9657ec9, + 0xc4d49215, 0x74c11401, 0x4970f8dd, 0x0fa2cdb9, 0x32132165, + 0x02fd8416, 0x3f4c68ca, 0x799e5dae, 0x442fb172, 0xf43a3766, + 0xc98bdbba, 0x8f59eede, 0xb2e80202, 0x3403e4b7, 0x09b2086b, + 0x4f603d0f, 0x72d1d1d3, 0xc2c457c7, 0xff75bb1b, 0xb9a78e7f, + 0x841662a3, 0x6f014554, 0x52b0a988, 0x14629cec, 0x29d37030, + 0x99c6f624, 0xa4771af8, 0xe2a52f9c, 0xdf14c340, 0x59ff25f5, + 0x644ec929, 0x229cfc4d, 0x1f2d1091, 0xaf389685, 0x92897a59, + 0xd45b4f3d, 0xe9eaa3e1, 0xb58605db, 0x8837e907, 0xcee5dc63, + 0xf35430bf, 0x4341b6ab, 0x7ef05a77, 0x38226f13, 0x059383cf, + 0x8378657a, 0xbec989a6, 0xf81bbcc2, 0xc5aa501e, 0x75bfd60a, + 0x480e3ad6, 0x0edc0fb2, 0x336de36e, 0xd87ac499, 0xe5cb2845, + 0xa3191d21, 0x9ea8f1fd, 0x2ebd77e9, 0x130c9b35, 0x55deae51, + 0x686f428d, 0xee84a438, 0xd33548e4, 0x95e77d80, 0xa856915c, + 0x18431748, 0x25f2fb94, 0x6320cef0, 0x5e91222c, 0x6e7f875f, + 0x53ce6b83, 0x151c5ee7, 0x28adb23b, 0x98b8342f, 0xa509d8f3, + 0xe3dbed97, 0xde6a014b, 0x5881e7fe, 0x65300b22, 0x23e23e46, + 0x1e53d29a, 0xae46548e, 0x93f7b852, 0xd5258d36, 0xe89461ea, + 0x0383461d, 0x3e32aac1, 0x78e09fa5, 0x45517379, 0xf544f56d, + 0xc8f519b1, 0x8e272cd5, 0xb396c009, 0x357d26bc, 0x08ccca60, + 0x4e1eff04, 0x73af13d8, 0xc3ba95cc, 0xfe0b7910, 0xb8d94c74, + 0x8568a0a8}, + {0x00000000, 0x69790b65, 0xd2f216ca, 0xbb8b1daf, 0x7e952bd5, + 0x17ec20b0, 0xac673d1f, 0xc51e367a, 0xfd2a57aa, 0x94535ccf, + 0x2fd84160, 0x46a14a05, 0x83bf7c7f, 0xeac6771a, 0x514d6ab5, + 0x383461d0, 0x2125a915, 0x485ca270, 0xf3d7bfdf, 0x9aaeb4ba, + 0x5fb082c0, 0x36c989a5, 0x8d42940a, 0xe43b9f6f, 0xdc0ffebf, + 0xb576f5da, 0x0efde875, 0x6784e310, 0xa29ad56a, 0xcbe3de0f, + 0x7068c3a0, 0x1911c8c5, 0x424b522a, 0x2b32594f, 0x90b944e0, + 0xf9c04f85, 0x3cde79ff, 0x55a7729a, 0xee2c6f35, 0x87556450, + 0xbf610580, 0xd6180ee5, 0x6d93134a, 0x04ea182f, 0xc1f42e55, + 0xa88d2530, 0x1306389f, 0x7a7f33fa, 0x636efb3f, 0x0a17f05a, + 0xb19cedf5, 0xd8e5e690, 0x1dfbd0ea, 0x7482db8f, 0xcf09c620, + 0xa670cd45, 0x9e44ac95, 0xf73da7f0, 0x4cb6ba5f, 0x25cfb13a, + 0xe0d18740, 0x89a88c25, 0x3223918a, 0x5b5a9aef, 0x8496a454, + 0xedefaf31, 0x5664b29e, 0x3f1db9fb, 0xfa038f81, 0x937a84e4, + 0x28f1994b, 0x4188922e, 0x79bcf3fe, 0x10c5f89b, 0xab4ee534, + 0xc237ee51, 0x0729d82b, 0x6e50d34e, 0xd5dbcee1, 0xbca2c584, + 0xa5b30d41, 0xccca0624, 0x77411b8b, 0x1e3810ee, 0xdb262694, + 0xb25f2df1, 0x09d4305e, 0x60ad3b3b, 0x58995aeb, 0x31e0518e, + 0x8a6b4c21, 0xe3124744, 0x260c713e, 0x4f757a5b, 0xf4fe67f4, + 0x9d876c91, 0xc6ddf67e, 0xafa4fd1b, 0x142fe0b4, 0x7d56ebd1, + 0xb848ddab, 0xd131d6ce, 0x6abacb61, 0x03c3c004, 0x3bf7a1d4, + 0x528eaab1, 0xe905b71e, 0x807cbc7b, 0x45628a01, 0x2c1b8164, + 0x97909ccb, 0xfee997ae, 0xe7f85f6b, 0x8e81540e, 0x350a49a1, + 0x5c7342c4, 0x996d74be, 0xf0147fdb, 0x4b9f6274, 0x22e66911, + 0x1ad208c1, 0x73ab03a4, 0xc8201e0b, 0xa159156e, 0x64472314, + 0x0d3e2871, 0xb6b535de, 0xdfcc3ebb, 0xd25c4ee9, 0xbb25458c, + 0x00ae5823, 0x69d75346, 0xacc9653c, 0xc5b06e59, 0x7e3b73f6, + 0x17427893, 0x2f761943, 0x460f1226, 0xfd840f89, 0x94fd04ec, + 0x51e33296, 0x389a39f3, 0x8311245c, 0xea682f39, 0xf379e7fc, + 0x9a00ec99, 0x218bf136, 0x48f2fa53, 0x8deccc29, 0xe495c74c, + 0x5f1edae3, 0x3667d186, 0x0e53b056, 0x672abb33, 0xdca1a69c, + 0xb5d8adf9, 0x70c69b83, 0x19bf90e6, 0xa2348d49, 0xcb4d862c, + 0x90171cc3, 0xf96e17a6, 0x42e50a09, 0x2b9c016c, 0xee823716, + 0x87fb3c73, 0x3c7021dc, 0x55092ab9, 0x6d3d4b69, 0x0444400c, + 0xbfcf5da3, 0xd6b656c6, 0x13a860bc, 0x7ad16bd9, 0xc15a7676, + 0xa8237d13, 0xb132b5d6, 0xd84bbeb3, 0x63c0a31c, 0x0ab9a879, + 0xcfa79e03, 0xa6de9566, 0x1d5588c9, 0x742c83ac, 0x4c18e27c, + 0x2561e919, 0x9eeaf4b6, 0xf793ffd3, 0x328dc9a9, 0x5bf4c2cc, + 0xe07fdf63, 0x8906d406, 0x56caeabd, 0x3fb3e1d8, 0x8438fc77, + 0xed41f712, 0x285fc168, 0x4126ca0d, 0xfaadd7a2, 0x93d4dcc7, + 0xabe0bd17, 0xc299b672, 0x7912abdd, 0x106ba0b8, 0xd57596c2, + 0xbc0c9da7, 0x07878008, 0x6efe8b6d, 0x77ef43a8, 0x1e9648cd, + 0xa51d5562, 0xcc645e07, 0x097a687d, 0x60036318, 0xdb887eb7, + 0xb2f175d2, 0x8ac51402, 0xe3bc1f67, 0x583702c8, 0x314e09ad, + 0xf4503fd7, 0x9d2934b2, 0x26a2291d, 0x4fdb2278, 0x1481b897, + 0x7df8b3f2, 0xc673ae5d, 0xaf0aa538, 0x6a149342, 0x036d9827, + 0xb8e68588, 0xd19f8eed, 0xe9abef3d, 0x80d2e458, 0x3b59f9f7, + 0x5220f292, 0x973ec4e8, 0xfe47cf8d, 0x45ccd222, 0x2cb5d947, + 0x35a41182, 0x5cdd1ae7, 0xe7560748, 0x8e2f0c2d, 0x4b313a57, + 0x22483132, 0x99c32c9d, 0xf0ba27f8, 0xc88e4628, 0xa1f74d4d, + 0x1a7c50e2, 0x73055b87, 0xb61b6dfd, 0xdf626698, 0x64e97b37, + 0x0d907052}, + {0x00000000, 0x7fc99b93, 0xff933726, 0x805aacb5, 0x2457680d, + 0x5b9ef39e, 0xdbc45f2b, 0xa40dc4b8, 0x48aed01a, 0x37674b89, + 0xb73de73c, 0xc8f47caf, 0x6cf9b817, 0x13302384, 0x936a8f31, + 0xeca314a2, 0x915da034, 0xee943ba7, 0x6ece9712, 0x11070c81, + 0xb50ac839, 0xcac353aa, 0x4a99ff1f, 0x3550648c, 0xd9f3702e, + 0xa63aebbd, 0x26604708, 0x59a9dc9b, 0xfda41823, 0x826d83b0, + 0x02372f05, 0x7dfeb496, 0xf9ca4629, 0x8603ddba, 0x0659710f, + 0x7990ea9c, 0xdd9d2e24, 0xa254b5b7, 0x220e1902, 0x5dc78291, + 0xb1649633, 0xcead0da0, 0x4ef7a115, 0x313e3a86, 0x9533fe3e, + 0xeafa65ad, 0x6aa0c918, 0x1569528b, 0x6897e61d, 0x175e7d8e, + 0x9704d13b, 0xe8cd4aa8, 0x4cc08e10, 0x33091583, 0xb353b936, + 0xcc9a22a5, 0x20393607, 0x5ff0ad94, 0xdfaa0121, 0xa0639ab2, + 0x046e5e0a, 0x7ba7c599, 0xfbfd692c, 0x8434f2bf, 0x28e58a13, + 0x572c1180, 0xd776bd35, 0xa8bf26a6, 0x0cb2e21e, 0x737b798d, + 0xf321d538, 0x8ce84eab, 0x604b5a09, 0x1f82c19a, 0x9fd86d2f, + 0xe011f6bc, 0x441c3204, 0x3bd5a997, 0xbb8f0522, 0xc4469eb1, + 0xb9b82a27, 0xc671b1b4, 0x462b1d01, 0x39e28692, 0x9def422a, + 0xe226d9b9, 0x627c750c, 0x1db5ee9f, 0xf116fa3d, 0x8edf61ae, + 0x0e85cd1b, 0x714c5688, 0xd5419230, 0xaa8809a3, 0x2ad2a516, + 0x551b3e85, 0xd12fcc3a, 0xaee657a9, 0x2ebcfb1c, 0x5175608f, + 0xf578a437, 0x8ab13fa4, 0x0aeb9311, 0x75220882, 0x99811c20, + 0xe64887b3, 0x66122b06, 0x19dbb095, 0xbdd6742d, 0xc21fefbe, + 0x4245430b, 0x3d8cd898, 0x40726c0e, 0x3fbbf79d, 0xbfe15b28, + 0xc028c0bb, 0x64250403, 0x1bec9f90, 0x9bb63325, 0xe47fa8b6, + 0x08dcbc14, 0x77152787, 0xf74f8b32, 0x888610a1, 0x2c8bd419, + 0x53424f8a, 0xd318e33f, 0xacd178ac, 0x51cb1426, 0x2e028fb5, + 0xae582300, 0xd191b893, 0x759c7c2b, 0x0a55e7b8, 0x8a0f4b0d, + 0xf5c6d09e, 0x1965c43c, 0x66ac5faf, 0xe6f6f31a, 0x993f6889, + 0x3d32ac31, 0x42fb37a2, 0xc2a19b17, 0xbd680084, 0xc096b412, + 0xbf5f2f81, 0x3f058334, 0x40cc18a7, 0xe4c1dc1f, 0x9b08478c, + 0x1b52eb39, 0x649b70aa, 0x88386408, 0xf7f1ff9b, 0x77ab532e, + 0x0862c8bd, 0xac6f0c05, 0xd3a69796, 0x53fc3b23, 0x2c35a0b0, + 0xa801520f, 0xd7c8c99c, 0x57926529, 0x285bfeba, 0x8c563a02, + 0xf39fa191, 0x73c50d24, 0x0c0c96b7, 0xe0af8215, 0x9f661986, + 0x1f3cb533, 0x60f52ea0, 0xc4f8ea18, 0xbb31718b, 0x3b6bdd3e, + 0x44a246ad, 0x395cf23b, 0x469569a8, 0xc6cfc51d, 0xb9065e8e, + 0x1d0b9a36, 0x62c201a5, 0xe298ad10, 0x9d513683, 0x71f22221, + 0x0e3bb9b2, 0x8e611507, 0xf1a88e94, 0x55a54a2c, 0x2a6cd1bf, + 0xaa367d0a, 0xd5ffe699, 0x792e9e35, 0x06e705a6, 0x86bda913, + 0xf9743280, 0x5d79f638, 0x22b06dab, 0xa2eac11e, 0xdd235a8d, + 0x31804e2f, 0x4e49d5bc, 0xce137909, 0xb1dae29a, 0x15d72622, + 0x6a1ebdb1, 0xea441104, 0x958d8a97, 0xe8733e01, 0x97baa592, + 0x17e00927, 0x682992b4, 0xcc24560c, 0xb3edcd9f, 0x33b7612a, + 0x4c7efab9, 0xa0ddee1b, 0xdf147588, 0x5f4ed93d, 0x208742ae, + 0x848a8616, 0xfb431d85, 0x7b19b130, 0x04d02aa3, 0x80e4d81c, + 0xff2d438f, 0x7f77ef3a, 0x00be74a9, 0xa4b3b011, 0xdb7a2b82, + 0x5b208737, 0x24e91ca4, 0xc84a0806, 0xb7839395, 0x37d93f20, + 0x4810a4b3, 0xec1d600b, 0x93d4fb98, 0x138e572d, 0x6c47ccbe, + 0x11b97828, 0x6e70e3bb, 0xee2a4f0e, 0x91e3d49d, 0x35ee1025, + 0x4a278bb6, 0xca7d2703, 0xb5b4bc90, 0x5917a832, 0x26de33a1, + 0xa6849f14, 0xd94d0487, 0x7d40c03f, 0x02895bac, 0x82d3f719, + 0xfd1a6c8a}, + {0x00000000, 0xa396284c, 0x9c5d56d9, 0x3fcb7e95, 0xe3cbabf3, + 0x405d83bf, 0x7f96fd2a, 0xdc00d566, 0x1ce651a7, 0xbf7079eb, + 0x80bb077e, 0x232d2f32, 0xff2dfa54, 0x5cbbd218, 0x6370ac8d, + 0xc0e684c1, 0x39cca34e, 0x9a5a8b02, 0xa591f597, 0x0607dddb, + 0xda0708bd, 0x799120f1, 0x465a5e64, 0xe5cc7628, 0x252af2e9, + 0x86bcdaa5, 0xb977a430, 0x1ae18c7c, 0xc6e1591a, 0x65777156, + 0x5abc0fc3, 0xf92a278f, 0x7399469c, 0xd00f6ed0, 0xefc41045, + 0x4c523809, 0x9052ed6f, 0x33c4c523, 0x0c0fbbb6, 0xaf9993fa, + 0x6f7f173b, 0xcce93f77, 0xf32241e2, 0x50b469ae, 0x8cb4bcc8, + 0x2f229484, 0x10e9ea11, 0xb37fc25d, 0x4a55e5d2, 0xe9c3cd9e, + 0xd608b30b, 0x759e9b47, 0xa99e4e21, 0x0a08666d, 0x35c318f8, + 0x965530b4, 0x56b3b475, 0xf5259c39, 0xcaeee2ac, 0x6978cae0, + 0xb5781f86, 0x16ee37ca, 0x2925495f, 0x8ab36113, 0xe7328d38, + 0x44a4a574, 0x7b6fdbe1, 0xd8f9f3ad, 0x04f926cb, 0xa76f0e87, + 0x98a47012, 0x3b32585e, 0xfbd4dc9f, 0x5842f4d3, 0x67898a46, + 0xc41fa20a, 0x181f776c, 0xbb895f20, 0x844221b5, 0x27d409f9, + 0xdefe2e76, 0x7d68063a, 0x42a378af, 0xe13550e3, 0x3d358585, + 0x9ea3adc9, 0xa168d35c, 0x02fefb10, 0xc2187fd1, 0x618e579d, + 0x5e452908, 0xfdd30144, 0x21d3d422, 0x8245fc6e, 0xbd8e82fb, + 0x1e18aab7, 0x94abcba4, 0x373de3e8, 0x08f69d7d, 0xab60b531, + 0x77606057, 0xd4f6481b, 0xeb3d368e, 0x48ab1ec2, 0x884d9a03, + 0x2bdbb24f, 0x1410ccda, 0xb786e496, 0x6b8631f0, 0xc81019bc, + 0xf7db6729, 0x544d4f65, 0xad6768ea, 0x0ef140a6, 0x313a3e33, + 0x92ac167f, 0x4eacc319, 0xed3aeb55, 0xd2f195c0, 0x7167bd8c, + 0xb181394d, 0x12171101, 0x2ddc6f94, 0x8e4a47d8, 0x524a92be, + 0xf1dcbaf2, 0xce17c467, 0x6d81ec2b, 0x15141c31, 0xb682347d, + 0x89494ae8, 0x2adf62a4, 0xf6dfb7c2, 0x55499f8e, 0x6a82e11b, + 0xc914c957, 0x09f24d96, 0xaa6465da, 0x95af1b4f, 0x36393303, + 0xea39e665, 0x49afce29, 0x7664b0bc, 0xd5f298f0, 0x2cd8bf7f, + 0x8f4e9733, 0xb085e9a6, 0x1313c1ea, 0xcf13148c, 0x6c853cc0, + 0x534e4255, 0xf0d86a19, 0x303eeed8, 0x93a8c694, 0xac63b801, + 0x0ff5904d, 0xd3f5452b, 0x70636d67, 0x4fa813f2, 0xec3e3bbe, + 0x668d5aad, 0xc51b72e1, 0xfad00c74, 0x59462438, 0x8546f15e, + 0x26d0d912, 0x191ba787, 0xba8d8fcb, 0x7a6b0b0a, 0xd9fd2346, + 0xe6365dd3, 0x45a0759f, 0x99a0a0f9, 0x3a3688b5, 0x05fdf620, + 0xa66bde6c, 0x5f41f9e3, 0xfcd7d1af, 0xc31caf3a, 0x608a8776, + 0xbc8a5210, 0x1f1c7a5c, 0x20d704c9, 0x83412c85, 0x43a7a844, + 0xe0318008, 0xdffafe9d, 0x7c6cd6d1, 0xa06c03b7, 0x03fa2bfb, + 0x3c31556e, 0x9fa77d22, 0xf2269109, 0x51b0b945, 0x6e7bc7d0, + 0xcdedef9c, 0x11ed3afa, 0xb27b12b6, 0x8db06c23, 0x2e26446f, + 0xeec0c0ae, 0x4d56e8e2, 0x729d9677, 0xd10bbe3b, 0x0d0b6b5d, + 0xae9d4311, 0x91563d84, 0x32c015c8, 0xcbea3247, 0x687c1a0b, + 0x57b7649e, 0xf4214cd2, 0x282199b4, 0x8bb7b1f8, 0xb47ccf6d, + 0x17eae721, 0xd70c63e0, 0x749a4bac, 0x4b513539, 0xe8c71d75, + 0x34c7c813, 0x9751e05f, 0xa89a9eca, 0x0b0cb686, 0x81bfd795, + 0x2229ffd9, 0x1de2814c, 0xbe74a900, 0x62747c66, 0xc1e2542a, + 0xfe292abf, 0x5dbf02f3, 0x9d598632, 0x3ecfae7e, 0x0104d0eb, + 0xa292f8a7, 0x7e922dc1, 0xdd04058d, 0xe2cf7b18, 0x41595354, + 0xb87374db, 0x1be55c97, 0x242e2202, 0x87b80a4e, 0x5bb8df28, + 0xf82ef764, 0xc7e589f1, 0x6473a1bd, 0xa495257c, 0x07030d30, + 0x38c873a5, 0x9b5e5be9, 0x475e8e8f, 0xe4c8a6c3, 0xdb03d856, + 0x7895f01a}, + {0x00000000, 0x2a283862, 0x545070c4, 0x7e7848a6, 0xa8a0e188, + 0x8288d9ea, 0xfcf0914c, 0xd6d8a92e, 0x8a30c551, 0xa018fd33, + 0xde60b595, 0xf4488df7, 0x229024d9, 0x08b81cbb, 0x76c0541d, + 0x5ce86c7f, 0xcf108ce3, 0xe538b481, 0x9b40fc27, 0xb168c445, + 0x67b06d6b, 0x4d985509, 0x33e01daf, 0x19c825cd, 0x452049b2, + 0x6f0871d0, 0x11703976, 0x3b580114, 0xed80a83a, 0xc7a89058, + 0xb9d0d8fe, 0x93f8e09c, 0x45501f87, 0x6f7827e5, 0x11006f43, + 0x3b285721, 0xedf0fe0f, 0xc7d8c66d, 0xb9a08ecb, 0x9388b6a9, + 0xcf60dad6, 0xe548e2b4, 0x9b30aa12, 0xb1189270, 0x67c03b5e, + 0x4de8033c, 0x33904b9a, 0x19b873f8, 0x8a409364, 0xa068ab06, + 0xde10e3a0, 0xf438dbc2, 0x22e072ec, 0x08c84a8e, 0x76b00228, + 0x5c983a4a, 0x00705635, 0x2a586e57, 0x542026f1, 0x7e081e93, + 0xa8d0b7bd, 0x82f88fdf, 0xfc80c779, 0xd6a8ff1b, 0x8aa03f0e, + 0xa088076c, 0xdef04fca, 0xf4d877a8, 0x2200de86, 0x0828e6e4, + 0x7650ae42, 0x5c789620, 0x0090fa5f, 0x2ab8c23d, 0x54c08a9b, + 0x7ee8b2f9, 0xa8301bd7, 0x821823b5, 0xfc606b13, 0xd6485371, + 0x45b0b3ed, 0x6f988b8f, 0x11e0c329, 0x3bc8fb4b, 0xed105265, + 0xc7386a07, 0xb94022a1, 0x93681ac3, 0xcf8076bc, 0xe5a84ede, + 0x9bd00678, 0xb1f83e1a, 0x67209734, 0x4d08af56, 0x3370e7f0, + 0x1958df92, 0xcff02089, 0xe5d818eb, 0x9ba0504d, 0xb188682f, + 0x6750c101, 0x4d78f963, 0x3300b1c5, 0x192889a7, 0x45c0e5d8, + 0x6fe8ddba, 0x1190951c, 0x3bb8ad7e, 0xed600450, 0xc7483c32, + 0xb9307494, 0x93184cf6, 0x00e0ac6a, 0x2ac89408, 0x54b0dcae, + 0x7e98e4cc, 0xa8404de2, 0x82687580, 0xfc103d26, 0xd6380544, + 0x8ad0693b, 0xa0f85159, 0xde8019ff, 0xf4a8219d, 0x227088b3, + 0x0858b0d1, 0x7620f877, 0x5c08c015, 0xce31785d, 0xe419403f, + 0x9a610899, 0xb04930fb, 0x669199d5, 0x4cb9a1b7, 0x32c1e911, + 0x18e9d173, 0x4401bd0c, 0x6e29856e, 0x1051cdc8, 0x3a79f5aa, + 0xeca15c84, 0xc68964e6, 0xb8f12c40, 0x92d91422, 0x0121f4be, + 0x2b09ccdc, 0x5571847a, 0x7f59bc18, 0xa9811536, 0x83a92d54, + 0xfdd165f2, 0xd7f95d90, 0x8b1131ef, 0xa139098d, 0xdf41412b, + 0xf5697949, 0x23b1d067, 0x0999e805, 0x77e1a0a3, 0x5dc998c1, + 0x8b6167da, 0xa1495fb8, 0xdf31171e, 0xf5192f7c, 0x23c18652, + 0x09e9be30, 0x7791f696, 0x5db9cef4, 0x0151a28b, 0x2b799ae9, + 0x5501d24f, 0x7f29ea2d, 0xa9f14303, 0x83d97b61, 0xfda133c7, + 0xd7890ba5, 0x4471eb39, 0x6e59d35b, 0x10219bfd, 0x3a09a39f, + 0xecd10ab1, 0xc6f932d3, 0xb8817a75, 0x92a94217, 0xce412e68, + 0xe469160a, 0x9a115eac, 0xb03966ce, 0x66e1cfe0, 0x4cc9f782, + 0x32b1bf24, 0x18998746, 0x44914753, 0x6eb97f31, 0x10c13797, + 0x3ae90ff5, 0xec31a6db, 0xc6199eb9, 0xb861d61f, 0x9249ee7d, + 0xcea18202, 0xe489ba60, 0x9af1f2c6, 0xb0d9caa4, 0x6601638a, + 0x4c295be8, 0x3251134e, 0x18792b2c, 0x8b81cbb0, 0xa1a9f3d2, + 0xdfd1bb74, 0xf5f98316, 0x23212a38, 0x0909125a, 0x77715afc, + 0x5d59629e, 0x01b10ee1, 0x2b993683, 0x55e17e25, 0x7fc94647, + 0xa911ef69, 0x8339d70b, 0xfd419fad, 0xd769a7cf, 0x01c158d4, + 0x2be960b6, 0x55912810, 0x7fb91072, 0xa961b95c, 0x8349813e, + 0xfd31c998, 0xd719f1fa, 0x8bf19d85, 0xa1d9a5e7, 0xdfa1ed41, + 0xf589d523, 0x23517c0d, 0x0979446f, 0x77010cc9, 0x5d2934ab, + 0xced1d437, 0xe4f9ec55, 0x9a81a4f3, 0xb0a99c91, 0x667135bf, + 0x4c590ddd, 0x3221457b, 0x18097d19, 0x44e11166, 0x6ec92904, + 0x10b161a2, 0x3a9959c0, 0xec41f0ee, 0xc669c88c, 0xb811802a, + 0x9239b848}, + {0x00000000, 0x4713f6fb, 0x8e27edf6, 0xc9341b0d, 0xc73eddad, + 0x802d2b56, 0x4919305b, 0x0e0ac6a0, 0x550cbd1b, 0x121f4be0, + 0xdb2b50ed, 0x9c38a616, 0x923260b6, 0xd521964d, 0x1c158d40, + 0x5b067bbb, 0xaa197a36, 0xed0a8ccd, 0x243e97c0, 0x632d613b, + 0x6d27a79b, 0x2a345160, 0xe3004a6d, 0xa413bc96, 0xff15c72d, + 0xb80631d6, 0x71322adb, 0x3621dc20, 0x382b1a80, 0x7f38ec7b, + 0xb60cf776, 0xf11f018d, 0x8f43f22d, 0xc85004d6, 0x01641fdb, + 0x4677e920, 0x487d2f80, 0x0f6ed97b, 0xc65ac276, 0x8149348d, + 0xda4f4f36, 0x9d5cb9cd, 0x5468a2c0, 0x137b543b, 0x1d71929b, + 0x5a626460, 0x93567f6d, 0xd4458996, 0x255a881b, 0x62497ee0, + 0xab7d65ed, 0xec6e9316, 0xe26455b6, 0xa577a34d, 0x6c43b840, + 0x2b504ebb, 0x70563500, 0x3745c3fb, 0xfe71d8f6, 0xb9622e0d, + 0xb768e8ad, 0xf07b1e56, 0x394f055b, 0x7e5cf3a0, 0xc5f6e21b, + 0x82e514e0, 0x4bd10fed, 0x0cc2f916, 0x02c83fb6, 0x45dbc94d, + 0x8cefd240, 0xcbfc24bb, 0x90fa5f00, 0xd7e9a9fb, 0x1eddb2f6, + 0x59ce440d, 0x57c482ad, 0x10d77456, 0xd9e36f5b, 0x9ef099a0, + 0x6fef982d, 0x28fc6ed6, 0xe1c875db, 0xa6db8320, 0xa8d14580, + 0xefc2b37b, 0x26f6a876, 0x61e55e8d, 0x3ae32536, 0x7df0d3cd, + 0xb4c4c8c0, 0xf3d73e3b, 0xfdddf89b, 0xbace0e60, 0x73fa156d, + 0x34e9e396, 0x4ab51036, 0x0da6e6cd, 0xc492fdc0, 0x83810b3b, + 0x8d8bcd9b, 0xca983b60, 0x03ac206d, 0x44bfd696, 0x1fb9ad2d, + 0x58aa5bd6, 0x919e40db, 0xd68db620, 0xd8877080, 0x9f94867b, + 0x56a09d76, 0x11b36b8d, 0xe0ac6a00, 0xa7bf9cfb, 0x6e8b87f6, + 0x2998710d, 0x2792b7ad, 0x60814156, 0xa9b55a5b, 0xeea6aca0, + 0xb5a0d71b, 0xf2b321e0, 0x3b873aed, 0x7c94cc16, 0x729e0ab6, + 0x358dfc4d, 0xfcb9e740, 0xbbaa11bb, 0x509cc277, 0x178f348c, + 0xdebb2f81, 0x99a8d97a, 0x97a21fda, 0xd0b1e921, 0x1985f22c, + 0x5e9604d7, 0x05907f6c, 0x42838997, 0x8bb7929a, 0xcca46461, + 0xc2aea2c1, 0x85bd543a, 0x4c894f37, 0x0b9ab9cc, 0xfa85b841, + 0xbd964eba, 0x74a255b7, 0x33b1a34c, 0x3dbb65ec, 0x7aa89317, + 0xb39c881a, 0xf48f7ee1, 0xaf89055a, 0xe89af3a1, 0x21aee8ac, + 0x66bd1e57, 0x68b7d8f7, 0x2fa42e0c, 0xe6903501, 0xa183c3fa, + 0xdfdf305a, 0x98ccc6a1, 0x51f8ddac, 0x16eb2b57, 0x18e1edf7, + 0x5ff21b0c, 0x96c60001, 0xd1d5f6fa, 0x8ad38d41, 0xcdc07bba, + 0x04f460b7, 0x43e7964c, 0x4ded50ec, 0x0afea617, 0xc3cabd1a, + 0x84d94be1, 0x75c64a6c, 0x32d5bc97, 0xfbe1a79a, 0xbcf25161, + 0xb2f897c1, 0xf5eb613a, 0x3cdf7a37, 0x7bcc8ccc, 0x20caf777, + 0x67d9018c, 0xaeed1a81, 0xe9feec7a, 0xe7f42ada, 0xa0e7dc21, + 0x69d3c72c, 0x2ec031d7, 0x956a206c, 0xd279d697, 0x1b4dcd9a, + 0x5c5e3b61, 0x5254fdc1, 0x15470b3a, 0xdc731037, 0x9b60e6cc, + 0xc0669d77, 0x87756b8c, 0x4e417081, 0x0952867a, 0x075840da, + 0x404bb621, 0x897fad2c, 0xce6c5bd7, 0x3f735a5a, 0x7860aca1, + 0xb154b7ac, 0xf6474157, 0xf84d87f7, 0xbf5e710c, 0x766a6a01, + 0x31799cfa, 0x6a7fe741, 0x2d6c11ba, 0xe4580ab7, 0xa34bfc4c, + 0xad413aec, 0xea52cc17, 0x2366d71a, 0x647521e1, 0x1a29d241, + 0x5d3a24ba, 0x940e3fb7, 0xd31dc94c, 0xdd170fec, 0x9a04f917, + 0x5330e21a, 0x142314e1, 0x4f256f5a, 0x083699a1, 0xc10282ac, + 0x86117457, 0x881bb2f7, 0xcf08440c, 0x063c5f01, 0x412fa9fa, + 0xb030a877, 0xf7235e8c, 0x3e174581, 0x7904b37a, 0x770e75da, + 0x301d8321, 0xf929982c, 0xbe3a6ed7, 0xe53c156c, 0xa22fe397, + 0x6b1bf89a, 0x2c080e61, 0x2202c8c1, 0x65113e3a, 0xac252537, + 0xeb36d3cc}, + {0x00000000, 0xa13984ee, 0x99020f9d, 0x383b8b73, 0xe975197b, + 0x484c9d95, 0x707716e6, 0xd14e9208, 0x099b34b7, 0xa8a2b059, + 0x90993b2a, 0x31a0bfc4, 0xe0ee2dcc, 0x41d7a922, 0x79ec2251, + 0xd8d5a6bf, 0x1336696e, 0xb20fed80, 0x8a3466f3, 0x2b0de21d, + 0xfa437015, 0x5b7af4fb, 0x63417f88, 0xc278fb66, 0x1aad5dd9, + 0xbb94d937, 0x83af5244, 0x2296d6aa, 0xf3d844a2, 0x52e1c04c, + 0x6ada4b3f, 0xcbe3cfd1, 0x266cd2dc, 0x87555632, 0xbf6edd41, + 0x1e5759af, 0xcf19cba7, 0x6e204f49, 0x561bc43a, 0xf72240d4, + 0x2ff7e66b, 0x8ece6285, 0xb6f5e9f6, 0x17cc6d18, 0xc682ff10, + 0x67bb7bfe, 0x5f80f08d, 0xfeb97463, 0x355abbb2, 0x94633f5c, + 0xac58b42f, 0x0d6130c1, 0xdc2fa2c9, 0x7d162627, 0x452dad54, + 0xe41429ba, 0x3cc18f05, 0x9df80beb, 0xa5c38098, 0x04fa0476, + 0xd5b4967e, 0x748d1290, 0x4cb699e3, 0xed8f1d0d, 0x4cd9a5b8, + 0xede02156, 0xd5dbaa25, 0x74e22ecb, 0xa5acbcc3, 0x0495382d, + 0x3caeb35e, 0x9d9737b0, 0x4542910f, 0xe47b15e1, 0xdc409e92, + 0x7d791a7c, 0xac378874, 0x0d0e0c9a, 0x353587e9, 0x940c0307, + 0x5fefccd6, 0xfed64838, 0xc6edc34b, 0x67d447a5, 0xb69ad5ad, + 0x17a35143, 0x2f98da30, 0x8ea15ede, 0x5674f861, 0xf74d7c8f, + 0xcf76f7fc, 0x6e4f7312, 0xbf01e11a, 0x1e3865f4, 0x2603ee87, + 0x873a6a69, 0x6ab57764, 0xcb8cf38a, 0xf3b778f9, 0x528efc17, + 0x83c06e1f, 0x22f9eaf1, 0x1ac26182, 0xbbfbe56c, 0x632e43d3, + 0xc217c73d, 0xfa2c4c4e, 0x5b15c8a0, 0x8a5b5aa8, 0x2b62de46, + 0x13595535, 0xb260d1db, 0x79831e0a, 0xd8ba9ae4, 0xe0811197, + 0x41b89579, 0x90f60771, 0x31cf839f, 0x09f408ec, 0xa8cd8c02, + 0x70182abd, 0xd121ae53, 0xe91a2520, 0x4823a1ce, 0x996d33c6, + 0x3854b728, 0x006f3c5b, 0xa156b8b5, 0x99b34b70, 0x388acf9e, + 0x00b144ed, 0xa188c003, 0x70c6520b, 0xd1ffd6e5, 0xe9c45d96, + 0x48fdd978, 0x90287fc7, 0x3111fb29, 0x092a705a, 0xa813f4b4, + 0x795d66bc, 0xd864e252, 0xe05f6921, 0x4166edcf, 0x8a85221e, + 0x2bbca6f0, 0x13872d83, 0xb2bea96d, 0x63f03b65, 0xc2c9bf8b, + 0xfaf234f8, 0x5bcbb016, 0x831e16a9, 0x22279247, 0x1a1c1934, + 0xbb259dda, 0x6a6b0fd2, 0xcb528b3c, 0xf369004f, 0x525084a1, + 0xbfdf99ac, 0x1ee61d42, 0x26dd9631, 0x87e412df, 0x56aa80d7, + 0xf7930439, 0xcfa88f4a, 0x6e910ba4, 0xb644ad1b, 0x177d29f5, + 0x2f46a286, 0x8e7f2668, 0x5f31b460, 0xfe08308e, 0xc633bbfd, + 0x670a3f13, 0xace9f0c2, 0x0dd0742c, 0x35ebff5f, 0x94d27bb1, + 0x459ce9b9, 0xe4a56d57, 0xdc9ee624, 0x7da762ca, 0xa572c475, + 0x044b409b, 0x3c70cbe8, 0x9d494f06, 0x4c07dd0e, 0xed3e59e0, + 0xd505d293, 0x743c567d, 0xd56aeec8, 0x74536a26, 0x4c68e155, + 0xed5165bb, 0x3c1ff7b3, 0x9d26735d, 0xa51df82e, 0x04247cc0, + 0xdcf1da7f, 0x7dc85e91, 0x45f3d5e2, 0xe4ca510c, 0x3584c304, + 0x94bd47ea, 0xac86cc99, 0x0dbf4877, 0xc65c87a6, 0x67650348, + 0x5f5e883b, 0xfe670cd5, 0x2f299edd, 0x8e101a33, 0xb62b9140, + 0x171215ae, 0xcfc7b311, 0x6efe37ff, 0x56c5bc8c, 0xf7fc3862, + 0x26b2aa6a, 0x878b2e84, 0xbfb0a5f7, 0x1e892119, 0xf3063c14, + 0x523fb8fa, 0x6a043389, 0xcb3db767, 0x1a73256f, 0xbb4aa181, + 0x83712af2, 0x2248ae1c, 0xfa9d08a3, 0x5ba48c4d, 0x639f073e, + 0xc2a683d0, 0x13e811d8, 0xb2d19536, 0x8aea1e45, 0x2bd39aab, + 0xe030557a, 0x4109d194, 0x79325ae7, 0xd80bde09, 0x09454c01, + 0xa87cc8ef, 0x9047439c, 0x317ec772, 0xe9ab61cd, 0x4892e523, + 0x70a96e50, 0xd190eabe, 0x00de78b6, 0xa1e7fc58, 0x99dc772b, + 0x38e5f3c5}, + {0x00000000, 0xe81790a1, 0x0b5e2703, 0xe349b7a2, 0x16bc4e06, + 0xfeabdea7, 0x1de26905, 0xf5f5f9a4, 0x2d789c0c, 0xc56f0cad, + 0x2626bb0f, 0xce312bae, 0x3bc4d20a, 0xd3d342ab, 0x309af509, + 0xd88d65a8, 0x5af13818, 0xb2e6a8b9, 0x51af1f1b, 0xb9b88fba, + 0x4c4d761e, 0xa45ae6bf, 0x4713511d, 0xaf04c1bc, 0x7789a414, + 0x9f9e34b5, 0x7cd78317, 0x94c013b6, 0x6135ea12, 0x89227ab3, + 0x6a6bcd11, 0x827c5db0, 0xb5e27030, 0x5df5e091, 0xbebc5733, + 0x56abc792, 0xa35e3e36, 0x4b49ae97, 0xa8001935, 0x40178994, + 0x989aec3c, 0x708d7c9d, 0x93c4cb3f, 0x7bd35b9e, 0x8e26a23a, + 0x6631329b, 0x85788539, 0x6d6f1598, 0xef134828, 0x0704d889, + 0xe44d6f2b, 0x0c5aff8a, 0xf9af062e, 0x11b8968f, 0xf2f1212d, + 0x1ae6b18c, 0xc26bd424, 0x2a7c4485, 0xc935f327, 0x21226386, + 0xd4d79a22, 0x3cc00a83, 0xdf89bd21, 0x379e2d80, 0xb0b5e621, + 0x58a27680, 0xbbebc122, 0x53fc5183, 0xa609a827, 0x4e1e3886, + 0xad578f24, 0x45401f85, 0x9dcd7a2d, 0x75daea8c, 0x96935d2e, + 0x7e84cd8f, 0x8b71342b, 0x6366a48a, 0x802f1328, 0x68388389, + 0xea44de39, 0x02534e98, 0xe11af93a, 0x090d699b, 0xfcf8903f, + 0x14ef009e, 0xf7a6b73c, 0x1fb1279d, 0xc73c4235, 0x2f2bd294, + 0xcc626536, 0x2475f597, 0xd1800c33, 0x39979c92, 0xdade2b30, + 0x32c9bb91, 0x05579611, 0xed4006b0, 0x0e09b112, 0xe61e21b3, + 0x13ebd817, 0xfbfc48b6, 0x18b5ff14, 0xf0a26fb5, 0x282f0a1d, + 0xc0389abc, 0x23712d1e, 0xcb66bdbf, 0x3e93441b, 0xd684d4ba, + 0x35cd6318, 0xdddaf3b9, 0x5fa6ae09, 0xb7b13ea8, 0x54f8890a, + 0xbcef19ab, 0x491ae00f, 0xa10d70ae, 0x4244c70c, 0xaa5357ad, + 0x72de3205, 0x9ac9a2a4, 0x79801506, 0x919785a7, 0x64627c03, + 0x8c75eca2, 0x6f3c5b00, 0x872bcba1, 0xba1aca03, 0x520d5aa2, + 0xb144ed00, 0x59537da1, 0xaca68405, 0x44b114a4, 0xa7f8a306, + 0x4fef33a7, 0x9762560f, 0x7f75c6ae, 0x9c3c710c, 0x742be1ad, + 0x81de1809, 0x69c988a8, 0x8a803f0a, 0x6297afab, 0xe0ebf21b, + 0x08fc62ba, 0xebb5d518, 0x03a245b9, 0xf657bc1d, 0x1e402cbc, + 0xfd099b1e, 0x151e0bbf, 0xcd936e17, 0x2584feb6, 0xc6cd4914, + 0x2edad9b5, 0xdb2f2011, 0x3338b0b0, 0xd0710712, 0x386697b3, + 0x0ff8ba33, 0xe7ef2a92, 0x04a69d30, 0xecb10d91, 0x1944f435, + 0xf1536494, 0x121ad336, 0xfa0d4397, 0x2280263f, 0xca97b69e, + 0x29de013c, 0xc1c9919d, 0x343c6839, 0xdc2bf898, 0x3f624f3a, + 0xd775df9b, 0x5509822b, 0xbd1e128a, 0x5e57a528, 0xb6403589, + 0x43b5cc2d, 0xaba25c8c, 0x48ebeb2e, 0xa0fc7b8f, 0x78711e27, + 0x90668e86, 0x732f3924, 0x9b38a985, 0x6ecd5021, 0x86dac080, + 0x65937722, 0x8d84e783, 0x0aaf2c22, 0xe2b8bc83, 0x01f10b21, + 0xe9e69b80, 0x1c136224, 0xf404f285, 0x174d4527, 0xff5ad586, + 0x27d7b02e, 0xcfc0208f, 0x2c89972d, 0xc49e078c, 0x316bfe28, + 0xd97c6e89, 0x3a35d92b, 0xd222498a, 0x505e143a, 0xb849849b, + 0x5b003339, 0xb317a398, 0x46e25a3c, 0xaef5ca9d, 0x4dbc7d3f, + 0xa5abed9e, 0x7d268836, 0x95311897, 0x7678af35, 0x9e6f3f94, + 0x6b9ac630, 0x838d5691, 0x60c4e133, 0x88d37192, 0xbf4d5c12, + 0x575accb3, 0xb4137b11, 0x5c04ebb0, 0xa9f11214, 0x41e682b5, + 0xa2af3517, 0x4ab8a5b6, 0x9235c01e, 0x7a2250bf, 0x996be71d, + 0x717c77bc, 0x84898e18, 0x6c9e1eb9, 0x8fd7a91b, 0x67c039ba, + 0xe5bc640a, 0x0dabf4ab, 0xeee24309, 0x06f5d3a8, 0xf3002a0c, + 0x1b17baad, 0xf85e0d0f, 0x10499dae, 0xc8c4f806, 0x20d368a7, + 0xc39adf05, 0x2b8d4fa4, 0xde78b600, 0x366f26a1, 0xd5269103, + 0x3d3101a2}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0xa19017e800000000, 0x03275e0b00000000, + 0xa2b749e300000000, 0x064ebc1600000000, 0xa7deabfe00000000, + 0x0569e21d00000000, 0xa4f9f5f500000000, 0x0c9c782d00000000, + 0xad0c6fc500000000, 0x0fbb262600000000, 0xae2b31ce00000000, + 0x0ad2c43b00000000, 0xab42d3d300000000, 0x09f59a3000000000, + 0xa8658dd800000000, 0x1838f15a00000000, 0xb9a8e6b200000000, + 0x1b1faf5100000000, 0xba8fb8b900000000, 0x1e764d4c00000000, + 0xbfe65aa400000000, 0x1d51134700000000, 0xbcc104af00000000, + 0x14a4897700000000, 0xb5349e9f00000000, 0x1783d77c00000000, + 0xb613c09400000000, 0x12ea356100000000, 0xb37a228900000000, + 0x11cd6b6a00000000, 0xb05d7c8200000000, 0x3070e2b500000000, + 0x91e0f55d00000000, 0x3357bcbe00000000, 0x92c7ab5600000000, + 0x363e5ea300000000, 0x97ae494b00000000, 0x351900a800000000, + 0x9489174000000000, 0x3cec9a9800000000, 0x9d7c8d7000000000, + 0x3fcbc49300000000, 0x9e5bd37b00000000, 0x3aa2268e00000000, + 0x9b32316600000000, 0x3985788500000000, 0x98156f6d00000000, + 0x284813ef00000000, 0x89d8040700000000, 0x2b6f4de400000000, + 0x8aff5a0c00000000, 0x2e06aff900000000, 0x8f96b81100000000, + 0x2d21f1f200000000, 0x8cb1e61a00000000, 0x24d46bc200000000, + 0x85447c2a00000000, 0x27f335c900000000, 0x8663222100000000, + 0x229ad7d400000000, 0x830ac03c00000000, 0x21bd89df00000000, + 0x802d9e3700000000, 0x21e6b5b000000000, 0x8076a25800000000, + 0x22c1ebbb00000000, 0x8351fc5300000000, 0x27a809a600000000, + 0x86381e4e00000000, 0x248f57ad00000000, 0x851f404500000000, + 0x2d7acd9d00000000, 0x8ceada7500000000, 0x2e5d939600000000, + 0x8fcd847e00000000, 0x2b34718b00000000, 0x8aa4666300000000, + 0x28132f8000000000, 0x8983386800000000, 0x39de44ea00000000, + 0x984e530200000000, 0x3af91ae100000000, 0x9b690d0900000000, + 0x3f90f8fc00000000, 0x9e00ef1400000000, 0x3cb7a6f700000000, + 0x9d27b11f00000000, 0x35423cc700000000, 0x94d22b2f00000000, + 0x366562cc00000000, 0x97f5752400000000, 0x330c80d100000000, + 0x929c973900000000, 0x302bdeda00000000, 0x91bbc93200000000, + 0x1196570500000000, 0xb00640ed00000000, 0x12b1090e00000000, + 0xb3211ee600000000, 0x17d8eb1300000000, 0xb648fcfb00000000, + 0x14ffb51800000000, 0xb56fa2f000000000, 0x1d0a2f2800000000, + 0xbc9a38c000000000, 0x1e2d712300000000, 0xbfbd66cb00000000, + 0x1b44933e00000000, 0xbad484d600000000, 0x1863cd3500000000, + 0xb9f3dadd00000000, 0x09aea65f00000000, 0xa83eb1b700000000, + 0x0a89f85400000000, 0xab19efbc00000000, 0x0fe01a4900000000, + 0xae700da100000000, 0x0cc7444200000000, 0xad5753aa00000000, + 0x0532de7200000000, 0xa4a2c99a00000000, 0x0615807900000000, + 0xa785979100000000, 0x037c626400000000, 0xa2ec758c00000000, + 0x005b3c6f00000000, 0xa1cb2b8700000000, 0x03ca1aba00000000, + 0xa25a0d5200000000, 0x00ed44b100000000, 0xa17d535900000000, + 0x0584a6ac00000000, 0xa414b14400000000, 0x06a3f8a700000000, + 0xa733ef4f00000000, 0x0f56629700000000, 0xaec6757f00000000, + 0x0c713c9c00000000, 0xade12b7400000000, 0x0918de8100000000, + 0xa888c96900000000, 0x0a3f808a00000000, 0xabaf976200000000, + 0x1bf2ebe000000000, 0xba62fc0800000000, 0x18d5b5eb00000000, + 0xb945a20300000000, 0x1dbc57f600000000, 0xbc2c401e00000000, + 0x1e9b09fd00000000, 0xbf0b1e1500000000, 0x176e93cd00000000, + 0xb6fe842500000000, 0x1449cdc600000000, 0xb5d9da2e00000000, + 0x11202fdb00000000, 0xb0b0383300000000, 0x120771d000000000, + 0xb397663800000000, 0x33baf80f00000000, 0x922aefe700000000, + 0x309da60400000000, 0x910db1ec00000000, 0x35f4441900000000, + 0x946453f100000000, 0x36d31a1200000000, 0x97430dfa00000000, + 0x3f26802200000000, 0x9eb697ca00000000, 0x3c01de2900000000, + 0x9d91c9c100000000, 0x39683c3400000000, 0x98f82bdc00000000, + 0x3a4f623f00000000, 0x9bdf75d700000000, 0x2b82095500000000, + 0x8a121ebd00000000, 0x28a5575e00000000, 0x893540b600000000, + 0x2dccb54300000000, 0x8c5ca2ab00000000, 0x2eebeb4800000000, + 0x8f7bfca000000000, 0x271e717800000000, 0x868e669000000000, + 0x24392f7300000000, 0x85a9389b00000000, 0x2150cd6e00000000, + 0x80c0da8600000000, 0x2277936500000000, 0x83e7848d00000000, + 0x222caf0a00000000, 0x83bcb8e200000000, 0x210bf10100000000, + 0x809be6e900000000, 0x2462131c00000000, 0x85f204f400000000, + 0x27454d1700000000, 0x86d55aff00000000, 0x2eb0d72700000000, + 0x8f20c0cf00000000, 0x2d97892c00000000, 0x8c079ec400000000, + 0x28fe6b3100000000, 0x896e7cd900000000, 0x2bd9353a00000000, + 0x8a4922d200000000, 0x3a145e5000000000, 0x9b8449b800000000, + 0x3933005b00000000, 0x98a317b300000000, 0x3c5ae24600000000, + 0x9dcaf5ae00000000, 0x3f7dbc4d00000000, 0x9eedaba500000000, + 0x3688267d00000000, 0x9718319500000000, 0x35af787600000000, + 0x943f6f9e00000000, 0x30c69a6b00000000, 0x91568d8300000000, + 0x33e1c46000000000, 0x9271d38800000000, 0x125c4dbf00000000, + 0xb3cc5a5700000000, 0x117b13b400000000, 0xb0eb045c00000000, + 0x1412f1a900000000, 0xb582e64100000000, 0x1735afa200000000, + 0xb6a5b84a00000000, 0x1ec0359200000000, 0xbf50227a00000000, + 0x1de76b9900000000, 0xbc777c7100000000, 0x188e898400000000, + 0xb91e9e6c00000000, 0x1ba9d78f00000000, 0xba39c06700000000, + 0x0a64bce500000000, 0xabf4ab0d00000000, 0x0943e2ee00000000, + 0xa8d3f50600000000, 0x0c2a00f300000000, 0xadba171b00000000, + 0x0f0d5ef800000000, 0xae9d491000000000, 0x06f8c4c800000000, + 0xa768d32000000000, 0x05df9ac300000000, 0xa44f8d2b00000000, + 0x00b678de00000000, 0xa1266f3600000000, 0x039126d500000000, + 0xa201313d00000000}, + {0x0000000000000000, 0xee8439a100000000, 0x9d0f029900000000, + 0x738b3b3800000000, 0x7b1975e900000000, 0x959d4c4800000000, + 0xe616777000000000, 0x08924ed100000000, 0xb7349b0900000000, + 0x59b0a2a800000000, 0x2a3b999000000000, 0xc4bfa03100000000, + 0xcc2deee000000000, 0x22a9d74100000000, 0x5122ec7900000000, + 0xbfa6d5d800000000, 0x6e69361300000000, 0x80ed0fb200000000, + 0xf366348a00000000, 0x1de20d2b00000000, 0x157043fa00000000, + 0xfbf47a5b00000000, 0x887f416300000000, 0x66fb78c200000000, + 0xd95dad1a00000000, 0x37d994bb00000000, 0x4452af8300000000, + 0xaad6962200000000, 0xa244d8f300000000, 0x4cc0e15200000000, + 0x3f4bda6a00000000, 0xd1cfe3cb00000000, 0xdcd26c2600000000, + 0x3256558700000000, 0x41dd6ebf00000000, 0xaf59571e00000000, + 0xa7cb19cf00000000, 0x494f206e00000000, 0x3ac41b5600000000, + 0xd44022f700000000, 0x6be6f72f00000000, 0x8562ce8e00000000, + 0xf6e9f5b600000000, 0x186dcc1700000000, 0x10ff82c600000000, + 0xfe7bbb6700000000, 0x8df0805f00000000, 0x6374b9fe00000000, + 0xb2bb5a3500000000, 0x5c3f639400000000, 0x2fb458ac00000000, + 0xc130610d00000000, 0xc9a22fdc00000000, 0x2726167d00000000, + 0x54ad2d4500000000, 0xba2914e400000000, 0x058fc13c00000000, + 0xeb0bf89d00000000, 0x9880c3a500000000, 0x7604fa0400000000, + 0x7e96b4d500000000, 0x90128d7400000000, 0xe399b64c00000000, + 0x0d1d8fed00000000, 0xb8a5d94c00000000, 0x5621e0ed00000000, + 0x25aadbd500000000, 0xcb2ee27400000000, 0xc3bcaca500000000, + 0x2d38950400000000, 0x5eb3ae3c00000000, 0xb037979d00000000, + 0x0f91424500000000, 0xe1157be400000000, 0x929e40dc00000000, + 0x7c1a797d00000000, 0x748837ac00000000, 0x9a0c0e0d00000000, + 0xe987353500000000, 0x07030c9400000000, 0xd6ccef5f00000000, + 0x3848d6fe00000000, 0x4bc3edc600000000, 0xa547d46700000000, + 0xadd59ab600000000, 0x4351a31700000000, 0x30da982f00000000, + 0xde5ea18e00000000, 0x61f8745600000000, 0x8f7c4df700000000, + 0xfcf776cf00000000, 0x12734f6e00000000, 0x1ae101bf00000000, + 0xf465381e00000000, 0x87ee032600000000, 0x696a3a8700000000, + 0x6477b56a00000000, 0x8af38ccb00000000, 0xf978b7f300000000, + 0x17fc8e5200000000, 0x1f6ec08300000000, 0xf1eaf92200000000, + 0x8261c21a00000000, 0x6ce5fbbb00000000, 0xd3432e6300000000, + 0x3dc717c200000000, 0x4e4c2cfa00000000, 0xa0c8155b00000000, + 0xa85a5b8a00000000, 0x46de622b00000000, 0x3555591300000000, + 0xdbd160b200000000, 0x0a1e837900000000, 0xe49abad800000000, + 0x971181e000000000, 0x7995b84100000000, 0x7107f69000000000, + 0x9f83cf3100000000, 0xec08f40900000000, 0x028ccda800000000, + 0xbd2a187000000000, 0x53ae21d100000000, 0x20251ae900000000, + 0xcea1234800000000, 0xc6336d9900000000, 0x28b7543800000000, + 0x5b3c6f0000000000, 0xb5b856a100000000, 0x704bb39900000000, + 0x9ecf8a3800000000, 0xed44b10000000000, 0x03c088a100000000, + 0x0b52c67000000000, 0xe5d6ffd100000000, 0x965dc4e900000000, + 0x78d9fd4800000000, 0xc77f289000000000, 0x29fb113100000000, + 0x5a702a0900000000, 0xb4f413a800000000, 0xbc665d7900000000, + 0x52e264d800000000, 0x21695fe000000000, 0xcfed664100000000, + 0x1e22858a00000000, 0xf0a6bc2b00000000, 0x832d871300000000, + 0x6da9beb200000000, 0x653bf06300000000, 0x8bbfc9c200000000, + 0xf834f2fa00000000, 0x16b0cb5b00000000, 0xa9161e8300000000, + 0x4792272200000000, 0x34191c1a00000000, 0xda9d25bb00000000, + 0xd20f6b6a00000000, 0x3c8b52cb00000000, 0x4f0069f300000000, + 0xa184505200000000, 0xac99dfbf00000000, 0x421de61e00000000, + 0x3196dd2600000000, 0xdf12e48700000000, 0xd780aa5600000000, + 0x390493f700000000, 0x4a8fa8cf00000000, 0xa40b916e00000000, + 0x1bad44b600000000, 0xf5297d1700000000, 0x86a2462f00000000, + 0x68267f8e00000000, 0x60b4315f00000000, 0x8e3008fe00000000, + 0xfdbb33c600000000, 0x133f0a6700000000, 0xc2f0e9ac00000000, + 0x2c74d00d00000000, 0x5fffeb3500000000, 0xb17bd29400000000, + 0xb9e99c4500000000, 0x576da5e400000000, 0x24e69edc00000000, + 0xca62a77d00000000, 0x75c472a500000000, 0x9b404b0400000000, + 0xe8cb703c00000000, 0x064f499d00000000, 0x0edd074c00000000, + 0xe0593eed00000000, 0x93d205d500000000, 0x7d563c7400000000, + 0xc8ee6ad500000000, 0x266a537400000000, 0x55e1684c00000000, + 0xbb6551ed00000000, 0xb3f71f3c00000000, 0x5d73269d00000000, + 0x2ef81da500000000, 0xc07c240400000000, 0x7fdaf1dc00000000, + 0x915ec87d00000000, 0xe2d5f34500000000, 0x0c51cae400000000, + 0x04c3843500000000, 0xea47bd9400000000, 0x99cc86ac00000000, + 0x7748bf0d00000000, 0xa6875cc600000000, 0x4803656700000000, + 0x3b885e5f00000000, 0xd50c67fe00000000, 0xdd9e292f00000000, + 0x331a108e00000000, 0x40912bb600000000, 0xae15121700000000, + 0x11b3c7cf00000000, 0xff37fe6e00000000, 0x8cbcc55600000000, + 0x6238fcf700000000, 0x6aaab22600000000, 0x842e8b8700000000, + 0xf7a5b0bf00000000, 0x1921891e00000000, 0x143c06f300000000, + 0xfab83f5200000000, 0x8933046a00000000, 0x67b73dcb00000000, + 0x6f25731a00000000, 0x81a14abb00000000, 0xf22a718300000000, + 0x1cae482200000000, 0xa3089dfa00000000, 0x4d8ca45b00000000, + 0x3e079f6300000000, 0xd083a6c200000000, 0xd811e81300000000, + 0x3695d1b200000000, 0x451eea8a00000000, 0xab9ad32b00000000, + 0x7a5530e000000000, 0x94d1094100000000, 0xe75a327900000000, + 0x09de0bd800000000, 0x014c450900000000, 0xefc87ca800000000, + 0x9c43479000000000, 0x72c77e3100000000, 0xcd61abe900000000, + 0x23e5924800000000, 0x506ea97000000000, 0xbeea90d100000000, + 0xb678de0000000000, 0x58fce7a100000000, 0x2b77dc9900000000, + 0xc5f3e53800000000}, + {0x0000000000000000, 0xfbf6134700000000, 0xf6ed278e00000000, + 0x0d1b34c900000000, 0xaddd3ec700000000, 0x562b2d8000000000, + 0x5b30194900000000, 0xa0c60a0e00000000, 0x1bbd0c5500000000, + 0xe04b1f1200000000, 0xed502bdb00000000, 0x16a6389c00000000, + 0xb660329200000000, 0x4d9621d500000000, 0x408d151c00000000, + 0xbb7b065b00000000, 0x367a19aa00000000, 0xcd8c0aed00000000, + 0xc0973e2400000000, 0x3b612d6300000000, 0x9ba7276d00000000, + 0x6051342a00000000, 0x6d4a00e300000000, 0x96bc13a400000000, + 0x2dc715ff00000000, 0xd63106b800000000, 0xdb2a327100000000, + 0x20dc213600000000, 0x801a2b3800000000, 0x7bec387f00000000, + 0x76f70cb600000000, 0x8d011ff100000000, 0x2df2438f00000000, + 0xd60450c800000000, 0xdb1f640100000000, 0x20e9774600000000, + 0x802f7d4800000000, 0x7bd96e0f00000000, 0x76c25ac600000000, + 0x8d34498100000000, 0x364f4fda00000000, 0xcdb95c9d00000000, + 0xc0a2685400000000, 0x3b547b1300000000, 0x9b92711d00000000, + 0x6064625a00000000, 0x6d7f569300000000, 0x968945d400000000, + 0x1b885a2500000000, 0xe07e496200000000, 0xed657dab00000000, + 0x16936eec00000000, 0xb65564e200000000, 0x4da377a500000000, + 0x40b8436c00000000, 0xbb4e502b00000000, 0x0035567000000000, + 0xfbc3453700000000, 0xf6d871fe00000000, 0x0d2e62b900000000, + 0xade868b700000000, 0x561e7bf000000000, 0x5b054f3900000000, + 0xa0f35c7e00000000, 0x1be2f6c500000000, 0xe014e58200000000, + 0xed0fd14b00000000, 0x16f9c20c00000000, 0xb63fc80200000000, + 0x4dc9db4500000000, 0x40d2ef8c00000000, 0xbb24fccb00000000, + 0x005ffa9000000000, 0xfba9e9d700000000, 0xf6b2dd1e00000000, + 0x0d44ce5900000000, 0xad82c45700000000, 0x5674d71000000000, + 0x5b6fe3d900000000, 0xa099f09e00000000, 0x2d98ef6f00000000, + 0xd66efc2800000000, 0xdb75c8e100000000, 0x2083dba600000000, + 0x8045d1a800000000, 0x7bb3c2ef00000000, 0x76a8f62600000000, + 0x8d5ee56100000000, 0x3625e33a00000000, 0xcdd3f07d00000000, + 0xc0c8c4b400000000, 0x3b3ed7f300000000, 0x9bf8ddfd00000000, + 0x600eceba00000000, 0x6d15fa7300000000, 0x96e3e93400000000, + 0x3610b54a00000000, 0xcde6a60d00000000, 0xc0fd92c400000000, + 0x3b0b818300000000, 0x9bcd8b8d00000000, 0x603b98ca00000000, + 0x6d20ac0300000000, 0x96d6bf4400000000, 0x2dadb91f00000000, + 0xd65baa5800000000, 0xdb409e9100000000, 0x20b68dd600000000, + 0x807087d800000000, 0x7b86949f00000000, 0x769da05600000000, + 0x8d6bb31100000000, 0x006aace000000000, 0xfb9cbfa700000000, + 0xf6878b6e00000000, 0x0d71982900000000, 0xadb7922700000000, + 0x5641816000000000, 0x5b5ab5a900000000, 0xa0aca6ee00000000, + 0x1bd7a0b500000000, 0xe021b3f200000000, 0xed3a873b00000000, + 0x16cc947c00000000, 0xb60a9e7200000000, 0x4dfc8d3500000000, + 0x40e7b9fc00000000, 0xbb11aabb00000000, 0x77c29c5000000000, + 0x8c348f1700000000, 0x812fbbde00000000, 0x7ad9a89900000000, + 0xda1fa29700000000, 0x21e9b1d000000000, 0x2cf2851900000000, + 0xd704965e00000000, 0x6c7f900500000000, 0x9789834200000000, + 0x9a92b78b00000000, 0x6164a4cc00000000, 0xc1a2aec200000000, + 0x3a54bd8500000000, 0x374f894c00000000, 0xccb99a0b00000000, + 0x41b885fa00000000, 0xba4e96bd00000000, 0xb755a27400000000, + 0x4ca3b13300000000, 0xec65bb3d00000000, 0x1793a87a00000000, + 0x1a889cb300000000, 0xe17e8ff400000000, 0x5a0589af00000000, + 0xa1f39ae800000000, 0xace8ae2100000000, 0x571ebd6600000000, + 0xf7d8b76800000000, 0x0c2ea42f00000000, 0x013590e600000000, + 0xfac383a100000000, 0x5a30dfdf00000000, 0xa1c6cc9800000000, + 0xacddf85100000000, 0x572beb1600000000, 0xf7ede11800000000, + 0x0c1bf25f00000000, 0x0100c69600000000, 0xfaf6d5d100000000, + 0x418dd38a00000000, 0xba7bc0cd00000000, 0xb760f40400000000, + 0x4c96e74300000000, 0xec50ed4d00000000, 0x17a6fe0a00000000, + 0x1abdcac300000000, 0xe14bd98400000000, 0x6c4ac67500000000, + 0x97bcd53200000000, 0x9aa7e1fb00000000, 0x6151f2bc00000000, + 0xc197f8b200000000, 0x3a61ebf500000000, 0x377adf3c00000000, + 0xcc8ccc7b00000000, 0x77f7ca2000000000, 0x8c01d96700000000, + 0x811aedae00000000, 0x7aecfee900000000, 0xda2af4e700000000, + 0x21dce7a000000000, 0x2cc7d36900000000, 0xd731c02e00000000, + 0x6c206a9500000000, 0x97d679d200000000, 0x9acd4d1b00000000, + 0x613b5e5c00000000, 0xc1fd545200000000, 0x3a0b471500000000, + 0x371073dc00000000, 0xcce6609b00000000, 0x779d66c000000000, + 0x8c6b758700000000, 0x8170414e00000000, 0x7a86520900000000, + 0xda40580700000000, 0x21b64b4000000000, 0x2cad7f8900000000, + 0xd75b6cce00000000, 0x5a5a733f00000000, 0xa1ac607800000000, + 0xacb754b100000000, 0x574147f600000000, 0xf7874df800000000, + 0x0c715ebf00000000, 0x016a6a7600000000, 0xfa9c793100000000, + 0x41e77f6a00000000, 0xba116c2d00000000, 0xb70a58e400000000, + 0x4cfc4ba300000000, 0xec3a41ad00000000, 0x17cc52ea00000000, + 0x1ad7662300000000, 0xe121756400000000, 0x41d2291a00000000, + 0xba243a5d00000000, 0xb73f0e9400000000, 0x4cc91dd300000000, + 0xec0f17dd00000000, 0x17f9049a00000000, 0x1ae2305300000000, + 0xe114231400000000, 0x5a6f254f00000000, 0xa199360800000000, + 0xac8202c100000000, 0x5774118600000000, 0xf7b21b8800000000, + 0x0c4408cf00000000, 0x015f3c0600000000, 0xfaa92f4100000000, + 0x77a830b000000000, 0x8c5e23f700000000, 0x8145173e00000000, + 0x7ab3047900000000, 0xda750e7700000000, 0x21831d3000000000, + 0x2c9829f900000000, 0xd76e3abe00000000, 0x6c153ce500000000, + 0x97e32fa200000000, 0x9af81b6b00000000, 0x610e082c00000000, + 0xc1c8022200000000, 0x3a3e116500000000, 0x372525ac00000000, + 0xccd336eb00000000}, + {0x0000000000000000, 0x6238282a00000000, 0xc470505400000000, + 0xa648787e00000000, 0x88e1a0a800000000, 0xead9888200000000, + 0x4c91f0fc00000000, 0x2ea9d8d600000000, 0x51c5308a00000000, + 0x33fd18a000000000, 0x95b560de00000000, 0xf78d48f400000000, + 0xd924902200000000, 0xbb1cb80800000000, 0x1d54c07600000000, + 0x7f6ce85c00000000, 0xe38c10cf00000000, 0x81b438e500000000, + 0x27fc409b00000000, 0x45c468b100000000, 0x6b6db06700000000, + 0x0955984d00000000, 0xaf1de03300000000, 0xcd25c81900000000, + 0xb249204500000000, 0xd071086f00000000, 0x7639701100000000, + 0x1401583b00000000, 0x3aa880ed00000000, 0x5890a8c700000000, + 0xfed8d0b900000000, 0x9ce0f89300000000, 0x871f504500000000, + 0xe527786f00000000, 0x436f001100000000, 0x2157283b00000000, + 0x0ffef0ed00000000, 0x6dc6d8c700000000, 0xcb8ea0b900000000, + 0xa9b6889300000000, 0xd6da60cf00000000, 0xb4e248e500000000, + 0x12aa309b00000000, 0x709218b100000000, 0x5e3bc06700000000, + 0x3c03e84d00000000, 0x9a4b903300000000, 0xf873b81900000000, + 0x6493408a00000000, 0x06ab68a000000000, 0xa0e310de00000000, + 0xc2db38f400000000, 0xec72e02200000000, 0x8e4ac80800000000, + 0x2802b07600000000, 0x4a3a985c00000000, 0x3556700000000000, + 0x576e582a00000000, 0xf126205400000000, 0x931e087e00000000, + 0xbdb7d0a800000000, 0xdf8ff88200000000, 0x79c780fc00000000, + 0x1bffa8d600000000, 0x0e3fa08a00000000, 0x6c0788a000000000, + 0xca4ff0de00000000, 0xa877d8f400000000, 0x86de002200000000, + 0xe4e6280800000000, 0x42ae507600000000, 0x2096785c00000000, + 0x5ffa900000000000, 0x3dc2b82a00000000, 0x9b8ac05400000000, + 0xf9b2e87e00000000, 0xd71b30a800000000, 0xb523188200000000, + 0x136b60fc00000000, 0x715348d600000000, 0xedb3b04500000000, + 0x8f8b986f00000000, 0x29c3e01100000000, 0x4bfbc83b00000000, + 0x655210ed00000000, 0x076a38c700000000, 0xa12240b900000000, + 0xc31a689300000000, 0xbc7680cf00000000, 0xde4ea8e500000000, + 0x7806d09b00000000, 0x1a3ef8b100000000, 0x3497206700000000, + 0x56af084d00000000, 0xf0e7703300000000, 0x92df581900000000, + 0x8920f0cf00000000, 0xeb18d8e500000000, 0x4d50a09b00000000, + 0x2f6888b100000000, 0x01c1506700000000, 0x63f9784d00000000, + 0xc5b1003300000000, 0xa789281900000000, 0xd8e5c04500000000, + 0xbadde86f00000000, 0x1c95901100000000, 0x7eadb83b00000000, + 0x500460ed00000000, 0x323c48c700000000, 0x947430b900000000, + 0xf64c189300000000, 0x6aace00000000000, 0x0894c82a00000000, + 0xaedcb05400000000, 0xcce4987e00000000, 0xe24d40a800000000, + 0x8075688200000000, 0x263d10fc00000000, 0x440538d600000000, + 0x3b69d08a00000000, 0x5951f8a000000000, 0xff1980de00000000, + 0x9d21a8f400000000, 0xb388702200000000, 0xd1b0580800000000, + 0x77f8207600000000, 0x15c0085c00000000, 0x5d7831ce00000000, + 0x3f4019e400000000, 0x9908619a00000000, 0xfb3049b000000000, + 0xd599916600000000, 0xb7a1b94c00000000, 0x11e9c13200000000, + 0x73d1e91800000000, 0x0cbd014400000000, 0x6e85296e00000000, + 0xc8cd511000000000, 0xaaf5793a00000000, 0x845ca1ec00000000, + 0xe66489c600000000, 0x402cf1b800000000, 0x2214d99200000000, + 0xbef4210100000000, 0xdccc092b00000000, 0x7a84715500000000, + 0x18bc597f00000000, 0x361581a900000000, 0x542da98300000000, + 0xf265d1fd00000000, 0x905df9d700000000, 0xef31118b00000000, + 0x8d0939a100000000, 0x2b4141df00000000, 0x497969f500000000, + 0x67d0b12300000000, 0x05e8990900000000, 0xa3a0e17700000000, + 0xc198c95d00000000, 0xda67618b00000000, 0xb85f49a100000000, + 0x1e1731df00000000, 0x7c2f19f500000000, 0x5286c12300000000, + 0x30bee90900000000, 0x96f6917700000000, 0xf4ceb95d00000000, + 0x8ba2510100000000, 0xe99a792b00000000, 0x4fd2015500000000, + 0x2dea297f00000000, 0x0343f1a900000000, 0x617bd98300000000, + 0xc733a1fd00000000, 0xa50b89d700000000, 0x39eb714400000000, + 0x5bd3596e00000000, 0xfd9b211000000000, 0x9fa3093a00000000, + 0xb10ad1ec00000000, 0xd332f9c600000000, 0x757a81b800000000, + 0x1742a99200000000, 0x682e41ce00000000, 0x0a1669e400000000, + 0xac5e119a00000000, 0xce6639b000000000, 0xe0cfe16600000000, + 0x82f7c94c00000000, 0x24bfb13200000000, 0x4687991800000000, + 0x5347914400000000, 0x317fb96e00000000, 0x9737c11000000000, + 0xf50fe93a00000000, 0xdba631ec00000000, 0xb99e19c600000000, + 0x1fd661b800000000, 0x7dee499200000000, 0x0282a1ce00000000, + 0x60ba89e400000000, 0xc6f2f19a00000000, 0xa4cad9b000000000, + 0x8a63016600000000, 0xe85b294c00000000, 0x4e13513200000000, + 0x2c2b791800000000, 0xb0cb818b00000000, 0xd2f3a9a100000000, + 0x74bbd1df00000000, 0x1683f9f500000000, 0x382a212300000000, + 0x5a12090900000000, 0xfc5a717700000000, 0x9e62595d00000000, + 0xe10eb10100000000, 0x8336992b00000000, 0x257ee15500000000, + 0x4746c97f00000000, 0x69ef11a900000000, 0x0bd7398300000000, + 0xad9f41fd00000000, 0xcfa769d700000000, 0xd458c10100000000, + 0xb660e92b00000000, 0x1028915500000000, 0x7210b97f00000000, + 0x5cb961a900000000, 0x3e81498300000000, 0x98c931fd00000000, + 0xfaf119d700000000, 0x859df18b00000000, 0xe7a5d9a100000000, + 0x41eda1df00000000, 0x23d589f500000000, 0x0d7c512300000000, + 0x6f44790900000000, 0xc90c017700000000, 0xab34295d00000000, + 0x37d4d1ce00000000, 0x55ecf9e400000000, 0xf3a4819a00000000, + 0x919ca9b000000000, 0xbf35716600000000, 0xdd0d594c00000000, + 0x7b45213200000000, 0x197d091800000000, 0x6611e14400000000, + 0x0429c96e00000000, 0xa261b11000000000, 0xc059993a00000000, + 0xeef041ec00000000, 0x8cc869c600000000, 0x2a8011b800000000, + 0x48b8399200000000}, + {0x0000000000000000, 0x4c2896a300000000, 0xd9565d9c00000000, + 0x957ecb3f00000000, 0xf3abcbe300000000, 0xbf835d4000000000, + 0x2afd967f00000000, 0x66d500dc00000000, 0xa751e61c00000000, + 0xeb7970bf00000000, 0x7e07bb8000000000, 0x322f2d2300000000, + 0x54fa2dff00000000, 0x18d2bb5c00000000, 0x8dac706300000000, + 0xc184e6c000000000, 0x4ea3cc3900000000, 0x028b5a9a00000000, + 0x97f591a500000000, 0xdbdd070600000000, 0xbd0807da00000000, + 0xf120917900000000, 0x645e5a4600000000, 0x2876cce500000000, + 0xe9f22a2500000000, 0xa5dabc8600000000, 0x30a477b900000000, + 0x7c8ce11a00000000, 0x1a59e1c600000000, 0x5671776500000000, + 0xc30fbc5a00000000, 0x8f272af900000000, 0x9c46997300000000, + 0xd06e0fd000000000, 0x4510c4ef00000000, 0x0938524c00000000, + 0x6fed529000000000, 0x23c5c43300000000, 0xb6bb0f0c00000000, + 0xfa9399af00000000, 0x3b177f6f00000000, 0x773fe9cc00000000, + 0xe24122f300000000, 0xae69b45000000000, 0xc8bcb48c00000000, + 0x8494222f00000000, 0x11eae91000000000, 0x5dc27fb300000000, + 0xd2e5554a00000000, 0x9ecdc3e900000000, 0x0bb308d600000000, + 0x479b9e7500000000, 0x214e9ea900000000, 0x6d66080a00000000, + 0xf818c33500000000, 0xb430559600000000, 0x75b4b35600000000, + 0x399c25f500000000, 0xace2eeca00000000, 0xe0ca786900000000, + 0x861f78b500000000, 0xca37ee1600000000, 0x5f49252900000000, + 0x1361b38a00000000, 0x388d32e700000000, 0x74a5a44400000000, + 0xe1db6f7b00000000, 0xadf3f9d800000000, 0xcb26f90400000000, + 0x870e6fa700000000, 0x1270a49800000000, 0x5e58323b00000000, + 0x9fdcd4fb00000000, 0xd3f4425800000000, 0x468a896700000000, + 0x0aa21fc400000000, 0x6c771f1800000000, 0x205f89bb00000000, + 0xb521428400000000, 0xf909d42700000000, 0x762efede00000000, + 0x3a06687d00000000, 0xaf78a34200000000, 0xe35035e100000000, + 0x8585353d00000000, 0xc9ada39e00000000, 0x5cd368a100000000, + 0x10fbfe0200000000, 0xd17f18c200000000, 0x9d578e6100000000, + 0x0829455e00000000, 0x4401d3fd00000000, 0x22d4d32100000000, + 0x6efc458200000000, 0xfb828ebd00000000, 0xb7aa181e00000000, + 0xa4cbab9400000000, 0xe8e33d3700000000, 0x7d9df60800000000, + 0x31b560ab00000000, 0x5760607700000000, 0x1b48f6d400000000, + 0x8e363deb00000000, 0xc21eab4800000000, 0x039a4d8800000000, + 0x4fb2db2b00000000, 0xdacc101400000000, 0x96e486b700000000, + 0xf031866b00000000, 0xbc1910c800000000, 0x2967dbf700000000, + 0x654f4d5400000000, 0xea6867ad00000000, 0xa640f10e00000000, + 0x333e3a3100000000, 0x7f16ac9200000000, 0x19c3ac4e00000000, + 0x55eb3aed00000000, 0xc095f1d200000000, 0x8cbd677100000000, + 0x4d3981b100000000, 0x0111171200000000, 0x946fdc2d00000000, + 0xd8474a8e00000000, 0xbe924a5200000000, 0xf2badcf100000000, + 0x67c417ce00000000, 0x2bec816d00000000, 0x311c141500000000, + 0x7d3482b600000000, 0xe84a498900000000, 0xa462df2a00000000, + 0xc2b7dff600000000, 0x8e9f495500000000, 0x1be1826a00000000, + 0x57c914c900000000, 0x964df20900000000, 0xda6564aa00000000, + 0x4f1baf9500000000, 0x0333393600000000, 0x65e639ea00000000, + 0x29ceaf4900000000, 0xbcb0647600000000, 0xf098f2d500000000, + 0x7fbfd82c00000000, 0x33974e8f00000000, 0xa6e985b000000000, + 0xeac1131300000000, 0x8c1413cf00000000, 0xc03c856c00000000, + 0x55424e5300000000, 0x196ad8f000000000, 0xd8ee3e3000000000, + 0x94c6a89300000000, 0x01b863ac00000000, 0x4d90f50f00000000, + 0x2b45f5d300000000, 0x676d637000000000, 0xf213a84f00000000, + 0xbe3b3eec00000000, 0xad5a8d6600000000, 0xe1721bc500000000, + 0x740cd0fa00000000, 0x3824465900000000, 0x5ef1468500000000, + 0x12d9d02600000000, 0x87a71b1900000000, 0xcb8f8dba00000000, + 0x0a0b6b7a00000000, 0x4623fdd900000000, 0xd35d36e600000000, + 0x9f75a04500000000, 0xf9a0a09900000000, 0xb588363a00000000, + 0x20f6fd0500000000, 0x6cde6ba600000000, 0xe3f9415f00000000, + 0xafd1d7fc00000000, 0x3aaf1cc300000000, 0x76878a6000000000, + 0x10528abc00000000, 0x5c7a1c1f00000000, 0xc904d72000000000, + 0x852c418300000000, 0x44a8a74300000000, 0x088031e000000000, + 0x9dfefadf00000000, 0xd1d66c7c00000000, 0xb7036ca000000000, + 0xfb2bfa0300000000, 0x6e55313c00000000, 0x227da79f00000000, + 0x099126f200000000, 0x45b9b05100000000, 0xd0c77b6e00000000, + 0x9cefedcd00000000, 0xfa3aed1100000000, 0xb6127bb200000000, + 0x236cb08d00000000, 0x6f44262e00000000, 0xaec0c0ee00000000, + 0xe2e8564d00000000, 0x77969d7200000000, 0x3bbe0bd100000000, + 0x5d6b0b0d00000000, 0x11439dae00000000, 0x843d569100000000, + 0xc815c03200000000, 0x4732eacb00000000, 0x0b1a7c6800000000, + 0x9e64b75700000000, 0xd24c21f400000000, 0xb499212800000000, + 0xf8b1b78b00000000, 0x6dcf7cb400000000, 0x21e7ea1700000000, + 0xe0630cd700000000, 0xac4b9a7400000000, 0x3935514b00000000, + 0x751dc7e800000000, 0x13c8c73400000000, 0x5fe0519700000000, + 0xca9e9aa800000000, 0x86b60c0b00000000, 0x95d7bf8100000000, + 0xd9ff292200000000, 0x4c81e21d00000000, 0x00a974be00000000, + 0x667c746200000000, 0x2a54e2c100000000, 0xbf2a29fe00000000, + 0xf302bf5d00000000, 0x3286599d00000000, 0x7eaecf3e00000000, + 0xebd0040100000000, 0xa7f892a200000000, 0xc12d927e00000000, + 0x8d0504dd00000000, 0x187bcfe200000000, 0x5453594100000000, + 0xdb7473b800000000, 0x975ce51b00000000, 0x02222e2400000000, + 0x4e0ab88700000000, 0x28dfb85b00000000, 0x64f72ef800000000, + 0xf189e5c700000000, 0xbda1736400000000, 0x7c2595a400000000, + 0x300d030700000000, 0xa573c83800000000, 0xe95b5e9b00000000, + 0x8f8e5e4700000000, 0xc3a6c8e400000000, 0x56d803db00000000, + 0x1af0957800000000}, + {0x0000000000000000, 0x939bc97f00000000, 0x263793ff00000000, + 0xb5ac5a8000000000, 0x0d68572400000000, 0x9ef39e5b00000000, + 0x2b5fc4db00000000, 0xb8c40da400000000, 0x1ad0ae4800000000, + 0x894b673700000000, 0x3ce73db700000000, 0xaf7cf4c800000000, + 0x17b8f96c00000000, 0x8423301300000000, 0x318f6a9300000000, + 0xa214a3ec00000000, 0x34a05d9100000000, 0xa73b94ee00000000, + 0x1297ce6e00000000, 0x810c071100000000, 0x39c80ab500000000, + 0xaa53c3ca00000000, 0x1fff994a00000000, 0x8c64503500000000, + 0x2e70f3d900000000, 0xbdeb3aa600000000, 0x0847602600000000, + 0x9bdca95900000000, 0x2318a4fd00000000, 0xb0836d8200000000, + 0x052f370200000000, 0x96b4fe7d00000000, 0x2946caf900000000, + 0xbadd038600000000, 0x0f71590600000000, 0x9cea907900000000, + 0x242e9ddd00000000, 0xb7b554a200000000, 0x02190e2200000000, + 0x9182c75d00000000, 0x339664b100000000, 0xa00dadce00000000, + 0x15a1f74e00000000, 0x863a3e3100000000, 0x3efe339500000000, + 0xad65faea00000000, 0x18c9a06a00000000, 0x8b52691500000000, + 0x1de6976800000000, 0x8e7d5e1700000000, 0x3bd1049700000000, + 0xa84acde800000000, 0x108ec04c00000000, 0x8315093300000000, + 0x36b953b300000000, 0xa5229acc00000000, 0x0736392000000000, + 0x94adf05f00000000, 0x2101aadf00000000, 0xb29a63a000000000, + 0x0a5e6e0400000000, 0x99c5a77b00000000, 0x2c69fdfb00000000, + 0xbff2348400000000, 0x138ae52800000000, 0x80112c5700000000, + 0x35bd76d700000000, 0xa626bfa800000000, 0x1ee2b20c00000000, + 0x8d797b7300000000, 0x38d521f300000000, 0xab4ee88c00000000, + 0x095a4b6000000000, 0x9ac1821f00000000, 0x2f6dd89f00000000, + 0xbcf611e000000000, 0x04321c4400000000, 0x97a9d53b00000000, + 0x22058fbb00000000, 0xb19e46c400000000, 0x272ab8b900000000, + 0xb4b171c600000000, 0x011d2b4600000000, 0x9286e23900000000, + 0x2a42ef9d00000000, 0xb9d926e200000000, 0x0c757c6200000000, + 0x9feeb51d00000000, 0x3dfa16f100000000, 0xae61df8e00000000, + 0x1bcd850e00000000, 0x88564c7100000000, 0x309241d500000000, + 0xa30988aa00000000, 0x16a5d22a00000000, 0x853e1b5500000000, + 0x3acc2fd100000000, 0xa957e6ae00000000, 0x1cfbbc2e00000000, + 0x8f60755100000000, 0x37a478f500000000, 0xa43fb18a00000000, + 0x1193eb0a00000000, 0x8208227500000000, 0x201c819900000000, + 0xb38748e600000000, 0x062b126600000000, 0x95b0db1900000000, + 0x2d74d6bd00000000, 0xbeef1fc200000000, 0x0b43454200000000, + 0x98d88c3d00000000, 0x0e6c724000000000, 0x9df7bb3f00000000, + 0x285be1bf00000000, 0xbbc028c000000000, 0x0304256400000000, + 0x909fec1b00000000, 0x2533b69b00000000, 0xb6a87fe400000000, + 0x14bcdc0800000000, 0x8727157700000000, 0x328b4ff700000000, + 0xa110868800000000, 0x19d48b2c00000000, 0x8a4f425300000000, + 0x3fe318d300000000, 0xac78d1ac00000000, 0x2614cb5100000000, + 0xb58f022e00000000, 0x002358ae00000000, 0x93b891d100000000, + 0x2b7c9c7500000000, 0xb8e7550a00000000, 0x0d4b0f8a00000000, + 0x9ed0c6f500000000, 0x3cc4651900000000, 0xaf5fac6600000000, + 0x1af3f6e600000000, 0x89683f9900000000, 0x31ac323d00000000, + 0xa237fb4200000000, 0x179ba1c200000000, 0x840068bd00000000, + 0x12b496c000000000, 0x812f5fbf00000000, 0x3483053f00000000, + 0xa718cc4000000000, 0x1fdcc1e400000000, 0x8c47089b00000000, + 0x39eb521b00000000, 0xaa709b6400000000, 0x0864388800000000, + 0x9bfff1f700000000, 0x2e53ab7700000000, 0xbdc8620800000000, + 0x050c6fac00000000, 0x9697a6d300000000, 0x233bfc5300000000, + 0xb0a0352c00000000, 0x0f5201a800000000, 0x9cc9c8d700000000, + 0x2965925700000000, 0xbafe5b2800000000, 0x023a568c00000000, + 0x91a19ff300000000, 0x240dc57300000000, 0xb7960c0c00000000, + 0x1582afe000000000, 0x8619669f00000000, 0x33b53c1f00000000, + 0xa02ef56000000000, 0x18eaf8c400000000, 0x8b7131bb00000000, + 0x3edd6b3b00000000, 0xad46a24400000000, 0x3bf25c3900000000, + 0xa869954600000000, 0x1dc5cfc600000000, 0x8e5e06b900000000, + 0x369a0b1d00000000, 0xa501c26200000000, 0x10ad98e200000000, + 0x8336519d00000000, 0x2122f27100000000, 0xb2b93b0e00000000, + 0x0715618e00000000, 0x948ea8f100000000, 0x2c4aa55500000000, + 0xbfd16c2a00000000, 0x0a7d36aa00000000, 0x99e6ffd500000000, + 0x359e2e7900000000, 0xa605e70600000000, 0x13a9bd8600000000, + 0x803274f900000000, 0x38f6795d00000000, 0xab6db02200000000, + 0x1ec1eaa200000000, 0x8d5a23dd00000000, 0x2f4e803100000000, + 0xbcd5494e00000000, 0x097913ce00000000, 0x9ae2dab100000000, + 0x2226d71500000000, 0xb1bd1e6a00000000, 0x041144ea00000000, + 0x978a8d9500000000, 0x013e73e800000000, 0x92a5ba9700000000, + 0x2709e01700000000, 0xb492296800000000, 0x0c5624cc00000000, + 0x9fcdedb300000000, 0x2a61b73300000000, 0xb9fa7e4c00000000, + 0x1beedda000000000, 0x887514df00000000, 0x3dd94e5f00000000, + 0xae42872000000000, 0x16868a8400000000, 0x851d43fb00000000, + 0x30b1197b00000000, 0xa32ad00400000000, 0x1cd8e48000000000, + 0x8f432dff00000000, 0x3aef777f00000000, 0xa974be0000000000, + 0x11b0b3a400000000, 0x822b7adb00000000, 0x3787205b00000000, + 0xa41ce92400000000, 0x06084ac800000000, 0x959383b700000000, + 0x203fd93700000000, 0xb3a4104800000000, 0x0b601dec00000000, + 0x98fbd49300000000, 0x2d578e1300000000, 0xbecc476c00000000, + 0x2878b91100000000, 0xbbe3706e00000000, 0x0e4f2aee00000000, + 0x9dd4e39100000000, 0x2510ee3500000000, 0xb68b274a00000000, + 0x03277dca00000000, 0x90bcb4b500000000, 0x32a8175900000000, + 0xa133de2600000000, 0x149f84a600000000, 0x87044dd900000000, + 0x3fc0407d00000000, 0xac5b890200000000, 0x19f7d38200000000, + 0x8a6c1afd00000000}, + {0x0000000000000000, 0x650b796900000000, 0xca16f2d200000000, + 0xaf1d8bbb00000000, 0xd52b957e00000000, 0xb020ec1700000000, + 0x1f3d67ac00000000, 0x7a361ec500000000, 0xaa572afd00000000, + 0xcf5c539400000000, 0x6041d82f00000000, 0x054aa14600000000, + 0x7f7cbf8300000000, 0x1a77c6ea00000000, 0xb56a4d5100000000, + 0xd061343800000000, 0x15a9252100000000, 0x70a25c4800000000, + 0xdfbfd7f300000000, 0xbab4ae9a00000000, 0xc082b05f00000000, + 0xa589c93600000000, 0x0a94428d00000000, 0x6f9f3be400000000, + 0xbffe0fdc00000000, 0xdaf576b500000000, 0x75e8fd0e00000000, + 0x10e3846700000000, 0x6ad59aa200000000, 0x0fdee3cb00000000, + 0xa0c3687000000000, 0xc5c8111900000000, 0x2a524b4200000000, + 0x4f59322b00000000, 0xe044b99000000000, 0x854fc0f900000000, + 0xff79de3c00000000, 0x9a72a75500000000, 0x356f2cee00000000, + 0x5064558700000000, 0x800561bf00000000, 0xe50e18d600000000, + 0x4a13936d00000000, 0x2f18ea0400000000, 0x552ef4c100000000, + 0x30258da800000000, 0x9f38061300000000, 0xfa337f7a00000000, + 0x3ffb6e6300000000, 0x5af0170a00000000, 0xf5ed9cb100000000, + 0x90e6e5d800000000, 0xead0fb1d00000000, 0x8fdb827400000000, + 0x20c609cf00000000, 0x45cd70a600000000, 0x95ac449e00000000, + 0xf0a73df700000000, 0x5fbab64c00000000, 0x3ab1cf2500000000, + 0x4087d1e000000000, 0x258ca88900000000, 0x8a91233200000000, + 0xef9a5a5b00000000, 0x54a4968400000000, 0x31afefed00000000, + 0x9eb2645600000000, 0xfbb91d3f00000000, 0x818f03fa00000000, + 0xe4847a9300000000, 0x4b99f12800000000, 0x2e92884100000000, + 0xfef3bc7900000000, 0x9bf8c51000000000, 0x34e54eab00000000, + 0x51ee37c200000000, 0x2bd8290700000000, 0x4ed3506e00000000, + 0xe1cedbd500000000, 0x84c5a2bc00000000, 0x410db3a500000000, + 0x2406cacc00000000, 0x8b1b417700000000, 0xee10381e00000000, + 0x942626db00000000, 0xf12d5fb200000000, 0x5e30d40900000000, + 0x3b3bad6000000000, 0xeb5a995800000000, 0x8e51e03100000000, + 0x214c6b8a00000000, 0x444712e300000000, 0x3e710c2600000000, + 0x5b7a754f00000000, 0xf467fef400000000, 0x916c879d00000000, + 0x7ef6ddc600000000, 0x1bfda4af00000000, 0xb4e02f1400000000, + 0xd1eb567d00000000, 0xabdd48b800000000, 0xced631d100000000, + 0x61cbba6a00000000, 0x04c0c30300000000, 0xd4a1f73b00000000, + 0xb1aa8e5200000000, 0x1eb705e900000000, 0x7bbc7c8000000000, + 0x018a624500000000, 0x64811b2c00000000, 0xcb9c909700000000, + 0xae97e9fe00000000, 0x6b5ff8e700000000, 0x0e54818e00000000, + 0xa1490a3500000000, 0xc442735c00000000, 0xbe746d9900000000, + 0xdb7f14f000000000, 0x74629f4b00000000, 0x1169e62200000000, + 0xc108d21a00000000, 0xa403ab7300000000, 0x0b1e20c800000000, + 0x6e1559a100000000, 0x1423476400000000, 0x71283e0d00000000, + 0xde35b5b600000000, 0xbb3eccdf00000000, 0xe94e5cd200000000, + 0x8c4525bb00000000, 0x2358ae0000000000, 0x4653d76900000000, + 0x3c65c9ac00000000, 0x596eb0c500000000, 0xf6733b7e00000000, + 0x9378421700000000, 0x4319762f00000000, 0x26120f4600000000, + 0x890f84fd00000000, 0xec04fd9400000000, 0x9632e35100000000, + 0xf3399a3800000000, 0x5c24118300000000, 0x392f68ea00000000, + 0xfce779f300000000, 0x99ec009a00000000, 0x36f18b2100000000, + 0x53faf24800000000, 0x29ccec8d00000000, 0x4cc795e400000000, + 0xe3da1e5f00000000, 0x86d1673600000000, 0x56b0530e00000000, + 0x33bb2a6700000000, 0x9ca6a1dc00000000, 0xf9add8b500000000, + 0x839bc67000000000, 0xe690bf1900000000, 0x498d34a200000000, + 0x2c864dcb00000000, 0xc31c179000000000, 0xa6176ef900000000, + 0x090ae54200000000, 0x6c019c2b00000000, 0x163782ee00000000, + 0x733cfb8700000000, 0xdc21703c00000000, 0xb92a095500000000, + 0x694b3d6d00000000, 0x0c40440400000000, 0xa35dcfbf00000000, + 0xc656b6d600000000, 0xbc60a81300000000, 0xd96bd17a00000000, + 0x76765ac100000000, 0x137d23a800000000, 0xd6b532b100000000, + 0xb3be4bd800000000, 0x1ca3c06300000000, 0x79a8b90a00000000, + 0x039ea7cf00000000, 0x6695dea600000000, 0xc988551d00000000, + 0xac832c7400000000, 0x7ce2184c00000000, 0x19e9612500000000, + 0xb6f4ea9e00000000, 0xd3ff93f700000000, 0xa9c98d3200000000, + 0xccc2f45b00000000, 0x63df7fe000000000, 0x06d4068900000000, + 0xbdeaca5600000000, 0xd8e1b33f00000000, 0x77fc388400000000, + 0x12f741ed00000000, 0x68c15f2800000000, 0x0dca264100000000, + 0xa2d7adfa00000000, 0xc7dcd49300000000, 0x17bde0ab00000000, + 0x72b699c200000000, 0xddab127900000000, 0xb8a06b1000000000, + 0xc29675d500000000, 0xa79d0cbc00000000, 0x0880870700000000, + 0x6d8bfe6e00000000, 0xa843ef7700000000, 0xcd48961e00000000, + 0x62551da500000000, 0x075e64cc00000000, 0x7d687a0900000000, + 0x1863036000000000, 0xb77e88db00000000, 0xd275f1b200000000, + 0x0214c58a00000000, 0x671fbce300000000, 0xc802375800000000, + 0xad094e3100000000, 0xd73f50f400000000, 0xb234299d00000000, + 0x1d29a22600000000, 0x7822db4f00000000, 0x97b8811400000000, + 0xf2b3f87d00000000, 0x5dae73c600000000, 0x38a50aaf00000000, + 0x4293146a00000000, 0x27986d0300000000, 0x8885e6b800000000, + 0xed8e9fd100000000, 0x3defabe900000000, 0x58e4d28000000000, + 0xf7f9593b00000000, 0x92f2205200000000, 0xe8c43e9700000000, + 0x8dcf47fe00000000, 0x22d2cc4500000000, 0x47d9b52c00000000, + 0x8211a43500000000, 0xe71add5c00000000, 0x480756e700000000, + 0x2d0c2f8e00000000, 0x573a314b00000000, 0x3231482200000000, + 0x9d2cc39900000000, 0xf827baf000000000, 0x28468ec800000000, + 0x4d4df7a100000000, 0xe2507c1a00000000, 0x875b057300000000, + 0xfd6d1bb600000000, 0x986662df00000000, 0x377be96400000000, + 0x5270900d00000000}, + {0x0000000000000000, 0xdcecb13d00000000, 0xb8d9637b00000000, + 0x6435d24600000000, 0x70b3c7f600000000, 0xac5f76cb00000000, + 0xc86aa48d00000000, 0x148615b000000000, 0xa160fe3600000000, + 0x7d8c4f0b00000000, 0x19b99d4d00000000, 0xc5552c7000000000, + 0xd1d339c000000000, 0x0d3f88fd00000000, 0x690a5abb00000000, + 0xb5e6eb8600000000, 0x42c1fc6d00000000, 0x9e2d4d5000000000, + 0xfa189f1600000000, 0x26f42e2b00000000, 0x32723b9b00000000, + 0xee9e8aa600000000, 0x8aab58e000000000, 0x5647e9dd00000000, + 0xe3a1025b00000000, 0x3f4db36600000000, 0x5b78612000000000, + 0x8794d01d00000000, 0x9312c5ad00000000, 0x4ffe749000000000, + 0x2bcba6d600000000, 0xf72717eb00000000, 0x8482f9db00000000, + 0x586e48e600000000, 0x3c5b9aa000000000, 0xe0b72b9d00000000, + 0xf4313e2d00000000, 0x28dd8f1000000000, 0x4ce85d5600000000, + 0x9004ec6b00000000, 0x25e207ed00000000, 0xf90eb6d000000000, + 0x9d3b649600000000, 0x41d7d5ab00000000, 0x5551c01b00000000, + 0x89bd712600000000, 0xed88a36000000000, 0x3164125d00000000, + 0xc64305b600000000, 0x1aafb48b00000000, 0x7e9a66cd00000000, + 0xa276d7f000000000, 0xb6f0c24000000000, 0x6a1c737d00000000, + 0x0e29a13b00000000, 0xd2c5100600000000, 0x6723fb8000000000, + 0xbbcf4abd00000000, 0xdffa98fb00000000, 0x031629c600000000, + 0x17903c7600000000, 0xcb7c8d4b00000000, 0xaf495f0d00000000, + 0x73a5ee3000000000, 0x4903826c00000000, 0x95ef335100000000, + 0xf1dae11700000000, 0x2d36502a00000000, 0x39b0459a00000000, + 0xe55cf4a700000000, 0x816926e100000000, 0x5d8597dc00000000, + 0xe8637c5a00000000, 0x348fcd6700000000, 0x50ba1f2100000000, + 0x8c56ae1c00000000, 0x98d0bbac00000000, 0x443c0a9100000000, + 0x2009d8d700000000, 0xfce569ea00000000, 0x0bc27e0100000000, + 0xd72ecf3c00000000, 0xb31b1d7a00000000, 0x6ff7ac4700000000, + 0x7b71b9f700000000, 0xa79d08ca00000000, 0xc3a8da8c00000000, + 0x1f446bb100000000, 0xaaa2803700000000, 0x764e310a00000000, + 0x127be34c00000000, 0xce97527100000000, 0xda1147c100000000, + 0x06fdf6fc00000000, 0x62c824ba00000000, 0xbe24958700000000, + 0xcd817bb700000000, 0x116dca8a00000000, 0x755818cc00000000, + 0xa9b4a9f100000000, 0xbd32bc4100000000, 0x61de0d7c00000000, + 0x05ebdf3a00000000, 0xd9076e0700000000, 0x6ce1858100000000, + 0xb00d34bc00000000, 0xd438e6fa00000000, 0x08d457c700000000, + 0x1c52427700000000, 0xc0bef34a00000000, 0xa48b210c00000000, + 0x7867903100000000, 0x8f4087da00000000, 0x53ac36e700000000, + 0x3799e4a100000000, 0xeb75559c00000000, 0xfff3402c00000000, + 0x231ff11100000000, 0x472a235700000000, 0x9bc6926a00000000, + 0x2e2079ec00000000, 0xf2ccc8d100000000, 0x96f91a9700000000, + 0x4a15abaa00000000, 0x5e93be1a00000000, 0x827f0f2700000000, + 0xe64add6100000000, 0x3aa66c5c00000000, 0x920604d900000000, + 0x4eeab5e400000000, 0x2adf67a200000000, 0xf633d69f00000000, + 0xe2b5c32f00000000, 0x3e59721200000000, 0x5a6ca05400000000, + 0x8680116900000000, 0x3366faef00000000, 0xef8a4bd200000000, + 0x8bbf999400000000, 0x575328a900000000, 0x43d53d1900000000, + 0x9f398c2400000000, 0xfb0c5e6200000000, 0x27e0ef5f00000000, + 0xd0c7f8b400000000, 0x0c2b498900000000, 0x681e9bcf00000000, + 0xb4f22af200000000, 0xa0743f4200000000, 0x7c988e7f00000000, + 0x18ad5c3900000000, 0xc441ed0400000000, 0x71a7068200000000, + 0xad4bb7bf00000000, 0xc97e65f900000000, 0x1592d4c400000000, + 0x0114c17400000000, 0xddf8704900000000, 0xb9cda20f00000000, + 0x6521133200000000, 0x1684fd0200000000, 0xca684c3f00000000, + 0xae5d9e7900000000, 0x72b12f4400000000, 0x66373af400000000, + 0xbadb8bc900000000, 0xdeee598f00000000, 0x0202e8b200000000, + 0xb7e4033400000000, 0x6b08b20900000000, 0x0f3d604f00000000, + 0xd3d1d17200000000, 0xc757c4c200000000, 0x1bbb75ff00000000, + 0x7f8ea7b900000000, 0xa362168400000000, 0x5445016f00000000, + 0x88a9b05200000000, 0xec9c621400000000, 0x3070d32900000000, + 0x24f6c69900000000, 0xf81a77a400000000, 0x9c2fa5e200000000, + 0x40c314df00000000, 0xf525ff5900000000, 0x29c94e6400000000, + 0x4dfc9c2200000000, 0x91102d1f00000000, 0x859638af00000000, + 0x597a899200000000, 0x3d4f5bd400000000, 0xe1a3eae900000000, + 0xdb0586b500000000, 0x07e9378800000000, 0x63dce5ce00000000, + 0xbf3054f300000000, 0xabb6414300000000, 0x775af07e00000000, + 0x136f223800000000, 0xcf83930500000000, 0x7a65788300000000, + 0xa689c9be00000000, 0xc2bc1bf800000000, 0x1e50aac500000000, + 0x0ad6bf7500000000, 0xd63a0e4800000000, 0xb20fdc0e00000000, + 0x6ee36d3300000000, 0x99c47ad800000000, 0x4528cbe500000000, + 0x211d19a300000000, 0xfdf1a89e00000000, 0xe977bd2e00000000, + 0x359b0c1300000000, 0x51aede5500000000, 0x8d426f6800000000, + 0x38a484ee00000000, 0xe44835d300000000, 0x807de79500000000, + 0x5c9156a800000000, 0x4817431800000000, 0x94fbf22500000000, + 0xf0ce206300000000, 0x2c22915e00000000, 0x5f877f6e00000000, + 0x836bce5300000000, 0xe75e1c1500000000, 0x3bb2ad2800000000, + 0x2f34b89800000000, 0xf3d809a500000000, 0x97eddbe300000000, + 0x4b016ade00000000, 0xfee7815800000000, 0x220b306500000000, + 0x463ee22300000000, 0x9ad2531e00000000, 0x8e5446ae00000000, + 0x52b8f79300000000, 0x368d25d500000000, 0xea6194e800000000, + 0x1d46830300000000, 0xc1aa323e00000000, 0xa59fe07800000000, + 0x7973514500000000, 0x6df544f500000000, 0xb119f5c800000000, + 0xd52c278e00000000, 0x09c096b300000000, 0xbc267d3500000000, + 0x60cacc0800000000, 0x04ff1e4e00000000, 0xd813af7300000000, + 0xcc95bac300000000, 0x10790bfe00000000, 0x744cd9b800000000, + 0xa8a0688500000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f, + 0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999, + 0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee, + 0xe3150bc9, 0x7f6b7f3d, 0xfe4e1a1a, 0xa650b332, 0x2775d615, + 0x166de162, 0x97488445, 0xcf562d6d, 0x4e73484a, 0xad664383, + 0x2c4326a4, 0x745d8f8c, 0xf578eaab, 0xc460dddc, 0x4545b8fb, + 0x1d5b11d3, 0x9c7e74f4, 0xfed6fe7a, 0x7ff39b5d, 0x27ed3275, + 0xa6c85752, 0x97d06025, 0x16f50502, 0x4eebac2a, 0xcfcec90d, + 0x2cdbc2c4, 0xadfea7e3, 0xf5e00ecb, 0x74c56bec, 0x45dd5c9b, + 0xc4f839bc, 0x9ce69094, 0x1dc3f5b3, 0x81bd8147, 0x0098e460, + 0x58864d48, 0xd9a3286f, 0xe8bb1f18, 0x699e7a3f, 0x3180d317, + 0xb0a5b630, 0x53b0bdf9, 0xd295d8de, 0x8a8b71f6, 0x0bae14d1, + 0x3ab623a6, 0xbb934681, 0xe38defa9, 0x62a88a8e, 0x26dcfab5, + 0xa7f99f92, 0xffe736ba, 0x7ec2539d, 0x4fda64ea, 0xceff01cd, + 0x96e1a8e5, 0x17c4cdc2, 0xf4d1c60b, 0x75f4a32c, 0x2dea0a04, + 0xaccf6f23, 0x9dd75854, 0x1cf23d73, 0x44ec945b, 0xc5c9f17c, + 0x59b78588, 0xd892e0af, 0x808c4987, 0x01a92ca0, 0x30b11bd7, + 0xb1947ef0, 0xe98ad7d8, 0x68afb2ff, 0x8bbab936, 0x0a9fdc11, + 0x52817539, 0xd3a4101e, 0xe2bc2769, 0x6399424e, 0x3b87eb66, + 0xbaa28e41, 0xd80a04cf, 0x592f61e8, 0x0131c8c0, 0x8014ade7, + 0xb10c9a90, 0x3029ffb7, 0x6837569f, 0xe91233b8, 0x0a073871, + 0x8b225d56, 0xd33cf47e, 0x52199159, 0x6301a62e, 0xe224c309, + 0xba3a6a21, 0x3b1f0f06, 0xa7617bf2, 0x26441ed5, 0x7e5ab7fd, + 0xff7fd2da, 0xce67e5ad, 0x4f42808a, 0x175c29a2, 0x96794c85, + 0x756c474c, 0xf449226b, 0xac578b43, 0x2d72ee64, 0x1c6ad913, + 0x9d4fbc34, 0xc551151c, 0x4474703b, 0x4db9f56a, 0xcc9c904d, + 0x94823965, 0x15a75c42, 0x24bf6b35, 0xa59a0e12, 0xfd84a73a, + 0x7ca1c21d, 0x9fb4c9d4, 0x1e91acf3, 0x468f05db, 0xc7aa60fc, + 0xf6b2578b, 0x779732ac, 0x2f899b84, 0xaeacfea3, 0x32d28a57, + 0xb3f7ef70, 0xebe94658, 0x6acc237f, 0x5bd41408, 0xdaf1712f, + 0x82efd807, 0x03cabd20, 0xe0dfb6e9, 0x61fad3ce, 0x39e47ae6, + 0xb8c11fc1, 0x89d928b6, 0x08fc4d91, 0x50e2e4b9, 0xd1c7819e, + 0xb36f0b10, 0x324a6e37, 0x6a54c71f, 0xeb71a238, 0xda69954f, + 0x5b4cf068, 0x03525940, 0x82773c67, 0x616237ae, 0xe0475289, + 0xb859fba1, 0x397c9e86, 0x0864a9f1, 0x8941ccd6, 0xd15f65fe, + 0x507a00d9, 0xcc04742d, 0x4d21110a, 0x153fb822, 0x941add05, + 0xa502ea72, 0x24278f55, 0x7c39267d, 0xfd1c435a, 0x1e094893, + 0x9f2c2db4, 0xc732849c, 0x4617e1bb, 0x770fd6cc, 0xf62ab3eb, + 0xae341ac3, 0x2f117fe4, 0x6b650fdf, 0xea406af8, 0xb25ec3d0, + 0x337ba6f7, 0x02639180, 0x8346f4a7, 0xdb585d8f, 0x5a7d38a8, + 0xb9683361, 0x384d5646, 0x6053ff6e, 0xe1769a49, 0xd06ead3e, + 0x514bc819, 0x09556131, 0x88700416, 0x140e70e2, 0x952b15c5, + 0xcd35bced, 0x4c10d9ca, 0x7d08eebd, 0xfc2d8b9a, 0xa43322b2, + 0x25164795, 0xc6034c5c, 0x4726297b, 0x1f388053, 0x9e1de574, + 0xaf05d203, 0x2e20b724, 0x763e1e0c, 0xf71b7b2b, 0x95b3f1a5, + 0x14969482, 0x4c883daa, 0xcdad588d, 0xfcb56ffa, 0x7d900add, + 0x258ea3f5, 0xa4abc6d2, 0x47becd1b, 0xc69ba83c, 0x9e850114, + 0x1fa06433, 0x2eb85344, 0xaf9d3663, 0xf7839f4b, 0x76a6fa6c, + 0xead88e98, 0x6bfdebbf, 0x33e34297, 0xb2c627b0, 0x83de10c7, + 0x02fb75e0, 0x5ae5dcc8, 0xdbc0b9ef, 0x38d5b226, 0xb9f0d701, + 0xe1ee7e29, 0x60cb1b0e, 0x51d32c79, 0xd0f6495e, 0x88e8e076, + 0x09cd8551}, + {0x00000000, 0x9b73ead4, 0xed96d3e9, 0x76e5393d, 0x005ca193, + 0x9b2f4b47, 0xedca727a, 0x76b998ae, 0x00b94326, 0x9bcaa9f2, + 0xed2f90cf, 0x765c7a1b, 0x00e5e2b5, 0x9b960861, 0xed73315c, + 0x7600db88, 0x0172864c, 0x9a016c98, 0xece455a5, 0x7797bf71, + 0x012e27df, 0x9a5dcd0b, 0xecb8f436, 0x77cb1ee2, 0x01cbc56a, + 0x9ab82fbe, 0xec5d1683, 0x772efc57, 0x019764f9, 0x9ae48e2d, + 0xec01b710, 0x77725dc4, 0x02e50c98, 0x9996e64c, 0xef73df71, + 0x740035a5, 0x02b9ad0b, 0x99ca47df, 0xef2f7ee2, 0x745c9436, + 0x025c4fbe, 0x992fa56a, 0xefca9c57, 0x74b97683, 0x0200ee2d, + 0x997304f9, 0xef963dc4, 0x74e5d710, 0x03978ad4, 0x98e46000, + 0xee01593d, 0x7572b3e9, 0x03cb2b47, 0x98b8c193, 0xee5df8ae, + 0x752e127a, 0x032ec9f2, 0x985d2326, 0xeeb81a1b, 0x75cbf0cf, + 0x03726861, 0x980182b5, 0xeee4bb88, 0x7597515c, 0x05ca1930, + 0x9eb9f3e4, 0xe85ccad9, 0x732f200d, 0x0596b8a3, 0x9ee55277, + 0xe8006b4a, 0x7373819e, 0x05735a16, 0x9e00b0c2, 0xe8e589ff, + 0x7396632b, 0x052ffb85, 0x9e5c1151, 0xe8b9286c, 0x73cac2b8, + 0x04b89f7c, 0x9fcb75a8, 0xe92e4c95, 0x725da641, 0x04e43eef, + 0x9f97d43b, 0xe972ed06, 0x720107d2, 0x0401dc5a, 0x9f72368e, + 0xe9970fb3, 0x72e4e567, 0x045d7dc9, 0x9f2e971d, 0xe9cbae20, + 0x72b844f4, 0x072f15a8, 0x9c5cff7c, 0xeab9c641, 0x71ca2c95, + 0x0773b43b, 0x9c005eef, 0xeae567d2, 0x71968d06, 0x0796568e, + 0x9ce5bc5a, 0xea008567, 0x71736fb3, 0x07caf71d, 0x9cb91dc9, + 0xea5c24f4, 0x712fce20, 0x065d93e4, 0x9d2e7930, 0xebcb400d, + 0x70b8aad9, 0x06013277, 0x9d72d8a3, 0xeb97e19e, 0x70e40b4a, + 0x06e4d0c2, 0x9d973a16, 0xeb72032b, 0x7001e9ff, 0x06b87151, + 0x9dcb9b85, 0xeb2ea2b8, 0x705d486c, 0x0b943260, 0x90e7d8b4, + 0xe602e189, 0x7d710b5d, 0x0bc893f3, 0x90bb7927, 0xe65e401a, + 0x7d2daace, 0x0b2d7146, 0x905e9b92, 0xe6bba2af, 0x7dc8487b, + 0x0b71d0d5, 0x90023a01, 0xe6e7033c, 0x7d94e9e8, 0x0ae6b42c, + 0x91955ef8, 0xe77067c5, 0x7c038d11, 0x0aba15bf, 0x91c9ff6b, + 0xe72cc656, 0x7c5f2c82, 0x0a5ff70a, 0x912c1dde, 0xe7c924e3, + 0x7cbace37, 0x0a035699, 0x9170bc4d, 0xe7958570, 0x7ce66fa4, + 0x09713ef8, 0x9202d42c, 0xe4e7ed11, 0x7f9407c5, 0x092d9f6b, + 0x925e75bf, 0xe4bb4c82, 0x7fc8a656, 0x09c87dde, 0x92bb970a, + 0xe45eae37, 0x7f2d44e3, 0x0994dc4d, 0x92e73699, 0xe4020fa4, + 0x7f71e570, 0x0803b8b4, 0x93705260, 0xe5956b5d, 0x7ee68189, + 0x085f1927, 0x932cf3f3, 0xe5c9cace, 0x7eba201a, 0x08bafb92, + 0x93c91146, 0xe52c287b, 0x7e5fc2af, 0x08e65a01, 0x9395b0d5, + 0xe57089e8, 0x7e03633c, 0x0e5e2b50, 0x952dc184, 0xe3c8f8b9, + 0x78bb126d, 0x0e028ac3, 0x95716017, 0xe394592a, 0x78e7b3fe, + 0x0ee76876, 0x959482a2, 0xe371bb9f, 0x7802514b, 0x0ebbc9e5, + 0x95c82331, 0xe32d1a0c, 0x785ef0d8, 0x0f2cad1c, 0x945f47c8, + 0xe2ba7ef5, 0x79c99421, 0x0f700c8f, 0x9403e65b, 0xe2e6df66, + 0x799535b2, 0x0f95ee3a, 0x94e604ee, 0xe2033dd3, 0x7970d707, + 0x0fc94fa9, 0x94baa57d, 0xe25f9c40, 0x792c7694, 0x0cbb27c8, + 0x97c8cd1c, 0xe12df421, 0x7a5e1ef5, 0x0ce7865b, 0x97946c8f, + 0xe17155b2, 0x7a02bf66, 0x0c0264ee, 0x97718e3a, 0xe194b707, + 0x7ae75dd3, 0x0c5ec57d, 0x972d2fa9, 0xe1c81694, 0x7abbfc40, + 0x0dc9a184, 0x96ba4b50, 0xe05f726d, 0x7b2c98b9, 0x0d950017, + 0x96e6eac3, 0xe003d3fe, 0x7b70392a, 0x0d70e2a2, 0x96030876, + 0xe0e6314b, 0x7b95db9f, 0x0d2c4331, 0x965fa9e5, 0xe0ba90d8, + 0x7bc97a0c}, + {0x00000000, 0x172864c0, 0x2e50c980, 0x3978ad40, 0x5ca19300, + 0x4b89f7c0, 0x72f15a80, 0x65d93e40, 0xb9432600, 0xae6b42c0, + 0x9713ef80, 0x803b8b40, 0xe5e2b500, 0xf2cad1c0, 0xcbb27c80, + 0xdc9a1840, 0xa9f74a41, 0xbedf2e81, 0x87a783c1, 0x908fe701, + 0xf556d941, 0xe27ebd81, 0xdb0610c1, 0xcc2e7401, 0x10b46c41, + 0x079c0881, 0x3ee4a5c1, 0x29ccc101, 0x4c15ff41, 0x5b3d9b81, + 0x624536c1, 0x756d5201, 0x889f92c3, 0x9fb7f603, 0xa6cf5b43, + 0xb1e73f83, 0xd43e01c3, 0xc3166503, 0xfa6ec843, 0xed46ac83, + 0x31dcb4c3, 0x26f4d003, 0x1f8c7d43, 0x08a41983, 0x6d7d27c3, + 0x7a554303, 0x432dee43, 0x54058a83, 0x2168d882, 0x3640bc42, + 0x0f381102, 0x181075c2, 0x7dc94b82, 0x6ae12f42, 0x53998202, + 0x44b1e6c2, 0x982bfe82, 0x8f039a42, 0xb67b3702, 0xa15353c2, + 0xc48a6d82, 0xd3a20942, 0xeadaa402, 0xfdf2c0c2, 0xca4e23c7, + 0xdd664707, 0xe41eea47, 0xf3368e87, 0x96efb0c7, 0x81c7d407, + 0xb8bf7947, 0xaf971d87, 0x730d05c7, 0x64256107, 0x5d5dcc47, + 0x4a75a887, 0x2fac96c7, 0x3884f207, 0x01fc5f47, 0x16d43b87, + 0x63b96986, 0x74910d46, 0x4de9a006, 0x5ac1c4c6, 0x3f18fa86, + 0x28309e46, 0x11483306, 0x066057c6, 0xdafa4f86, 0xcdd22b46, + 0xf4aa8606, 0xe382e2c6, 0x865bdc86, 0x9173b846, 0xa80b1506, + 0xbf2371c6, 0x42d1b104, 0x55f9d5c4, 0x6c817884, 0x7ba91c44, + 0x1e702204, 0x095846c4, 0x3020eb84, 0x27088f44, 0xfb929704, + 0xecbaf3c4, 0xd5c25e84, 0xc2ea3a44, 0xa7330404, 0xb01b60c4, + 0x8963cd84, 0x9e4ba944, 0xeb26fb45, 0xfc0e9f85, 0xc57632c5, + 0xd25e5605, 0xb7876845, 0xa0af0c85, 0x99d7a1c5, 0x8effc505, + 0x5265dd45, 0x454db985, 0x7c3514c5, 0x6b1d7005, 0x0ec44e45, + 0x19ec2a85, 0x209487c5, 0x37bce305, 0x4fed41cf, 0x58c5250f, + 0x61bd884f, 0x7695ec8f, 0x134cd2cf, 0x0464b60f, 0x3d1c1b4f, + 0x2a347f8f, 0xf6ae67cf, 0xe186030f, 0xd8feae4f, 0xcfd6ca8f, + 0xaa0ff4cf, 0xbd27900f, 0x845f3d4f, 0x9377598f, 0xe61a0b8e, + 0xf1326f4e, 0xc84ac20e, 0xdf62a6ce, 0xbabb988e, 0xad93fc4e, + 0x94eb510e, 0x83c335ce, 0x5f592d8e, 0x4871494e, 0x7109e40e, + 0x662180ce, 0x03f8be8e, 0x14d0da4e, 0x2da8770e, 0x3a8013ce, + 0xc772d30c, 0xd05ab7cc, 0xe9221a8c, 0xfe0a7e4c, 0x9bd3400c, + 0x8cfb24cc, 0xb583898c, 0xa2abed4c, 0x7e31f50c, 0x691991cc, + 0x50613c8c, 0x4749584c, 0x2290660c, 0x35b802cc, 0x0cc0af8c, + 0x1be8cb4c, 0x6e85994d, 0x79adfd8d, 0x40d550cd, 0x57fd340d, + 0x32240a4d, 0x250c6e8d, 0x1c74c3cd, 0x0b5ca70d, 0xd7c6bf4d, + 0xc0eedb8d, 0xf99676cd, 0xeebe120d, 0x8b672c4d, 0x9c4f488d, + 0xa537e5cd, 0xb21f810d, 0x85a36208, 0x928b06c8, 0xabf3ab88, + 0xbcdbcf48, 0xd902f108, 0xce2a95c8, 0xf7523888, 0xe07a5c48, + 0x3ce04408, 0x2bc820c8, 0x12b08d88, 0x0598e948, 0x6041d708, + 0x7769b3c8, 0x4e111e88, 0x59397a48, 0x2c542849, 0x3b7c4c89, + 0x0204e1c9, 0x152c8509, 0x70f5bb49, 0x67dddf89, 0x5ea572c9, + 0x498d1609, 0x95170e49, 0x823f6a89, 0xbb47c7c9, 0xac6fa309, + 0xc9b69d49, 0xde9ef989, 0xe7e654c9, 0xf0ce3009, 0x0d3cf0cb, + 0x1a14940b, 0x236c394b, 0x34445d8b, 0x519d63cb, 0x46b5070b, + 0x7fcdaa4b, 0x68e5ce8b, 0xb47fd6cb, 0xa357b20b, 0x9a2f1f4b, + 0x8d077b8b, 0xe8de45cb, 0xfff6210b, 0xc68e8c4b, 0xd1a6e88b, + 0xa4cbba8a, 0xb3e3de4a, 0x8a9b730a, 0x9db317ca, 0xf86a298a, + 0xef424d4a, 0xd63ae00a, 0xc11284ca, 0x1d889c8a, 0x0aa0f84a, + 0x33d8550a, 0x24f031ca, 0x41290f8a, 0x56016b4a, 0x6f79c60a, + 0x7851a2ca}, + {0x00000000, 0x9fda839e, 0xe4c4017d, 0x7b1e82e3, 0x12f904bb, + 0x8d238725, 0xf63d05c6, 0x69e78658, 0x25f20976, 0xba288ae8, + 0xc136080b, 0x5eec8b95, 0x370b0dcd, 0xa8d18e53, 0xd3cf0cb0, + 0x4c158f2e, 0x4be412ec, 0xd43e9172, 0xaf201391, 0x30fa900f, + 0x591d1657, 0xc6c795c9, 0xbdd9172a, 0x220394b4, 0x6e161b9a, + 0xf1cc9804, 0x8ad21ae7, 0x15089979, 0x7cef1f21, 0xe3359cbf, + 0x982b1e5c, 0x07f19dc2, 0x97c825d8, 0x0812a646, 0x730c24a5, + 0xecd6a73b, 0x85312163, 0x1aeba2fd, 0x61f5201e, 0xfe2fa380, + 0xb23a2cae, 0x2de0af30, 0x56fe2dd3, 0xc924ae4d, 0xa0c32815, + 0x3f19ab8b, 0x44072968, 0xdbddaaf6, 0xdc2c3734, 0x43f6b4aa, + 0x38e83649, 0xa732b5d7, 0xced5338f, 0x510fb011, 0x2a1132f2, + 0xb5cbb16c, 0xf9de3e42, 0x6604bddc, 0x1d1a3f3f, 0x82c0bca1, + 0xeb273af9, 0x74fdb967, 0x0fe33b84, 0x9039b81a, 0xf4e14df1, + 0x6b3bce6f, 0x10254c8c, 0x8fffcf12, 0xe618494a, 0x79c2cad4, + 0x02dc4837, 0x9d06cba9, 0xd1134487, 0x4ec9c719, 0x35d745fa, + 0xaa0dc664, 0xc3ea403c, 0x5c30c3a2, 0x272e4141, 0xb8f4c2df, + 0xbf055f1d, 0x20dfdc83, 0x5bc15e60, 0xc41bddfe, 0xadfc5ba6, + 0x3226d838, 0x49385adb, 0xd6e2d945, 0x9af7566b, 0x052dd5f5, + 0x7e335716, 0xe1e9d488, 0x880e52d0, 0x17d4d14e, 0x6cca53ad, + 0xf310d033, 0x63296829, 0xfcf3ebb7, 0x87ed6954, 0x1837eaca, + 0x71d06c92, 0xee0aef0c, 0x95146def, 0x0aceee71, 0x46db615f, + 0xd901e2c1, 0xa21f6022, 0x3dc5e3bc, 0x542265e4, 0xcbf8e67a, + 0xb0e66499, 0x2f3ce707, 0x28cd7ac5, 0xb717f95b, 0xcc097bb8, + 0x53d3f826, 0x3a347e7e, 0xa5eefde0, 0xdef07f03, 0x412afc9d, + 0x0d3f73b3, 0x92e5f02d, 0xe9fb72ce, 0x7621f150, 0x1fc67708, + 0x801cf496, 0xfb027675, 0x64d8f5eb, 0x32b39da3, 0xad691e3d, + 0xd6779cde, 0x49ad1f40, 0x204a9918, 0xbf901a86, 0xc48e9865, + 0x5b541bfb, 0x174194d5, 0x889b174b, 0xf38595a8, 0x6c5f1636, + 0x05b8906e, 0x9a6213f0, 0xe17c9113, 0x7ea6128d, 0x79578f4f, + 0xe68d0cd1, 0x9d938e32, 0x02490dac, 0x6bae8bf4, 0xf474086a, + 0x8f6a8a89, 0x10b00917, 0x5ca58639, 0xc37f05a7, 0xb8618744, + 0x27bb04da, 0x4e5c8282, 0xd186011c, 0xaa9883ff, 0x35420061, + 0xa57bb87b, 0x3aa13be5, 0x41bfb906, 0xde653a98, 0xb782bcc0, + 0x28583f5e, 0x5346bdbd, 0xcc9c3e23, 0x8089b10d, 0x1f533293, + 0x644db070, 0xfb9733ee, 0x9270b5b6, 0x0daa3628, 0x76b4b4cb, + 0xe96e3755, 0xee9faa97, 0x71452909, 0x0a5babea, 0x95812874, + 0xfc66ae2c, 0x63bc2db2, 0x18a2af51, 0x87782ccf, 0xcb6da3e1, + 0x54b7207f, 0x2fa9a29c, 0xb0732102, 0xd994a75a, 0x464e24c4, + 0x3d50a627, 0xa28a25b9, 0xc652d052, 0x598853cc, 0x2296d12f, + 0xbd4c52b1, 0xd4abd4e9, 0x4b715777, 0x306fd594, 0xafb5560a, + 0xe3a0d924, 0x7c7a5aba, 0x0764d859, 0x98be5bc7, 0xf159dd9f, + 0x6e835e01, 0x159ddce2, 0x8a475f7c, 0x8db6c2be, 0x126c4120, + 0x6972c3c3, 0xf6a8405d, 0x9f4fc605, 0x0095459b, 0x7b8bc778, + 0xe45144e6, 0xa844cbc8, 0x379e4856, 0x4c80cab5, 0xd35a492b, + 0xbabdcf73, 0x25674ced, 0x5e79ce0e, 0xc1a34d90, 0x519af58a, + 0xce407614, 0xb55ef4f7, 0x2a847769, 0x4363f131, 0xdcb972af, + 0xa7a7f04c, 0x387d73d2, 0x7468fcfc, 0xebb27f62, 0x90acfd81, + 0x0f767e1f, 0x6691f847, 0xf94b7bd9, 0x8255f93a, 0x1d8f7aa4, + 0x1a7ee766, 0x85a464f8, 0xfebae61b, 0x61606585, 0x0887e3dd, + 0x975d6043, 0xec43e2a0, 0x7399613e, 0x3f8cee10, 0xa0566d8e, + 0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6, + 0x566b6848}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x9e83da9f, 0x7d01c4e4, 0xe3821e7b, 0xbb04f912, + 0x2587238d, 0xc6053df6, 0x5886e769, 0x7609f225, 0xe88a28ba, + 0x0b0836c1, 0x958bec5e, 0xcd0d0b37, 0x538ed1a8, 0xb00ccfd3, + 0x2e8f154c, 0xec12e44b, 0x72913ed4, 0x911320af, 0x0f90fa30, + 0x57161d59, 0xc995c7c6, 0x2a17d9bd, 0xb4940322, 0x9a1b166e, + 0x0498ccf1, 0xe71ad28a, 0x79990815, 0x211fef7c, 0xbf9c35e3, + 0x5c1e2b98, 0xc29df107, 0xd825c897, 0x46a61208, 0xa5240c73, + 0x3ba7d6ec, 0x63213185, 0xfda2eb1a, 0x1e20f561, 0x80a32ffe, + 0xae2c3ab2, 0x30afe02d, 0xd32dfe56, 0x4dae24c9, 0x1528c3a0, + 0x8bab193f, 0x68290744, 0xf6aadddb, 0x34372cdc, 0xaab4f643, + 0x4936e838, 0xd7b532a7, 0x8f33d5ce, 0x11b00f51, 0xf232112a, + 0x6cb1cbb5, 0x423edef9, 0xdcbd0466, 0x3f3f1a1d, 0xa1bcc082, + 0xf93a27eb, 0x67b9fd74, 0x843be30f, 0x1ab83990, 0xf14de1f4, + 0x6fce3b6b, 0x8c4c2510, 0x12cfff8f, 0x4a4918e6, 0xd4cac279, + 0x3748dc02, 0xa9cb069d, 0x874413d1, 0x19c7c94e, 0xfa45d735, + 0x64c60daa, 0x3c40eac3, 0xa2c3305c, 0x41412e27, 0xdfc2f4b8, + 0x1d5f05bf, 0x83dcdf20, 0x605ec15b, 0xfedd1bc4, 0xa65bfcad, + 0x38d82632, 0xdb5a3849, 0x45d9e2d6, 0x6b56f79a, 0xf5d52d05, + 0x1657337e, 0x88d4e9e1, 0xd0520e88, 0x4ed1d417, 0xad53ca6c, + 0x33d010f3, 0x29682963, 0xb7ebf3fc, 0x5469ed87, 0xcaea3718, + 0x926cd071, 0x0cef0aee, 0xef6d1495, 0x71eece0a, 0x5f61db46, + 0xc1e201d9, 0x22601fa2, 0xbce3c53d, 0xe4652254, 0x7ae6f8cb, + 0x9964e6b0, 0x07e73c2f, 0xc57acd28, 0x5bf917b7, 0xb87b09cc, + 0x26f8d353, 0x7e7e343a, 0xe0fdeea5, 0x037ff0de, 0x9dfc2a41, + 0xb3733f0d, 0x2df0e592, 0xce72fbe9, 0x50f12176, 0x0877c61f, + 0x96f41c80, 0x757602fb, 0xebf5d864, 0xa39db332, 0x3d1e69ad, + 0xde9c77d6, 0x401fad49, 0x18994a20, 0x861a90bf, 0x65988ec4, + 0xfb1b545b, 0xd5944117, 0x4b179b88, 0xa89585f3, 0x36165f6c, + 0x6e90b805, 0xf013629a, 0x13917ce1, 0x8d12a67e, 0x4f8f5779, + 0xd10c8de6, 0x328e939d, 0xac0d4902, 0xf48bae6b, 0x6a0874f4, + 0x898a6a8f, 0x1709b010, 0x3986a55c, 0xa7057fc3, 0x448761b8, + 0xda04bb27, 0x82825c4e, 0x1c0186d1, 0xff8398aa, 0x61004235, + 0x7bb87ba5, 0xe53ba13a, 0x06b9bf41, 0x983a65de, 0xc0bc82b7, + 0x5e3f5828, 0xbdbd4653, 0x233e9ccc, 0x0db18980, 0x9332531f, + 0x70b04d64, 0xee3397fb, 0xb6b57092, 0x2836aa0d, 0xcbb4b476, + 0x55376ee9, 0x97aa9fee, 0x09294571, 0xeaab5b0a, 0x74288195, + 0x2cae66fc, 0xb22dbc63, 0x51afa218, 0xcf2c7887, 0xe1a36dcb, + 0x7f20b754, 0x9ca2a92f, 0x022173b0, 0x5aa794d9, 0xc4244e46, + 0x27a6503d, 0xb9258aa2, 0x52d052c6, 0xcc538859, 0x2fd19622, + 0xb1524cbd, 0xe9d4abd4, 0x7757714b, 0x94d56f30, 0x0a56b5af, + 0x24d9a0e3, 0xba5a7a7c, 0x59d86407, 0xc75bbe98, 0x9fdd59f1, + 0x015e836e, 0xe2dc9d15, 0x7c5f478a, 0xbec2b68d, 0x20416c12, + 0xc3c37269, 0x5d40a8f6, 0x05c64f9f, 0x9b459500, 0x78c78b7b, + 0xe64451e4, 0xc8cb44a8, 0x56489e37, 0xb5ca804c, 0x2b495ad3, + 0x73cfbdba, 0xed4c6725, 0x0ece795e, 0x904da3c1, 0x8af59a51, + 0x147640ce, 0xf7f45eb5, 0x6977842a, 0x31f16343, 0xaf72b9dc, + 0x4cf0a7a7, 0xd2737d38, 0xfcfc6874, 0x627fb2eb, 0x81fdac90, + 0x1f7e760f, 0x47f89166, 0xd97b4bf9, 0x3af95582, 0xa47a8f1d, + 0x66e77e1a, 0xf864a485, 0x1be6bafe, 0x85656061, 0xdde38708, + 0x43605d97, 0xa0e243ec, 0x3e619973, 0x10ee8c3f, 0x8e6d56a0, + 0x6def48db, 0xf36c9244, 0xabea752d, 0x3569afb2, 0xd6ebb1c9, + 0x48686b56}, + {0x00000000, 0xc0642817, 0x80c9502e, 0x40ad7839, 0x0093a15c, + 0xc0f7894b, 0x805af172, 0x403ed965, 0x002643b9, 0xc0426bae, + 0x80ef1397, 0x408b3b80, 0x00b5e2e5, 0xc0d1caf2, 0x807cb2cb, + 0x40189adc, 0x414af7a9, 0x812edfbe, 0xc183a787, 0x01e78f90, + 0x41d956f5, 0x81bd7ee2, 0xc11006db, 0x01742ecc, 0x416cb410, + 0x81089c07, 0xc1a5e43e, 0x01c1cc29, 0x41ff154c, 0x819b3d5b, + 0xc1364562, 0x01526d75, 0xc3929f88, 0x03f6b79f, 0x435bcfa6, + 0x833fe7b1, 0xc3013ed4, 0x036516c3, 0x43c86efa, 0x83ac46ed, + 0xc3b4dc31, 0x03d0f426, 0x437d8c1f, 0x8319a408, 0xc3277d6d, + 0x0343557a, 0x43ee2d43, 0x838a0554, 0x82d86821, 0x42bc4036, + 0x0211380f, 0xc2751018, 0x824bc97d, 0x422fe16a, 0x02829953, + 0xc2e6b144, 0x82fe2b98, 0x429a038f, 0x02377bb6, 0xc25353a1, + 0x826d8ac4, 0x4209a2d3, 0x02a4daea, 0xc2c0f2fd, 0xc7234eca, + 0x074766dd, 0x47ea1ee4, 0x878e36f3, 0xc7b0ef96, 0x07d4c781, + 0x4779bfb8, 0x871d97af, 0xc7050d73, 0x07612564, 0x47cc5d5d, + 0x87a8754a, 0xc796ac2f, 0x07f28438, 0x475ffc01, 0x873bd416, + 0x8669b963, 0x460d9174, 0x06a0e94d, 0xc6c4c15a, 0x86fa183f, + 0x469e3028, 0x06334811, 0xc6576006, 0x864ffada, 0x462bd2cd, + 0x0686aaf4, 0xc6e282e3, 0x86dc5b86, 0x46b87391, 0x06150ba8, + 0xc67123bf, 0x04b1d142, 0xc4d5f955, 0x8478816c, 0x441ca97b, + 0x0422701e, 0xc4465809, 0x84eb2030, 0x448f0827, 0x049792fb, + 0xc4f3baec, 0x845ec2d5, 0x443aeac2, 0x040433a7, 0xc4601bb0, + 0x84cd6389, 0x44a94b9e, 0x45fb26eb, 0x859f0efc, 0xc53276c5, + 0x05565ed2, 0x456887b7, 0x850cafa0, 0xc5a1d799, 0x05c5ff8e, + 0x45dd6552, 0x85b94d45, 0xc514357c, 0x05701d6b, 0x454ec40e, + 0x852aec19, 0xc5879420, 0x05e3bc37, 0xcf41ed4f, 0x0f25c558, + 0x4f88bd61, 0x8fec9576, 0xcfd24c13, 0x0fb66404, 0x4f1b1c3d, + 0x8f7f342a, 0xcf67aef6, 0x0f0386e1, 0x4faefed8, 0x8fcad6cf, + 0xcff40faa, 0x0f9027bd, 0x4f3d5f84, 0x8f597793, 0x8e0b1ae6, + 0x4e6f32f1, 0x0ec24ac8, 0xcea662df, 0x8e98bbba, 0x4efc93ad, + 0x0e51eb94, 0xce35c383, 0x8e2d595f, 0x4e497148, 0x0ee40971, + 0xce802166, 0x8ebef803, 0x4edad014, 0x0e77a82d, 0xce13803a, + 0x0cd372c7, 0xccb75ad0, 0x8c1a22e9, 0x4c7e0afe, 0x0c40d39b, + 0xcc24fb8c, 0x8c8983b5, 0x4cedaba2, 0x0cf5317e, 0xcc911969, + 0x8c3c6150, 0x4c584947, 0x0c669022, 0xcc02b835, 0x8cafc00c, + 0x4ccbe81b, 0x4d99856e, 0x8dfdad79, 0xcd50d540, 0x0d34fd57, + 0x4d0a2432, 0x8d6e0c25, 0xcdc3741c, 0x0da75c0b, 0x4dbfc6d7, + 0x8ddbeec0, 0xcd7696f9, 0x0d12beee, 0x4d2c678b, 0x8d484f9c, + 0xcde537a5, 0x0d811fb2, 0x0862a385, 0xc8068b92, 0x88abf3ab, + 0x48cfdbbc, 0x08f102d9, 0xc8952ace, 0x883852f7, 0x485c7ae0, + 0x0844e03c, 0xc820c82b, 0x888db012, 0x48e99805, 0x08d74160, + 0xc8b36977, 0x881e114e, 0x487a3959, 0x4928542c, 0x894c7c3b, + 0xc9e10402, 0x09852c15, 0x49bbf570, 0x89dfdd67, 0xc972a55e, + 0x09168d49, 0x490e1795, 0x896a3f82, 0xc9c747bb, 0x09a36fac, + 0x499db6c9, 0x89f99ede, 0xc954e6e7, 0x0930cef0, 0xcbf03c0d, + 0x0b94141a, 0x4b396c23, 0x8b5d4434, 0xcb639d51, 0x0b07b546, + 0x4baacd7f, 0x8bcee568, 0xcbd67fb4, 0x0bb257a3, 0x4b1f2f9a, + 0x8b7b078d, 0xcb45dee8, 0x0b21f6ff, 0x4b8c8ec6, 0x8be8a6d1, + 0x8abacba4, 0x4adee3b3, 0x0a739b8a, 0xca17b39d, 0x8a296af8, + 0x4a4d42ef, 0x0ae03ad6, 0xca8412c1, 0x8a9c881d, 0x4af8a00a, + 0x0a55d833, 0xca31f024, 0x8a0f2941, 0x4a6b0156, 0x0ac6796f, + 0xcaa25178}, + {0x00000000, 0xd4ea739b, 0xe9d396ed, 0x3d39e576, 0x93a15c00, + 0x474b2f9b, 0x7a72caed, 0xae98b976, 0x2643b900, 0xf2a9ca9b, + 0xcf902fed, 0x1b7a5c76, 0xb5e2e500, 0x6108969b, 0x5c3173ed, + 0x88db0076, 0x4c867201, 0x986c019a, 0xa555e4ec, 0x71bf9777, + 0xdf272e01, 0x0bcd5d9a, 0x36f4b8ec, 0xe21ecb77, 0x6ac5cb01, + 0xbe2fb89a, 0x83165dec, 0x57fc2e77, 0xf9649701, 0x2d8ee49a, + 0x10b701ec, 0xc45d7277, 0x980ce502, 0x4ce69699, 0x71df73ef, + 0xa5350074, 0x0badb902, 0xdf47ca99, 0xe27e2fef, 0x36945c74, + 0xbe4f5c02, 0x6aa52f99, 0x579ccaef, 0x8376b974, 0x2dee0002, + 0xf9047399, 0xc43d96ef, 0x10d7e574, 0xd48a9703, 0x0060e498, + 0x3d5901ee, 0xe9b37275, 0x472bcb03, 0x93c1b898, 0xaef85dee, + 0x7a122e75, 0xf2c92e03, 0x26235d98, 0x1b1ab8ee, 0xcff0cb75, + 0x61687203, 0xb5820198, 0x88bbe4ee, 0x5c519775, 0x3019ca05, + 0xe4f3b99e, 0xd9ca5ce8, 0x0d202f73, 0xa3b89605, 0x7752e59e, + 0x4a6b00e8, 0x9e817373, 0x165a7305, 0xc2b0009e, 0xff89e5e8, + 0x2b639673, 0x85fb2f05, 0x51115c9e, 0x6c28b9e8, 0xb8c2ca73, + 0x7c9fb804, 0xa875cb9f, 0x954c2ee9, 0x41a65d72, 0xef3ee404, + 0x3bd4979f, 0x06ed72e9, 0xd2070172, 0x5adc0104, 0x8e36729f, + 0xb30f97e9, 0x67e5e472, 0xc97d5d04, 0x1d972e9f, 0x20aecbe9, + 0xf444b872, 0xa8152f07, 0x7cff5c9c, 0x41c6b9ea, 0x952cca71, + 0x3bb47307, 0xef5e009c, 0xd267e5ea, 0x068d9671, 0x8e569607, + 0x5abce59c, 0x678500ea, 0xb36f7371, 0x1df7ca07, 0xc91db99c, + 0xf4245cea, 0x20ce2f71, 0xe4935d06, 0x30792e9d, 0x0d40cbeb, + 0xd9aab870, 0x77320106, 0xa3d8729d, 0x9ee197eb, 0x4a0be470, + 0xc2d0e406, 0x163a979d, 0x2b0372eb, 0xffe90170, 0x5171b806, + 0x859bcb9d, 0xb8a22eeb, 0x6c485d70, 0x6032940b, 0xb4d8e790, + 0x89e102e6, 0x5d0b717d, 0xf393c80b, 0x2779bb90, 0x1a405ee6, + 0xceaa2d7d, 0x46712d0b, 0x929b5e90, 0xafa2bbe6, 0x7b48c87d, + 0xd5d0710b, 0x013a0290, 0x3c03e7e6, 0xe8e9947d, 0x2cb4e60a, + 0xf85e9591, 0xc56770e7, 0x118d037c, 0xbf15ba0a, 0x6bffc991, + 0x56c62ce7, 0x822c5f7c, 0x0af75f0a, 0xde1d2c91, 0xe324c9e7, + 0x37ceba7c, 0x9956030a, 0x4dbc7091, 0x708595e7, 0xa46fe67c, + 0xf83e7109, 0x2cd40292, 0x11ede7e4, 0xc507947f, 0x6b9f2d09, + 0xbf755e92, 0x824cbbe4, 0x56a6c87f, 0xde7dc809, 0x0a97bb92, + 0x37ae5ee4, 0xe3442d7f, 0x4ddc9409, 0x9936e792, 0xa40f02e4, + 0x70e5717f, 0xb4b80308, 0x60527093, 0x5d6b95e5, 0x8981e67e, + 0x27195f08, 0xf3f32c93, 0xcecac9e5, 0x1a20ba7e, 0x92fbba08, + 0x4611c993, 0x7b282ce5, 0xafc25f7e, 0x015ae608, 0xd5b09593, + 0xe88970e5, 0x3c63037e, 0x502b5e0e, 0x84c12d95, 0xb9f8c8e3, + 0x6d12bb78, 0xc38a020e, 0x17607195, 0x2a5994e3, 0xfeb3e778, + 0x7668e70e, 0xa2829495, 0x9fbb71e3, 0x4b510278, 0xe5c9bb0e, + 0x3123c895, 0x0c1a2de3, 0xd8f05e78, 0x1cad2c0f, 0xc8475f94, + 0xf57ebae2, 0x2194c979, 0x8f0c700f, 0x5be60394, 0x66dfe6e2, + 0xb2359579, 0x3aee950f, 0xee04e694, 0xd33d03e2, 0x07d77079, + 0xa94fc90f, 0x7da5ba94, 0x409c5fe2, 0x94762c79, 0xc827bb0c, + 0x1ccdc897, 0x21f42de1, 0xf51e5e7a, 0x5b86e70c, 0x8f6c9497, + 0xb25571e1, 0x66bf027a, 0xee64020c, 0x3a8e7197, 0x07b794e1, + 0xd35de77a, 0x7dc55e0c, 0xa92f2d97, 0x9416c8e1, 0x40fcbb7a, + 0x84a1c90d, 0x504bba96, 0x6d725fe0, 0xb9982c7b, 0x1700950d, + 0xc3eae696, 0xfed303e0, 0x2a39707b, 0xa2e2700d, 0x76080396, + 0x4b31e6e0, 0x9fdb957b, 0x31432c0d, 0xe5a95f96, 0xd890bae0, + 0x0c7ac97b}, + {0x00000000, 0x27652581, 0x0fcc3bd9, 0x28a91e58, 0x5f9e0669, + 0x78fb23e8, 0x50523db0, 0x77371831, 0xbe3c0dd2, 0x99592853, + 0xb1f0360b, 0x9695138a, 0xe1a20bbb, 0xc6c72e3a, 0xee6e3062, + 0xc90b15e3, 0x3d7f6b7f, 0x1a1a4efe, 0x32b350a6, 0x15d67527, + 0x62e16d16, 0x45844897, 0x6d2d56cf, 0x4a48734e, 0x834366ad, + 0xa426432c, 0x8c8f5d74, 0xabea78f5, 0xdcdd60c4, 0xfbb84545, + 0xd3115b1d, 0xf4747e9c, 0x7afed6fe, 0x5d9bf37f, 0x7532ed27, + 0x5257c8a6, 0x2560d097, 0x0205f516, 0x2aaceb4e, 0x0dc9cecf, + 0xc4c2db2c, 0xe3a7fead, 0xcb0ee0f5, 0xec6bc574, 0x9b5cdd45, + 0xbc39f8c4, 0x9490e69c, 0xb3f5c31d, 0x4781bd81, 0x60e49800, + 0x484d8658, 0x6f28a3d9, 0x181fbbe8, 0x3f7a9e69, 0x17d38031, + 0x30b6a5b0, 0xf9bdb053, 0xded895d2, 0xf6718b8a, 0xd114ae0b, + 0xa623b63a, 0x814693bb, 0xa9ef8de3, 0x8e8aa862, 0xb5fadc26, + 0x929ff9a7, 0xba36e7ff, 0x9d53c27e, 0xea64da4f, 0xcd01ffce, + 0xe5a8e196, 0xc2cdc417, 0x0bc6d1f4, 0x2ca3f475, 0x040aea2d, + 0x236fcfac, 0x5458d79d, 0x733df21c, 0x5b94ec44, 0x7cf1c9c5, + 0x8885b759, 0xafe092d8, 0x87498c80, 0xa02ca901, 0xd71bb130, + 0xf07e94b1, 0xd8d78ae9, 0xffb2af68, 0x36b9ba8b, 0x11dc9f0a, + 0x39758152, 0x1e10a4d3, 0x6927bce2, 0x4e429963, 0x66eb873b, + 0x418ea2ba, 0xcf040ad8, 0xe8612f59, 0xc0c83101, 0xe7ad1480, + 0x909a0cb1, 0xb7ff2930, 0x9f563768, 0xb83312e9, 0x7138070a, + 0x565d228b, 0x7ef43cd3, 0x59911952, 0x2ea60163, 0x09c324e2, + 0x216a3aba, 0x060f1f3b, 0xf27b61a7, 0xd51e4426, 0xfdb75a7e, + 0xdad27fff, 0xade567ce, 0x8a80424f, 0xa2295c17, 0x854c7996, + 0x4c476c75, 0x6b2249f4, 0x438b57ac, 0x64ee722d, 0x13d96a1c, + 0x34bc4f9d, 0x1c1551c5, 0x3b707444, 0x6af5b94d, 0x4d909ccc, + 0x65398294, 0x425ca715, 0x356bbf24, 0x120e9aa5, 0x3aa784fd, + 0x1dc2a17c, 0xd4c9b49f, 0xf3ac911e, 0xdb058f46, 0xfc60aac7, + 0x8b57b2f6, 0xac329777, 0x849b892f, 0xa3feacae, 0x578ad232, + 0x70eff7b3, 0x5846e9eb, 0x7f23cc6a, 0x0814d45b, 0x2f71f1da, + 0x07d8ef82, 0x20bdca03, 0xe9b6dfe0, 0xced3fa61, 0xe67ae439, + 0xc11fc1b8, 0xb628d989, 0x914dfc08, 0xb9e4e250, 0x9e81c7d1, + 0x100b6fb3, 0x376e4a32, 0x1fc7546a, 0x38a271eb, 0x4f9569da, + 0x68f04c5b, 0x40595203, 0x673c7782, 0xae376261, 0x895247e0, + 0xa1fb59b8, 0x869e7c39, 0xf1a96408, 0xd6cc4189, 0xfe655fd1, + 0xd9007a50, 0x2d7404cc, 0x0a11214d, 0x22b83f15, 0x05dd1a94, + 0x72ea02a5, 0x558f2724, 0x7d26397c, 0x5a431cfd, 0x9348091e, + 0xb42d2c9f, 0x9c8432c7, 0xbbe11746, 0xccd60f77, 0xebb32af6, + 0xc31a34ae, 0xe47f112f, 0xdf0f656b, 0xf86a40ea, 0xd0c35eb2, + 0xf7a67b33, 0x80916302, 0xa7f44683, 0x8f5d58db, 0xa8387d5a, + 0x613368b9, 0x46564d38, 0x6eff5360, 0x499a76e1, 0x3ead6ed0, + 0x19c84b51, 0x31615509, 0x16047088, 0xe2700e14, 0xc5152b95, + 0xedbc35cd, 0xcad9104c, 0xbdee087d, 0x9a8b2dfc, 0xb22233a4, + 0x95471625, 0x5c4c03c6, 0x7b292647, 0x5380381f, 0x74e51d9e, + 0x03d205af, 0x24b7202e, 0x0c1e3e76, 0x2b7b1bf7, 0xa5f1b395, + 0x82949614, 0xaa3d884c, 0x8d58adcd, 0xfa6fb5fc, 0xdd0a907d, + 0xf5a38e25, 0xd2c6aba4, 0x1bcdbe47, 0x3ca89bc6, 0x1401859e, + 0x3364a01f, 0x4453b82e, 0x63369daf, 0x4b9f83f7, 0x6cfaa676, + 0x988ed8ea, 0xbfebfd6b, 0x9742e333, 0xb027c6b2, 0xc710de83, + 0xe075fb02, 0xc8dce55a, 0xefb9c0db, 0x26b2d538, 0x01d7f0b9, + 0x297eeee1, 0x0e1bcb60, 0x792cd351, 0x5e49f6d0, 0x76e0e888, + 0x5185cd09}}; + +#endif + +#endif + +#endif + +local const z_crc_t FAR x2n_table[] = { + 0x40000000, 0x20000000, 0x08000000, 0x00800000, 0x00008000, + 0xedb88320, 0xb1e6b092, 0xa06a2517, 0xed627dae, 0x88d14467, + 0xd7bbfe6a, 0xec447f11, 0x8e7ea170, 0x6427800e, 0x4d47bae0, + 0x09fe548f, 0x83852d0f, 0x30362f1a, 0x7b5a9cc3, 0x31fec169, + 0x9fec022a, 0x6c8dedc4, 0x15d6874d, 0x5fde7a4e, 0xbad90e37, + 0x2e4e5eef, 0x4eaba214, 0xa8a472c0, 0x429a969e, 0x148d302a, + 0xc40ba6d0, 0xc4e22c3c}; diff --git a/vendor/libgit2/deps/zlib/deflate.c b/vendor/libgit2/deps/zlib/deflate.c index 8d44869e..bd011751 100644 --- a/vendor/libgit2/deps/zlib/deflate.c +++ b/vendor/libgit2/deps/zlib/deflate.c @@ -1,5 +1,5 @@ /* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler + * Copyright (C) 1995-2023 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -52,7 +52,7 @@ #include "deflate.h" const char deflate_copyright[] = - " deflate 1.2.11 Copyright 1995-2017 Jean-loup Gailly and Mark Adler "; + " deflate 1.3 Copyright 1995-2023 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -60,9 +60,6 @@ const char deflate_copyright[] = copyright string in the executable of your product. */ -/* =========================================================================== - * Function prototypes. - */ typedef enum { need_more, /* block not completed, need more input or more output */ block_done, /* block flush performed */ @@ -70,35 +67,16 @@ typedef enum { finish_done /* finish done, accept no more input or output */ } block_state; -typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +typedef block_state (*compress_func)(deflate_state *s, int flush); /* Compression function. Returns the block state after the call. */ -local int deflateStateCheck OF((z_streamp strm)); -local void slide_hash OF((deflate_state *s)); -local void fill_window OF((deflate_state *s)); -local block_state deflate_stored OF((deflate_state *s, int flush)); -local block_state deflate_fast OF((deflate_state *s, int flush)); +local block_state deflate_stored(deflate_state *s, int flush); +local block_state deflate_fast(deflate_state *s, int flush); #ifndef FASTEST -local block_state deflate_slow OF((deflate_state *s, int flush)); -#endif -local block_state deflate_rle OF((deflate_state *s, int flush)); -local block_state deflate_huff OF((deflate_state *s, int flush)); -local void lm_init OF((deflate_state *s)); -local void putShortMSB OF((deflate_state *s, uInt b)); -local void flush_pending OF((z_streamp strm)); -local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); -#ifdef ASMV -# pragma message("Assembler code may have bugs -- use at your own risk") - void match_init OF((void)); /* asm code initialization */ - uInt longest_match OF((deflate_state *s, IPos cur_match)); -#else -local uInt longest_match OF((deflate_state *s, IPos cur_match)); -#endif - -#ifdef ZLIB_DEBUG -local void check_match OF((deflate_state *s, IPos start, IPos match, - int length)); +local block_state deflate_slow(deflate_state *s, int flush); #endif +local block_state deflate_rle(deflate_state *s, int flush); +local block_state deflate_huff(deflate_state *s, int flush); /* =========================================================================== * Local data @@ -160,7 +138,7 @@ local const config configuration_table[10] = { * characters, so that a running hash key can be computed from the previous * key instead of complete recalculation each time. */ -#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) +#define UPDATE_HASH(s,h,c) (h = (((h) << s->hash_shift) ^ (c)) & s->hash_mask) /* =========================================================================== @@ -190,17 +168,23 @@ local const config configuration_table[10] = { * prev[] will be initialized on the fly. */ #define CLEAR_HASH(s) \ - s->head[s->hash_size-1] = NIL; \ - zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + do { \ + s->head[s->hash_size - 1] = NIL; \ + zmemzero((Bytef *)s->head, \ + (unsigned)(s->hash_size - 1)*sizeof(*s->head)); \ + } while (0) /* =========================================================================== * Slide the hash table when sliding the window down (could be avoided with 32 * bit values at the expense of memory usage). We slide even when level == 0 to * keep the hash table consistent if we switch back to level > 0 later. */ -local void slide_hash(s) - deflate_state *s; -{ +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) + __attribute__((no_sanitize("memory"))) +# endif +#endif +local void slide_hash(deflate_state *s) { unsigned n, m; Posf *p; uInt wsize = s->w_size; @@ -224,39 +208,181 @@ local void slide_hash(s) #endif } +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local unsigned read_buf(z_streamp strm, Bytef *buf, unsigned size) { + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + zmemcpy(buf, strm->next_in, len); + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, buf, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, buf, len); + } +#endif + strm->next_in += len; + strm->total_in += len; + + return len; +} + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(deflate_state *s) { + unsigned n; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize + MAX_DIST(s)) { + + zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + if (s->insert > s->strstart) + s->insert = s->strstart; + slide_hash(s); + more += wsize; + } + if (s->strm->avail_in == 0) break; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead + s->insert >= MIN_MATCH) { + uInt str = s->strstart - s->insert; + s->ins_h = s->window[str]; + UPDATE_HASH(s, s->ins_h, s->window[str + 1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + while (s->insert) { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + s->insert--; + if (s->lookahead + s->insert < MIN_MATCH) + break; + } + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ + if (s->high_water < s->window_size) { + ulg curr = s->strstart + (ulg)(s->lookahead); + ulg init; + + if (s->high_water < curr) { + /* Previous high water mark below current data -- zero WIN_INIT + * bytes or up to end of window, whichever is less. + */ + init = s->window_size - curr; + if (init > WIN_INIT) + init = WIN_INIT; + zmemzero(s->window + curr, (unsigned)init); + s->high_water = curr + init; + } + else if (s->high_water < (ulg)curr + WIN_INIT) { + /* High water mark at or above current data, but below current data + * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up + * to end of window, whichever is less. + */ + init = (ulg)curr + WIN_INIT - s->high_water; + if (init > s->window_size - s->high_water) + init = s->window_size - s->high_water; + zmemzero(s->window + s->high_water, (unsigned)init); + s->high_water += init; + } + } + + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "not enough room for search"); +} + /* ========================================================================= */ -int ZEXPORT deflateInit_(strm, level, version, stream_size) - z_streamp strm; - int level; - const char *version; - int stream_size; -{ +int ZEXPORT deflateInit_(z_streamp strm, int level, const char *version, + int stream_size) { return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, version, stream_size); /* To do: ignore strm->next_in if we use it as window */ } /* ========================================================================= */ -int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, - version, stream_size) - z_streamp strm; - int level; - int method; - int windowBits; - int memLevel; - int strategy; - const char *version; - int stream_size; -{ +int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, + int windowBits, int memLevel, int strategy, + const char *version, int stream_size) { deflate_state *s; int wrap = 1; static const char my_version[] = ZLIB_VERSION; - ushf *overlay; - /* We overlay pending_buf and d_buf+l_buf. This works since the average - * output size for (length,distance) codes is <= 24 bits. - */ - if (version == Z_NULL || version[0] != my_version[0] || stream_size != sizeof(z_stream)) { return Z_VERSION_ERROR; @@ -287,6 +413,8 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, if (windowBits < 0) { /* suppress zlib wrapper */ wrap = 0; + if (windowBits < -15) + return Z_STREAM_ERROR; windowBits = -windowBits; } #ifdef GZIP @@ -316,20 +444,57 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, s->hash_bits = (uInt)memLevel + 7; s->hash_size = 1 << s->hash_bits; s->hash_mask = s->hash_size - 1; - s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + s->hash_shift = ((s->hash_bits + MIN_MATCH-1) / MIN_MATCH); s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); - memset(s->prev, 0, s->w_size * sizeof(Pos)); s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); s->high_water = 0; /* nothing written to s->window yet */ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ - overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); - s->pending_buf = (uchf *) overlay; - s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + /* We overlay pending_buf and sym_buf. This works since the average size + * for length/distance pairs over any compressed block is assured to be 31 + * bits or less. + * + * Analysis: The longest fixed codes are a length code of 8 bits plus 5 + * extra bits, for lengths 131 to 257. The longest fixed distance codes are + * 5 bits plus 13 extra bits, for distances 16385 to 32768. The longest + * possible fixed-codes length/distance pair is then 31 bits total. + * + * sym_buf starts one-fourth of the way into pending_buf. So there are + * three bytes in sym_buf for every four bytes in pending_buf. Each symbol + * in sym_buf is three bytes -- two for the distance and one for the + * literal/length. As each symbol is consumed, the pointer to the next + * sym_buf value to read moves forward three bytes. From that symbol, up to + * 31 bits are written to pending_buf. The closest the written pending_buf + * bits gets to the next sym_buf symbol to read is just before the last + * code is written. At that time, 31*(n - 2) bits have been written, just + * after 24*(n - 2) bits have been consumed from sym_buf. sym_buf starts at + * 8*n bits into pending_buf. (Note that the symbol buffer fills when n - 1 + * symbols are written.) The closest the writing gets to what is unread is + * then n + 14 bits. Here n is lit_bufsize, which is 16384 by default, and + * can range from 128 to 32768. + * + * Therefore, at a minimum, there are 142 bits of space between what is + * written and what is read in the overlain buffers, so the symbols cannot + * be overwritten by the compressed data. That space is actually 139 bits, + * due to the three-bit fixed-code block header. + * + * That covers the case where either Z_FIXED is specified, forcing fixed + * codes, or when the use of fixed codes is chosen, because that choice + * results in a smaller compressed block than dynamic codes. That latter + * condition then assures that the above analysis also covers all dynamic + * blocks. A dynamic-code block will only be chosen to be emitted if it has + * fewer bits than a fixed-code block would for the same set of symbols. + * Therefore its average symbol length is assured to be less than 31. So + * the compressed data for a dynamic block also cannot overwrite the + * symbols from which it is being constructed. + */ + + s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, 4); + s->pending_buf_size = (ulg)s->lit_bufsize * 4; if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || s->pending_buf == Z_NULL) { @@ -338,8 +503,12 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, deflateEnd (strm); return Z_MEM_ERROR; } - s->d_buf = overlay + s->lit_bufsize/sizeof(ush); - s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + s->sym_buf = s->pending_buf + s->lit_bufsize; + s->sym_end = (s->lit_bufsize - 1) * 3; + /* We avoid equality with lit_bufsize*3 because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ s->level = level; s->strategy = strategy; @@ -351,9 +520,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, /* ========================================================================= * Check for a valid deflate stream state. Return 0 if ok, 1 if not. */ -local int deflateStateCheck (strm) - z_streamp strm; -{ +local int deflateStateCheck(z_streamp strm) { deflate_state *s; if (strm == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) @@ -374,11 +541,8 @@ local int deflateStateCheck (strm) } /* ========================================================================= */ -int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) - z_streamp strm; - const Bytef *dictionary; - uInt dictLength; -{ +int ZEXPORT deflateSetDictionary(z_streamp strm, const Bytef *dictionary, + uInt dictLength) { deflate_state *s; uInt str, n; int wrap; @@ -443,11 +607,8 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) } /* ========================================================================= */ -int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength) - z_streamp strm; - Bytef *dictionary; - uInt *dictLength; -{ +int ZEXPORT deflateGetDictionary(z_streamp strm, Bytef *dictionary, + uInt *dictLength) { deflate_state *s; uInt len; @@ -465,9 +626,7 @@ int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength) } /* ========================================================================= */ -int ZEXPORT deflateResetKeep (strm) - z_streamp strm; -{ +int ZEXPORT deflateResetKeep(z_streamp strm) { deflate_state *s; if (deflateStateCheck(strm)) { @@ -489,23 +648,45 @@ int ZEXPORT deflateResetKeep (strm) #ifdef GZIP s->wrap == 2 ? GZIP_STATE : #endif - s->wrap ? INIT_STATE : BUSY_STATE; + INIT_STATE; strm->adler = #ifdef GZIP s->wrap == 2 ? crc32(0L, Z_NULL, 0) : #endif adler32(0L, Z_NULL, 0); - s->last_flush = Z_NO_FLUSH; + s->last_flush = -2; _tr_init(s); return Z_OK; } +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init(deflate_state *s) { + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->insert = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +} + /* ========================================================================= */ -int ZEXPORT deflateReset (strm) - z_streamp strm; -{ +int ZEXPORT deflateReset(z_streamp strm) { int ret; ret = deflateResetKeep(strm); @@ -515,10 +696,7 @@ int ZEXPORT deflateReset (strm) } /* ========================================================================= */ -int ZEXPORT deflateSetHeader (strm, head) - z_streamp strm; - gz_headerp head; -{ +int ZEXPORT deflateSetHeader(z_streamp strm, gz_headerp head) { if (deflateStateCheck(strm) || strm->state->wrap != 2) return Z_STREAM_ERROR; strm->state->gzhead = head; @@ -526,11 +704,7 @@ int ZEXPORT deflateSetHeader (strm, head) } /* ========================================================================= */ -int ZEXPORT deflatePending (strm, pending, bits) - unsigned *pending; - int *bits; - z_streamp strm; -{ +int ZEXPORT deflatePending(z_streamp strm, unsigned *pending, int *bits) { if (deflateStateCheck(strm)) return Z_STREAM_ERROR; if (pending != Z_NULL) *pending = strm->state->pending; @@ -540,17 +714,14 @@ int ZEXPORT deflatePending (strm, pending, bits) } /* ========================================================================= */ -int ZEXPORT deflatePrime (strm, bits, value) - z_streamp strm; - int bits; - int value; -{ +int ZEXPORT deflatePrime(z_streamp strm, int bits, int value) { deflate_state *s; int put; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; - if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3)) + if (bits < 0 || bits > 16 || + s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3)) return Z_BUF_ERROR; do { put = Buf_size - s->bi_valid; @@ -566,11 +737,7 @@ int ZEXPORT deflatePrime (strm, bits, value) } /* ========================================================================= */ -int ZEXPORT deflateParams(strm, level, strategy) - z_streamp strm; - int level; - int strategy; -{ +int ZEXPORT deflateParams(z_streamp strm, int level, int strategy) { deflate_state *s; compress_func func; @@ -588,12 +755,12 @@ int ZEXPORT deflateParams(strm, level, strategy) func = configuration_table[s->level].func; if ((strategy != s->strategy || func != configuration_table[level].func) && - s->high_water) { + s->last_flush != -2) { /* Flush the last buffer: */ int err = deflate(strm, Z_BLOCK); if (err == Z_STREAM_ERROR) return err; - if (strm->avail_out == 0) + if (strm->avail_in || (s->strstart - s->block_start) + s->lookahead) return Z_BUF_ERROR; } if (s->level != level) { @@ -615,13 +782,8 @@ int ZEXPORT deflateParams(strm, level, strategy) } /* ========================================================================= */ -int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) - z_streamp strm; - int good_length; - int max_lazy; - int nice_length; - int max_chain; -{ +int ZEXPORT deflateTune(z_streamp strm, int good_length, int max_lazy, + int nice_length, int max_chain) { deflate_state *s; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -634,36 +796,47 @@ int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) } /* ========================================================================= - * For the default windowBits of 15 and memLevel of 8, this function returns - * a close to exact, as well as small, upper bound on the compressed size. - * They are coded as constants here for a reason--if the #define's are - * changed, then this function needs to be changed as well. The return - * value for 15 and 8 only works for those exact settings. + * For the default windowBits of 15 and memLevel of 8, this function returns a + * close to exact, as well as small, upper bound on the compressed size. This + * is an expansion of ~0.03%, plus a small constant. * - * For any setting other than those defaults for windowBits and memLevel, - * the value returned is a conservative worst case for the maximum expansion - * resulting from using fixed blocks instead of stored blocks, which deflate - * can emit on compressed data for some combinations of the parameters. + * For any setting other than those defaults for windowBits and memLevel, one + * of two worst case bounds is returned. This is at most an expansion of ~4% or + * ~13%, plus a small constant. * - * This function could be more sophisticated to provide closer upper bounds for - * every combination of windowBits and memLevel. But even the conservative - * upper bound of about 14% expansion does not seem onerous for output buffer - * allocation. + * Both the 0.03% and 4% derive from the overhead of stored blocks. The first + * one is for stored blocks of 16383 bytes (memLevel == 8), whereas the second + * is for stored blocks of 127 bytes (the worst case memLevel == 1). The + * expansion results from five bytes of header for each stored block. + * + * The larger expansion of 13% results from a window size less than or equal to + * the symbols buffer size (windowBits <= memLevel + 7). In that case some of + * the data being compressed may have slid out of the sliding window, impeding + * a stored block from being emitted. Then the only choice is a fixed or + * dynamic block, where a fixed block limits the maximum expansion to 9 bits + * per 8-bit byte, plus 10 bits for every block. The smallest block size for + * which this can occur is 255 (memLevel == 2). + * + * Shifts are used to approximate divisions, for speed. */ -uLong ZEXPORT deflateBound(strm, sourceLen) - z_streamp strm; - uLong sourceLen; -{ +uLong ZEXPORT deflateBound(z_streamp strm, uLong sourceLen) { deflate_state *s; - uLong complen, wraplen; + uLong fixedlen, storelen, wraplen; + + /* upper bound for fixed blocks with 9-bit literals and length 255 + (memLevel == 2, which is the lowest that may not use stored blocks) -- + ~13% overhead plus a small constant */ + fixedlen = sourceLen + (sourceLen >> 3) + (sourceLen >> 8) + + (sourceLen >> 9) + 4; - /* conservative upper bound for compressed data */ - complen = sourceLen + - ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; + /* upper bound for stored blocks with length 127 (memLevel == 1) -- + ~4% overhead plus a small constant */ + storelen = sourceLen + (sourceLen >> 5) + (sourceLen >> 7) + + (sourceLen >> 11) + 7; - /* if can't get parameters, return conservative bound plus zlib wrapper */ + /* if can't get parameters, return larger bound plus a zlib wrapper */ if (deflateStateCheck(strm)) - return complen + 6; + return (fixedlen > storelen ? fixedlen : storelen) + 6; /* compute wrapper length */ s = strm->state; @@ -700,11 +873,13 @@ uLong ZEXPORT deflateBound(strm, sourceLen) wraplen = 6; } - /* if not default parameters, return conservative bound */ + /* if not default parameters, return one of the conservative bounds */ if (s->w_bits != 15 || s->hash_bits != 8 + 7) - return complen + wraplen; + return (s->w_bits <= s->hash_bits && s->level ? fixedlen : storelen) + + wraplen; - /* default settings: return tight bound for that case */ + /* default settings: return tight bound for that case -- ~0.03% overhead + plus a small constant */ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13 - 6 + wraplen; } @@ -714,10 +889,7 @@ uLong ZEXPORT deflateBound(strm, sourceLen) * IN assertion: the stream state is correct and there is enough room in * pending_buf. */ -local void putShortMSB (s, b) - deflate_state *s; - uInt b; -{ +local void putShortMSB(deflate_state *s, uInt b) { put_byte(s, (Byte)(b >> 8)); put_byte(s, (Byte)(b & 0xff)); } @@ -728,9 +900,7 @@ local void putShortMSB (s, b) * applications may wish to modify it to avoid allocating a large * strm->next_out buffer and copying into it. (See also read_buf()). */ -local void flush_pending(strm) - z_streamp strm; -{ +local void flush_pending(z_streamp strm) { unsigned len; deflate_state *s = strm->state; @@ -761,10 +931,7 @@ local void flush_pending(strm) } while (0) /* ========================================================================= */ -int ZEXPORT deflate (strm, flush) - z_streamp strm; - int flush; -{ +int ZEXPORT deflate(z_streamp strm, int flush) { int old_flush; /* value of flush param for previous deflate call */ deflate_state *s; @@ -812,9 +979,11 @@ int ZEXPORT deflate (strm, flush) } /* Write the header */ + if (s->status == INIT_STATE && s->wrap == 0) + s->status = BUSY_STATE; if (s->status == INIT_STATE) { /* zlib header */ - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt header = (Z_DEFLATED + ((s->w_bits - 8) << 4)) << 8; uInt level_flags; if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) @@ -1074,9 +1243,7 @@ int ZEXPORT deflate (strm, flush) } /* ========================================================================= */ -int ZEXPORT deflateEnd (strm) - z_streamp strm; -{ +int ZEXPORT deflateEnd(z_streamp strm) { int status; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -1100,16 +1267,14 @@ int ZEXPORT deflateEnd (strm) * To simplify the source, this is not supported for 16-bit MSDOS (which * doesn't have enough memory anyway to duplicate compression states). */ -int ZEXPORT deflateCopy (dest, source) - z_streamp dest; - z_streamp source; -{ +int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) { #ifdef MAXSEG_64K + (void)dest; + (void)source; return Z_STREAM_ERROR; #else deflate_state *ds; deflate_state *ss; - ushf *overlay; if (deflateStateCheck(source) || dest == Z_NULL) { @@ -1129,8 +1294,7 @@ int ZEXPORT deflateCopy (dest, source) ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); - overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); - ds->pending_buf = (uchf *) overlay; + ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, 4); if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || ds->pending_buf == Z_NULL) { @@ -1144,8 +1308,7 @@ int ZEXPORT deflateCopy (dest, source) zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); - ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); - ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + ds->sym_buf = ds->pending_buf + ds->lit_bufsize; ds->l_desc.dyn_tree = ds->dyn_ltree; ds->d_desc.dyn_tree = ds->dyn_dtree; @@ -1155,71 +1318,6 @@ int ZEXPORT deflateCopy (dest, source) #endif /* MAXSEG_64K */ } -/* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->next_in buffer and copying from it. - * (See also flush_pending()). - */ -local unsigned read_buf(strm, buf, size) - z_streamp strm; - Bytef *buf; - unsigned size; -{ - unsigned len = strm->avail_in; - - if (len > size) len = size; - if (len == 0) return 0; - - strm->avail_in -= len; - - zmemcpy(buf, strm->next_in, len); - if (strm->state->wrap == 1) { - strm->adler = adler32(strm->adler, buf, len); - } -#ifdef GZIP - else if (strm->state->wrap == 2) { - strm->adler = crc32(strm->adler, buf, len); - } -#endif - strm->next_in += len; - strm->total_in += len; - - return len; -} - -/* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ -local void lm_init (s) - deflate_state *s; -{ - s->window_size = (ulg)2L*s->w_size; - - CLEAR_HASH(s); - - /* Set the default configuration parameters: - */ - s->max_lazy_match = configuration_table[s->level].max_lazy; - s->good_match = configuration_table[s->level].good_length; - s->nice_match = configuration_table[s->level].nice_length; - s->max_chain_length = configuration_table[s->level].max_chain; - - s->strstart = 0; - s->block_start = 0L; - s->lookahead = 0; - s->insert = 0; - s->match_length = s->prev_length = MIN_MATCH-1; - s->match_available = 0; - s->ins_h = 0; -#ifndef FASTEST -#ifdef ASMV - match_init(); /* initialize the asm code */ -#endif -#endif -} - #ifndef FASTEST /* =========================================================================== * Set match_start to the longest match starting at the given string and @@ -1230,14 +1328,7 @@ local void lm_init (s) * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 * OUT assertion: the match length is not greater than s->lookahead. */ -#ifndef ASMV -/* For 80x86 and 680x0, an optimized version will be provided in match.asm or - * match.S. The code will be functionally equivalent. - */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ +local uInt longest_match(deflate_state *s, IPos cur_match) { unsigned chain_length = s->max_chain_length;/* max hash chain length */ register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ @@ -1258,10 +1349,10 @@ local uInt longest_match(s, cur_match) */ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; register ush scan_start = *(ushf*)scan; - register ush scan_end = *(ushf*)(scan+best_len-1); + register ush scan_end = *(ushf*)(scan + best_len - 1); #else register Bytef *strend = s->window + s->strstart + MAX_MATCH; - register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end1 = scan[best_len - 1]; register Byte scan_end = scan[best_len]; #endif @@ -1279,7 +1370,8 @@ local uInt longest_match(s, cur_match) */ if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead; - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "need lookahead"); do { Assert(cur_match < s->strstart, "no future"); @@ -1297,43 +1389,44 @@ local uInt longest_match(s, cur_match) /* This code assumes sizeof(unsigned short) == 2. Do not use * UNALIGNED_OK if your compiler uses a different size. */ - if (*(ushf*)(match+best_len-1) != scan_end || + if (*(ushf*)(match + best_len - 1) != scan_end || *(ushf*)match != scan_start) continue; /* It is not necessary to compare scan[2] and match[2] since they are * always equal when the other bytes match, given that the hash keys * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at - * strstart+3, +5, ... up to strstart+257. We check for insufficient + * strstart + 3, + 5, up to strstart + 257. We check for insufficient * lookahead only every 4th comparison; the 128th check will be made - * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * at strstart + 257. If MAX_MATCH-2 is not a multiple of 8, it is * necessary to put more guard bytes at the end of the window, or * to check more often for insufficient lookahead. */ Assert(scan[2] == match[2], "scan[2]?"); scan++, match++; do { - } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + } while (*(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && scan < strend); /* The funny "do {}" generates better code on most compilers */ - /* Here, scan <= window+strstart+257 */ - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + /* Here, scan <= window + strstart + 257 */ + Assert(scan <= s->window + (unsigned)(s->window_size - 1), + "wild scan"); if (*scan == *match) scan++; - len = (MAX_MATCH - 1) - (int)(strend-scan); + len = (MAX_MATCH - 1) - (int)(strend - scan); scan = strend - (MAX_MATCH-1); #else /* UNALIGNED_OK */ - if (match[best_len] != scan_end || - match[best_len-1] != scan_end1 || - *match != *scan || - *++match != scan[1]) continue; + if (match[best_len] != scan_end || + match[best_len - 1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; - /* The check at best_len-1 can be removed because it will be made + /* The check at best_len - 1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that @@ -1343,7 +1436,7 @@ local uInt longest_match(s, cur_match) Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. + * the 256th check will be made at strstart + 258. */ do { } while (*++scan == *++match && *++scan == *++match && @@ -1352,7 +1445,8 @@ local uInt longest_match(s, cur_match) *++scan == *++match && *++scan == *++match && scan < strend); - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + Assert(scan <= s->window + (unsigned)(s->window_size - 1), + "wild scan"); len = MAX_MATCH - (int)(strend - scan); scan = strend - MAX_MATCH; @@ -1364,9 +1458,9 @@ local uInt longest_match(s, cur_match) best_len = len; if (len >= nice_match) break; #ifdef UNALIGNED_OK - scan_end = *(ushf*)(scan+best_len-1); + scan_end = *(ushf*)(scan + best_len - 1); #else - scan_end1 = scan[best_len-1]; + scan_end1 = scan[best_len - 1]; scan_end = scan[best_len]; #endif } @@ -1376,17 +1470,13 @@ local uInt longest_match(s, cur_match) if ((uInt)best_len <= s->lookahead) return (uInt)best_len; return s->lookahead; } -#endif /* ASMV */ #else /* FASTEST */ /* --------------------------------------------------------------------------- * Optimized version for FASTEST only */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ +local uInt longest_match(deflate_state *s, IPos cur_match) { register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ @@ -1397,7 +1487,8 @@ local uInt longest_match(s, cur_match) */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "need lookahead"); Assert(cur_match < s->strstart, "no future"); @@ -1407,7 +1498,7 @@ local uInt longest_match(s, cur_match) */ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; - /* The check at best_len-1 can be removed because it will be made + /* The check at best_len - 1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that @@ -1417,7 +1508,7 @@ local uInt longest_match(s, cur_match) Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. + * the 256th check will be made at strstart + 258. */ do { } while (*++scan == *++match && *++scan == *++match && @@ -1426,7 +1517,7 @@ local uInt longest_match(s, cur_match) *++scan == *++match && *++scan == *++match && scan < strend); - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + Assert(scan <= s->window + (unsigned)(s->window_size - 1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); @@ -1446,11 +1537,7 @@ local uInt longest_match(s, cur_match) /* =========================================================================== * Check that the match at match_start is indeed a match. */ -local void check_match(s, start, match, length) - deflate_state *s; - IPos start, match; - int length; -{ +local void check_match(deflate_state *s, IPos start, IPos match, int length) { /* check that the match is indeed a match */ if (zmemcmp(s->window + match, s->window + start, length) != EQUAL) { @@ -1462,7 +1549,7 @@ local void check_match(s, start, match, length) z_error("invalid match"); } if (z_verbose > 1) { - fprintf(stderr,"\\[%d,%d]", start-match, length); + fprintf(stderr,"\\[%d,%d]", start - match, length); do { putc(s->window[start++], stderr); } while (--length != 0); } } @@ -1470,135 +1557,6 @@ local void check_match(s, start, match, length) # define check_match(s, start, match, length) #endif /* ZLIB_DEBUG */ -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ -local void fill_window(s) - deflate_state *s; -{ - unsigned n; - unsigned more; /* Amount of free space at the end of the window. */ - uInt wsize = s->w_size; - - Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); - - do { - more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); - - /* Deal with !@#$% 64K limit: */ - if (sizeof(int) <= 2) { - if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - more = wsize; - - } else if (more == (unsigned)(-1)) { - /* Very unlikely, but possible on 16 bit machine if - * strstart == 0 && lookahead == 1 (input done a byte at time) - */ - more--; - } - } - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (s->strstart >= wsize+MAX_DIST(s)) { - - zmemcpy(s->window, s->window+wsize, (unsigned)wsize - more); - s->match_start -= wsize; - s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ - s->block_start -= (long) wsize; - slide_hash(s); - more += wsize; - } - if (s->strm->avail_in == 0) break; - - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - Assert(more >= 2, "more < 2"); - - n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); - s->lookahead += n; - - /* Initialize the hash value now that we have some input: */ - if (s->lookahead + s->insert >= MIN_MATCH) { - uInt str = s->strstart - s->insert; - s->ins_h = s->window[str]; - UPDATE_HASH(s, s->ins_h, s->window[str + 1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - while (s->insert) { - UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); -#ifndef FASTEST - s->prev[str & s->w_mask] = s->head[s->ins_h]; -#endif - s->head[s->ins_h] = (Pos)str; - str++; - s->insert--; - if (s->lookahead + s->insert < MIN_MATCH) - break; - } - } - /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - * but this is not important since only literal bytes will be emitted. - */ - - } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); - - /* If the WIN_INIT bytes after the end of the current data have never been - * written, then zero those bytes in order to avoid memory check reports of - * the use of uninitialized (or uninitialised as Julian writes) bytes by - * the longest match routines. Update the high water mark for the next - * time through here. WIN_INIT is set to MAX_MATCH since the longest match - * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. - */ - if (s->high_water < s->window_size) { - ulg curr = s->strstart + (ulg)(s->lookahead); - ulg init; - - if (s->high_water < curr) { - /* Previous high water mark below current data -- zero WIN_INIT - * bytes or up to end of window, whichever is less. - */ - init = s->window_size - curr; - if (init > WIN_INIT) - init = WIN_INIT; - zmemzero(s->window + curr, (unsigned)init); - s->high_water = curr + init; - } - else if (s->high_water < (ulg)curr + WIN_INIT) { - /* High water mark at or above current data, but below current data - * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up - * to end of window, whichever is less. - */ - init = (ulg)curr + WIN_INIT - s->high_water; - if (init > s->window_size - s->high_water) - init = s->window_size - s->high_water; - zmemzero(s->window + s->high_water, (unsigned)init); - s->high_water += init; - } - } - - Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, - "not enough room for search"); -} - /* =========================================================================== * Flush the current block, with given end-of-file flag. * IN assertion: strstart is set to the end of the current match. @@ -1639,12 +1597,9 @@ local void fill_window(s) * * deflate_stored() is written to minimize the number of times an input byte is * copied. It is most efficient with large input and output buffers, which - * maximizes the opportunites to have a single copy from next_in to next_out. + * maximizes the opportunities to have a single copy from next_in to next_out. */ -local block_state deflate_stored(s, flush) - deflate_state *s; - int flush; -{ +local block_state deflate_stored(deflate_state *s, int flush) { /* Smallest worthy block size when not flushing or finishing. By default * this is 32K. This can be as small as 507 bytes for memLevel == 1. For * large input and output buffers, the stored block size will be larger. @@ -1743,6 +1698,7 @@ local block_state deflate_stored(s, flush) s->matches = 2; /* clear hash */ zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size); s->strstart = s->w_size; + s->insert = s->strstart; } else { if (s->window_size - s->strstart <= used) { @@ -1751,12 +1707,14 @@ local block_state deflate_stored(s, flush) zmemcpy(s->window, s->window + s->w_size, s->strstart); if (s->matches < 2) s->matches++; /* add a pending slide_hash() */ + if (s->insert > s->strstart) + s->insert = s->strstart; } zmemcpy(s->window + s->strstart, s->strm->next_in - used, used); s->strstart += used; + s->insert += MIN(used, s->w_size - s->insert); } s->block_start = s->strstart; - s->insert += MIN(used, s->w_size - s->insert); } if (s->high_water < s->strstart) s->high_water = s->strstart; @@ -1771,7 +1729,7 @@ local block_state deflate_stored(s, flush) return block_done; /* Fill the window with any remaining input. */ - have = s->window_size - s->strstart - 1; + have = s->window_size - s->strstart; if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) { /* Slide the window down. */ s->block_start -= s->w_size; @@ -1780,12 +1738,15 @@ local block_state deflate_stored(s, flush) if (s->matches < 2) s->matches++; /* add a pending slide_hash() */ have += s->w_size; /* more space now */ + if (s->insert > s->strstart) + s->insert = s->strstart; } if (have > s->strm->avail_in) have = s->strm->avail_in; if (have) { read_buf(s->strm, s->window + s->strstart, have); s->strstart += have; + s->insert += MIN(have, s->w_size - s->insert); } if (s->high_water < s->strstart) s->high_water = s->strstart; @@ -1822,10 +1783,7 @@ local block_state deflate_stored(s, flush) * new strings in the dictionary only for unmatched strings or for short * matches. It is used only for the fast compression options. */ -local block_state deflate_fast(s, flush) - deflate_state *s; - int flush; -{ +local block_state deflate_fast(deflate_state *s, int flush) { IPos hash_head; /* head of the hash chain */ int bflush; /* set if current block must be flushed */ @@ -1843,7 +1801,7 @@ local block_state deflate_fast(s, flush) if (s->lookahead == 0) break; /* flush the current block */ } - /* Insert the string window[strstart .. strstart+2] in the + /* Insert the string window[strstart .. strstart + 2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; @@ -1891,7 +1849,7 @@ local block_state deflate_fast(s, flush) s->strstart += s->match_length; s->match_length = 0; s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); + UPDATE_HASH(s, s->ins_h, s->window[s->strstart + 1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif @@ -1902,7 +1860,7 @@ local block_state deflate_fast(s, flush) } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); + _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } @@ -1913,7 +1871,7 @@ local block_state deflate_fast(s, flush) FLUSH_BLOCK(s, 1); return finish_done; } - if (s->last_lit) + if (s->sym_next) FLUSH_BLOCK(s, 0); return block_done; } @@ -1924,10 +1882,7 @@ local block_state deflate_fast(s, flush) * evaluation for matches: a match is finally adopted only if there is * no better match at the next window position. */ -local block_state deflate_slow(s, flush) - deflate_state *s; - int flush; -{ +local block_state deflate_slow(deflate_state *s, int flush) { IPos hash_head; /* head of hash chain */ int bflush; /* set if current block must be flushed */ @@ -1946,7 +1901,7 @@ local block_state deflate_slow(s, flush) if (s->lookahead == 0) break; /* flush the current block */ } - /* Insert the string window[strstart .. strstart+2] in the + /* Insert the string window[strstart .. strstart + 2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; @@ -1988,17 +1943,17 @@ local block_state deflate_slow(s, flush) uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; /* Do not insert strings in hash table beyond this. */ - check_match(s, s->strstart-1, s->prev_match, s->prev_length); + check_match(s, s->strstart - 1, s->prev_match, s->prev_length); - _tr_tally_dist(s, s->strstart -1 - s->prev_match, + _tr_tally_dist(s, s->strstart - 1 - s->prev_match, s->prev_length - MIN_MATCH, bflush); /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not + * strstart - 1 and strstart are already inserted. If there is not * enough lookahead, the last two strings are not inserted in * the hash table. */ - s->lookahead -= s->prev_length-1; + s->lookahead -= s->prev_length - 1; s->prev_length -= 2; do { if (++s->strstart <= max_insert) { @@ -2016,8 +1971,8 @@ local block_state deflate_slow(s, flush) * single literal. If there was a match but the current match * is longer, truncate the previous match to a single literal. */ - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); + Tracevv((stderr,"%c", s->window[s->strstart - 1])); + _tr_tally_lit(s, s->window[s->strstart - 1], bflush); if (bflush) { FLUSH_BLOCK_ONLY(s, 0); } @@ -2035,8 +1990,8 @@ local block_state deflate_slow(s, flush) } Assert (flush != Z_NO_FLUSH, "no flush?"); if (s->match_available) { - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); + Tracevv((stderr,"%c", s->window[s->strstart - 1])); + _tr_tally_lit(s, s->window[s->strstart - 1], bflush); s->match_available = 0; } s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; @@ -2044,7 +1999,7 @@ local block_state deflate_slow(s, flush) FLUSH_BLOCK(s, 1); return finish_done; } - if (s->last_lit) + if (s->sym_next) FLUSH_BLOCK(s, 0); return block_done; } @@ -2055,10 +2010,7 @@ local block_state deflate_slow(s, flush) * one. Do not maintain a hash table. (It will be regenerated if this run of * deflate switches away from Z_RLE.) */ -local block_state deflate_rle(s, flush) - deflate_state *s; - int flush; -{ +local block_state deflate_rle(deflate_state *s, int flush) { int bflush; /* set if current block must be flushed */ uInt prev; /* byte at distance one to match */ Bytef *scan, *strend; /* scan goes up to strend for length of run */ @@ -2093,7 +2045,8 @@ local block_state deflate_rle(s, flush) if (s->match_length > s->lookahead) s->match_length = s->lookahead; } - Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); + Assert(scan <= s->window + (uInt)(s->window_size - 1), + "wild scan"); } /* Emit match if have run of MIN_MATCH or longer, else emit literal */ @@ -2108,7 +2061,7 @@ local block_state deflate_rle(s, flush) } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); + _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } @@ -2119,7 +2072,7 @@ local block_state deflate_rle(s, flush) FLUSH_BLOCK(s, 1); return finish_done; } - if (s->last_lit) + if (s->sym_next) FLUSH_BLOCK(s, 0); return block_done; } @@ -2128,10 +2081,7 @@ local block_state deflate_rle(s, flush) * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. * (It will be regenerated if this run of deflate switches away from Huffman.) */ -local block_state deflate_huff(s, flush) - deflate_state *s; - int flush; -{ +local block_state deflate_huff(deflate_state *s, int flush) { int bflush; /* set if current block must be flushed */ for (;;) { @@ -2148,7 +2098,7 @@ local block_state deflate_huff(s, flush) /* Output a literal byte */ s->match_length = 0; Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); + _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); @@ -2158,7 +2108,7 @@ local block_state deflate_huff(s, flush) FLUSH_BLOCK(s, 1); return finish_done; } - if (s->last_lit) + if (s->sym_next) FLUSH_BLOCK(s, 0); return block_done; } diff --git a/vendor/libgit2/deps/zlib/deflate.h b/vendor/libgit2/deps/zlib/deflate.h index 23ecdd31..86967914 100644 --- a/vendor/libgit2/deps/zlib/deflate.h +++ b/vendor/libgit2/deps/zlib/deflate.h @@ -1,5 +1,5 @@ /* deflate.h -- internal compression state - * Copyright (C) 1995-2016 Jean-loup Gailly + * Copyright (C) 1995-2018 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -217,7 +217,7 @@ typedef struct internal_state { /* Depth of each subtree used as tie breaker for trees of equal frequency */ - uchf *l_buf; /* buffer for literals or lengths */ + uchf *sym_buf; /* buffer for distances and literals/lengths */ uInt lit_bufsize; /* Size of match buffer for literals/lengths. There are 4 reasons for @@ -239,13 +239,8 @@ typedef struct internal_state { * - I can't count above 4 */ - uInt last_lit; /* running index in l_buf */ - - ushf *d_buf; - /* Buffer for distances. To simplify the code, d_buf and l_buf have - * the same number of elements. To use different lengths, an extra flag - * array would be necessary. - */ + uInt sym_next; /* running index in sym_buf */ + uInt sym_end; /* symbol table full when sym_next reaches this */ ulg opt_len; /* bit length of current block with optimal trees */ ulg static_len; /* bit length of current block with static trees */ @@ -296,14 +291,14 @@ typedef struct internal_state { memory checker errors from longest match routines */ /* in trees.c */ -void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); -int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); -void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, - ulg stored_len, int last)); -void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); -void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); -void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, - ulg stored_len, int last)); +void ZLIB_INTERNAL _tr_init(deflate_state *s); +int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc); +void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf, + ulg stored_len, int last); +void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s); +void ZLIB_INTERNAL _tr_align(deflate_state *s); +void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf, + ulg stored_len, int last); #define d_code(dist) \ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) @@ -325,20 +320,22 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, # define _tr_tally_lit(s, c, flush) \ { uch cc = (c); \ - s->d_buf[s->last_lit] = 0; \ - s->l_buf[s->last_lit++] = cc; \ + s->sym_buf[s->sym_next++] = 0; \ + s->sym_buf[s->sym_next++] = 0; \ + s->sym_buf[s->sym_next++] = cc; \ s->dyn_ltree[cc].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ + flush = (s->sym_next == s->sym_end); \ } # define _tr_tally_dist(s, distance, length, flush) \ { uch len = (uch)(length); \ ush dist = (ush)(distance); \ - s->d_buf[s->last_lit] = dist; \ - s->l_buf[s->last_lit++] = len; \ + s->sym_buf[s->sym_next++] = (uch)dist; \ + s->sym_buf[s->sym_next++] = (uch)(dist >> 8); \ + s->sym_buf[s->sym_next++] = len; \ dist--; \ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ s->dyn_dtree[d_code(dist)].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ + flush = (s->sym_next == s->sym_end); \ } #else # define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) diff --git a/vendor/libgit2/deps/zlib/gzguts.h b/vendor/libgit2/deps/zlib/gzguts.h index 990a4d25..f9375047 100644 --- a/vendor/libgit2/deps/zlib/gzguts.h +++ b/vendor/libgit2/deps/zlib/gzguts.h @@ -1,5 +1,5 @@ /* gzguts.h -- zlib internal header definitions for gz* operations - * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler + * Copyright (C) 2004-2019 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -7,9 +7,8 @@ # ifndef _LARGEFILE_SOURCE # define _LARGEFILE_SOURCE 1 # endif -# ifdef _FILE_OFFSET_BITS -# undef _FILE_OFFSET_BITS -# endif +# undef _FILE_OFFSET_BITS +# undef _TIME_BITS #endif #ifdef HAVE_HIDDEN @@ -39,7 +38,7 @@ # include #endif -#if defined(_WIN32) || defined(__CYGWIN__) +#if defined(_WIN32) # define WIDECHAR #endif @@ -119,8 +118,8 @@ /* gz* functions always use library allocation functions */ #ifndef STDC - extern voidp malloc OF((uInt size)); - extern void free OF((voidpf ptr)); + extern voidp malloc(uInt size); + extern void free(voidpf ptr); #endif /* get errno and strerror definition */ @@ -138,10 +137,10 @@ /* provide prototypes for these when building zlib without LFS */ #if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 - ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); - ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); - ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); - ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int); + ZEXTERN z_off64_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile); #endif /* default memLevel */ @@ -190,6 +189,7 @@ typedef struct { /* just for writing */ int level; /* compression level */ int strategy; /* compression strategy */ + int reset; /* true if a reset is pending after a Z_FINISH */ /* seek request */ z_off64_t skip; /* amount to skip (already rewound if backwards) */ int seek; /* true if seek request pending */ @@ -202,9 +202,9 @@ typedef struct { typedef gz_state FAR *gz_statep; /* shared functions */ -void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); +void ZLIB_INTERNAL gz_error(gz_statep, int, const char *); #if defined UNDER_CE -char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); +char ZLIB_INTERNAL *gz_strwinerror(DWORD error); #endif /* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t @@ -213,6 +213,6 @@ char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); #ifdef INT_MAX # define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) #else -unsigned ZLIB_INTERNAL gz_intmax OF((void)); +unsigned ZLIB_INTERNAL gz_intmax(void); # define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) #endif diff --git a/vendor/libgit2/deps/zlib/infback.c b/vendor/libgit2/deps/zlib/infback.c index 59679ecb..e7b25b30 100644 --- a/vendor/libgit2/deps/zlib/infback.c +++ b/vendor/libgit2/deps/zlib/infback.c @@ -1,5 +1,5 @@ /* infback.c -- inflate using a call-back interface - * Copyright (C) 1995-2016 Mark Adler + * Copyright (C) 1995-2022 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -15,9 +15,6 @@ #include "inflate.h" #include "inffast.h" -/* function prototypes */ -local void fixedtables OF((struct inflate_state FAR *state)); - /* strm provides memory allocation functions in zalloc and zfree, or Z_NULL to use the library memory allocation functions. @@ -25,13 +22,9 @@ local void fixedtables OF((struct inflate_state FAR *state)); windowBits is in the range 8..15, and window is a user-supplied window and output buffer that is 2**windowBits bytes. */ -int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) -z_streamp strm; -int windowBits; -unsigned char FAR *window; -const char *version; -int stream_size; -{ +int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits, + unsigned char FAR *window, const char *version, + int stream_size) { struct inflate_state FAR *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || @@ -66,6 +59,7 @@ int stream_size; state->window = window; state->wnext = 0; state->whave = 0; + state->sane = 1; return Z_OK; } @@ -79,9 +73,7 @@ int stream_size; used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ +local void fixedtables(struct inflate_state FAR *state) { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; @@ -247,13 +239,8 @@ struct inflate_state FAR *state; inflateBack() can also return Z_STREAM_ERROR if the input parameters are not correct, i.e. strm is Z_NULL or the state was not initialized. */ -int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) -z_streamp strm; -in_func in; -void FAR *in_desc; -out_func out; -void FAR *out_desc; -{ +int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc) { struct inflate_state FAR *state; z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ @@ -477,6 +464,7 @@ void FAR *out_desc; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN; + /* fallthrough */ case LEN: /* use inflate_fast() if we have enough input and output */ @@ -604,33 +592,33 @@ void FAR *out_desc; break; case DONE: - /* inflate stream terminated properly -- write leftover output */ + /* inflate stream terminated properly */ ret = Z_STREAM_END; - if (left < state->wsize) { - if (out(out_desc, state->window, state->wsize - left)) - ret = Z_BUF_ERROR; - } goto inf_leave; case BAD: ret = Z_DATA_ERROR; goto inf_leave; - default: /* can't happen, but makes compilers happy */ + default: + /* can't happen, but makes compilers happy */ ret = Z_STREAM_ERROR; goto inf_leave; } - /* Return unused input */ + /* Write leftover output and return unused input */ inf_leave: + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left) && + ret == Z_STREAM_END) + ret = Z_BUF_ERROR; + } strm->next_in = next; strm->avail_in = have; return ret; } -int ZEXPORT inflateBackEnd(strm) -z_streamp strm; -{ +int ZEXPORT inflateBackEnd(z_streamp strm) { if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) return Z_STREAM_ERROR; ZFREE(strm, strm->state); diff --git a/vendor/libgit2/deps/zlib/inffast.c b/vendor/libgit2/deps/zlib/inffast.c index 0dbd1dbc..9354676e 100644 --- a/vendor/libgit2/deps/zlib/inffast.c +++ b/vendor/libgit2/deps/zlib/inffast.c @@ -47,10 +47,7 @@ requires strm->avail_out >= 258 for each loop to avoid checking for output space. */ -void ZLIB_INTERNAL inflate_fast(strm, start) -z_streamp strm; -unsigned start; /* inflate()'s starting value for strm->avail_out */ -{ +void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) { struct inflate_state FAR *state; z_const unsigned char FAR *in; /* local strm->next_in */ z_const unsigned char FAR *last; /* have enough input while in < last */ @@ -70,7 +67,7 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ code const FAR *dcode; /* local strm->distcode */ unsigned lmask; /* mask for first level of length codes */ unsigned dmask; /* mask for first level of distance codes */ - code here; /* retrieved table entry */ + code const *here; /* retrieved table entry */ unsigned op; /* code bits, operation, extra bits, or */ /* window position, window bytes to copy */ unsigned len; /* match length, unused bytes */ @@ -107,20 +104,20 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ hold += (unsigned long)(*in++) << bits; bits += 8; } - here = lcode[hold & lmask]; + here = lcode + (hold & lmask); dolen: - op = (unsigned)(here.bits); + op = (unsigned)(here->bits); hold >>= op; bits -= op; - op = (unsigned)(here.op); + op = (unsigned)(here->op); if (op == 0) { /* literal */ - Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ? "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", here.val)); - *out++ = (unsigned char)(here.val); + "inflate: literal 0x%02x\n", here->val)); + *out++ = (unsigned char)(here->val); } else if (op & 16) { /* length base */ - len = (unsigned)(here.val); + len = (unsigned)(here->val); op &= 15; /* number of extra bits */ if (op) { if (bits < op) { @@ -138,14 +135,14 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ hold += (unsigned long)(*in++) << bits; bits += 8; } - here = dcode[hold & dmask]; + here = dcode + (hold & dmask); dodist: - op = (unsigned)(here.bits); + op = (unsigned)(here->bits); hold >>= op; bits -= op; - op = (unsigned)(here.op); + op = (unsigned)(here->op); if (op & 16) { /* distance base */ - dist = (unsigned)(here.val); + dist = (unsigned)(here->val); op &= 15; /* number of extra bits */ if (bits < op) { hold += (unsigned long)(*in++) << bits; @@ -264,7 +261,7 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ } } else if ((op & 64) == 0) { /* 2nd level distance code */ - here = dcode[here.val + (hold & ((1U << op) - 1))]; + here = dcode + here->val + (hold & ((1U << op) - 1)); goto dodist; } else { @@ -274,7 +271,7 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ } } else if ((op & 64) == 0) { /* 2nd level length code */ - here = lcode[here.val + (hold & ((1U << op) - 1))]; + here = lcode + here->val + (hold & ((1U << op) - 1)); goto dolen; } else if (op & 32) { /* end-of-block */ diff --git a/vendor/libgit2/deps/zlib/inffast.h b/vendor/libgit2/deps/zlib/inffast.h index e5c1aa4c..49c6d156 100644 --- a/vendor/libgit2/deps/zlib/inffast.h +++ b/vendor/libgit2/deps/zlib/inffast.h @@ -8,4 +8,4 @@ subject to change. Applications should only use zlib.h. */ -void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); +void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start); diff --git a/vendor/libgit2/deps/zlib/inflate.c b/vendor/libgit2/deps/zlib/inflate.c index ac333e8c..b0757a9b 100644 --- a/vendor/libgit2/deps/zlib/inflate.c +++ b/vendor/libgit2/deps/zlib/inflate.c @@ -1,5 +1,5 @@ /* inflate.c -- zlib decompression - * Copyright (C) 1995-2016 Mark Adler + * Copyright (C) 1995-2022 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -91,20 +91,7 @@ # endif #endif -/* function prototypes */ -local int inflateStateCheck OF((z_streamp strm)); -local void fixedtables OF((struct inflate_state FAR *state)); -local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, - unsigned copy)); -#ifdef BUILDFIXED - void makefixed OF((void)); -#endif -local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, - unsigned len)); - -local int inflateStateCheck(strm) -z_streamp strm; -{ +local int inflateStateCheck(z_streamp strm) { struct inflate_state FAR *state; if (strm == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) @@ -116,9 +103,7 @@ z_streamp strm; return 0; } -int ZEXPORT inflateResetKeep(strm) -z_streamp strm; -{ +int ZEXPORT inflateResetKeep(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -130,6 +115,7 @@ z_streamp strm; state->mode = HEAD; state->last = 0; state->havedict = 0; + state->flags = -1; state->dmax = 32768U; state->head = Z_NULL; state->hold = 0; @@ -141,9 +127,7 @@ z_streamp strm; return Z_OK; } -int ZEXPORT inflateReset(strm) -z_streamp strm; -{ +int ZEXPORT inflateReset(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -154,10 +138,7 @@ z_streamp strm; return inflateResetKeep(strm); } -int ZEXPORT inflateReset2(strm, windowBits) -z_streamp strm; -int windowBits; -{ +int ZEXPORT inflateReset2(z_streamp strm, int windowBits) { int wrap; struct inflate_state FAR *state; @@ -167,6 +148,8 @@ int windowBits; /* extract wrap request from windowBits parameter */ if (windowBits < 0) { + if (windowBits < -15) + return Z_STREAM_ERROR; wrap = 0; windowBits = -windowBits; } @@ -192,12 +175,8 @@ int windowBits; return inflateReset(strm); } -int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) -z_streamp strm; -int windowBits; -const char *version; -int stream_size; -{ +int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, + const char *version, int stream_size) { int ret; struct inflate_state FAR *state; @@ -236,22 +215,17 @@ int stream_size; return ret; } -int ZEXPORT inflateInit_(strm, version, stream_size) -z_streamp strm; -const char *version; -int stream_size; -{ +int ZEXPORT inflateInit_(z_streamp strm, const char *version, + int stream_size) { return inflateInit2_(strm, DEF_WBITS, version, stream_size); } -int ZEXPORT inflatePrime(strm, bits, value) -z_streamp strm; -int bits; -int value; -{ +int ZEXPORT inflatePrime(z_streamp strm, int bits, int value) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + if (bits == 0) + return Z_OK; state = (struct inflate_state FAR *)strm->state; if (bits < 0) { state->hold = 0; @@ -275,9 +249,7 @@ int value; used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ +local void fixedtables(struct inflate_state FAR *state) { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; @@ -339,7 +311,7 @@ struct inflate_state FAR *state; a.out > inffixed.h */ -void makefixed() +void makefixed(void) { unsigned low, size; struct inflate_state state; @@ -393,11 +365,7 @@ void makefixed() output will fall in the output data, making match copies simpler and faster. The advantage may be dependent on the size of the processor's data caches. */ -local int updatewindow(strm, end, copy) -z_streamp strm; -const Bytef *end; -unsigned copy; -{ +local int updatewindow(z_streamp strm, const Bytef *end, unsigned copy) { struct inflate_state FAR *state; unsigned dist; @@ -447,10 +415,10 @@ unsigned copy; /* check function to use adler32() for zlib or crc32() for gzip */ #ifdef GUNZIP -# define UPDATE(check, buf, len) \ +# define UPDATE_CHECK(check, buf, len) \ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) #else -# define UPDATE(check, buf, len) adler32(check, buf, len) +# define UPDATE_CHECK(check, buf, len) adler32(check, buf, len) #endif /* check macros for header crc */ @@ -619,10 +587,7 @@ unsigned copy; will return Z_BUF_ERROR if it has not reached the end of the stream. */ -int ZEXPORT inflate(strm, flush) -z_streamp strm; -int flush; -{ +int ZEXPORT inflate(z_streamp strm, int flush) { struct inflate_state FAR *state; z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ @@ -670,7 +635,6 @@ int flush; state->mode = FLAGS; break; } - state->flags = 0; /* expect zlib header */ if (state->head != Z_NULL) state->head->done = -1; if (!(state->wrap & 1) || /* check if zlib header allowed */ @@ -697,6 +661,7 @@ int flush; break; } state->dmax = 1U << len; + state->flags = 0; /* indicate zlib header */ Tracev((stderr, "inflate: zlib header ok\n")); strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = hold & 0x200 ? DICTID : TYPE; @@ -722,6 +687,7 @@ int flush; CRC2(state->check, hold); INITBITS(); state->mode = TIME; + /* fallthrough */ case TIME: NEEDBITS(32); if (state->head != Z_NULL) @@ -730,6 +696,7 @@ int flush; CRC4(state->check, hold); INITBITS(); state->mode = OS; + /* fallthrough */ case OS: NEEDBITS(16); if (state->head != Z_NULL) { @@ -740,6 +707,7 @@ int flush; CRC2(state->check, hold); INITBITS(); state->mode = EXLEN; + /* fallthrough */ case EXLEN: if (state->flags & 0x0400) { NEEDBITS(16); @@ -753,14 +721,16 @@ int flush; else if (state->head != Z_NULL) state->head->extra = Z_NULL; state->mode = EXTRA; + /* fallthrough */ case EXTRA: if (state->flags & 0x0400) { copy = state->length; if (copy > have) copy = have; if (copy) { if (state->head != Z_NULL && - state->head->extra != Z_NULL) { - len = state->head->extra_len - state->length; + state->head->extra != Z_NULL && + (len = state->head->extra_len - state->length) < + state->head->extra_max) { zmemcpy(state->head->extra + len, next, len + copy > state->head->extra_max ? state->head->extra_max - len : copy); @@ -775,6 +745,7 @@ int flush; } state->length = 0; state->mode = NAME; + /* fallthrough */ case NAME: if (state->flags & 0x0800) { if (have == 0) goto inf_leave; @@ -796,6 +767,7 @@ int flush; state->head->name = Z_NULL; state->length = 0; state->mode = COMMENT; + /* fallthrough */ case COMMENT: if (state->flags & 0x1000) { if (have == 0) goto inf_leave; @@ -816,6 +788,7 @@ int flush; else if (state->head != Z_NULL) state->head->comment = Z_NULL; state->mode = HCRC; + /* fallthrough */ case HCRC: if (state->flags & 0x0200) { NEEDBITS(16); @@ -839,6 +812,7 @@ int flush; strm->adler = state->check = ZSWAP32(hold); INITBITS(); state->mode = DICT; + /* fallthrough */ case DICT: if (state->havedict == 0) { RESTORE(); @@ -846,8 +820,10 @@ int flush; } strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = TYPE; + /* fallthrough */ case TYPE: if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; + /* fallthrough */ case TYPEDO: if (state->last) { BYTEBITS(); @@ -898,8 +874,10 @@ int flush; INITBITS(); state->mode = COPY_; if (flush == Z_TREES) goto inf_leave; + /* fallthrough */ case COPY_: state->mode = COPY; + /* fallthrough */ case COPY: copy = state->length; if (copy) { @@ -935,6 +913,7 @@ int flush; Tracev((stderr, "inflate: table sizes ok\n")); state->have = 0; state->mode = LENLENS; + /* fallthrough */ case LENLENS: while (state->have < state->ncode) { NEEDBITS(3); @@ -956,6 +935,7 @@ int flush; Tracev((stderr, "inflate: code lengths ok\n")); state->have = 0; state->mode = CODELENS; + /* fallthrough */ case CODELENS: while (state->have < state->nlen + state->ndist) { for (;;) { @@ -1039,8 +1019,10 @@ int flush; Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN_; if (flush == Z_TREES) goto inf_leave; + /* fallthrough */ case LEN_: state->mode = LEN; + /* fallthrough */ case LEN: if (have >= 6 && left >= 258) { RESTORE(); @@ -1090,6 +1072,7 @@ int flush; } state->extra = (unsigned)(here.op) & 15; state->mode = LENEXT; + /* fallthrough */ case LENEXT: if (state->extra) { NEEDBITS(state->extra); @@ -1100,6 +1083,7 @@ int flush; Tracevv((stderr, "inflate: length %u\n", state->length)); state->was = state->length; state->mode = DIST; + /* fallthrough */ case DIST: for (;;) { here = state->distcode[BITS(state->distbits)]; @@ -1127,6 +1111,7 @@ int flush; state->offset = (unsigned)here.val; state->extra = (unsigned)(here.op) & 15; state->mode = DISTEXT; + /* fallthrough */ case DISTEXT: if (state->extra) { NEEDBITS(state->extra); @@ -1143,6 +1128,7 @@ int flush; #endif Tracevv((stderr, "inflate: distance %u\n", state->offset)); state->mode = MATCH; + /* fallthrough */ case MATCH: if (left == 0) goto inf_leave; copy = out - left; @@ -1202,7 +1188,7 @@ int flush; state->total += out; if ((state->wrap & 4) && out) strm->adler = state->check = - UPDATE(state->check, put - out, out); + UPDATE_CHECK(state->check, put - out, out); out = left; if ((state->wrap & 4) && ( #ifdef GUNZIP @@ -1218,10 +1204,11 @@ int flush; } #ifdef GUNZIP state->mode = LENGTH; + /* fallthrough */ case LENGTH: if (state->wrap && state->flags) { NEEDBITS(32); - if (hold != (state->total & 0xffffffffUL)) { + if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) { strm->msg = (char *)"incorrect length check"; state->mode = BAD; break; @@ -1231,6 +1218,7 @@ int flush; } #endif state->mode = DONE; + /* fallthrough */ case DONE: ret = Z_STREAM_END; goto inf_leave; @@ -1240,6 +1228,7 @@ int flush; case MEM: return Z_MEM_ERROR; case SYNC: + /* fallthrough */ default: return Z_STREAM_ERROR; } @@ -1265,7 +1254,7 @@ int flush; state->total += out; if ((state->wrap & 4) && out) strm->adler = state->check = - UPDATE(state->check, strm->next_out - out, out); + UPDATE_CHECK(state->check, strm->next_out - out, out); strm->data_type = (int)state->bits + (state->last ? 64 : 0) + (state->mode == TYPE ? 128 : 0) + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); @@ -1274,9 +1263,7 @@ int flush; return ret; } -int ZEXPORT inflateEnd(strm) -z_streamp strm; -{ +int ZEXPORT inflateEnd(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -1288,11 +1275,8 @@ z_streamp strm; return Z_OK; } -int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength) -z_streamp strm; -Bytef *dictionary; -uInt *dictLength; -{ +int ZEXPORT inflateGetDictionary(z_streamp strm, Bytef *dictionary, + uInt *dictLength) { struct inflate_state FAR *state; /* check state */ @@ -1311,11 +1295,8 @@ uInt *dictLength; return Z_OK; } -int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) -z_streamp strm; -const Bytef *dictionary; -uInt dictLength; -{ +int ZEXPORT inflateSetDictionary(z_streamp strm, const Bytef *dictionary, + uInt dictLength) { struct inflate_state FAR *state; unsigned long dictid; int ret; @@ -1346,10 +1327,7 @@ uInt dictLength; return Z_OK; } -int ZEXPORT inflateGetHeader(strm, head) -z_streamp strm; -gz_headerp head; -{ +int ZEXPORT inflateGetHeader(z_streamp strm, gz_headerp head) { struct inflate_state FAR *state; /* check state */ @@ -1374,11 +1352,8 @@ gz_headerp head; called again with more data and the *have state. *have is initialized to zero for the first call. */ -local unsigned syncsearch(have, buf, len) -unsigned FAR *have; -const unsigned char FAR *buf; -unsigned len; -{ +local unsigned syncsearch(unsigned FAR *have, const unsigned char FAR *buf, + unsigned len) { unsigned got; unsigned next; @@ -1397,10 +1372,9 @@ unsigned len; return next; } -int ZEXPORT inflateSync(strm) -z_streamp strm; -{ +int ZEXPORT inflateSync(z_streamp strm) { unsigned len; /* number of bytes to look at or looked at */ + int flags; /* temporary to save header status */ unsigned long in, out; /* temporary to save total_in and total_out */ unsigned char buf[4]; /* to restore bit buffer to byte string */ struct inflate_state FAR *state; @@ -1433,9 +1407,15 @@ z_streamp strm; /* return no joy or set up to restart inflate() on a new block */ if (state->have != 4) return Z_DATA_ERROR; + if (state->flags == -1) + state->wrap = 0; /* if no header yet, treat as raw */ + else + state->wrap &= ~4; /* no point in computing a check value now */ + flags = state->flags; in = strm->total_in; out = strm->total_out; inflateReset(strm); strm->total_in = in; strm->total_out = out; + state->flags = flags; state->mode = TYPE; return Z_OK; } @@ -1448,9 +1428,7 @@ z_streamp strm; block. When decompressing, PPP checks that at the end of input packet, inflate is waiting for these length bytes. */ -int ZEXPORT inflateSyncPoint(strm) -z_streamp strm; -{ +int ZEXPORT inflateSyncPoint(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -1458,10 +1436,7 @@ z_streamp strm; return state->mode == STORED && state->bits == 0; } -int ZEXPORT inflateCopy(dest, source) -z_streamp dest; -z_streamp source; -{ +int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) { struct inflate_state FAR *state; struct inflate_state FAR *copy; unsigned char FAR *window; @@ -1505,10 +1480,7 @@ z_streamp source; return Z_OK; } -int ZEXPORT inflateUndermine(strm, subvert) -z_streamp strm; -int subvert; -{ +int ZEXPORT inflateUndermine(z_streamp strm, int subvert) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -1523,24 +1495,19 @@ int subvert; #endif } -int ZEXPORT inflateValidate(strm, check) -z_streamp strm; -int check; -{ +int ZEXPORT inflateValidate(z_streamp strm, int check) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; - if (check) + if (check && state->wrap) state->wrap |= 4; else state->wrap &= ~4; return Z_OK; } -long ZEXPORT inflateMark(strm) -z_streamp strm; -{ +long ZEXPORT inflateMark(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) @@ -1551,9 +1518,7 @@ z_streamp strm; (state->mode == MATCH ? state->was - state->length : 0)); } -unsigned long ZEXPORT inflateCodesUsed(strm) -z_streamp strm; -{ +unsigned long ZEXPORT inflateCodesUsed(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return (unsigned long)-1; state = (struct inflate_state FAR *)strm->state; diff --git a/vendor/libgit2/deps/zlib/inflate.h b/vendor/libgit2/deps/zlib/inflate.h index a46cce6b..f127b6b1 100644 --- a/vendor/libgit2/deps/zlib/inflate.h +++ b/vendor/libgit2/deps/zlib/inflate.h @@ -1,5 +1,5 @@ /* inflate.h -- internal inflate state definition - * Copyright (C) 1995-2016 Mark Adler + * Copyright (C) 1995-2019 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -86,7 +86,8 @@ struct inflate_state { int wrap; /* bit 0 true for zlib, bit 1 true for gzip, bit 2 true to validate check value */ int havedict; /* true if dictionary provided */ - int flags; /* gzip header method and flags (0 if zlib) */ + int flags; /* gzip header method and flags, 0 if zlib, or + -1 if raw or no header yet */ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ unsigned long check; /* protected copy of check value */ unsigned long total; /* protected copy of output count */ diff --git a/vendor/libgit2/deps/zlib/inftrees.c b/vendor/libgit2/deps/zlib/inftrees.c index 2ea08fc1..8a208c2d 100644 --- a/vendor/libgit2/deps/zlib/inftrees.c +++ b/vendor/libgit2/deps/zlib/inftrees.c @@ -1,5 +1,5 @@ /* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2017 Mark Adler + * Copyright (C) 1995-2023 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -9,7 +9,7 @@ #define MAXBITS 15 const char inflate_copyright[] = - " inflate 1.2.11 Copyright 1995-2017 Mark Adler "; + " inflate 1.3 Copyright 1995-2023 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -29,14 +29,9 @@ const char inflate_copyright[] = table index bits. It will differ if the request is greater than the longest code or if it is less than the shortest code. */ -int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) -codetype type; -unsigned short FAR *lens; -unsigned codes; -code FAR * FAR *table; -unsigned FAR *bits; -unsigned short FAR *work; -{ +int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work) { unsigned len; /* a code's length in bits */ unsigned sym; /* index of code symbols */ unsigned min, max; /* minimum and maximum code lengths */ @@ -62,7 +57,7 @@ unsigned short FAR *work; 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 77, 202}; + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 198, 203}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, diff --git a/vendor/libgit2/deps/zlib/inftrees.h b/vendor/libgit2/deps/zlib/inftrees.h index baa53a0b..a10712d8 100644 --- a/vendor/libgit2/deps/zlib/inftrees.h +++ b/vendor/libgit2/deps/zlib/inftrees.h @@ -38,7 +38,7 @@ typedef struct { /* Maximum size of the dynamic table. The maximum number of code structures is 1444, which is the sum of 852 for literal/length codes and 592 for distance codes. These values were found by exhaustive searches using the program - examples/enough.c found in the zlib distribtution. The arguments to that + examples/enough.c found in the zlib distribution. The arguments to that program are the number of symbols, the initial root table size, and the maximum bit length of a code. "enough 286 9 15" for literal/length codes returns returns 852, and "enough 30 6 15" for distance codes returns 592. @@ -57,6 +57,6 @@ typedef enum { DISTS } codetype; -int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, - unsigned codes, code FAR * FAR *table, - unsigned FAR *bits, unsigned short FAR *work)); +int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work); diff --git a/vendor/libgit2/deps/zlib/trees.c b/vendor/libgit2/deps/zlib/trees.c index 50cf4b45..8dbdc40b 100644 --- a/vendor/libgit2/deps/zlib/trees.c +++ b/vendor/libgit2/deps/zlib/trees.c @@ -1,5 +1,5 @@ /* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-2017 Jean-loup Gailly + * Copyright (C) 1995-2021 Jean-loup Gailly * detect_data_type() function provided freely by Cosmin Truta, 2006 * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -122,39 +122,116 @@ struct static_tree_desc_s { int max_length; /* max bit length for the codes */ }; -local const static_tree_desc static_l_desc = +#ifdef NO_INIT_GLOBAL_POINTERS +# define TCONST +#else +# define TCONST const +#endif + +local TCONST static_tree_desc static_l_desc = {static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; -local const static_tree_desc static_d_desc = +local TCONST static_tree_desc static_d_desc = {static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; -local const static_tree_desc static_bl_desc = +local TCONST static_tree_desc static_bl_desc = {(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; /* =========================================================================== - * Local (static) routines in this file. + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} -local void tr_static_init OF((void)); -local void init_block OF((deflate_state *s)); -local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); -local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); -local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); -local void build_tree OF((deflate_state *s, tree_desc *desc)); -local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local int build_bl_tree OF((deflate_state *s)); -local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, - int blcodes)); -local void compress_block OF((deflate_state *s, const ct_data *ltree, - const ct_data *dtree)); -local int detect_data_type OF((deflate_state *s)); -local unsigned bi_reverse OF((unsigned value, int length)); -local void bi_windup OF((deflate_state *s)); -local void bi_flush OF((deflate_state *s)); +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(unsigned code, int len) { + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(deflate_state *s) { + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(deflate_state *s) { + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef ZLIB_DEBUG + s->bits_sent = (s->bits_sent + 7) & ~7; +#endif +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes(ct_data *tree, int max_code, ushf *bl_count) { + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + unsigned code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + code = (code + bl_count[bits - 1]) << 1; + next_code[bits] = (ush)code; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1, + "inconsistent bit counts"); + Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); + + for (n = 0; n <= max_code; n++) { + int len = tree[n].Len; + if (len == 0) continue; + /* Now reverse the bits */ + tree[n].Code = (ush)bi_reverse(next_code[len]++, len); + + Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", + n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len] - 1)); + } +} #ifdef GEN_TREES_H -local void gen_trees_header OF((void)); +local void gen_trees_header(void); #endif #ifndef ZLIB_DEBUG @@ -167,33 +244,18 @@ local void gen_trees_header OF((void)); send_bits(s, tree[c].Code, tree[c].Len); } #endif -/* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pendingBuf. - */ -#define put_short(s, w) { \ - put_byte(s, (uch)((w) & 0xff)); \ - put_byte(s, (uch)((ush)(w) >> 8)); \ -} - /* =========================================================================== * Send a value on a given number of bits. * IN assertion: length <= 16 and value fits in length bits. */ #ifdef ZLIB_DEBUG -local void send_bits OF((deflate_state *s, int value, int length)); - -local void send_bits(s, value, length) - deflate_state *s; - int value; /* value to send */ - int length; /* number of bits */ -{ +local void send_bits(deflate_state *s, int value, int length) { Tracevv((stderr," l %2d v %4x ", length, value)); Assert(length > 0 && length <= 15, "invalid length"); s->bits_sent += (ulg)length; /* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * (16 - bi_valid) bits from value, leaving (width - (16 - bi_valid)) * unused bits in value. */ if (s->bi_valid > (int)Buf_size - length) { @@ -229,8 +291,7 @@ local void send_bits(s, value, length) /* =========================================================================== * Initialize the various 'constant' tables. */ -local void tr_static_init() -{ +local void tr_static_init(void) { #if defined(GEN_TREES_H) || !defined(STDC) static int static_init_done = 0; int n; /* iterates over tree elements */ @@ -256,7 +317,7 @@ local void tr_static_init() length = 0; for (code = 0; code < LENGTH_CODES-1; code++) { base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ dist = 0; for (code = 0 ; code < 16; code++) { base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ for ( ; code < D_CODES; code++) { base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { _dist_code[256 + dist++] = (uch)code; } } - Assert (dist == 256, "tr_static_init: 256+dist != 512"); + Assert (dist == 256, "tr_static_init: 256 + dist != 512"); /* Construct the codes of the static literal tree */ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; @@ -312,7 +373,7 @@ local void tr_static_init() } /* =========================================================================== - * Genererate the file trees.h describing the static trees. + * Generate the file trees.h describing the static trees. */ #ifdef GEN_TREES_H # ifndef ZLIB_DEBUG @@ -321,10 +382,9 @@ local void tr_static_init() # define SEPARATOR(i, last, width) \ ((i) == (last)? "\n};\n\n" : \ - ((i) % (width) == (width)-1 ? ",\n" : ", ")) + ((i) % (width) == (width) - 1 ? ",\n" : ", ")) -void gen_trees_header() -{ +void gen_trees_header(void) { FILE *header = fopen("trees.h", "w"); int i; @@ -373,12 +433,26 @@ void gen_trees_header() } #endif /* GEN_TREES_H */ +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(deflate_state *s) { + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->sym_next = s->matches = 0; +} + /* =========================================================================== * Initialize the tree data structures for a new zlib stream. */ -void ZLIB_INTERNAL _tr_init(s) - deflate_state *s; -{ +void ZLIB_INTERNAL _tr_init(deflate_state *s) { tr_static_init(); s->l_desc.dyn_tree = s->dyn_ltree; @@ -401,24 +475,6 @@ void ZLIB_INTERNAL _tr_init(s) init_block(s); } -/* =========================================================================== - * Initialize a new block. - */ -local void init_block(s) - deflate_state *s; -{ - int n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; - for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; - for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; - - s->dyn_ltree[END_BLOCK].Freq = 1; - s->opt_len = s->static_len = 0L; - s->last_lit = s->matches = 0; -} - #define SMALLEST 1 /* Index within the heap array of least frequent node in the Huffman tree */ @@ -448,17 +504,13 @@ local void init_block(s) * when the heap property is re-established (each father smaller than its * two sons). */ -local void pqdownheap(s, tree, k) - deflate_state *s; - ct_data *tree; /* the tree to restore */ - int k; /* node to move down */ -{ +local void pqdownheap(deflate_state *s, ct_data *tree, int k) { int v = s->heap[k]; int j = k << 1; /* left son of k */ while (j <= s->heap_len) { /* Set j to the smallest of the two sons: */ if (j < s->heap_len && - smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + smaller(tree, s->heap[j + 1], s->heap[j], s->depth)) { j++; } /* Exit if v is smaller than both sons */ @@ -483,10 +535,7 @@ local void pqdownheap(s, tree, k) * The length opt_len is updated; static_len is also updated if stree is * not null. */ -local void gen_bitlen(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ -{ +local void gen_bitlen(deflate_state *s, tree_desc *desc) { ct_data *tree = desc->dyn_tree; int max_code = desc->max_code; const ct_data *stree = desc->stat_desc->static_tree; @@ -507,7 +556,7 @@ local void gen_bitlen(s, desc) */ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ - for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + for (h = s->heap_max + 1; h < HEAP_SIZE; h++) { n = s->heap[h]; bits = tree[tree[n].Dad].Len + 1; if (bits > max_length) bits = max_length, overflow++; @@ -518,7 +567,7 @@ local void gen_bitlen(s, desc) s->bl_count[bits]++; xbits = 0; - if (n >= base) xbits = extra[n-base]; + if (n >= base) xbits = extra[n - base]; f = tree[n].Freq; s->opt_len += (ulg)f * (unsigned)(bits + xbits); if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits); @@ -530,10 +579,10 @@ local void gen_bitlen(s, desc) /* Find the first bit length which could increase: */ do { - bits = max_length-1; + bits = max_length - 1; while (s->bl_count[bits] == 0) bits--; - s->bl_count[bits]--; /* move one leaf down the tree */ - s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits + 1] += 2; /* move one overflow item as its brother */ s->bl_count[max_length]--; /* The brother of the overflow item also moves one step up, * but this does not affect bl_count[max_length] @@ -561,48 +610,9 @@ local void gen_bitlen(s, desc) } } -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -local void gen_codes (tree, max_code, bl_count) - ct_data *tree; /* the tree to decorate */ - int max_code; /* largest code with non zero frequency */ - ushf *bl_count; /* number of codes at each bit length */ -{ - ush next_code[MAX_BITS+1]; /* next code value for each bit length */ - unsigned code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - code = (code + bl_count[bits-1]) << 1; - next_code[bits] = (ush)code; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - Assert (code + bl_count[MAX_BITS]-1 == (1< +#endif /* =========================================================================== * Construct one Huffman tree and assigns the code bit strings and lengths. @@ -612,10 +622,7 @@ local void gen_codes (tree, max_code, bl_count) * and corresponding code. The length opt_len is updated; static_len is * also updated if stree is not null. The field max_code is set. */ -local void build_tree(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ -{ +local void build_tree(deflate_state *s, tree_desc *desc) { ct_data *tree = desc->dyn_tree; const ct_data *stree = desc->stat_desc->static_tree; int elems = desc->stat_desc->elems; @@ -624,7 +631,7 @@ local void build_tree(s, desc) int node; /* new node being created */ /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n + 1]. * heap[0] is not used. */ s->heap_len = 0, s->heap_max = HEAP_SIZE; @@ -652,7 +659,7 @@ local void build_tree(s, desc) } desc->max_code = max_code; - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + /* The elements heap[heap_len/2 + 1 .. heap_len] are leaves of the tree, * establish sub-heaps of increasing lengths: */ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); @@ -700,11 +707,7 @@ local void build_tree(s, desc) * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ -local void scan_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ +local void scan_tree(deflate_state *s, ct_data *tree, int max_code) { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ @@ -714,10 +717,10 @@ local void scan_tree (s, tree, max_code) int min_count = 4; /* min repeat count */ if (nextlen == 0) max_count = 138, min_count = 3; - tree[max_code+1].Len = (ush)0xffff; /* guard */ + tree[max_code + 1].Len = (ush)0xffff; /* guard */ for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; + curlen = nextlen; nextlen = tree[n + 1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { @@ -745,11 +748,7 @@ local void scan_tree (s, tree, max_code) * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ -local void send_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ +local void send_tree(deflate_state *s, ct_data *tree, int max_code) { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ @@ -758,11 +757,11 @@ local void send_tree (s, tree, max_code) int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ - /* tree[max_code+1].Len = -1; */ /* guard already set */ + /* tree[max_code + 1].Len = -1; */ /* guard already set */ if (nextlen == 0) max_count = 138, min_count = 3; for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; + curlen = nextlen; nextlen = tree[n + 1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { @@ -773,13 +772,13 @@ local void send_tree (s, tree, max_code) send_code(s, curlen, s->bl_tree); count--; } Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count - 3, 2); } else if (count <= 10) { - send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count - 3, 3); } else { - send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count - 11, 7); } count = 0; prevlen = curlen; if (nextlen == 0) { @@ -796,9 +795,7 @@ local void send_tree (s, tree, max_code) * Construct the Huffman tree for the bit lengths and return the index in * bl_order of the last bit length code to send. */ -local int build_bl_tree(s) - deflate_state *s; -{ +local int build_bl_tree(deflate_state *s) { int max_blindex; /* index of last bit length code of non zero freq */ /* Determine the bit length frequencies for literal and distance trees */ @@ -807,8 +804,8 @@ local int build_bl_tree(s) /* Build the bit length tree: */ build_tree(s, (tree_desc *)(&(s->bl_desc))); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + /* opt_len now includes the length of the tree representations, except the + * lengths of the bit lengths codes and the 5 + 5 + 4 bits for the counts. */ /* Determine the number of bit length codes to send. The pkzip format @@ -819,7 +816,7 @@ local int build_bl_tree(s) if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; } /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4; + s->opt_len += 3*((ulg)max_blindex + 1) + 5 + 5 + 4; Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", s->opt_len, s->static_len)); @@ -831,61 +828,54 @@ local int build_bl_tree(s) * lengths of the bit length codes, the literal tree and the distance tree. * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. */ -local void send_all_trees(s, lcodes, dcodes, blcodes) - deflate_state *s; - int lcodes, dcodes, blcodes; /* number of codes for each tree */ -{ +local void send_all_trees(deflate_state *s, int lcodes, int dcodes, + int blcodes) { int rank; /* index in bl_order */ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes - 1, 5); + send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */ for (rank = 0; rank < blcodes; rank++) { Tracev((stderr, "\nbl code %2d ", bl_order[rank])); send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); } Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + send_tree(s, (ct_data *)s->dyn_ltree, lcodes - 1); /* literal tree */ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + send_tree(s, (ct_data *)s->dyn_dtree, dcodes - 1); /* distance tree */ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); } /* =========================================================================== * Send a stored block */ -void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) - deflate_state *s; - charf *buf; /* input block */ - ulg stored_len; /* length of input block */ - int last; /* one if this is the last block for a file */ -{ - send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ +void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf, + ulg stored_len, int last) { + send_bits(s, (STORED_BLOCK<<1) + last, 3); /* send block type */ bi_windup(s); /* align on byte boundary */ put_short(s, (ush)stored_len); put_short(s, (ush)~stored_len); - zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len); + if (stored_len) + zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len); s->pending += stored_len; #ifdef ZLIB_DEBUG s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; s->compressed_len += (stored_len + 4) << 3; s->bits_sent += 2*16; - s->bits_sent += stored_len<<3; + s->bits_sent += stored_len << 3; #endif } /* =========================================================================== * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) */ -void ZLIB_INTERNAL _tr_flush_bits(s) - deflate_state *s; -{ +void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s) { bi_flush(s); } @@ -893,9 +883,7 @@ void ZLIB_INTERNAL _tr_flush_bits(s) * Send one empty static block to give enough lookahead for inflate. * This takes 10 bits, of which 7 may remain in the bit buffer. */ -void ZLIB_INTERNAL _tr_align(s) - deflate_state *s; -{ +void ZLIB_INTERNAL _tr_align(deflate_state *s) { send_bits(s, STATIC_TREES<<1, 3); send_code(s, END_BLOCK, static_ltree); #ifdef ZLIB_DEBUG @@ -904,16 +892,99 @@ void ZLIB_INTERNAL _tr_align(s) bi_flush(s); } +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(deflate_state *s, const ct_data *ltree, + const ct_data *dtree) { + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned sx = 0; /* running index in sym_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->sym_next != 0) do { + dist = s->sym_buf[sx++] & 0xff; + dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8; + lc = s->sym_buf[sx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code + LITERALS + 1, ltree); /* send length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= (unsigned)base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and sym_buf is ok: */ + Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow"); + + } while (sx < s->sym_next); + + send_code(s, END_BLOCK, ltree); +} + +/* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "block list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local int detect_data_type(deflate_state *s) { + /* block_mask is the bit mask of block-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + unsigned long block_mask = 0xf3ffc07fUL; + int n; + + /* Check for non-textual ("block-listed") bytes. */ + for (n = 0; n <= 31; n++, block_mask >>= 1) + if ((block_mask & 1) && (s->dyn_ltree[n].Freq != 0)) + return Z_BINARY; + + /* Check for textual ("allow-listed") bytes. */ + if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 + || s->dyn_ltree[13].Freq != 0) + return Z_TEXT; + for (n = 32; n < LITERALS; n++) + if (s->dyn_ltree[n].Freq != 0) + return Z_TEXT; + + /* There are no "block-listed" or "allow-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; +} + /* =========================================================================== * Determine the best encoding for the current block: dynamic trees, static * trees or store, and write out the encoded block. */ -void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) - deflate_state *s; - charf *buf; /* input block, or NULL if too old */ - ulg stored_len; /* length of input block */ - int last; /* one if this is the last block for a file */ -{ +void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf, + ulg stored_len, int last) { ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ int max_blindex = 0; /* index of last bit length code of non zero freq */ @@ -942,14 +1013,17 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) max_blindex = build_bl_tree(s); /* Determine the best encoding. Compute the block lengths in bytes. */ - opt_lenb = (s->opt_len+3+7)>>3; - static_lenb = (s->static_len+3+7)>>3; + opt_lenb = (s->opt_len + 3 + 7) >> 3; + static_lenb = (s->static_len + 3 + 7) >> 3; Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, - s->last_lit)); + s->sym_next / 3)); - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; +#ifndef FORCE_STATIC + if (static_lenb <= opt_lenb || s->strategy == Z_FIXED) +#endif + opt_lenb = static_lenb; } else { Assert(buf != (char*)0, "lost buf"); @@ -959,7 +1033,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) #ifdef FORCE_STORED if (buf != (char*)0) { /* force stored block */ #else - if (stored_len+4 <= opt_lenb && buf != (char*)0) { + if (stored_len + 4 <= opt_lenb && buf != (char*)0) { /* 4: two words for the lengths */ #endif /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. @@ -970,21 +1044,17 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) */ _tr_stored_block(s, buf, stored_len, last); -#ifdef FORCE_STATIC - } else if (static_lenb >= 0) { /* force static trees */ -#else - } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { -#endif - send_bits(s, (STATIC_TREES<<1)+last, 3); + } else if (static_lenb == opt_lenb) { + send_bits(s, (STATIC_TREES<<1) + last, 3); compress_block(s, (const ct_data *)static_ltree, (const ct_data *)static_dtree); #ifdef ZLIB_DEBUG s->compressed_len += 3 + s->static_len; #endif } else { - send_bits(s, (DYN_TREES<<1)+last, 3); - send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, - max_blindex+1); + send_bits(s, (DYN_TREES<<1) + last, 3); + send_all_trees(s, s->l_desc.max_code + 1, s->d_desc.max_code + 1, + max_blindex + 1); compress_block(s, (const ct_data *)s->dyn_ltree, (const ct_data *)s->dyn_dtree); #ifdef ZLIB_DEBUG @@ -1003,21 +1073,18 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) s->compressed_len += 7; /* align on byte boundary */ #endif } - Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - s->compressed_len-7*last)); + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len >> 3, + s->compressed_len - 7*last)); } /* =========================================================================== * Save the match info and tally the frequency counts. Return true if * the current block must be flushed. */ -int ZLIB_INTERNAL _tr_tally (s, dist, lc) - deflate_state *s; - unsigned dist; /* distance of matched string */ - unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ -{ - s->d_buf[s->last_lit] = (ush)dist; - s->l_buf[s->last_lit++] = (uch)lc; +int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc) { + s->sym_buf[s->sym_next++] = (uch)dist; + s->sym_buf[s->sym_next++] = (uch)(dist >> 8); + s->sym_buf[s->sym_next++] = (uch)lc; if (dist == 0) { /* lc is the unmatched char */ s->dyn_ltree[lc].Freq++; @@ -1029,175 +1096,8 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc) (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_ltree[_length_code[lc] + LITERALS + 1].Freq++; s->dyn_dtree[d_code(dist)].Freq++; } - -#ifdef TRUNCATE_BLOCK - /* Try to guess if it is profitable to stop the current block here */ - if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { - /* Compute an upper bound for the compressed length */ - ulg out_length = (ulg)s->last_lit*8L; - ulg in_length = (ulg)((long)s->strstart - s->block_start); - int dcode; - for (dcode = 0; dcode < D_CODES; dcode++) { - out_length += (ulg)s->dyn_dtree[dcode].Freq * - (5L+extra_dbits[dcode]); - } - out_length >>= 3; - Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", - s->last_lit, in_length, out_length, - 100L - out_length*100L/in_length)); - if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; - } -#endif - return (s->last_lit == s->lit_bufsize-1); - /* We avoid equality with lit_bufsize because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ -} - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -local void compress_block(s, ltree, dtree) - deflate_state *s; - const ct_data *ltree; /* literal tree */ - const ct_data *dtree; /* distance tree */ -{ - unsigned dist; /* distance of matched string */ - int lc; /* match length or unmatched char (if dist == 0) */ - unsigned lx = 0; /* running index in l_buf */ - unsigned code; /* the code to send */ - int extra; /* number of extra bits to send */ - - if (s->last_lit != 0) do { - dist = s->d_buf[lx]; - lc = s->l_buf[lx++]; - if (dist == 0) { - send_code(s, lc, ltree); /* send a literal byte */ - Tracecv(isgraph(lc), (stderr," '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = _length_code[lc]; - send_code(s, code+LITERALS+1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra != 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); /* send the extra length bits */ - } - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - Assert (code < D_CODES, "bad d_code"); - - send_code(s, code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra != 0) { - dist -= (unsigned)base_dist[code]; - send_bits(s, dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - - /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ - Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, - "pendingBuf overflow"); - - } while (lx < s->last_lit); - - send_code(s, END_BLOCK, ltree); -} - -/* =========================================================================== - * Check if the data type is TEXT or BINARY, using the following algorithm: - * - TEXT if the two conditions below are satisfied: - * a) There are no non-portable control characters belonging to the - * "black list" (0..6, 14..25, 28..31). - * b) There is at least one printable character belonging to the - * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). - * - BINARY otherwise. - * - The following partially-portable control characters form a - * "gray list" that is ignored in this detection algorithm: - * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). - * IN assertion: the fields Freq of dyn_ltree are set. - */ -local int detect_data_type(s) - deflate_state *s; -{ - /* black_mask is the bit mask of black-listed bytes - * set bits 0..6, 14..25, and 28..31 - * 0xf3ffc07f = binary 11110011111111111100000001111111 - */ - unsigned long black_mask = 0xf3ffc07fUL; - int n; - - /* Check for non-textual ("black-listed") bytes. */ - for (n = 0; n <= 31; n++, black_mask >>= 1) - if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0)) - return Z_BINARY; - - /* Check for textual ("white-listed") bytes. */ - if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 - || s->dyn_ltree[13].Freq != 0) - return Z_TEXT; - for (n = 32; n < LITERALS; n++) - if (s->dyn_ltree[n].Freq != 0) - return Z_TEXT; - - /* There are no "black-listed" or "white-listed" bytes: - * this stream either is empty or has tolerated ("gray-listed") bytes only. - */ - return Z_BINARY; -} - -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -local unsigned bi_reverse(code, len) - unsigned code; /* the value to invert */ - int len; /* its bit length */ -{ - register unsigned res = 0; - do { - res |= code & 1; - code >>= 1, res <<= 1; - } while (--len > 0); - return res >> 1; -} - -/* =========================================================================== - * Flush the bit buffer, keeping at most 7 bits in it. - */ -local void bi_flush(s) - deflate_state *s; -{ - if (s->bi_valid == 16) { - put_short(s, s->bi_buf); - s->bi_buf = 0; - s->bi_valid = 0; - } else if (s->bi_valid >= 8) { - put_byte(s, (Byte)s->bi_buf); - s->bi_buf >>= 8; - s->bi_valid -= 8; - } -} - -/* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ -local void bi_windup(s) - deflate_state *s; -{ - if (s->bi_valid > 8) { - put_short(s, s->bi_buf); - } else if (s->bi_valid > 0) { - put_byte(s, (Byte)s->bi_buf); - } - s->bi_buf = 0; - s->bi_valid = 0; -#ifdef ZLIB_DEBUG - s->bits_sent = (s->bits_sent+7) & ~7; -#endif + return (s->sym_next == s->sym_end); } diff --git a/vendor/libgit2/deps/zlib/zconf.h b/vendor/libgit2/deps/zlib/zconf.h index 5e1d68a0..fb76ffe3 100644 --- a/vendor/libgit2/deps/zlib/zconf.h +++ b/vendor/libgit2/deps/zlib/zconf.h @@ -38,6 +38,9 @@ # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 +# define crc32_combine_gen z_crc32_combine_gen +# define crc32_combine_gen64 z_crc32_combine_gen64 +# define crc32_combine_op z_crc32_combine_op # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound @@ -238,7 +241,11 @@ #endif #ifdef Z_SOLO - typedef unsigned long z_size_t; +# ifdef _WIN64 + typedef unsigned long long z_size_t; +# else + typedef unsigned long z_size_t; +# endif #else # define z_longlong long long # if defined(NO_SIZE_T) @@ -349,6 +356,9 @@ # ifdef FAR # undef FAR # endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif # include /* No need for _export, use ZLIB.DEF instead. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ @@ -467,11 +477,18 @@ typedef uLong FAR uLongf; # undef _LARGEFILE64_SOURCE #endif -#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) -# define Z_HAVE_UNISTD_H +#ifndef Z_HAVE_UNISTD_H +# ifdef __WATCOMC__ +# define Z_HAVE_UNISTD_H +# endif +#endif +#ifndef Z_HAVE_UNISTD_H +# if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32) +# define Z_HAVE_UNISTD_H +# endif #endif #ifndef Z_SOLO -# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# if defined(Z_HAVE_UNISTD_H) # include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include /* for off_t */ @@ -507,7 +524,7 @@ typedef uLong FAR uLongf; #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else -# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# if defined(_WIN32) && !defined(__GNUC__) # define z_off64_t __int64 # else # define z_off64_t z_off_t diff --git a/vendor/libgit2/deps/zlib/zlib.h b/vendor/libgit2/deps/zlib/zlib.h index f09cdaf1..6b7244f9 100644 --- a/vendor/libgit2/deps/zlib/zlib.h +++ b/vendor/libgit2/deps/zlib/zlib.h @@ -1,7 +1,7 @@ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.11, January 15th, 2017 + version 1.3, August 18th, 2023 - Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler + Copyright (C) 1995-2023 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -37,11 +37,11 @@ extern "C" { #endif -#define ZLIB_VERSION "1.2.11" -#define ZLIB_VERNUM 0x12b0 +#define ZLIB_VERSION "1.3" +#define ZLIB_VERNUM 0x1300 #define ZLIB_VER_MAJOR 1 -#define ZLIB_VER_MINOR 2 -#define ZLIB_VER_REVISION 11 +#define ZLIB_VER_MINOR 3 +#define ZLIB_VER_REVISION 0 #define ZLIB_VER_SUBREVISION 0 /* @@ -78,8 +78,8 @@ extern "C" { even in the case of corrupted input. */ -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address)); +typedef voidpf (*alloc_func)(voidpf opaque, uInt items, uInt size); +typedef void (*free_func)(voidpf opaque, voidpf address); struct internal_state; @@ -217,7 +217,7 @@ typedef gz_header FAR *gz_headerp; /* basic functions */ -ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +ZEXTERN const char * ZEXPORT zlibVersion(void); /* The application can compare zlibVersion and ZLIB_VERSION for consistency. If the first character differs, the library code actually used is not compatible with the zlib.h header file used by the application. This check @@ -225,12 +225,12 @@ ZEXTERN const char * ZEXPORT zlibVersion OF((void)); */ /* -ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); +ZEXTERN int ZEXPORT deflateInit(z_streamp strm, int level); Initializes the internal stream state for compression. The fields zalloc, zfree and opaque must be initialized before by the caller. If zalloc and zfree are set to Z_NULL, deflateInit updates them to use default - allocation functions. + allocation functions. total_in, total_out, adler, and msg are initialized. The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: 1 gives best speed, 9 gives best compression, 0 gives no compression at all @@ -247,7 +247,7 @@ ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); */ -ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +ZEXTERN int ZEXPORT deflate(z_streamp strm, int flush); /* deflate compresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce @@ -276,7 +276,7 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. See deflatePending(), - which can be used if desired to determine whether or not there is more ouput + which can be used if desired to determine whether or not there is more output in that case. Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to @@ -320,8 +320,8 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that - avail_out is greater than six to avoid repeated flush markers due to - avail_out == 0 on return. + avail_out is greater than six when the flush marker begins, in order to avoid + repeated flush markers upon calling deflate() again when avail_out == 0. If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there was @@ -360,7 +360,7 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); */ -ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +ZEXTERN int ZEXPORT deflateEnd(z_streamp strm); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending @@ -375,7 +375,7 @@ ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); /* -ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); +ZEXTERN int ZEXPORT inflateInit(z_streamp strm); Initializes the internal stream state for decompression. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by @@ -383,7 +383,8 @@ ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); read or consumed. The allocation of a sliding window will be deferred to the first call of inflate (if the decompression does not complete on the first call). If zalloc and zfree are set to Z_NULL, inflateInit updates - them to use default allocation functions. + them to use default allocation functions. total_in, total_out, adler, and + msg are initialized. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the @@ -397,7 +398,7 @@ ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); */ -ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +ZEXTERN int ZEXPORT inflate(z_streamp strm, int flush); /* inflate decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce @@ -517,7 +518,7 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); */ -ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +ZEXTERN int ZEXPORT inflateEnd(z_streamp strm); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending @@ -535,16 +536,15 @@ ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); */ /* -ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy)); +ZEXTERN int ZEXPORT deflateInit2(z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy); This is another version of deflateInit with more compression options. The - fields next_in, zalloc, zfree and opaque must be initialized before by the - caller. + fields zalloc, zfree and opaque must be initialized before by the caller. The method parameter is the compression method. It must be Z_DEFLATED in this version of the library. @@ -608,9 +608,9 @@ ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, compression: this will be done by deflate(). */ -ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); +ZEXTERN int ZEXPORT deflateSetDictionary(z_streamp strm, + const Bytef *dictionary, + uInt dictLength); /* Initializes the compression dictionary from the given byte sequence without producing any compressed output. When using the zlib format, this @@ -652,16 +652,16 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, not perform any compression: this will be done by deflate(). */ -ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, - Bytef *dictionary, - uInt *dictLength)); +ZEXTERN int ZEXPORT deflateGetDictionary(z_streamp strm, + Bytef *dictionary, + uInt *dictLength); /* Returns the sliding dictionary being maintained by deflate. dictLength is set to the number of bytes in the dictionary, and that many bytes are copied to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If deflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. - Similary, if dictLength is Z_NULL, then it is not set. + Similarly, if dictLength is Z_NULL, then it is not set. deflateGetDictionary() may return a length less than the window size, even when more than the window size in input has been provided. It may return up @@ -674,8 +674,8 @@ ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, stream state is inconsistent. */ -ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, - z_streamp source)); +ZEXTERN int ZEXPORT deflateCopy(z_streamp dest, + z_streamp source); /* Sets the destination stream as a complete copy of the source stream. @@ -692,31 +692,32 @@ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, destination. */ -ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +ZEXTERN int ZEXPORT deflateReset(z_streamp strm); /* This function is equivalent to deflateEnd followed by deflateInit, but does not free and reallocate the internal compression state. The stream will leave the compression level and any other attributes that may have been - set unchanged. + set unchanged. total_in, total_out, adler, and msg are initialized. deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ -ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, - int level, - int strategy)); +ZEXTERN int ZEXPORT deflateParams(z_streamp strm, + int level, + int strategy); /* Dynamically update the compression level and compression strategy. The interpretation of level and strategy is as in deflateInit2(). This can be used to switch between compression and straight copy of the input data, or to switch to a different kind of input data requiring a different strategy. If the compression approach (which is a function of the level) or the - strategy is changed, and if any input has been consumed in a previous - deflate() call, then the input available so far is compressed with the old - level and strategy using deflate(strm, Z_BLOCK). There are three approaches - for the compression levels 0, 1..3, and 4..9 respectively. The new level - and strategy will take effect at the next call of deflate(). + strategy is changed, and if there have been any deflate() calls since the + state was initialized or reset, then the input available so far is + compressed with the old level and strategy using deflate(strm, Z_BLOCK). + There are three approaches for the compression levels 0, 1..3, and 4..9 + respectively. The new level and strategy will take effect at the next call + of deflate(). If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does not have enough output space to complete, then the parameter change will not @@ -729,7 +730,7 @@ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, Then no more input data should be provided before the deflateParams() call. If this is done, the old level and strategy will be applied to the data compressed before deflateParams(), and the new level and strategy will be - applied to the the data compressed after deflateParams(). + applied to the data compressed after deflateParams(). deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if @@ -740,11 +741,11 @@ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, retried with more output space. */ -ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, - int good_length, - int max_lazy, - int nice_length, - int max_chain)); +ZEXTERN int ZEXPORT deflateTune(z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain); /* Fine tune deflate's internal compression parameters. This should only be used by someone who understands the algorithm used by zlib's deflate for @@ -757,8 +758,8 @@ ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. */ -ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, - uLong sourceLen)); +ZEXTERN uLong ZEXPORT deflateBound(z_streamp strm, + uLong sourceLen); /* deflateBound() returns an upper bound on the compressed size after deflation of sourceLen bytes. It must be called after deflateInit() or @@ -772,9 +773,9 @@ ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, than Z_FINISH or Z_NO_FLUSH are used. */ -ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, - unsigned *pending, - int *bits)); +ZEXTERN int ZEXPORT deflatePending(z_streamp strm, + unsigned *pending, + int *bits); /* deflatePending() returns the number of bytes and bits of output that have been generated, but not yet provided in the available output. The bytes not @@ -787,9 +788,9 @@ ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, stream state was inconsistent. */ -ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, - int bits, - int value)); +ZEXTERN int ZEXPORT deflatePrime(z_streamp strm, + int bits, + int value); /* deflatePrime() inserts bits in the deflate output stream. The intent is that this function is used to start off the deflate output with the bits @@ -804,8 +805,8 @@ ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, source stream state was inconsistent. */ -ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, - gz_headerp head)); +ZEXTERN int ZEXPORT deflateSetHeader(z_streamp strm, + gz_headerp head); /* deflateSetHeader() provides gzip header information for when a gzip stream is requested by deflateInit2(). deflateSetHeader() may be called @@ -821,16 +822,17 @@ ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, gzip file" and give up. If deflateSetHeader is not used, the default gzip header has text false, - the time set to zero, and os set to 255, with no extra, name, or comment - fields. The gzip header is returned to the default state by deflateReset(). + the time set to zero, and os set to the current operating system, with no + extra, name, or comment fields. The gzip header is returned to the default + state by deflateReset(). deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* -ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, - int windowBits)); +ZEXTERN int ZEXPORT inflateInit2(z_streamp strm, + int windowBits); This is another version of inflateInit with an extra parameter. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized @@ -865,9 +867,11 @@ ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, detection, or add 16 to decode only the gzip format (the zlib format will return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see - below), inflate() will not automatically decode concatenated gzip streams. - inflate() will return Z_STREAM_END at the end of the gzip stream. The state - would need to be reset to continue decoding a subsequent gzip stream. + below), inflate() will *not* automatically decode concatenated gzip members. + inflate() will return Z_STREAM_END at the end of the gzip member. The state + would need to be reset to continue decoding a subsequent gzip member. This + *must* be done if there is more data after a gzip member, in order for the + decompression to be compliant with the gzip standard (RFC 1952). inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the @@ -881,9 +885,9 @@ ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, deferred until inflate() is called. */ -ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); +ZEXTERN int ZEXPORT inflateSetDictionary(z_streamp strm, + const Bytef *dictionary, + uInt dictLength); /* Initializes the decompression dictionary from the given uncompressed byte sequence. This function must be called immediately after a call of inflate, @@ -904,22 +908,22 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, inflate(). */ -ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, - Bytef *dictionary, - uInt *dictLength)); +ZEXTERN int ZEXPORT inflateGetDictionary(z_streamp strm, + Bytef *dictionary, + uInt *dictLength); /* Returns the sliding dictionary being maintained by inflate. dictLength is set to the number of bytes in the dictionary, and that many bytes are copied to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If inflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. - Similary, if dictLength is Z_NULL, then it is not set. + Similarly, if dictLength is Z_NULL, then it is not set. inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the stream state is inconsistent. */ -ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +ZEXTERN int ZEXPORT inflateSync(z_streamp strm); /* Skips invalid compressed data until a possible full flush point (see above for the description of deflate with Z_FULL_FLUSH) can be found, or until all @@ -938,8 +942,8 @@ ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); input each time, until success or end of the input data. */ -ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, - z_streamp source)); +ZEXTERN int ZEXPORT inflateCopy(z_streamp dest, + z_streamp source); /* Sets the destination stream as a complete copy of the source stream. @@ -954,18 +958,19 @@ ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, destination. */ -ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +ZEXTERN int ZEXPORT inflateReset(z_streamp strm); /* This function is equivalent to inflateEnd followed by inflateInit, but does not free and reallocate the internal decompression state. The stream will keep attributes that may have been set by inflateInit2. + total_in, total_out, adler, and msg are initialized. inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ -ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, - int windowBits)); +ZEXTERN int ZEXPORT inflateReset2(z_streamp strm, + int windowBits); /* This function is the same as inflateReset, but it also permits changing the wrap and window size requests. The windowBits parameter is interpreted @@ -978,9 +983,9 @@ ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, the windowBits parameter is invalid. */ -ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, - int bits, - int value)); +ZEXTERN int ZEXPORT inflatePrime(z_streamp strm, + int bits, + int value); /* This function inserts bits in the inflate input stream. The intent is that this function is used to start inflating at a bit position in the @@ -999,7 +1004,7 @@ ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, stream state was inconsistent. */ -ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +ZEXTERN long ZEXPORT inflateMark(z_streamp strm); /* This function returns two values, one in the lower 16 bits of the return value, and the other in the remaining upper bits, obtained by shifting the @@ -1027,8 +1032,8 @@ ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); source stream state was inconsistent. */ -ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, - gz_headerp head)); +ZEXTERN int ZEXPORT inflateGetHeader(z_streamp strm, + gz_headerp head); /* inflateGetHeader() requests that gzip header information be stored in the provided gz_header structure. inflateGetHeader() may be called after @@ -1068,8 +1073,8 @@ ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, */ /* -ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, - unsigned char FAR *window)); +ZEXTERN int ZEXPORT inflateBackInit(z_streamp strm, int windowBits, + unsigned char FAR *window); Initialize the internal stream state for decompression using inflateBack() calls. The fields zalloc, zfree and opaque in strm must be initialized @@ -1089,13 +1094,13 @@ ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, the version of the header file. */ -typedef unsigned (*in_func) OF((void FAR *, - z_const unsigned char FAR * FAR *)); -typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); +typedef unsigned (*in_func)(void FAR *, + z_const unsigned char FAR * FAR *); +typedef int (*out_func)(void FAR *, unsigned char FAR *, unsigned); -ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, - in_func in, void FAR *in_desc, - out_func out, void FAR *out_desc)); +ZEXTERN int ZEXPORT inflateBack(z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc); /* inflateBack() does a raw inflate with a single call using a call-back interface for input and output. This is potentially more efficient than @@ -1163,7 +1168,7 @@ ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, cannot return Z_OK. */ -ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +ZEXTERN int ZEXPORT inflateBackEnd(z_streamp strm); /* All memory allocated by inflateBackInit() is freed. @@ -1171,7 +1176,7 @@ ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); state was inconsistent. */ -ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +ZEXTERN uLong ZEXPORT zlibCompileFlags(void); /* Return flags indicating compile-time options. Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: @@ -1224,8 +1229,8 @@ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); you need special options. */ -ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); +ZEXTERN int ZEXPORT compress(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen); /* Compresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size @@ -1239,9 +1244,9 @@ ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, buffer. */ -ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen, - int level)); +ZEXTERN int ZEXPORT compress2(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level); /* Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte @@ -1255,15 +1260,15 @@ ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, Z_STREAM_ERROR if the level parameter is invalid. */ -ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +ZEXTERN uLong ZEXPORT compressBound(uLong sourceLen); /* compressBound() returns an upper bound on the compressed size after compress() or compress2() on sourceLen bytes. It would be used before a compress() or compress2() call to allocate the destination buffer. */ -ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); +ZEXTERN int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen); /* Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size @@ -1280,8 +1285,8 @@ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, buffer with the uncompressed data up to that point. */ -ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong *sourceLen)); +ZEXTERN int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong *sourceLen); /* Same as uncompress, except that sourceLen is a pointer, where the length of the source is *sourceLen. On return, *sourceLen is the number of @@ -1300,16 +1305,16 @@ ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen, typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ /* -ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +ZEXTERN gzFile ZEXPORT gzopen(const char *path, const char *mode); - Opens a gzip (.gz) file for reading or writing. The mode parameter is as - in fopen ("rb" or "wb") but can also include a compression level ("wb9") or - a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only - compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' - for fixed code compression as in "wb9F". (See the description of - deflateInit2 for more information about the strategy parameter.) 'T' will - request transparent writing or appending with no compression and not using - the gzip format. + Open the gzip (.gz) file at path for reading and decompressing, or + compressing and writing. The mode parameter is as in fopen ("rb" or "wb") + but can also include a compression level ("wb9") or a strategy: 'f' for + filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", + 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression + as in "wb9F". (See the description of deflateInit2 for more information + about the strategy parameter.) 'T' will request transparent writing or + appending with no compression and not using the gzip format. "a" can be used instead of "w" to request that the gzip stream that will be written be appended to the file. "+" will result in an error, since @@ -1337,11 +1342,11 @@ ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); file could not be opened. */ -ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +ZEXTERN gzFile ZEXPORT gzdopen(int fd, const char *mode); /* - gzdopen associates a gzFile with the file descriptor fd. File descriptors - are obtained from calls like open, dup, creat, pipe or fileno (if the file - has been previously opened with fopen). The mode parameter is as in gzopen. + Associate a gzFile with the file descriptor fd. File descriptors are + obtained from calls like open, dup, creat, pipe or fileno (if the file has + been previously opened with fopen). The mode parameter is as in gzopen. The next call of gzclose on the returned gzFile will also close the file descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor @@ -1360,15 +1365,15 @@ ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); will not detect if fd is invalid (unless fd is -1). */ -ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +ZEXTERN int ZEXPORT gzbuffer(gzFile file, unsigned size); /* - Set the internal buffer size used by this library's functions. The - default buffer size is 8192 bytes. This function must be called after - gzopen() or gzdopen(), and before any other calls that read or write the - file. The buffer memory allocation is always deferred to the first read or - write. Three times that size in buffer space is allocated. A larger buffer - size of, for example, 64K or 128K bytes will noticeably increase the speed - of decompression (reading). + Set the internal buffer size used by this library's functions for file to + size. The default buffer size is 8192 bytes. This function must be called + after gzopen() or gzdopen(), and before any other calls that read or write + the file. The buffer memory allocation is always deferred to the first read + or write. Three times that size in buffer space is allocated. A larger + buffer size of, for example, 64K or 128K bytes will noticeably increase the + speed of decompression (reading). The new buffer size also affects the maximum length for gzprintf(). @@ -1376,20 +1381,20 @@ ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); too late. */ -ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +ZEXTERN int ZEXPORT gzsetparams(gzFile file, int level, int strategy); /* - Dynamically update the compression level or strategy. See the description - of deflateInit2 for the meaning of these parameters. Previously provided - data is flushed before the parameter change. + Dynamically update the compression level and strategy for file. See the + description of deflateInit2 for the meaning of these parameters. Previously + provided data is flushed before applying the parameter changes. gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not opened for writing, Z_ERRNO if there is an error writing the flushed data, or Z_MEM_ERROR if there is a memory allocation error. */ -ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +ZEXTERN int ZEXPORT gzread(gzFile file, voidp buf, unsigned len); /* - Reads the given number of uncompressed bytes from the compressed file. If + Read and decompress up to len uncompressed bytes from file into buf. If the input file is not in gzip format, gzread copies the given number of bytes into the buffer directly from the file. @@ -1417,14 +1422,14 @@ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); Z_STREAM_ERROR. */ -ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, - gzFile file)); +ZEXTERN z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, + gzFile file); /* - Read up to nitems items of size size from file to buf, otherwise operating - as gzread() does. This duplicates the interface of stdio's fread(), with - size_t request and return types. If the library defines size_t, then - z_size_t is identical to size_t. If not, then z_size_t is an unsigned - integer type that can contain a pointer. + Read and decompress up to nitems items of size size from file into buf, + otherwise operating as gzread() does. This duplicates the interface of + stdio's fread(), with size_t request and return types. If the library + defines size_t, then z_size_t is identical to size_t. If not, then z_size_t + is an unsigned integer type that can contain a pointer. gzfread() returns the number of full items read of size size, or zero if the end of the file was reached and a full item could not be read, or if @@ -1435,26 +1440,24 @@ ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, In the event that the end of file is reached and only a partial item is available at the end, i.e. the remaining uncompressed data length is not a - multiple of size, then the final partial item is nevetheless read into buf + multiple of size, then the final partial item is nevertheless read into buf and the end-of-file flag is set. The length of the partial item read is not provided, but could be inferred from the result of gztell(). This behavior is the same as the behavior of fread() implementations in common libraries, but it prevents the direct use of gzfread() to read a concurrently written - file, reseting and retrying on end-of-file, when size is not 1. + file, resetting and retrying on end-of-file, when size is not 1. */ -ZEXTERN int ZEXPORT gzwrite OF((gzFile file, - voidpc buf, unsigned len)); +ZEXTERN int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len); /* - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of uncompressed bytes written or 0 in case of - error. + Compress and write the len uncompressed bytes at buf to file. gzwrite + returns the number of uncompressed bytes written or 0 in case of error. */ -ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size, - z_size_t nitems, gzFile file)); +ZEXTERN z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, + z_size_t nitems, gzFile file); /* - gzfwrite() writes nitems items of size size from buf to file, duplicating + Compress and write nitems items of size size from buf to file, duplicating the interface of stdio's fwrite(), with size_t request and return types. If the library defines size_t, then z_size_t is identical to size_t. If not, then z_size_t is an unsigned integer type that can contain a pointer. @@ -1465,61 +1468,62 @@ ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size, is returned, and the error state is set to Z_STREAM_ERROR. */ -ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); +ZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...); /* - Converts, formats, and writes the arguments to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of + Convert, format, compress, and write the arguments (...) to file under + control of the string format, as in fprintf. gzprintf returns the number of uncompressed bytes actually written, or a negative zlib error code in case of error. The number of uncompressed bytes written is limited to 8191, or one less than the buffer size given to gzbuffer(). The caller should assure that this limit is not exceeded. If it is exceeded, then gzprintf() will return an error (0) with nothing written. In this case, there may also be a buffer overflow with unpredictable consequences, which is possible only if - zlib was compiled with the insecure functions sprintf() or vsprintf() + zlib was compiled with the insecure functions sprintf() or vsprintf(), because the secure snprintf() or vsnprintf() functions were not available. This can be determined using zlibCompileFlags(). */ -ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +ZEXTERN int ZEXPORT gzputs(gzFile file, const char *s); /* - Writes the given null-terminated string to the compressed file, excluding + Compress and write the given null-terminated string s to file, excluding the terminating null character. gzputs returns the number of characters written, or -1 in case of error. */ -ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +ZEXTERN char * ZEXPORT gzgets(gzFile file, char *buf, int len); /* - Reads bytes from the compressed file until len-1 characters are read, or a - newline character is read and transferred to buf, or an end-of-file - condition is encountered. If any characters are read or if len == 1, the - string is terminated with a null character. If no characters are read due - to an end-of-file or len < 1, then the buffer is left untouched. + Read and decompress bytes from file into buf, until len-1 characters are + read, or until a newline character is read and transferred to buf, or an + end-of-file condition is encountered. If any characters are read or if len + is one, the string is terminated with a null character. If no characters + are read due to an end-of-file or len is less than one, then the buffer is + left untouched. gzgets returns buf which is a null-terminated string, or it returns NULL for end-of-file or in case of error. If there was an error, the contents at buf are indeterminate. */ -ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +ZEXTERN int ZEXPORT gzputc(gzFile file, int c); /* - Writes c, converted to an unsigned char, into the compressed file. gzputc + Compress and write c, converted to an unsigned char, into file. gzputc returns the value that was written, or -1 in case of error. */ -ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +ZEXTERN int ZEXPORT gzgetc(gzFile file); /* - Reads one byte from the compressed file. gzgetc returns this byte or -1 + Read and decompress one byte from file. gzgetc returns this byte or -1 in case of end of file or error. This is implemented as a macro for speed. As such, it does not do all of the checking the other functions do. I.e. it does not check to see if file is NULL, nor whether the structure file points to has been clobbered or not. */ -ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +ZEXTERN int ZEXPORT gzungetc(int c, gzFile file); /* - Push one character back onto the stream to be read as the first character - on the next read. At least one character of push-back is allowed. + Push c back onto the stream for file to be read as the first character on + the next read. At least one character of push-back is always allowed. gzungetc() returns the character pushed, or -1 on failure. gzungetc() will fail if c is -1, and may fail if a character has been pushed but not read yet. If gzungetc is used immediately after gzopen or gzdopen, at least the @@ -1528,11 +1532,11 @@ ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); gzseek() or gzrewind(). */ -ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +ZEXTERN int ZEXPORT gzflush(gzFile file, int flush); /* - Flushes all pending output into the compressed file. The parameter flush - is as in the deflate() function. The return value is the zlib error number - (see function gzerror below). gzflush is only permitted when writing. + Flush all pending output to file. The parameter flush is as in the + deflate() function. The return value is the zlib error number (see function + gzerror below). gzflush is only permitted when writing. If the flush parameter is Z_FINISH, the remaining data is written and the gzip stream is completed in the output. If gzwrite() is called again, a new @@ -1544,11 +1548,11 @@ ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); */ /* -ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, - z_off_t offset, int whence)); +ZEXTERN z_off_t ZEXPORT gzseek(gzFile file, + z_off_t offset, int whence); - Sets the starting position for the next gzread or gzwrite on the given - compressed file. The offset represents a number of bytes in the + Set the starting position to offset relative to whence for the next gzread + or gzwrite on file. The offset represents a number of bytes in the uncompressed data stream. The whence parameter is defined as in lseek(2); the value SEEK_END is not supported. @@ -1563,52 +1567,52 @@ ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, would be before the current position. */ -ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +ZEXTERN int ZEXPORT gzrewind(gzFile file); /* - Rewinds the given file. This function is supported only for reading. + Rewind file. This function is supported only for reading. - gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET). */ /* -ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +ZEXTERN z_off_t ZEXPORT gztell(gzFile file); - Returns the starting position for the next gzread or gzwrite on the given - compressed file. This position represents a number of bytes in the - uncompressed data stream, and is zero when starting, even if appending or - reading a gzip stream from the middle of a file using gzdopen(). + Return the starting position for the next gzread or gzwrite on file. + This position represents a number of bytes in the uncompressed data stream, + and is zero when starting, even if appending or reading a gzip stream from + the middle of a file using gzdopen(). gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) */ /* -ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); +ZEXTERN z_off_t ZEXPORT gzoffset(gzFile file); - Returns the current offset in the file being read or written. This offset - includes the count of bytes that precede the gzip stream, for example when - appending or when using gzdopen() for reading. When reading, the offset - does not include as yet unused buffered input. This information can be used - for a progress indicator. On error, gzoffset() returns -1. + Return the current compressed (actual) read or write offset of file. This + offset includes the count of bytes that precede the gzip stream, for example + when appending or when using gzdopen() for reading. When reading, the + offset does not include as yet unused buffered input. This information can + be used for a progress indicator. On error, gzoffset() returns -1. */ -ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +ZEXTERN int ZEXPORT gzeof(gzFile file); /* - Returns true (1) if the end-of-file indicator has been set while reading, - false (0) otherwise. Note that the end-of-file indicator is set only if the - read tried to go past the end of the input, but came up short. Therefore, - just like feof(), gzeof() may return false even if there is no more data to - read, in the event that the last read request was for the exact number of - bytes remaining in the input file. This will happen if the input file size - is an exact multiple of the buffer size. + Return true (1) if the end-of-file indicator for file has been set while + reading, false (0) otherwise. Note that the end-of-file indicator is set + only if the read tried to go past the end of the input, but came up short. + Therefore, just like feof(), gzeof() may return false even if there is no + more data to read, in the event that the last read request was for the exact + number of bytes remaining in the input file. This will happen if the input + file size is an exact multiple of the buffer size. If gzeof() returns true, then the read functions will return no more data, unless the end-of-file indicator is reset by gzclearerr() and the input file has grown since the previous end of file was detected. */ -ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +ZEXTERN int ZEXPORT gzdirect(gzFile file); /* - Returns true (1) if file is being copied directly while reading, or false + Return true (1) if file is being copied directly while reading, or false (0) if file is a gzip stream being decompressed. If the input file is empty, gzdirect() will return true, since the input @@ -1627,10 +1631,10 @@ ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); gzip file reading and decompression, which may not be desired.) */ -ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose(gzFile file); /* - Flushes all pending output if necessary, closes the compressed file and - deallocates the (de)compression state. Note that once file is closed, you + Flush all pending output for file, if necessary, close file and + deallocate the (de)compression state. Note that once file is closed, you cannot call gzerror with file, since its structures have been deallocated. gzclose must not be called more than once on the same file, just as free must not be called more than once on the same allocation. @@ -1640,8 +1644,8 @@ ZEXTERN int ZEXPORT gzclose OF((gzFile file)); last read ended in the middle of a gzip stream, or Z_OK on success. */ -ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); -ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_r(gzFile file); +ZEXTERN int ZEXPORT gzclose_w(gzFile file); /* Same as gzclose(), but gzclose_r() is only for use when reading, and gzclose_w() is only for use when writing or appending. The advantage to @@ -1652,12 +1656,12 @@ ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); zlib library. */ -ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +ZEXTERN const char * ZEXPORT gzerror(gzFile file, int *errnum); /* - Returns the error message for the last error which occurred on the given - compressed file. errnum is set to zlib error number. If an error occurred - in the file system and not in the compression library, errnum is set to - Z_ERRNO and the application may consult errno to get the exact error code. + Return the error message for the last error which occurred on file. + errnum is set to zlib error number. If an error occurred in the file system + and not in the compression library, errnum is set to Z_ERRNO and the + application may consult errno to get the exact error code. The application must not modify the returned string. Future calls to this function may invalidate the previously returned string. If file is @@ -1668,9 +1672,9 @@ ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); functions above that do not distinguish those cases in their return values. */ -ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +ZEXTERN void ZEXPORT gzclearerr(gzFile file); /* - Clears the error and end-of-file flags for file. This is analogous to the + Clear the error and end-of-file flags for file. This is analogous to the clearerr() function in stdio. This is useful for continuing to read a gzip file that is being written concurrently. */ @@ -1685,11 +1689,12 @@ ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); library. */ -ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +ZEXTERN uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len); /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and - return the updated checksum. If buf is Z_NULL, this function returns the - required initial value for the checksum. + return the updated checksum. An Adler-32 value is in the range of a 32-bit + unsigned integer. If buf is Z_NULL, this function returns the required + initial value for the checksum. An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed much faster. @@ -1704,15 +1709,15 @@ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); if (adler != original_adler) error(); */ -ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf, - z_size_t len)); +ZEXTERN uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, + z_size_t len); /* Same as adler32(), but with a size_t length. */ /* -ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, - z_off_t len2)); +ZEXTERN uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, + z_off_t len2); Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for @@ -1722,12 +1727,13 @@ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, negative, the result has no meaning or utility. */ -ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +ZEXTERN uLong ZEXPORT crc32(uLong crc, const Bytef *buf, uInt len); /* Update a running CRC-32 with the bytes buf[0..len-1] and return the - updated CRC-32. If buf is Z_NULL, this function returns the required - initial value for the crc. Pre- and post-conditioning (one's complement) is - performed within this function so it shouldn't be done by the application. + updated CRC-32. A CRC-32 value is in the range of a 32-bit unsigned integer. + If buf is Z_NULL, this function returns the required initial value for the + crc. Pre- and post-conditioning (one's complement) is performed within this + function so it shouldn't be done by the application. Usage example: @@ -1739,14 +1745,14 @@ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); if (crc != original_crc) error(); */ -ZEXTERN uLong ZEXPORT crc32_z OF((uLong adler, const Bytef *buf, - z_size_t len)); +ZEXTERN uLong ZEXPORT crc32_z(uLong crc, const Bytef *buf, + z_size_t len); /* Same as crc32(), but with a size_t length. */ /* -ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); +ZEXTERN uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2); Combine two CRC-32 check values into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, CRC-32 check values were @@ -1755,26 +1761,40 @@ ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); len2. */ +/* +ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t len2); + + Return the operator corresponding to length len2, to be used with + crc32_combine_op(). +*/ + +ZEXTERN uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op); +/* + Give the same result as crc32_combine(), using op in place of len2. op is + is generated from len2 by crc32_combine_gen(). This will be faster than + crc32_combine() if the generated op is used more than once. +*/ + /* various hacks, don't look :) */ /* deflateInit and inflateInit are macros to allow checking the zlib version * and the compiler's view of z_stream: */ -ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, - int windowBits, int memLevel, - int strategy, const char *version, - int stream_size)); -ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, - unsigned char FAR *window, - const char *version, - int stream_size)); +ZEXTERN int ZEXPORT deflateInit_(z_streamp strm, int level, + const char *version, int stream_size); +ZEXTERN int ZEXPORT inflateInit_(z_streamp strm, + const char *version, int stream_size); +ZEXTERN int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size); +ZEXTERN int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, + const char *version, int stream_size); +ZEXTERN int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size); #ifdef Z_PREFIX_SET # define z_deflateInit(strm, level) \ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) @@ -1819,7 +1839,7 @@ struct gzFile_s { unsigned char *next; z_off64_t pos; }; -ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ +ZEXTERN int ZEXPORT gzgetc_(gzFile file); /* backward compatibility */ #ifdef Z_PREFIX_SET # undef z_gzgetc # define z_gzgetc(g) \ @@ -1836,12 +1856,13 @@ ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ * without large file support, _LFS64_LARGEFILE must also be true */ #ifdef Z_LARGE64 - ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); - ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); - ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); - ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); - ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); - ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int); + ZEXTERN z_off64_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off64_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off64_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off64_t); #endif #if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) @@ -1852,6 +1873,7 @@ ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ # define z_gzoffset z_gzoffset64 # define z_adler32_combine z_adler32_combine64 # define z_crc32_combine z_crc32_combine64 +# define z_crc32_combine_gen z_crc32_combine_gen64 # else # define gzopen gzopen64 # define gzseek gzseek64 @@ -1859,49 +1881,53 @@ ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ # define gzoffset gzoffset64 # define adler32_combine adler32_combine64 # define crc32_combine crc32_combine64 +# define crc32_combine_gen crc32_combine_gen64 # endif # ifndef Z_LARGE64 - ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); - ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); - ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); - ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); - ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off_t ZEXPORT gzseek64(gzFile, z_off_t, int); + ZEXTERN z_off_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off_t ZEXPORT gzoffset64(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t); # endif #else - ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); - ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); - ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); - ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); - ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN gzFile ZEXPORT gzopen(const char *, const char *); + ZEXTERN z_off_t ZEXPORT gzseek(gzFile, z_off_t, int); + ZEXTERN z_off_t ZEXPORT gztell(gzFile); + ZEXTERN z_off_t ZEXPORT gzoffset(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t); #endif #else /* Z_SOLO */ - ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t); #endif /* !Z_SOLO */ /* undocumented functions */ -ZEXTERN const char * ZEXPORT zError OF((int)); -ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); -ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); -ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); -ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); -ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF ((z_streamp)); -ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); -ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); -#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(Z_SOLO) -ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, - const char *mode)); +ZEXTERN const char * ZEXPORT zError(int); +ZEXTERN int ZEXPORT inflateSyncPoint(z_streamp); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table(void); +ZEXTERN int ZEXPORT inflateUndermine(z_streamp, int); +ZEXTERN int ZEXPORT inflateValidate(z_streamp, int); +ZEXTERN unsigned long ZEXPORT inflateCodesUsed(z_streamp); +ZEXTERN int ZEXPORT inflateResetKeep(z_streamp); +ZEXTERN int ZEXPORT deflateResetKeep(z_streamp); +#if defined(_WIN32) && !defined(Z_SOLO) +ZEXTERN gzFile ZEXPORT gzopen_w(const wchar_t *path, + const char *mode); #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifndef Z_SOLO -ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, - const char *format, - va_list va)); +ZEXTERN int ZEXPORTVA gzvprintf(gzFile file, + const char *format, + va_list va); # endif #endif diff --git a/vendor/libgit2/deps/zlib/zutil.c b/vendor/libgit2/deps/zlib/zutil.c index a76c6b0c..b1c5d2d3 100644 --- a/vendor/libgit2/deps/zlib/zutil.c +++ b/vendor/libgit2/deps/zlib/zutil.c @@ -24,13 +24,11 @@ z_const char * const z_errmsg[10] = { }; -const char * ZEXPORT zlibVersion() -{ +const char * ZEXPORT zlibVersion(void) { return ZLIB_VERSION; } -uLong ZEXPORT zlibCompileFlags() -{ +uLong ZEXPORT zlibCompileFlags(void) { uLong flags; flags = 0; @@ -61,9 +59,11 @@ uLong ZEXPORT zlibCompileFlags() #ifdef ZLIB_DEBUG flags += 1 << 8; #endif + /* #if defined(ASMV) || defined(ASMINF) flags += 1 << 9; #endif + */ #ifdef ZLIB_WINAPI flags += 1 << 10; #endif @@ -119,9 +119,7 @@ uLong ZEXPORT zlibCompileFlags() # endif int ZLIB_INTERNAL z_verbose = verbose; -void ZLIB_INTERNAL z_error (m) - char *m; -{ +void ZLIB_INTERNAL z_error(char *m) { fprintf(stderr, "%s\n", m); exit(1); } @@ -130,14 +128,12 @@ void ZLIB_INTERNAL z_error (m) /* exported to allow conversion of error code to string for compress() and * uncompress() */ -const char * ZEXPORT zError(err) - int err; -{ +const char * ZEXPORT zError(int err) { return ERR_MSG(err); } -#if defined(_WIN32_WCE) - /* The Microsoft C Run-Time Library for Windows CE doesn't have +#if defined(_WIN32_WCE) && _WIN32_WCE < 0x800 + /* The older Microsoft C Run-Time Library for Windows CE doesn't have * errno. We define it as a global variable to simplify porting. * Its value is always 0 and should not be used. */ @@ -146,22 +142,14 @@ const char * ZEXPORT zError(err) #ifndef HAVE_MEMCPY -void ZLIB_INTERNAL zmemcpy(dest, source, len) - Bytef* dest; - const Bytef* source; - uInt len; -{ +void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len) { if (len == 0) return; do { *dest++ = *source++; /* ??? to be unrolled */ } while (--len != 0); } -int ZLIB_INTERNAL zmemcmp(s1, s2, len) - const Bytef* s1; - const Bytef* s2; - uInt len; -{ +int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len) { uInt j; for (j = 0; j < len; j++) { @@ -170,10 +158,7 @@ int ZLIB_INTERNAL zmemcmp(s1, s2, len) return 0; } -void ZLIB_INTERNAL zmemzero(dest, len) - Bytef* dest; - uInt len; -{ +void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len) { if (len == 0) return; do { *dest++ = 0; /* ??? to be unrolled */ @@ -214,8 +199,7 @@ local ptr_table table[MAX_PTR]; * a protected system like OS/2. Use Microsoft C instead. */ -voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) -{ +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { voidpf buf; ulg bsize = (ulg)items*size; @@ -240,8 +224,7 @@ voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) return buf; } -void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) -{ +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { int n; (void)opaque; @@ -277,14 +260,12 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) # define _hfree hfree #endif -voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) -{ +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) { (void)opaque; return _halloc((long)items, size); } -void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) -{ +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { (void)opaque; _hfree(ptr); } @@ -297,25 +278,18 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) #ifndef MY_ZCALLOC /* Any system without a special alloc function */ #ifndef STDC -extern voidp malloc OF((uInt size)); -extern voidp calloc OF((uInt items, uInt size)); -extern void free OF((voidpf ptr)); +extern voidp malloc(uInt size); +extern voidp calloc(uInt items, uInt size); +extern void free(voidpf ptr); #endif -voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) - voidpf opaque; - unsigned items; - unsigned size; -{ +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { (void)opaque; return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : (voidpf)calloc(items, size); } -void ZLIB_INTERNAL zcfree (opaque, ptr) - voidpf opaque; - voidpf ptr; -{ +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { (void)opaque; free(ptr); } diff --git a/vendor/libgit2/deps/zlib/zutil.h b/vendor/libgit2/deps/zlib/zutil.h index b079ea6a..902a304c 100644 --- a/vendor/libgit2/deps/zlib/zutil.h +++ b/vendor/libgit2/deps/zlib/zutil.h @@ -1,5 +1,5 @@ /* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler + * Copyright (C) 1995-2022 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -29,10 +29,6 @@ # include #endif -#ifdef Z_SOLO - typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ -#endif - #ifndef local # define local static #endif @@ -46,6 +42,17 @@ typedef unsigned short ush; typedef ush FAR ushf; typedef unsigned long ulg; +#if !defined(Z_U8) && !defined(Z_SOLO) && defined(STDC) +# include +# if (ULONG_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned long +# elif (ULLONG_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned long long +# elif (UINT_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned +# endif +#endif + extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* (size given to avoid silly warnings with Visual C++) */ @@ -170,10 +177,6 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ #if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX # if defined(_WIN32_WCE) # define fdopen(fd,mode) NULL /* No fdopen() */ -# ifndef _PTRDIFF_T_DEFINED - typedef int ptrdiff_t; -# define _PTRDIFF_T_DEFINED -# endif # else # define fdopen(fd,type) _fdopen(fd,type) # endif @@ -188,8 +191,9 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* provide prototypes for these when building zlib without LFS */ #if !defined(_WIN32) && \ (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) - ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t); #endif /* common defaults */ @@ -228,16 +232,16 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ # define zmemzero(dest, len) memset(dest, 0, len) # endif #else - void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); - int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); - void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); + void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len); + int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len); + void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len); #endif /* Diagnostic functions */ #ifdef ZLIB_DEBUG # include extern int ZLIB_INTERNAL z_verbose; - extern void ZLIB_INTERNAL z_error OF((char *m)); + extern void ZLIB_INTERNAL z_error(char *m); # define Assert(cond,msg) {if(!(cond)) z_error(msg);} # define Trace(x) {if (z_verbose>=0) fprintf x ;} # define Tracev(x) {if (z_verbose>0) fprintf x ;} @@ -254,9 +258,9 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ #endif #ifndef Z_SOLO - voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, - unsigned size)); - void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); + voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, + unsigned size); + void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr); #endif #define ZALLOC(strm, items, size) \ diff --git a/vendor/libgit2/docs/changelog.md b/vendor/libgit2/docs/changelog.md index 32a67d2c..d4cbb395 100644 --- a/vendor/libgit2/docs/changelog.md +++ b/vendor/libgit2/docs/changelog.md @@ -1,39 +1,823 @@ -v1.4.3 +v1.8.5 ------ -🔒 This is a security release to provide compatibility with git's changes to address [CVE 2022-24765](https://github.blog/2022-04-12-git-security-vulnerability-announced/). +This is a security release with multiple changes. -**libgit2 is not directly affected** by this vulnerability, because libgit2 does not directly invoke any executable. But we are providing these changes as a security release for any users that use libgit2 for repository discovery and then _also_ use git on that repository. In this release, we will now validate that the user opening the repository is the same user that owns the on-disk repository. This is to match git's behavior. +* A bug in the external SSH execution is fixed that could cause + arbitrary command execution. Remote repository names were improperly + sent to the shell without quoting. Arguments to the external SSH + command are now sent parameterized. -In addition, we are providing several correctness fixes where invalid input can lead to a crash. These may prevent possible denial of service attacks. At this time there are not known exploits to these issues. +* A bug in SSH credential creation is fixed that could cause a + buffer overflow. Public keys that are not NUL terminated were + improperly zeroed. The given length of public keys is now honored. -Full list of changes: +v1.8.4 +------ -* Validate repository directory ownership (v1.4) by @ethomson in https://github.com/libgit2/libgit2/pull/6267 -* midx: Fix an undefined behavior (left-shift signed overflow) by @lhchavez in https://github.com/libgit2/libgit2/pull/6260 -* fetch: support OID refspec without dst by @ethomson in https://github.com/libgit2/libgit2/pull/6251 -* Fix crash when regenerating a patch with unquoted spaces in filename by @jorio in https://github.com/libgit2/libgit2/pull/6244 +We erroneously shipped v1.8.3 without actually including the change +in v1.8.2. This release re-re-introduces the pre-v1.8.0 `commit` +constness behavior. -All users of the v1.4 release line are recommended to upgrade. +## What's Changed -**Full Changelog**: https://github.com/libgit2/libgit2/compare/v1.4.2...v1.4.3 +### Bug fixes + +* Fix constness issue introduced in #6716 by @ethomson in https://github.com/libgit2/libgit2/pull/6829 -v1.4.2 +**Full Changelog**: https://github.com/libgit2/libgit2/compare/v1.8.3...v1.8.4 + +v1.8.3 ------ -This is a bugfix release with the following changes: +This release fixes a bug introduced in v1.8.1 for users of the legacy +[Node.js http-parser](https://github.com/nodejs/http-parser) +dependency. -* remote: do store the update_tips callback error value by @carlosmn in https://github.com/libgit2/libgit2/pull/6226 -* win32: `find_system_dirs` does not return `GIT_ENOTFOUND` by @ethomson in https://github.com/libgit2/libgit2/pull/6228 +## What's Changed + +### Bug fixes -v1.4.1 +* http: Backport on_status initialize fix for http-parser by @ethomson in https://github.com/libgit2/libgit2/pull/6931 + +v1.8.2 ------ -This is a bugfix release with the following changes: +This release reverts a const-correctness change introduced in +v1.8.0 for the `git_commit_create` functions. We now retain the +const-behavior for the `commits` arguments from prior to v1.8.0. + +This change was meant to resolve compatibility issues with bindings +and downstream users. + +## What's Changed + +### New features + +* Introduce a stricter debugging allocator for testing by @ethomson in https://github.com/libgit2/libgit2/pull/6811 + +### Bug fixes + +* Fix constness issue introduced in #6716 by @ethomson in https://github.com/libgit2/libgit2/pull/6829 + +### Build and CI improvements + +* README: add experimental builds to ci table by @ethomson in https://github.com/libgit2/libgit2/pull/6816 + +**Full Changelog**: https://github.com/libgit2/libgit2/compare/v1.8.1...v1.8.2 + +v1.8.1 +------ + +This release primarily includes straightforward bugfixes, as well as +new functionality to have more control over the HTTP User-Agent header. +However, there is an API change from v1.8 that was required for +improved compatibility. + +In v1.8, libgit2 introduced the `report_unchanged ` member in the +`git_fetch_options` structure. We mistakenly introduced this as a +bitfield, which is not suitable for our public API. To correct this +mistake, we have _removed_ the `report_unchanged ` member. To support +the report unchanged tips option, users can set the `update_fetchhead` +member to include the `GIT_REMOTE_UPDATE_REPORT_UNCHANGED` value. + +The libgit2 projects regrets the API change, but this was required to +support cross-platform compatibility. + +## What's Changed + +### New features + +* Allow more control over the user-agent by @ethomson in + https://github.com/libgit2/libgit2/pull/6788 + +### Bug fixes + +* commit: Fix git_commit_create_from_stage without author and + committer by @florianpircher in + https://github.com/libgit2/libgit2/pull/6781 +* process.c: fix environ for macOS by @barracuda156 in + https://github.com/libgit2/libgit2/pull/6792 +* Bounds check for pack index read by @ConradIrwin in + https://github.com/libgit2/libgit2/pull/6796 +* transport: provide a useful error message during cancellation + by @ethomson in https://github.com/libgit2/libgit2/pull/6802 +* transport: support sha256 oids by @ethomson in + https://github.com/libgit2/libgit2/pull/6803 +* Revparse: Correctly accept ref with '@' at the end by @csware in + https://github.com/libgit2/libgit2/pull/6809 +* remote: drop bitfields in git_remote_fetch_options by @ethomson in + https://github.com/libgit2/libgit2/pull/6806 +* examples: fix memory leak in for-each-ref.c by @qaqland in + https://github.com/libgit2/libgit2/pull/6808 +* xdiff: use proper free function by @ethomson in + https://github.com/libgit2/libgit2/pull/6810 +* rand: avoid uninitialized loadavg warnings by @ethomson in + https://github.com/libgit2/libgit2/pull/6812 +* cli: include alloca on illumos / solaris / sunos by @ethomson in + https://github.com/libgit2/libgit2/pull/6813 +* Update git_array allocator to obey strict aliasing rules + by @ethomson in https://github.com/libgit2/libgit2/pull/6814 +* tree: avoid mixed signedness comparison by @ethomson in + https://github.com/libgit2/libgit2/pull/6815 + +### Build and CI improvements + +* ci: update nightly workflows by @ethomson in + https://github.com/libgit2/libgit2/pull/6773 +* ci: give all nightly builds a unique id by @ethomson in + https://github.com/libgit2/libgit2/pull/6782 +* cmake: remove workaround that isn't compatible with Windows on + ARM by @hackhaslam in https://github.com/libgit2/libgit2/pull/6794 + +### Documentation improvements + +* Docs meta-updates by @ethomson in + https://github.com/libgit2/libgit2/pull/6787 + +### Dependency updates + +* Enable llhttp for HTTP parsing by @sgallagher in + https://github.com/libgit2/libgit2/pull/6713 + +## New Contributors + +* @florianpircher made their first contribution in + https://github.com/libgit2/libgit2/pull/6781 +* @barracuda156 made their first contribution in + https://github.com/libgit2/libgit2/pull/6792 +* @sgallagher made their first contribution in + https://github.com/libgit2/libgit2/pull/6713 +* @ConradIrwin made their first contribution in + https://github.com/libgit2/libgit2/pull/6796 +* @qaqland made their first contribution in + https://github.com/libgit2/libgit2/pull/6808 + +**Full Changelog**: https://github.com/libgit2/libgit2/compare/v1.8.0...v1.8.1 + +v1.8 +---- + +This is release v1.8.0, "Das Fliegende Klassenzimmer". This release +includes optional, experimental support for invoking OpenSSH to fetch +and push, an easier mechanism to perform the default behavior of +`git commit`, and has many improvements for worktrees. This release +also includes many other new features and bugfixes. + +## Major changes + +* **Executable SSH (OpenSSH) support** + libgit2 can now invoke the command-line OpenSSH to fetch from and push + to remotes over SSH. This support takes the place of libssh2 support. + To use it, configure libgit2 with `cmake -DUSE_SSH=exec`, and please + report any problems that you discover. By @ethomson in + https://github.com/libgit2/libgit2/pull/6617 + +* **Simplified commit creation** + The `git_commit_create_from_stage` API was introduced to allow users to + better emulate the behavior of `git commit` without needing to provide + unnecessary information. The current state of the index is committed to + the current branch. By @ethomson in + https://github.com/libgit2/libgit2/pull/6716 + +* **Worktree improvements** + A number of worktree improvements have been made for better + compatibility with core git. First, libgit2 now understands per-worktree + references, thanks to @csware in + https://github.com/libgit2/libgit2/pull/6387. Worktree-specific + configuration is now supported, thanks to @vermiculus in + https://github.com/libgit2/libgit2/pull/6202. And improved compatibility + with `git worktree add` is now supported, thanks to @herrerog in + https://github.com/libgit2/libgit2/pull/5319. + +## Breaking changes + +* **Adding `WORKTREE` configuration level** (ABI breaking change) + To support worktree configurations at the appropriate level (higher + priority than local configuration, but lower priority than app-specific + configuration), the `GIT_CONFIG_LEVEL_WORKTREE` level was introduced at + priority 6. `GIT_CONFIG_LEVEL_APP` now begins at priority 7. + +* **Changes to `git_config_entry`** (ABI breaking change) + The `git_config_entry` structure now contains information about the + `backend_type` and `origin_path`. The unused `payload` value has been + removed. + +* **`git_push_options` includes remote push options** (ABI breaking change) + The `git_push_options` structure now contains a value for remote push + options. + +## Other changes + +### New features + +* config: provide an "origin" for config entries by @ethomson in + https://github.com/libgit2/libgit2/pull/6615 +* cli: add a `git config` command by @ethomson in + https://github.com/libgit2/libgit2/pull/6616 +* Add OpenSSH support by @ethomson in + https://github.com/libgit2/libgit2/pull/6617 +* remote: optionally report unchanged tips by @ethomson in + https://github.com/libgit2/libgit2/pull/6645 +* Support setting oid type for in-memory repositories by @kcsaul in + https://github.com/libgit2/libgit2/pull/6671 +* cli: add `index-pack` command by @ethomson in + https://github.com/libgit2/libgit2/pull/6681 +* Add `git_repository_commit_parents` to identify the parents of the next + commit given the repository state by @ethomson in + https://github.com/libgit2/libgit2/pull/6707 +* commit: introduce `git_commit_create_from_stage` by @ethomson in + https://github.com/libgit2/libgit2/pull/6716 +* set SSH timeout by @vafada in + https://github.com/libgit2/libgit2/pull/6721 +* Implement push options on push by @russell in + https://github.com/libgit2/libgit2/pull/6439 +* Support index.skipHash true config by @parnic in + https://github.com/libgit2/libgit2/pull/6738 +* worktree: mimic 'git worktree add' behavior. by @herrerog in + https://github.com/libgit2/libgit2/pull/5319 +* Support the extension for worktree-specific config by @vermiculus in + https://github.com/libgit2/libgit2/pull/6202 +* Separate config reader and writer backend priorities (for worktree + configs) by @ethomson in https://github.com/libgit2/libgit2/pull/6756 +* fetch: enable deepening/shortening shallow clones by @kempniu in + https://github.com/libgit2/libgit2/pull/6662 + +### Bug fixes + +* repository: make cleanup safe for re-use with grafts by @carlosmn in + https://github.com/libgit2/libgit2/pull/6600 +* fix: Add missing include for `oidarray`. by @dvzrv in + https://github.com/libgit2/libgit2/pull/6608 +* ssh: fix `known_hosts` leak in `_git_ssh_setup_conn` by @steven9724 in + https://github.com/libgit2/libgit2/pull/6599 +* proxy: Return an error for invalid proxy URLs instead of crashing by + @lrm29 in https://github.com/libgit2/libgit2/pull/6597 +* errors: refactoring - never return `NULL` in `git_error_last()` by + @ethomson in https://github.com/libgit2/libgit2/pull/6625 +* Reject potential option injections over ssh by @carlosmn in + https://github.com/libgit2/libgit2/pull/6636 +* remote: fix memory leak in `git_remote_download()` by @7Ji in + https://github.com/libgit2/libgit2/pull/6651 +* git2: Fix crash when called w/o parameters by @csware in + https://github.com/libgit2/libgit2/pull/6673 +* Avoid macro redefinition of `ENABLE_INTSAFE_SIGNED_FUNCTIONS` by @csware + in https://github.com/libgit2/libgit2/pull/6666 +* util: suppress some uninitialized variable warnings by @boretrk in + https://github.com/libgit2/libgit2/pull/6659 +* push: set generic error in `push_negotiation` cb by @ethomson in + https://github.com/libgit2/libgit2/pull/6675 +* process: test `/usr/bin/false` on BSDs by @ethomson in + https://github.com/libgit2/libgit2/pull/6677 +* clone: don't mix up "http://url" with "http:/url" when figuring out if we + should do a local clone by @boretrk in + https://github.com/libgit2/libgit2/pull/6361 +* Several compatibility fixes by @ethomson in + https://github.com/libgit2/libgit2/pull/6678 +* Git blame buffer gives the wrong result in many cases where there are + by @thosey in https://github.com/libgit2/libgit2/pull/6572 +* Fix 'path cannot exist in repository' during diff for in-memory repository + by @kcsaul in https://github.com/libgit2/libgit2/pull/6683 +* process: don't try to close the status by @ethomson in + https://github.com/libgit2/libgit2/pull/6693 +* Minor bug fixes by @ethomson in + https://github.com/libgit2/libgit2/pull/6695 +* Bypass shallow clone support for in-memory repositories by @kcsaul in + https://github.com/libgit2/libgit2/pull/6684 +* examples: use `unsigned` int for bitfields by @ethomson in + https://github.com/libgit2/libgit2/pull/6699 +* Fix some bugs caught by UBscan by @ethomson in + https://github.com/libgit2/libgit2/pull/6700 +* `git_diff_find_similar` doesn't always remove unmodified deltas by @yori + in https://github.com/libgit2/libgit2/pull/6642 +* httpclient: clear `client->parser.data` after use by @ethomson in + https://github.com/libgit2/libgit2/pull/6705 +* Do not normalize `safe.directory` paths by @csware in + https://github.com/libgit2/libgit2/pull/6668 +* clone: don't swallow error in `should_checkout` by @ethomson in + https://github.com/libgit2/libgit2/pull/6727 +* Correct index add directory/file conflict detection by @ethomson in + https://github.com/libgit2/libgit2/pull/6729 +* Correct `git_revparse_single` and add revparse fuzzing by @ethomson in + https://github.com/libgit2/libgit2/pull/6730 +* config: properly delete or rename section containing multivars by + @samueltardieu in https://github.com/libgit2/libgit2/pull/6723 +* revparse: ensure bare '@' is truly bare by @ethomson in + https://github.com/libgit2/libgit2/pull/6742 +* repo: ensure we can initialize win32 paths by @ethomson in + https://github.com/libgit2/libgit2/pull/6743 +* Swap `GIT_DIFF_LINE_(ADD|DEL)_EOFNL` to match other Diffs by @xphoniex in + https://github.com/libgit2/libgit2/pull/6240 +* diff: fix test for SHA256 support in `diff_from_buffer` by @ethomson in + https://github.com/libgit2/libgit2/pull/6745 +* http: support empty http.proxy config setting by @ethomson in + https://github.com/libgit2/libgit2/pull/6744 +* More `safe.directory` improvements by @ethomson in + https://github.com/libgit2/libgit2/pull/6739 +* Ensure that completely ignored diff is empty by @ethomson in + https://github.com/libgit2/libgit2/pull/5893 +* Fix broken regexp that matches submodule names containing ".path" by + @csware in https://github.com/libgit2/libgit2/pull/6749 +* Fix memory leaks by @csware in + https://github.com/libgit2/libgit2/pull/6748 +* Make `refdb_fs` (hopefully) fully aware of per worktree refs by @csware in + https://github.com/libgit2/libgit2/pull/6387 +* fix log example by @albfan in https://github.com/libgit2/libgit2/pull/6359 +* fetch: fail on depth for local transport by @ethomson in + https://github.com/libgit2/libgit2/pull/6757 +* Fix message trailer parsing by @ethomson in + https://github.com/libgit2/libgit2/pull/6761 +* config: correct fetching the `HIGHEST_LEVEL` config by @ethomson in + https://github.com/libgit2/libgit2/pull/6766 +* Avoid some API breaking changes in v1.8 by @ethomson in + https://github.com/libgit2/libgit2/pull/6768 + +### Build and CI improvements + +* meta: update version numbers to v1.8 by @ethomson in + https://github.com/libgit2/libgit2/pull/6596 +* Revert "CMake: Search for ssh2 instead of libssh2." by @ethomson in + https://github.com/libgit2/libgit2/pull/6619 +* cmake: fix openssl build on win32 by @lazka in + https://github.com/libgit2/libgit2/pull/6626 +* ci: retry flaky online tests by @ethomson in + https://github.com/libgit2/libgit2/pull/6628 +* ci: update to macOS 12 by @ethomson in + https://github.com/libgit2/libgit2/pull/6629 +* Use `#!/bin/bash` for script with bash-specific commands by @roehling in + https://github.com/libgit2/libgit2/pull/6581 +* ci: overwrite nonsense in `/usr/local` during macOS setup by @ethomson in + https://github.com/libgit2/libgit2/pull/6664 +* release: add a compatibility label by @ethomson in + https://github.com/libgit2/libgit2/pull/6676 +* actions: set permissions by @ethomson in + https://github.com/libgit2/libgit2/pull/6680 +* cmake: rename FindIconv to avoid collision with cmake by @ethomson in + https://github.com/libgit2/libgit2/pull/6682 +* ci: allow workflows to read and write packages by @ethomson in + https://github.com/libgit2/libgit2/pull/6687 +* ci: allow workflows to push changes by @ethomson in + https://github.com/libgit2/libgit2/pull/6688 +* tests: remove test for strcasecmp by @boretrk in + https://github.com/libgit2/libgit2/pull/6691 +* CI fixes by @ethomson in + https://github.com/libgit2/libgit2/pull/6694 +* ci: improvements to prepare for Cygwin support by @ethomson in + https://github.com/libgit2/libgit2/pull/6696 +* Yet more CI improvements by @ethomson in + https://github.com/libgit2/libgit2/pull/6697 +* Fix nightly builds by @ethomson in + https://github.com/libgit2/libgit2/pull/6709 +* Benchmarks: add a site to view results by @ethomson in + https://github.com/libgit2/libgit2/pull/6715 +* `GIT_RAND_GETENTROPY`: do not include `sys/random.h` by @semarie in + https://github.com/libgit2/libgit2/pull/6736 +* add dl to `LIBGIT2_SYSTEM_LIBS` by @christopherfujino in + https://github.com/libgit2/libgit2/pull/6631 +* meta: add dependency tag to release.yml by @ethomson in + https://github.com/libgit2/libgit2/pull/6740 +* CI: fix our nightlies by @ethomson in + https://github.com/libgit2/libgit2/pull/6751 +* trace: Re-enable tests as tracing is now enabled by default by @lrm29 in + https://github.com/libgit2/libgit2/pull/6752 +* tests: don't free an unininitialized repo by @ethomson in + https://github.com/libgit2/libgit2/pull/6763 +* ci: reduce ASLR randomization for TSAN by @ethomson in + https://github.com/libgit2/libgit2/pull/6764 +* packbuilder: adjust nondeterministic tests by @ethomson in + https://github.com/libgit2/libgit2/pull/6762 +* Allow libgit2 to be compiled with mbedtls3. by @adamharrison in + https://github.com/libgit2/libgit2/pull/6759 +* build: update to latest actions versions by @ethomson in + https://github.com/libgit2/libgit2/pull/6765 +* ctype: cast characters to unsigned when classifying characters by + @boretrk in https://github.com/libgit2/libgit2/pull/6679 and + @ethomson in https://github.com/libgit2/libgit2/pull/6770 +* valgrind: suppress OpenSSL warnings by @ethomson in https://github.com/libgit2/libgit2/pull/6769 + +### Documentation improvements + +* README.md: Fix link to conan packages by @lrm29 in + https://github.com/libgit2/libgit2/pull/6621 +* README: replace gmaster with GitButler by @ethomson in + https://github.com/libgit2/libgit2/pull/6692 +* blame example: Fix support for line range in CLI by @wetneb in + https://github.com/libgit2/libgit2/pull/6638 +* Support authentication in push example by @pluehne in + https://github.com/libgit2/libgit2/pull/5904 +* docs: fix mistake in attr.h by @DavHau in + https://github.com/libgit2/libgit2/pull/6714 +* Fix broken links by @csware in + https://github.com/libgit2/libgit2/pull/6747 + +### Platform compatibility fixes + +* stransport: macOS: replace `errSSLNetworkTimeout`, with hard-coded + value by @mascguy in https://github.com/libgit2/libgit2/pull/6610 + +### Git compatibility fixes + +* Do not trim dots from usernames by @georgthegreat in + https://github.com/libgit2/libgit2/pull/6657 +* merge: fix incorrect rename detection for empty files by @herrerog in + https://github.com/libgit2/libgit2/pull/6717 + +### Dependency updates + +* zlib: upgrade bundled zlib to v1.3 by @ethomson in + https://github.com/libgit2/libgit2/pull/6698 +* ntlmclient: update to latest upstream ntlmclient by @ethomson in + https://github.com/libgit2/libgit2/pull/6704 + +## New Contributors + +* @dvzrv made their first contribution in + https://github.com/libgit2/libgit2/pull/6608 +* @mascguy made their first contribution in + https://github.com/libgit2/libgit2/pull/6610 +* @steven9724 made their first contribution in + https://github.com/libgit2/libgit2/pull/6599 +* @lazka made their first contribution in + https://github.com/libgit2/libgit2/pull/6626 +* @roehling made their first contribution in + https://github.com/libgit2/libgit2/pull/6581 +* @7Ji made their first contribution in + https://github.com/libgit2/libgit2/pull/6651 +* @kempniu made their first contribution in + https://github.com/libgit2/libgit2/pull/6662 +* @thosey made their first contribution in + https://github.com/libgit2/libgit2/pull/6572 +* @wetneb made their first contribution in + https://github.com/libgit2/libgit2/pull/6638 +* @yori made their first contribution in + https://github.com/libgit2/libgit2/pull/6642 +* @pluehne made their first contribution in + https://github.com/libgit2/libgit2/pull/5904 +* @DavHau made their first contribution in + https://github.com/libgit2/libgit2/pull/6714 +* @vafada made their first contribution in + https://github.com/libgit2/libgit2/pull/6721 +* @semarie made their first contribution in + https://github.com/libgit2/libgit2/pull/6736 +* @christopherfujino made their first contribution in + https://github.com/libgit2/libgit2/pull/6631 +* @parnic made their first contribution in + https://github.com/libgit2/libgit2/pull/6738 +* @samueltardieu made their first contribution in + https://github.com/libgit2/libgit2/pull/6723 +* @xphoniex made their first contribution in + https://github.com/libgit2/libgit2/pull/6240 +* @adamharrison made their first contribution in + https://github.com/libgit2/libgit2/pull/6759 + +**Full Changelog**: https://github.com/libgit2/libgit2/compare/v1.7.0...v1.8.0 + +v1.7 +---- + +This is release v1.7.0, "Kleine Raupe Nimmersatt". This release adds +shallow clone support, completes the experimental SHA256 support, +adds Schannel support for Windows, and includes many other new +features and bugfixes. + +## Major changes + +* **Shallow clone support** + libgit2 now supports shallow clone and shallow repositories, thanks + to a significant investment from many community members -- hundreds + of commits by many contributors. + + * Shallow (#6396) with some fixes from review by @ethomson in + https://github.com/libgit2/libgit2/pull/6557 + * Shallow Clone Support by @lya001 in + https://github.com/libgit2/libgit2/pull/6396 + * Shallow support v2 by @pks-t in + https://github.com/libgit2/libgit2/pull/5254 + +* **SHA256 support** + libgit2 should now support SHA256 repositories using the + `extensions.objectFormat` configuration option when the library is + built with `EXPERIMENTAL_SHA256=ON`. Users are encouraged to begin + testing their applications with this option and provide bug reports + and feedback. This _is_ a breaking API change; SHA256 support will + be enabled by default in libgit2 v2.0. + + * sha256: less hardcoded SHA1 types and lengths by @ethomson in + https://github.com/libgit2/libgit2/pull/6549 + * Support SHA256 in git_repository_wrap_odb by @ethomson in + https://github.com/libgit2/libgit2/pull/6556 + +* **Schannel and SSPI for Windows** + libgit2 now supports the Windows Schannel and SSPI APIs for HTTPS + support on Windows, when configured with `USE_HTTPS=Schannel`. + Setting this option will not use the existing WinHTTP support, but + will use libgit2's standard HTTP client stack with Windows TLS + primitives. Windows users are encouraged to begin testing their + applications with this option and provide bug reports and feedback. + This will be enabled by default in a future version of libgit2. + + * Introduce Schannel and SSPI for Windows by @ethomson in + https://github.com/libgit2/libgit2/pull/6533 + +## Breaking changes + +* **Simplify custom pluggable allocator** (System API / ABI breaking change) + The `git_allocator` structure (configurable by the + `GIT_OPT_SET_ALLOCATOR` option) now only contains `gmalloc`, + `grealloc` and `gfree` members. This simplifies both the work needed + by an implementer _and_ allows more flexibility and correctness in + libgit2 itself, especially during out-of-memory situations and + errors during bootstrapping. + + * tests: add allocator with limited number of bytes by @ethomson in + https://github.com/libgit2/libgit2/pull/6563 + +## Other changes + +### New features +* repo: honor environment variables for more scenarios by @ethomson in + https://github.com/libgit2/libgit2/pull/6544 +* Introduce timeouts on sockets by @ethomson in + https://github.com/libgit2/libgit2/pull/6535 + +### Performance improvements +* midx: do not try to look at every object in the index by @carlosmn in + https://github.com/libgit2/libgit2/pull/6585 +* Partial fix for #6532: insert-by-date order. by @arroz in + https://github.com/libgit2/libgit2/pull/6539 + +### Bug fixes +* repo: don't allow repeated extensions by @ethomson in + https://github.com/libgit2/libgit2/pull/6505 +* config: return `GIT_ENOTFOUND` for missing programdata by @ethomson in + https://github.com/libgit2/libgit2/pull/6547 +* Fix missing oid type for "fake" repositories by @oreiche in + https://github.com/libgit2/libgit2/pull/6554 +* Thread-local storage: handle failure cases by @ethomson in + https://github.com/libgit2/libgit2/pull/5722 +* midx: allow unknown chunk ids in multi-pack index files by @carlosmn in + https://github.com/libgit2/libgit2/pull/6583 +* pack: cast the number of objects to size_t by @carlosmn in + https://github.com/libgit2/libgit2/pull/6584 +* Fixes #6344: git_branch_move now renames the reflog instead of deleting + by @arroz in https://github.com/libgit2/libgit2/pull/6345 +* #6576 git_diff_index_to_workdir reverse now loads untracked content by + @arroz in https://github.com/libgit2/libgit2/pull/6577 + +### Build and CI improvements +* meta: the main branch is now v1.7.0 by @ethomson in + https://github.com/libgit2/libgit2/pull/6516 +* xdiff: move xdiff to 'deps' by @ethomson in + https://github.com/libgit2/libgit2/pull/6482 +* util: detect all possible qsort_r and qsort_s variants by + @DimitryAndric in https://github.com/libgit2/libgit2/pull/6555 +* Work around -Werror problems when detecting qsort variants by + @DimitryAndric in https://github.com/libgit2/libgit2/pull/6558 +* actions: simplify execution with composite action by @ethomson in + https://github.com/libgit2/libgit2/pull/6488 +* CMake: Search for ssh2 instead of libssh2. by @Faless in + https://github.com/libgit2/libgit2/pull/6586 + +### Documentation improvements +* docs: fix IRC server from freenode to libera by @vincenzopalazzo in + https://github.com/libgit2/libgit2/pull/6590 + +### Dependency upgrades +* Update xdiff to git 2.40.1's version by @ethomson in + https://github.com/libgit2/libgit2/pull/6561 +* deps: update pcre to 8.45 by @ethomson in + https://github.com/libgit2/libgit2/pull/6593 + +## New Contributors +* @oreiche made their first contribution in + https://github.com/libgit2/libgit2/pull/6554 +* @DimitryAndric made their first contribution in + https://github.com/libgit2/libgit2/pull/6555 +* @vincenzopalazzo made their first contribution in + https://github.com/libgit2/libgit2/pull/6590 +* @Faless made their first contribution in + https://github.com/libgit2/libgit2/pull/6586 + +**Full Changelog**: https://github.com/libgit2/libgit2/compare/v1.6.3...v1.7.0 + +v1.6.3 +------ + +## What's Changed + +### Bug fixes + +* odb: restore `git_odb_open` by @ethomson in https://github.com/libgit2/libgit2/pull/6520 +* Ensure that `git_index_add_all` handles ignored directories by @ethomson in https://github.com/libgit2/libgit2/pull/6521 +* pack: use 64 bits for the number of objects by @carlosmn in https://github.com/libgit2/libgit2/pull/6530 + +### Build and CI improvements + +* Remove unused wditer variable by @georgthegreat in https://github.com/libgit2/libgit2/pull/6518 +* fs_path: let root run the ownership tests by @ethomson in https://github.com/libgit2/libgit2/pull/6513 +* sysdir: Do not declare win32 functions on non-win32 platforms by @Batchyx in https://github.com/libgit2/libgit2/pull/6527 +* cmake: don't include `include/git2` by @ethomson in https://github.com/libgit2/libgit2/pull/6529 + +## New Contributors +* @georgthegreat made their first contribution in https://github.com/libgit2/libgit2/pull/6518 + +**Full Changelog**: https://github.com/libgit2/libgit2/compare/v1.6.2...v1.6.3 + +v1.6.2 +------ + +## What's Changed +### Bug fixes + +* remote: always populate old id in update tips by @ethomson in https://github.com/libgit2/libgit2/pull/6506 + The update tips callback would not always be properly provided with an empty (`0000000...`) OID for new refs. + +* Revert #6503 by @ethomson in https://github.com/libgit2/libgit2/pull/6511 + The certificate callback added port information for callbacks in #6503, but the format was ambiguous with IPv6 addresses. Revert this change temporarily. + +* Add `git_odb_backend_loose` back by @ethomson in https://github.com/libgit2/libgit2/pull/6512 + During SHA256 refactoring, the `git_odb_backend_loose` API was accidentally removed. Add it back. + +* meta: configure pkg-config .pc correctly by @ethomson in https://github.com/libgit2/libgit2/pull/6514 + During SHA256 refactoring, the pkg-config `.pc` file was erroneously renamed to `git2` instead of `libgit2`. Repair this. + +**Full Changelog**: https://github.com/libgit2/libgit2/compare/v1.6.1...v1.6.2 -* xdiff: use xdl_free not free by @ethomson -* cmake: Fix package name for system http-parser by @mgorny -* Free parent and ref in lg2_commit before returning by @apnadkarni +v1.6 +---- + +This is release v1.6.1, "Hubbeliges Krokodil". This release adds experimental SHA256 support and includes many new features and bugfixes. This release replaces libgit2 v1.6.0, which did not correctly update its version number(s). + +## What's Changed + +### New features + +* **Support for bare repositories with SHA256 support (experimental)** by @ethomson in https://github.com/libgit2/libgit2/pull/6191 + You can configure experimental SHA256 support in libgit2 with `cmake -DEXPERIMENTAL_SHA256=ON` during project setup. This is useful for considering future integrations, work on clients, and work on language bindings. At present, working with bare repositories should largely work, including remote operations. But many pieces of functionality - including working with the index - are not yet supported. As a result, **libgit2 with SHA256 support should not be used in production or released with package distribution.** + +* **Support the notion of a home directory separately from global configuration directory** by @ethomson in https://github.com/libgit2/libgit2/pull/6455 and https://github.com/libgit2/libgit2/pull/6456 + Callers and language bindings can now configure the home directory that libgit2 uses for file lookups (eg, the `.ssh` directory). This configuration is separate from the git global configuration path. + +* **stash: partial stash specific files** by @gitkraken-jacobw in https://github.com/libgit2/libgit2/pull/6330 + A stash can be created with only specific files, using a pathspec. This is similar to the `git stash push` command. + +* **push: revparse refspec source, so you can push things that are not refs** by @sven-of-cord in https://github.com/libgit2/libgit2/pull/6362 + Pushes can be performed using refspecs instead of only references. + +* **Support OpenSSL3** by @ethomson in https://github.com/libgit2/libgit2/pull/6464 and https://github.com/libgit2/libgit2/pull/6471 + OpenSSL 3 is now supported, both when compiled directly and dynamically loaded. + +### Bug fixes +* winhttp: support long custom headers by @kcsaul in https://github.com/libgit2/libgit2/pull/6363 +* Fix memory leak by @csware in https://github.com/libgit2/libgit2/pull/6382 +* Don't fail the whole clone if you can't find a default branch by @torvalds in https://github.com/libgit2/libgit2/pull/6369 +* #6366: When a worktree is missing, return `GIT_ENOTFOUND`. by @arroz in https://github.com/libgit2/libgit2/pull/6395 +* commit-graph: only verify csum on `git_commit_graph_open()`. by @derrickstolee in https://github.com/libgit2/libgit2/pull/6420 +* Ignore missing 'safe.directory' config during ownership checks by @kcsaul in https://github.com/libgit2/libgit2/pull/6408 +* Fix leak in `git_tag_create_from_buffer` by @julianmesa-gitkraken in https://github.com/libgit2/libgit2/pull/6421 +* http: Update httpclient options when reusing an existing connection. by @slackner in https://github.com/libgit2/libgit2/pull/6416 +* Add support for `safe.directory *` by @csware in https://github.com/libgit2/libgit2/pull/6429 +* URL parsing for google-compatible URLs by @ethomson in https://github.com/libgit2/libgit2/pull/6326 +* Fixes #6433: `git_submodule_update` fails to update configured but missing submodule by @tagesuhu in https://github.com/libgit2/libgit2/pull/6434 +* transport: fix capabilities calculation by @russell in https://github.com/libgit2/libgit2/pull/6435 +* push: use resolved oid as the source by @ethomson in https://github.com/libgit2/libgit2/pull/6452 +* Use `git_clone__submodule` to avoid file checks in workdir by @abizjak in https://github.com/libgit2/libgit2/pull/6444 +* #6422: handle dangling symbolic refs gracefully by @arroz in https://github.com/libgit2/libgit2/pull/6423 +* `diff_file`: Fix crash when freeing a patch representing an empty untracked file by @jorio in https://github.com/libgit2/libgit2/pull/6475 +* clone: clean up options on failure by @ethomson in https://github.com/libgit2/libgit2/pull/6479 +* stash: update strarray usage by @ethomson in https://github.com/libgit2/libgit2/pull/6487 +* #6491: Sets `oid_type` on repos open with `git_repository_open_bare` by @arroz in https://github.com/libgit2/libgit2/pull/6492 +* Handle Win32 shares by @ethomson in https://github.com/libgit2/libgit2/pull/6493 +* Make failure to connect to ssh-agent non-fatal by @fxcoudert in https://github.com/libgit2/libgit2/pull/6497 +* odb: don't unconditionally add `oid_type` to stream by @ethomson in https://github.com/libgit2/libgit2/pull/6499 +* Pass hostkey & port to host verify callback by @fxcoudert in https://github.com/libgit2/libgit2/pull/6503 + +### Code cleanups +* meta: update version number to v1.6.0-alpha by @ethomson in https://github.com/libgit2/libgit2/pull/6352 +* sha256: indirection for experimental functions by @ethomson in https://github.com/libgit2/libgit2/pull/6354 +* Delete `create.c.bak` by @lrm29 in https://github.com/libgit2/libgit2/pull/6398 +* Support non-cmake builds with an in-tree `experimental.h` by @ethomson in https://github.com/libgit2/libgit2/pull/6405 + +### Build and CI improvements +* tests: skip flaky-ass googlesource tests by @ethomson in https://github.com/libgit2/libgit2/pull/6353 +* clar: remove ftrunacte from libgit2 tests by @boretrk in https://github.com/libgit2/libgit2/pull/6357 +* CI Improvements by @ethomson in https://github.com/libgit2/libgit2/pull/6403 +* fix compile on Windows with `-DWIN32_LEAN_AND_MEAN` by @christoph-cullmann in https://github.com/libgit2/libgit2/pull/6373 +* Fixes #6365 : Uppercase windows.h include fails build in case-sensitive OS by @Vinz2008 in https://github.com/libgit2/libgit2/pull/6377 +* ci: update version numbers of actions by @ethomson in https://github.com/libgit2/libgit2/pull/6448 +* thread: avoid warnings when building without threads by @ethomson in https://github.com/libgit2/libgit2/pull/6432 +* src: hide unused hmac() prototype by @0-wiz-0 in https://github.com/libgit2/libgit2/pull/6458 +* tests: update clar test runner by @ethomson in https://github.com/libgit2/libgit2/pull/6459 +* ci: always create test summaries, even on failure by @ethomson in https://github.com/libgit2/libgit2/pull/6460 +* Fix build failure with `-DEMBED_SSH_PATH` by @vicr123 in https://github.com/libgit2/libgit2/pull/6374 +* Define correct `off64_t` for AIX by @bzEq in https://github.com/libgit2/libgit2/pull/6376 +* Fix some warnings in main by @ethomson in https://github.com/libgit2/libgit2/pull/6480 +* strarray: remove deprecated declaration by @ethomson in https://github.com/libgit2/libgit2/pull/6486 +* tests: always unset `HTTP_PROXY` before starting tests by @ethomson in https://github.com/libgit2/libgit2/pull/6498 + +### Documentation improvements +* add 2-clause BSD license to COPYING by @martinvonz in https://github.com/libgit2/libgit2/pull/6413 +* Add new PHP bindings project to language bindings section of README.md by @RogerGee in https://github.com/libgit2/libgit2/pull/6473 +* README: clarify the linking exception by @ethomson in https://github.com/libgit2/libgit2/pull/6494 +* Correct the definition of "empty" in the docs for `git_repository_is_empty` by @timrogers in https://github.com/libgit2/libgit2/pull/6500 + +## New Contributors +* @christoph-cullmann made their first contribution in https://github.com/libgit2/libgit2/pull/6373 +* @Vinz2008 made their first contribution in https://github.com/libgit2/libgit2/pull/6377 +* @torvalds made their first contribution in https://github.com/libgit2/libgit2/pull/6369 +* @derrickstolee made their first contribution in https://github.com/libgit2/libgit2/pull/6420 +* @julianmesa-gitkraken made their first contribution in https://github.com/libgit2/libgit2/pull/6421 +* @slackner made their first contribution in https://github.com/libgit2/libgit2/pull/6416 +* @martinvonz made their first contribution in https://github.com/libgit2/libgit2/pull/6413 +* @tagesuhu made their first contribution in https://github.com/libgit2/libgit2/pull/6434 +* @russell made their first contribution in https://github.com/libgit2/libgit2/pull/6435 +* @sven-of-cord made their first contribution in https://github.com/libgit2/libgit2/pull/6362 +* @0-wiz-0 made their first contribution in https://github.com/libgit2/libgit2/pull/6458 +* @abizjak made their first contribution in https://github.com/libgit2/libgit2/pull/6444 +* @vicr123 made their first contribution in https://github.com/libgit2/libgit2/pull/6374 +* @bzEq made their first contribution in https://github.com/libgit2/libgit2/pull/6376 +* @gitkraken-jacobw made their first contribution in https://github.com/libgit2/libgit2/pull/6330 +* @fxcoudert made their first contribution in https://github.com/libgit2/libgit2/pull/6497 +* @timrogers made their first contribution in https://github.com/libgit2/libgit2/pull/6500 + +**Full Changelog**: https://github.com/libgit2/libgit2/compare/v1.5.0...v1.6.0 + +v1.5 +---- + +This is release v1.5.0, "Stubentiger". This release adds the basis for an experimental CLI, continues preparing for SHA256 support, adds a benchmarking utility, and has numerous new features and bugfixes. + +## What's Changed +### New features +* The beginnings of a git-compatible CLI for testing and benchmarking by @ethomson in https://github.com/libgit2/libgit2/pull/6133 +* Add `clone` support to the CLI @ethomson in https://github.com/libgit2/libgit2/pull/6274 +* A benchmarking suite to compare libgit2 functionality against git by @ethomson in https://github.com/libgit2/libgit2/pull/6235 +* SHA256: add a SHA256 implementation backend by @ethomson in https://github.com/libgit2/libgit2/pull/6144 +* SHA256: support dynamically loaded openssl by @ethomson in https://github.com/libgit2/libgit2/pull/6258 +* Transport: introduce `git_transport_smart_remote_connect_options` by @lhchavez in https://github.com/libgit2/libgit2/pull/6278 +### Bug fixes +* Free parent and ref in lg2_commit before returning. by @apnadkarni in https://github.com/libgit2/libgit2/pull/6219 +* xdiff: use xdl_free not free by @ethomson in https://github.com/libgit2/libgit2/pull/6223 +* remote: do store the update_tips callback error value by @carlosmn in https://github.com/libgit2/libgit2/pull/6226 +* win32: `find_system_dirs` does not return `GIT_ENOTFOUND` by @ethomson in https://github.com/libgit2/libgit2/pull/6228 +* Some minor fixes for issues discovered by coverity by @ethomson in https://github.com/libgit2/libgit2/pull/6238 +* Fix a string concatenation bug when validating extensions by @bierbaum in https://github.com/libgit2/libgit2/pull/6246 +* fetch: support OID refspec without dst by @ethomson in https://github.com/libgit2/libgit2/pull/6251 +* Fix crash when regenerating a patch with unquoted spaces in filename by @jorio in https://github.com/libgit2/libgit2/pull/6244 +* midx: Fix an undefined behavior (left-shift signed overflow) by @lhchavez in https://github.com/libgit2/libgit2/pull/6260 +* Validate repository directory ownership by @ethomson in https://github.com/libgit2/libgit2/pull/6266 +* midx: fix large offset table check. by @ccstolley in https://github.com/libgit2/libgit2/pull/6309 +* midx: do not verify the checksum on load by @carlosmn in https://github.com/libgit2/libgit2/pull/6291 +* revparse: Remove error-prone, redundant test by @dongcarl in https://github.com/libgit2/libgit2/pull/6299 +* refs: fix missing error message by @zawata in https://github.com/libgit2/libgit2/pull/6305 +* CLI: progress updates by @ethomson in https://github.com/libgit2/libgit2/pull/6319 +* A couple of simplications around mwindow by @carlosmn in https://github.com/libgit2/libgit2/pull/6288 +* config: update config entry iteration lifecycle by @ethomson in https://github.com/libgit2/libgit2/pull/6320 +* repo: allow administrator to own the configuration by @ethomson in https://github.com/libgit2/libgit2/pull/6321 +* filter: Fix Segfault by @zawata in https://github.com/libgit2/libgit2/pull/6303 +* ntlmclient: LibreSSL 3.5 removed HMAC_CTX_cleanup by @vishwin in https://github.com/libgit2/libgit2/pull/6340 +* Fix internal git_sysdir_find* function usage within public git_config_find* functions by @kcsaul in https://github.com/libgit2/libgit2/pull/6335 +* fix interactive rebase detect. by @i-tengfei in https://github.com/libgit2/libgit2/pull/6334 +* cmake: drop posix dependency from pcre* detection by @jpalus in https://github.com/libgit2/libgit2/pull/6333 +* Fix erroneously lax configuration ownership checks by @ethomson in https://github.com/libgit2/libgit2/pull/6341 +* pack: don't pretend we support pack files v3 by @ethomson in https://github.com/libgit2/libgit2/pull/6347 +* Fix creation of branches and tags with invalid names by @lya001 in https://github.com/libgit2/libgit2/pull/6348 +### Security fixes +* Fixes for CVE 2022-29187 by @ethomson in https://github.com/libgit2/libgit2/pull/6349 +* zlib: update bundled zlib to v1.2.12 by @ethomson in https://github.com/libgit2/libgit2/pull/6350 +### Code cleanups +* sha256: refactoring in preparation for sha256 by @ethomson in https://github.com/libgit2/libgit2/pull/6265 +* remote: Delete a now-inexistent API declaration by @lhchavez in https://github.com/libgit2/libgit2/pull/6276 +* Fix missing include by @cschlack in https://github.com/libgit2/libgit2/pull/6277 +### Build and CI improvements +* meta: show build status for v1.3 and v1.4 branches by @ethomson in https://github.com/libgit2/libgit2/pull/6216 +* cmake: Fix package name for system http-parser by @mgorny in https://github.com/libgit2/libgit2/pull/6217 +* meta: update version number to v1.5.0-alpha by @ethomson in https://github.com/libgit2/libgit2/pull/6220 +* cmake: export libraries needed to compile against libgit2 by @ethomson in https://github.com/libgit2/libgit2/pull/6239 +* clone: update bitbucket tests by @ethomson in https://github.com/libgit2/libgit2/pull/6252 +* diff: don't stat empty file on arm32 (flaky test) by @ethomson in https://github.com/libgit2/libgit2/pull/6259 +* tests: support flaky stat by @ethomson in https://github.com/libgit2/libgit2/pull/6262 +* Include test results data in CI by @ethomson in https://github.com/libgit2/libgit2/pull/6306 +* Add a .clang-format with our style by @ethomson in https://github.com/libgit2/libgit2/pull/6023 +* CI: limits actions scheduled workflows to the main repo by @ethomson in https://github.com/libgit2/libgit2/pull/6342 +* ci: update dockerfiles for mbedTLS new url by @ethomson in https://github.com/libgit2/libgit2/pull/6343 +### Documentation improvements +* Add Pharo to language bindings by @theseion in https://github.com/libgit2/libgit2/pull/6310 +* Add link to Tcl bindings for libgit2 by @apnadkarni in https://github.com/libgit2/libgit2/pull/6318 +* fix couple of typos by @SkinnyMind in https://github.com/libgit2/libgit2/pull/6287 +* update documentation for default status options by @ethomson in https://github.com/libgit2/libgit2/pull/6322 + +## New Contributors +* @bierbaum made their first contribution in https://github.com/libgit2/libgit2/pull/6246 +* @dongcarl made their first contribution in https://github.com/libgit2/libgit2/pull/6299 +* @SkinnyMind made their first contribution in https://github.com/libgit2/libgit2/pull/6287 +* @zawata made their first contribution in https://github.com/libgit2/libgit2/pull/6305 +* @vishwin made their first contribution in https://github.com/libgit2/libgit2/pull/6340 +* @i-tengfei made their first contribution in https://github.com/libgit2/libgit2/pull/6334 +* @jpalus made their first contribution in https://github.com/libgit2/libgit2/pull/6333 +* @lya001 made their first contribution in https://github.com/libgit2/libgit2/pull/6348 + +**Full Changelog**: https://github.com/libgit2/libgit2/compare/v1.4.0...v1.5.0 v1.4 ---- diff --git a/vendor/libgit2/docs/contributing.md b/vendor/libgit2/docs/contributing.md index 03e00170..382d9555 100644 --- a/vendor/libgit2/docs/contributing.md +++ b/vendor/libgit2/docs/contributing.md @@ -24,9 +24,8 @@ by the following licenses: ## Discussion & Chat -We hang out in the -[`#libgit2`](http://webchat.freenode.net/?channels=#libgit2)) channel on -irc.freenode.net. +We hang out in the [#libgit2](https://web.libera.chat/#libgit2) channel on +[libera](https://libera.chat). Also, feel free to open an [Issue](https://github.com/libgit2/libgit2/issues/new) to start a discussion diff --git a/vendor/libgit2/examples/CMakeLists.txt b/vendor/libgit2/examples/CMakeLists.txt index 235e72ad..8e38c7d4 100644 --- a/vendor/libgit2/examples/CMakeLists.txt +++ b/vendor/libgit2/examples/CMakeLists.txt @@ -1,3 +1,5 @@ +# examples: code usage examples of libgit2 + file(GLOB SRC_EXAMPLES *.c *.h) add_executable(lg2 ${SRC_EXAMPLES}) @@ -10,7 +12,7 @@ target_include_directories(lg2 PRIVATE ${LIBGIT2_INCLUDES} ${LIBGIT2_DEPENDENCY_ target_include_directories(lg2 SYSTEM PRIVATE ${LIBGIT2_SYSTEM_INCLUDES}) if(WIN32 OR ANDROID) - target_link_libraries(lg2 git2) + target_link_libraries(lg2 libgit2package) else() - target_link_libraries(lg2 git2 pthread) + target_link_libraries(lg2 libgit2package pthread) endif() diff --git a/vendor/libgit2/examples/README.md b/vendor/libgit2/examples/README.md index 769c4b26..0f1f2538 100644 --- a/vendor/libgit2/examples/README.md +++ b/vendor/libgit2/examples/README.md @@ -15,8 +15,8 @@ so there are no restrictions on their use. For annotated HTML versions, see the "Examples" section of: - http://libgit2.github.com/libgit2 + https://libgit2.org/libgit2 such as: - http://libgit2.github.com/libgit2/ex/HEAD/general.html + https://libgit2.org/libgit2/ex/HEAD/general.html diff --git a/vendor/libgit2/examples/args.h b/vendor/libgit2/examples/args.h index d626f98c..4db0493b 100644 --- a/vendor/libgit2/examples/args.h +++ b/vendor/libgit2/examples/args.h @@ -8,7 +8,7 @@ struct args_info { int argc; char **argv; int pos; - int opts_done : 1; /**< Did we see a -- separator */ + unsigned int opts_done : 1; /**< Did we see a -- separator */ }; #define ARGS_INFO_INIT { argc, argv, 0, 0 } #define ARGS_CURRENT(args) args->argv[args->pos] diff --git a/vendor/libgit2/examples/blame.c b/vendor/libgit2/examples/blame.c index 77087a57..0996e7a1 100644 --- a/vendor/libgit2/examples/blame.c +++ b/vendor/libgit2/examples/blame.c @@ -47,6 +47,10 @@ int lg2_blame(git_repository *repo, int argc, char *argv[]) if (o.M) blameopts.flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES; if (o.C) blameopts.flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES; if (o.F) blameopts.flags |= GIT_BLAME_FIRST_PARENT; + if (o.start_line && o.end_line) { + blameopts.min_line = o.start_line; + blameopts.max_line = o.end_line; + } /** * The commit range comes in "committish" form. Use the rev-parse API to diff --git a/vendor/libgit2/examples/cat-file.c b/vendor/libgit2/examples/cat-file.c index b81e9a8d..741edb48 100644 --- a/vendor/libgit2/examples/cat-file.c +++ b/vendor/libgit2/examples/cat-file.c @@ -49,7 +49,7 @@ static void show_blob(const git_blob *blob) static void show_tree(const git_tree *tree) { size_t i, max_i = (int)git_tree_entrycount(tree); - char oidstr[GIT_OID_HEXSZ + 1]; + char oidstr[GIT_OID_SHA1_HEXSIZE + 1]; const git_tree_entry *te; for (i = 0; i < max_i; ++i) { @@ -70,7 +70,7 @@ static void show_tree(const git_tree *tree) static void show_commit(const git_commit *commit) { unsigned int i, max_i; - char oidstr[GIT_OID_HEXSZ + 1]; + char oidstr[GIT_OID_SHA1_HEXSIZE + 1]; git_oid_tostr(oidstr, sizeof(oidstr), git_commit_tree_id(commit)); printf("tree %s\n", oidstr); @@ -90,7 +90,7 @@ static void show_commit(const git_commit *commit) static void show_tag(const git_tag *tag) { - char oidstr[GIT_OID_HEXSZ + 1]; + char oidstr[GIT_OID_SHA1_HEXSIZE + 1]; git_oid_tostr(oidstr, sizeof(oidstr), git_tag_target_id(tag));; printf("object %s\n", oidstr); @@ -125,7 +125,7 @@ int lg2_cat_file(git_repository *repo, int argc, char *argv[]) { struct catfile_options o = { ".", NULL, 0, 0 }; git_object *obj = NULL; - char oidstr[GIT_OID_HEXSZ + 1]; + char oidstr[GIT_OID_SHA1_HEXSIZE + 1]; parse_opts(&o, argc, argv); @@ -133,7 +133,7 @@ int lg2_cat_file(git_repository *repo, int argc, char *argv[]) "Could not resolve", o.rev); if (o.verbose) { - char oidstr[GIT_OID_HEXSZ + 1]; + char oidstr[GIT_OID_SHA1_HEXSIZE + 1]; git_oid_tostr(oidstr, sizeof(oidstr), git_object_id(obj)); printf("%s %s\n--\n", diff --git a/vendor/libgit2/examples/checkout.c b/vendor/libgit2/examples/checkout.c index ac7b7422..82567cdc 100644 --- a/vendor/libgit2/examples/checkout.c +++ b/vendor/libgit2/examples/checkout.c @@ -35,9 +35,9 @@ */ typedef struct { - int force : 1; - int progress : 1; - int perf : 1; + unsigned int force : 1; + unsigned int progress : 1; + unsigned int perf : 1; } checkout_options; static void print_usage(void) diff --git a/vendor/libgit2/examples/diff.c b/vendor/libgit2/examples/diff.c index a9fb5d44..80c5200e 100644 --- a/vendor/libgit2/examples/diff.c +++ b/vendor/libgit2/examples/diff.c @@ -188,9 +188,17 @@ static void compute_diff_no_index(git_diff **diff, struct diff_options *o) { check_lg2( git_patch_to_buf(&buf, patch), "patch to buf", NULL); + +#ifdef GIT_EXPERIMENTAL_SHA256 + check_lg2( + git_diff_from_buffer(diff, buf.ptr, buf.size, NULL), + "diff from patch", NULL); +#else check_lg2( git_diff_from_buffer(diff, buf.ptr, buf.size), "diff from patch", NULL); +#endif + git_patch_free(patch); git_buf_dispose(&buf); free(file1_str); diff --git a/vendor/libgit2/examples/fetch.c b/vendor/libgit2/examples/fetch.c index 2b5ed111..bbd882cf 100644 --- a/vendor/libgit2/examples/fetch.c +++ b/vendor/libgit2/examples/fetch.c @@ -15,17 +15,17 @@ static int progress_cb(const char *str, int len, void *data) */ static int update_cb(const char *refname, const git_oid *a, const git_oid *b, void *data) { - char a_str[GIT_OID_HEXSZ+1], b_str[GIT_OID_HEXSZ+1]; + char a_str[GIT_OID_SHA1_HEXSIZE+1], b_str[GIT_OID_SHA1_HEXSIZE+1]; (void)data; git_oid_fmt(b_str, b); - b_str[GIT_OID_HEXSZ] = '\0'; + b_str[GIT_OID_SHA1_HEXSIZE] = '\0'; if (git_oid_is_zero(a)) { printf("[new] %.20s %s\n", b_str, refname); } else { git_oid_fmt(a_str, a); - a_str[GIT_OID_HEXSZ] = '\0'; + a_str[GIT_OID_SHA1_HEXSIZE] = '\0'; printf("[updated] %.10s..%.10s %s\n", a_str, b_str, refname); } diff --git a/vendor/libgit2/examples/for-each-ref.c b/vendor/libgit2/examples/for-each-ref.c index 020dab47..f745bc38 100644 --- a/vendor/libgit2/examples/for-each-ref.c +++ b/vendor/libgit2/examples/for-each-ref.c @@ -5,7 +5,7 @@ static int show_ref(git_reference *ref, void *data) { git_repository *repo = data; git_reference *resolved = NULL; - char hex[GIT_OID_HEXSZ+1]; + char hex[GIT_OID_SHA1_HEXSIZE+1]; const git_oid *oid; git_object *obj; @@ -16,7 +16,7 @@ static int show_ref(git_reference *ref, void *data) oid = git_reference_target(resolved ? resolved : ref); git_oid_fmt(hex, oid); - hex[GIT_OID_HEXSZ] = 0; + hex[GIT_OID_SHA1_HEXSIZE] = 0; check_lg2(git_object_lookup(&obj, repo, oid, GIT_OBJECT_ANY), "Unable to lookup object", hex); @@ -25,6 +25,8 @@ static int show_ref(git_reference *ref, void *data) git_object_type2string(git_object_type(obj)), git_reference_name(ref)); + git_object_free(obj); + git_reference_free(ref); if (resolved) git_reference_free(resolved); return 0; diff --git a/vendor/libgit2/examples/general.c b/vendor/libgit2/examples/general.c index 2127ec0e..0275f84a 100644 --- a/vendor/libgit2/examples/general.c +++ b/vendor/libgit2/examples/general.c @@ -31,8 +31,8 @@ * Git Internals that you will need to know to work with Git at this level, * check out [Chapter 10][pg] of the Pro Git book. * - * [lg]: http://libgit2.github.com - * [ap]: http://libgit2.github.com/libgit2 + * [lg]: https://libgit2.org + * [ap]: https://libgit2.org/libgit2 * [pg]: https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain */ @@ -97,7 +97,7 @@ int lg2_general(git_repository *repo, int argc, char** argv) * * (Try running this program against tests/resources/testrepo.git.) * - * [me]: http://libgit2.github.com/libgit2/#HEAD/group/repository + * [me]: https://libgit2.org/libgit2/#HEAD/group/repository */ repo_path = (argc > 1) ? argv[1] : "/opt/libgit2-test/.git"; @@ -129,7 +129,7 @@ int lg2_general(git_repository *repo, int argc, char** argv) */ static void oid_parsing(git_oid *oid) { - char out[GIT_OID_HEXSZ+1]; + char out[GIT_OID_SHA1_HEXSIZE+1]; char hex[] = "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"; printf("*Hex to Raw*\n"); @@ -142,7 +142,11 @@ static void oid_parsing(git_oid *oid) * this throughout the example for storing the value of the current SHA * key we're working with. */ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_oid_fromstr(oid, hex, GIT_OID_SHA1); +#else git_oid_fromstr(oid, hex); +#endif /* * Once we've converted the string into the oid value, we can get the raw @@ -152,7 +156,7 @@ static void oid_parsing(git_oid *oid) * char hex value. */ printf("\n*Raw to Hex*\n"); - out[GIT_OID_HEXSZ] = '\0'; + out[GIT_OID_SHA1_HEXSIZE] = '\0'; /** * If you have a oid, you can easily get the hex value of the SHA as well. @@ -169,11 +173,11 @@ static void oid_parsing(git_oid *oid) * working with raw objects, we'll need to get this structure from the * repository. * - * [odb]: http://libgit2.github.com/libgit2/#HEAD/group/odb + * [odb]: https://libgit2.org/libgit2/#HEAD/group/odb */ static void object_database(git_repository *repo, git_oid *oid) { - char oid_hex[GIT_OID_HEXSZ+1] = { 0 }; + char oid_hex[GIT_OID_SHA1_HEXSIZE+1] = { 0 }; const unsigned char *data; const char *str_type; int error; @@ -258,7 +262,7 @@ static void object_database(git_repository *repo, git_oid *oid) * of them here. You can read about the other ones in the [commit API * docs][cd]. * - * [cd]: http://libgit2.github.com/libgit2/#HEAD/group/commit + * [cd]: https://libgit2.org/libgit2/#HEAD/group/commit */ static void commit_writing(git_repository *repo) { @@ -266,7 +270,7 @@ static void commit_writing(git_repository *repo) git_tree *tree; git_commit *parent; git_signature *author, *committer; - char oid_hex[GIT_OID_HEXSZ+1] = { 0 }; + char oid_hex[GIT_OID_SHA1_HEXSIZE+1] = { 0 }; printf("\n*Commit Writing*\n"); @@ -287,9 +291,14 @@ static void commit_writing(git_repository *repo) * parents. Here we're creating oid objects to create the commit with, * but you can also use */ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_oid_fromstr(&tree_id, "f60079018b664e4e79329a7ef9559c8d9e0378d1", GIT_OID_SHA1); + git_oid_fromstr(&parent_id, "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1); +#else git_oid_fromstr(&tree_id, "f60079018b664e4e79329a7ef9559c8d9e0378d1"); - git_tree_lookup(&tree, repo, &tree_id); git_oid_fromstr(&parent_id, "5b5b025afb0b4c913b4c338a42934a3863bf3644"); +#endif + git_tree_lookup(&tree, repo, &tree_id); git_commit_lookup(&parent, repo, &parent_id); /** @@ -338,14 +347,14 @@ static void commit_writing(git_repository *repo) * data in the commit - the author (name, email, datetime), committer * (same), tree, message, encoding and parent(s). * - * [pco]: http://libgit2.github.com/libgit2/#HEAD/group/commit + * [pco]: https://libgit2.org/libgit2/#HEAD/group/commit */ static void commit_parsing(git_repository *repo) { const git_signature *author, *cmtter; git_commit *commit, *parent; git_oid oid; - char oid_hex[GIT_OID_HEXSZ+1]; + char oid_hex[GIT_OID_SHA1_HEXSIZE+1]; const char *message; unsigned int parents, p; int error; @@ -353,7 +362,11 @@ static void commit_parsing(git_repository *repo) printf("\n*Commit Parsing*\n"); +#ifdef GIT_EXPERIMENTAL_SHA256 + git_oid_fromstr(&oid, "8496071c1b46c854b31185ea97743be6a8774479", GIT_OID_SHA1); +#else git_oid_fromstr(&oid, "8496071c1b46c854b31185ea97743be6a8774479"); +#endif error = git_commit_lookup(&commit, repo, &oid); check_error(error, "looking up commit"); @@ -405,7 +418,7 @@ static void commit_parsing(git_repository *repo) * functions very similarly to the commit lookup, parsing and creation * methods, since the objects themselves are very similar. * - * [tm]: http://libgit2.github.com/libgit2/#HEAD/group/tag + * [tm]: https://libgit2.org/libgit2/#HEAD/group/tag */ static void tag_parsing(git_repository *repo) { @@ -422,7 +435,11 @@ static void tag_parsing(git_repository *repo) * We create an oid for the tag object if we know the SHA and look it up * the same way that we would a commit (or any other object). */ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_oid_fromstr(&oid, "b25fa35b38051e4ae45d4222e795f9df2e43f1d1", GIT_OID_SHA1); +#else git_oid_fromstr(&oid, "b25fa35b38051e4ae45d4222e795f9df2e43f1d1"); +#endif error = git_tag_lookup(&tag, repo, &oid); check_error(error, "looking up tag"); @@ -455,7 +472,7 @@ static void tag_parsing(git_repository *repo) * object type in Git, but a useful structure for parsing and traversing * tree entries. * - * [tp]: http://libgit2.github.com/libgit2/#HEAD/group/tree + * [tp]: https://libgit2.org/libgit2/#HEAD/group/tree */ static void tree_parsing(git_repository *repo) { @@ -470,7 +487,11 @@ static void tree_parsing(git_repository *repo) /** * Create the oid and lookup the tree object just like the other objects. */ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_oid_fromstr(&oid, "f60079018b664e4e79329a7ef9559c8d9e0378d1", GIT_OID_SHA1); +#else git_oid_fromstr(&oid, "f60079018b664e4e79329a7ef9559c8d9e0378d1"); +#endif git_tree_lookup(&tree, repo, &oid); /** @@ -515,7 +536,7 @@ static void tree_parsing(git_repository *repo) * from disk and writing it to the db and getting the oid back so you * don't have to do all those steps yourself. * - * [ba]: http://libgit2.github.com/libgit2/#HEAD/group/blob + * [ba]: https://libgit2.org/libgit2/#HEAD/group/blob */ static void blob_parsing(git_repository *repo) { @@ -524,7 +545,11 @@ static void blob_parsing(git_repository *repo) printf("\n*Blob Parsing*\n"); +#ifdef GIT_EXPERIMENTAL_SHA256 + git_oid_fromstr(&oid, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OID_SHA1); +#else git_oid_fromstr(&oid, "1385f264afb75a56a5bec74243be9b367ba4ca08"); +#endif git_blob_lookup(&blob, repo, &oid); /** @@ -553,7 +578,7 @@ static void blob_parsing(git_repository *repo) * that were ancestors of (reachable from) a given starting point. This * can allow you to create `git log` type functionality. * - * [rw]: http://libgit2.github.com/libgit2/#HEAD/group/revwalk + * [rw]: https://libgit2.org/libgit2/#HEAD/group/revwalk */ static void revwalking(git_repository *repo) { @@ -566,7 +591,11 @@ static void revwalking(git_repository *repo) printf("\n*Revwalking*\n"); +#ifdef GIT_EXPERIMENTAL_SHA256 + git_oid_fromstr(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644", GIT_OID_SHA1); +#else git_oid_fromstr(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644"); +#endif /** * To use the revwalker, create a new walker, tell it how you want to sort @@ -614,7 +643,7 @@ static void revwalking(git_repository *repo) * The [index file API][gi] allows you to read, traverse, update and write * the Git index file (sometimes thought of as the staging area). * - * [gi]: http://libgit2.github.com/libgit2/#HEAD/group/index + * [gi]: https://libgit2.org/libgit2/#HEAD/group/index */ static void index_walking(git_repository *repo) { @@ -658,7 +687,7 @@ static void index_walking(git_repository *repo) * references such as branches, tags and remote references (everything in * the .git/refs directory). * - * [ref]: http://libgit2.github.com/libgit2/#HEAD/group/reference + * [ref]: https://libgit2.org/libgit2/#HEAD/group/reference */ static void reference_listing(git_repository *repo) { @@ -679,7 +708,7 @@ static void reference_listing(git_repository *repo) for (i = 0; i < ref_list.count; ++i) { git_reference *ref; - char oid_hex[GIT_OID_HEXSZ+1] = GIT_OID_HEX_ZERO; + char oid_hex[GIT_OID_SHA1_HEXSIZE+1] = GIT_OID_SHA1_HEXZERO; const char *refname; refname = ref_list.strings[i]; @@ -711,7 +740,7 @@ static void reference_listing(git_repository *repo) * The [config API][config] allows you to list and update config values * in any of the accessible config file locations (system, global, local). * - * [config]: http://libgit2.github.com/libgit2/#HEAD/group/config + * [config]: https://libgit2.org/libgit2/#HEAD/group/config */ static void config_files(const char *repo_path, git_repository* repo) { diff --git a/vendor/libgit2/examples/index-pack.c b/vendor/libgit2/examples/index-pack.c index df37dd0c..0f8234c7 100644 --- a/vendor/libgit2/examples/index-pack.c +++ b/vendor/libgit2/examples/index-pack.c @@ -28,11 +28,18 @@ int lg2_index_pack(git_repository *repo, int argc, char **argv) return EXIT_FAILURE; } - if (git_indexer_new(&idx, ".", 0, NULL, NULL) < 0) { +#ifdef GIT_EXPERIMENTAL_SHA256 + error = git_indexer_new(&idx, ".", git_repository_oid_type(repo), NULL); +#else + error = git_indexer_new(&idx, ".", 0, NULL, NULL); +#endif + + if (error < 0) { puts("bad idx"); return -1; } + if ((fd = open(argv[1], 0)) < 0) { perror("open"); return -1; diff --git a/vendor/libgit2/examples/log.c b/vendor/libgit2/examples/log.c index 9060f3f3..62a6eb58 100644 --- a/vendor/libgit2/examples/log.c +++ b/vendor/libgit2/examples/log.c @@ -50,6 +50,7 @@ static int add_revision(struct log_state *s, const char *revstr); /** log_options holds other command line options that affect log output */ struct log_options { int show_diff; + int show_oneline; int show_log_size; int skip, limit; int min_parents, max_parents; @@ -81,9 +82,11 @@ int lg2_log(git_repository *repo, int argc, char *argv[]) git_commit *commit = NULL; git_pathspec *ps = NULL; + memset(&s, 0, sizeof(s)); + /** Parse arguments and set up revwalker. */ - last_arg = parse_options(&s, &opt, argc, argv); s.repo = repo; + last_arg = parse_options(&s, &opt, argc, argv); diffopts.pathspec.strings = &argv[last_arg]; diffopts.pathspec.count = argc - last_arg; @@ -329,40 +332,51 @@ static void print_time(const git_time *intime, const char *prefix) /** Helper to print a commit object. */ static void print_commit(git_commit *commit, struct log_options *opts) { - char buf[GIT_OID_HEXSZ + 1]; + char buf[GIT_OID_SHA1_HEXSIZE + 1]; int i, count; const git_signature *sig; const char *scan, *eol; git_oid_tostr(buf, sizeof(buf), git_commit_id(commit)); - printf("commit %s\n", buf); - if (opts->show_log_size) { - printf("log size %d\n", (int)strlen(git_commit_message(commit))); - } + if (opts->show_oneline) { + printf("%s ", buf); + } else { + printf("commit %s\n", buf); - if ((count = (int)git_commit_parentcount(commit)) > 1) { - printf("Merge:"); - for (i = 0; i < count; ++i) { - git_oid_tostr(buf, 8, git_commit_parent_id(commit, i)); - printf(" %s", buf); + if (opts->show_log_size) { + printf("log size %d\n", (int)strlen(git_commit_message(commit))); + } + + if ((count = (int)git_commit_parentcount(commit)) > 1) { + printf("Merge:"); + for (i = 0; i < count; ++i) { + git_oid_tostr(buf, 8, git_commit_parent_id(commit, i)); + printf(" %s", buf); + } + printf("\n"); } - printf("\n"); - } - if ((sig = git_commit_author(commit)) != NULL) { - printf("Author: %s <%s>\n", sig->name, sig->email); - print_time(&sig->when, "Date: "); + if ((sig = git_commit_author(commit)) != NULL) { + printf("Author: %s <%s>\n", sig->name, sig->email); + print_time(&sig->when, "Date: "); + } + printf("\n"); } - printf("\n"); for (scan = git_commit_message(commit); scan && *scan; ) { for (eol = scan; *eol && *eol != '\n'; ++eol) /* find eol */; - printf(" %.*s\n", (int)(eol - scan), scan); + if (opts->show_oneline) + printf("%.*s\n", (int)(eol - scan), scan); + else + printf(" %.*s\n", (int)(eol - scan), scan); scan = *eol ? eol + 1 : NULL; + if (opts->show_oneline) + break; } - printf("\n"); + if (!opts->show_oneline) + printf("\n"); } /** Helper to find how many files in a commit changed from its nth parent. */ @@ -407,8 +421,6 @@ static int parse_options( struct log_state *s, struct log_options *opt, int argc, char **argv) { struct args_info args = ARGS_INFO_INIT; - - memset(s, 0, sizeof(*s)); s->sorting = GIT_SORT_TIME; memset(opt, 0, sizeof(*opt)); @@ -424,7 +436,7 @@ static int parse_options( else /** Try failed revision parse as filename. */ break; - } else if (!match_arg_separator(&args)) { + } else if (match_arg_separator(&args)) { break; } else if (!strcmp(a, "--date-order")) @@ -474,6 +486,8 @@ static int parse_options( opt->show_diff = 1; else if (!strcmp(a, "--log-size")) opt->show_log_size = 1; + else if (!strcmp(a, "--oneline")) + opt->show_oneline = 1; else usage("Unsupported argument", a); } diff --git a/vendor/libgit2/examples/ls-remote.c b/vendor/libgit2/examples/ls-remote.c index 03ed887d..24caae71 100644 --- a/vendor/libgit2/examples/ls-remote.c +++ b/vendor/libgit2/examples/ls-remote.c @@ -34,7 +34,7 @@ static int use_remote(git_repository *repo, char *name) goto cleanup; for (i = 0; i < refs_len; i++) { - char oid[GIT_OID_HEXSZ + 1] = {0}; + char oid[GIT_OID_SHA1_HEXSIZE + 1] = {0}; git_oid_fmt(oid, &refs[i]->oid); printf("%s\t%s\n", oid, refs[i]->name); } diff --git a/vendor/libgit2/examples/merge.c b/vendor/libgit2/examples/merge.c index 460c06a2..7a76912c 100644 --- a/vendor/libgit2/examples/merge.c +++ b/vendor/libgit2/examples/merge.c @@ -30,7 +30,7 @@ struct merge_options { git_annotated_commit **annotated; size_t annotated_count; - int no_commit : 1; + unsigned int no_commit : 1; }; static void print_usage(void) diff --git a/vendor/libgit2/examples/push.c b/vendor/libgit2/examples/push.c index bcf30760..5113eed3 100644 --- a/vendor/libgit2/examples/push.c +++ b/vendor/libgit2/examples/push.c @@ -32,6 +32,7 @@ /** Entry point for this command */ int lg2_push(git_repository *repo, int argc, char **argv) { git_push_options options; + git_remote_callbacks callbacks; git_remote* remote = NULL; char *refspec = "refs/heads/master"; const git_strarray refspecs = { @@ -47,7 +48,11 @@ int lg2_push(git_repository *repo, int argc, char **argv) { check_lg2(git_remote_lookup(&remote, repo, "origin" ), "Unable to lookup remote", NULL); + check_lg2(git_remote_init_callbacks(&callbacks, GIT_REMOTE_CALLBACKS_VERSION), "Error initializing remote callbacks", NULL); + callbacks.credentials = cred_acquire_cb; + check_lg2(git_push_options_init(&options, GIT_PUSH_OPTIONS_VERSION ), "Error initializing push", NULL); + options.callbacks = callbacks; check_lg2(git_remote_push(remote, &refspecs, &options), "Error pushing", NULL); diff --git a/vendor/libgit2/examples/rev-list.c b/vendor/libgit2/examples/rev-list.c index d10f1669..cf8ac30c 100644 --- a/vendor/libgit2/examples/rev-list.c +++ b/vendor/libgit2/examples/rev-list.c @@ -26,7 +26,7 @@ int lg2_rev_list(git_repository *repo, int argc, char **argv) git_revwalk *walk; git_oid oid; git_sort_t sort; - char buf[GIT_OID_HEXSZ+1]; + char buf[GIT_OID_SHA1_HEXSIZE+1]; check_lg2(revwalk_parse_options(&sort, &args), "parsing options", NULL); @@ -36,7 +36,7 @@ int lg2_rev_list(git_repository *repo, int argc, char **argv) while (!git_revwalk_next(&oid, walk)) { git_oid_fmt(buf, &oid); - buf[GIT_OID_HEXSZ] = '\0'; + buf[GIT_OID_SHA1_HEXSIZE] = '\0'; printf("%s\n", buf); } @@ -140,8 +140,14 @@ static int revwalk_parse_revs(git_repository *repo, git_revwalk *walk, struct ar if (push_spec(repo, walk, curr, hide) == 0) continue; +#ifdef GIT_EXPERIMENTAL_SHA256 + if ((error = git_oid_fromstr(&oid, curr, GIT_OID_SHA1))) + return error; +#else if ((error = git_oid_fromstr(&oid, curr))) return error; +#endif + if ((error = push_commit(walk, &oid, hide))) return error; } diff --git a/vendor/libgit2/examples/rev-parse.c b/vendor/libgit2/examples/rev-parse.c index 90258c10..3f68d79b 100644 --- a/vendor/libgit2/examples/rev-parse.c +++ b/vendor/libgit2/examples/rev-parse.c @@ -65,7 +65,7 @@ static void parse_opts(struct parse_state *ps, int argc, char *argv[]) static int parse_revision(git_repository *repo, struct parse_state *ps) { git_revspec rs; - char str[GIT_OID_HEXSZ + 1]; + char str[GIT_OID_SHA1_HEXSIZE + 1]; check_lg2(git_revparse(&rs, repo, ps->spec), "Could not parse", ps->spec); diff --git a/vendor/libgit2/examples/show-index.c b/vendor/libgit2/examples/show-index.c index 7aaa45e6..0a5e7d1a 100644 --- a/vendor/libgit2/examples/show-index.c +++ b/vendor/libgit2/examples/show-index.c @@ -20,8 +20,8 @@ int lg2_show_index(git_repository *repo, int argc, char **argv) size_t i, ecount; char *dir = "."; size_t dirlen; - char out[GIT_OID_HEXSZ+1]; - out[GIT_OID_HEXSZ] = '\0'; + char out[GIT_OID_SHA1_HEXSIZE+1]; + out[GIT_OID_SHA1_HEXSIZE] = '\0'; if (argc > 2) fatal("usage: showindex []", NULL); @@ -30,7 +30,11 @@ int lg2_show_index(git_repository *repo, int argc, char **argv) dirlen = strlen(dir); if (dirlen > 5 && strcmp(dir + dirlen - 5, "index") == 0) { +#ifdef GIT_EXPERIMENTAL_SHA256 + check_lg2(git_index_open(&index, dir, GIT_OID_SHA1), "could not open index", dir); +#else check_lg2(git_index_open(&index, dir), "could not open index", dir); +#endif } else { check_lg2(git_repository_open_ext(&repo, dir, 0, NULL), "could not open repository", dir); check_lg2(git_repository_index(&index, repo), "could not open repository index", NULL); diff --git a/vendor/libgit2/fuzzers/CMakeLists.txt b/vendor/libgit2/fuzzers/CMakeLists.txt index eaa490fd..01f0f519 100644 --- a/vendor/libgit2/fuzzers/CMakeLists.txt +++ b/vendor/libgit2/fuzzers/CMakeLists.txt @@ -1,3 +1,5 @@ +# fuzzers: libFuzzer and standalone fuzzing utilities + if(BUILD_FUZZERS AND NOT USE_STANDALONE_FUZZERS) set(CMAKE_REQUIRED_FLAGS "-fsanitize=fuzzer-no-link") add_c_flag(-fsanitize=fuzzer) @@ -10,10 +12,13 @@ foreach(fuzz_target_src ${SRC_FUZZERS}) string(REPLACE ".c" "" fuzz_target_name ${fuzz_target_src}) string(REPLACE "_fuzzer" "" fuzz_name ${fuzz_target_name}) - set(${fuzz_target_name}_SOURCES ${fuzz_target_src} ${LIBGIT2_OBJECTS}) + set(${fuzz_target_name}_SOURCES + ${fuzz_target_src} "fuzzer_utils.c" ${LIBGIT2_OBJECTS}) + if(USE_STANDALONE_FUZZERS) list(APPEND ${fuzz_target_name}_SOURCES "standalone_driver.c") endif() + add_executable(${fuzz_target_name} ${${fuzz_target_name}_SOURCES}) set_target_properties(${fuzz_target_name} PROPERTIES C_STANDARD 90) diff --git a/vendor/libgit2/fuzzers/commit_graph_fuzzer.c b/vendor/libgit2/fuzzers/commit_graph_fuzzer.c index 1c46d78c..9c1443e5 100644 --- a/vendor/libgit2/fuzzers/commit_graph_fuzzer.c +++ b/vendor/libgit2/fuzzers/commit_graph_fuzzer.c @@ -37,7 +37,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) git_commit_graph_entry e; git_str commit_graph_buf = GIT_STR_INIT; unsigned char hash[GIT_HASH_SHA1_SIZE]; - git_oid oid = {{0}}; + git_oid oid = GIT_OID_NONE; bool append_hash = false; if (size < 4) @@ -62,7 +62,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) memcpy(commit_graph_buf.ptr, data, size); memcpy(commit_graph_buf.ptr + size, hash, GIT_HASH_SHA1_SIZE); - memcpy(oid.id, hash, GIT_OID_RAWSZ); + memcpy(oid.id, hash, GIT_OID_SHA1_SIZE); } else { git_str_attach_notowned(&commit_graph_buf, (char *)data, size); } @@ -75,7 +75,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) goto cleanup; /* Search for any oid, just to exercise that codepath. */ - if (git_commit_graph_entry_find(&e, &file, &oid, GIT_OID_HEXSZ) < 0) + if (git_commit_graph_entry_find(&e, &file, &oid, GIT_OID_SHA1_HEXSIZE) < 0) goto cleanup; cleanup: diff --git a/vendor/libgit2/fuzzers/config_file_fuzzer.c b/vendor/libgit2/fuzzers/config_file_fuzzer.c index 890adbfc..76303696 100644 --- a/vendor/libgit2/fuzzers/config_file_fuzzer.c +++ b/vendor/libgit2/fuzzers/config_file_fuzzer.c @@ -43,7 +43,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) goto out; } - if ((err = git_config_backend_from_string(&backend, (const char*)data, size)) != 0) { + if ((err = git_config_backend_from_string(&backend, (const char*)data, size, NULL)) != 0) { goto out; } if ((err = git_config_add_backend(cfg, backend, 0, NULL, 0)) != 0) { diff --git a/vendor/libgit2/fuzzers/corpora/revparse/head b/vendor/libgit2/fuzzers/corpora/revparse/head new file mode 100644 index 00000000..e5517e4c --- /dev/null +++ b/vendor/libgit2/fuzzers/corpora/revparse/head @@ -0,0 +1 @@ +HEAD \ No newline at end of file diff --git a/vendor/libgit2/fuzzers/corpora/revparse/revat b/vendor/libgit2/fuzzers/corpora/revparse/revat new file mode 100644 index 00000000..382ffc0b --- /dev/null +++ b/vendor/libgit2/fuzzers/corpora/revparse/revat @@ -0,0 +1 @@ +xxxxxxxxxxxxxxxx@ \ No newline at end of file diff --git a/vendor/libgit2/fuzzers/download_refs_fuzzer.c b/vendor/libgit2/fuzzers/download_refs_fuzzer.c index ff95cd10..c2b80ccb 100644 --- a/vendor/libgit2/fuzzers/download_refs_fuzzer.c +++ b/vendor/libgit2/fuzzers/download_refs_fuzzer.c @@ -16,6 +16,7 @@ #include "futils.h" #include "standalone_driver.h" +#include "fuzzer_utils.h" #define UNUSED(x) (void)(x) @@ -157,33 +158,10 @@ static int fuzzer_transport_cb(git_transport **out, git_remote *owner, void *par return git_transport_smart(out, owner, &def); } -static void fuzzer_git_abort(const char *op) -{ - const git_error *err = git_error_last(); - fprintf(stderr, "unexpected libgit error: %s: %s\n", - op, err ? err->message : ""); - abort(); -} - int LLVMFuzzerInitialize(int *argc, char ***argv) { -#if defined(_WIN32) - char tmpdir[MAX_PATH], path[MAX_PATH]; - - if (GetTempPath((DWORD)sizeof(tmpdir), tmpdir) == 0) - abort(); - - if (GetTempFileName(tmpdir, "lg2", 1, path) == 0) - abort(); - - if (git_futils_mkdir(path, 0700, 0) < 0) - abort(); -#else - char path[] = "/tmp/git2.XXXXXX"; - - if (mkdtemp(path) != path) - abort(); -#endif + UNUSED(argc); + UNUSED(argv); if (git_libgit2_init() < 0) abort(); @@ -191,12 +169,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv) if (git_libgit2_opts(GIT_OPT_SET_PACK_MAX_OBJECTS, 10000000) < 0) abort(); - UNUSED(argc); - UNUSED(argv); - - if (git_repository_init(&repo, path, 1) < 0) - fuzzer_git_abort("git_repository_init"); - + repo = fuzzer_repo_init(); return 0; } diff --git a/vendor/libgit2/fuzzers/fuzzer_utils.c b/vendor/libgit2/fuzzers/fuzzer_utils.c new file mode 100644 index 00000000..cde5065d --- /dev/null +++ b/vendor/libgit2/fuzzers/fuzzer_utils.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include +#include + +#include "git2.h" +#include "futils.h" + +#include "fuzzer_utils.h" + +void fuzzer_git_abort(const char *op) +{ + const git_error *err = git_error_last(); + fprintf(stderr, "unexpected libgit error: %s: %s\n", + op, err ? err->message : ""); + abort(); +} + +git_repository *fuzzer_repo_init(void) +{ + git_repository *repo; + +#if defined(_WIN32) + char tmpdir[MAX_PATH], path[MAX_PATH]; + + if (GetTempPath((DWORD)sizeof(tmpdir), tmpdir) == 0) + abort(); + + if (GetTempFileName(tmpdir, "lg2", 1, path) == 0) + abort(); + + if (git_futils_mkdir(path, 0700, 0) < 0) + abort(); +#else + char path[] = "/tmp/git2.XXXXXX"; + + if (mkdtemp(path) != path) + abort(); +#endif + + if (git_repository_init(&repo, path, 1) < 0) + fuzzer_git_abort("git_repository_init"); + + return repo; +} diff --git a/vendor/libgit2/fuzzers/fuzzer_utils.h b/vendor/libgit2/fuzzers/fuzzer_utils.h new file mode 100644 index 00000000..6b67c9a6 --- /dev/null +++ b/vendor/libgit2/fuzzers/fuzzer_utils.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_fuzzer_utils_h__ +#define INCLUDE_fuzzer_utils_h__ + +extern void fuzzer_git_abort(const char *op); +extern git_repository *fuzzer_repo_init(void); + +#endif diff --git a/vendor/libgit2/fuzzers/midx_fuzzer.c b/vendor/libgit2/fuzzers/midx_fuzzer.c index 4c3124e4..21fb9036 100644 --- a/vendor/libgit2/fuzzers/midx_fuzzer.c +++ b/vendor/libgit2/fuzzers/midx_fuzzer.c @@ -36,7 +36,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) git_midx_entry e; git_str midx_buf = GIT_STR_INIT; unsigned char hash[GIT_HASH_SHA1_SIZE]; - git_oid oid = {{0}}; + git_oid oid = GIT_OID_NONE; bool append_hash = false; if (size < 4) @@ -61,7 +61,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) memcpy(midx_buf.ptr, data, size); memcpy(midx_buf.ptr + size, hash, GIT_HASH_SHA1_SIZE); - memcpy(oid.id, hash, GIT_OID_RAWSZ); + memcpy(oid.id, hash, GIT_OID_SHA1_SIZE); } else { git_str_attach_notowned(&midx_buf, (char *)data, size); } @@ -70,7 +70,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) goto cleanup; /* Search for any oid, just to exercise that codepath. */ - if (git_midx_entry_find(&e, &idx, &oid, GIT_OID_HEXSZ) < 0) + if (git_midx_entry_find(&e, &idx, &oid, GIT_OID_SHA1_HEXSIZE) < 0) goto cleanup; cleanup: diff --git a/vendor/libgit2/fuzzers/objects_fuzzer.c b/vendor/libgit2/fuzzers/objects_fuzzer.c index 51b4a1ed..7294e9b3 100644 --- a/vendor/libgit2/fuzzers/objects_fuzzer.c +++ b/vendor/libgit2/fuzzers/objects_fuzzer.c @@ -39,7 +39,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) * to do. */ for (i = 0; i < ARRAY_SIZE(types); i++) { - if (git_object__from_raw(&object, (const char *) data, size, types[i]) < 0) + if (git_object__from_raw(&object, (const char *) data, size, types[i], GIT_OID_SHA1) < 0) continue; git_object_free(object); object = NULL; diff --git a/vendor/libgit2/fuzzers/packfile_fuzzer.c b/vendor/libgit2/fuzzers/packfile_fuzzer.c index 6002fa1d..aeba9575 100644 --- a/vendor/libgit2/fuzzers/packfile_fuzzer.c +++ b/vendor/libgit2/fuzzers/packfile_fuzzer.c @@ -36,10 +36,19 @@ int LLVMFuzzerInitialize(int *argc, char ***argv) fprintf(stderr, "Failed to limit maximum pack object count\n"); abort(); } + +#ifdef GIT_EXPERIMENTAL_SHA256 + if (git_odb_new(&odb, NULL) < 0) { + fprintf(stderr, "Failed to create the odb\n"); + abort(); + } +#else if (git_odb_new(&odb) < 0) { fprintf(stderr, "Failed to create the odb\n"); abort(); } +#endif + if (git_mempack_new(&mempack) < 0) { fprintf(stderr, "Failed to create the mempack\n"); abort(); @@ -58,6 +67,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) git_str path = GIT_STR_INIT; git_oid oid; bool append_hash = false; + int error; if (size == 0) return 0; @@ -73,7 +83,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) abort(); } - if (git_indexer_new(&indexer, ".", 0, odb, NULL) < 0) { +#ifdef GIT_EXPERIMENTAL_SHA256 + error = git_indexer_new(&indexer, ".", GIT_OID_SHA1, NULL); +#else + error = git_indexer_new(&indexer, ".", 0, odb, NULL); +#endif + + if (error < 0) { fprintf(stderr, "Failed to create the indexer: %s\n", git_error_last()->message); abort(); @@ -90,11 +106,19 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) if (git_indexer_append(indexer, data, size, &stats) < 0) goto cleanup; if (append_hash) { +#ifdef GIT_EXPERIMENTAL_SHA256 + if (git_odb_hash(&oid, data, size, GIT_OBJECT_BLOB, GIT_OID_SHA1) < 0) { + fprintf(stderr, "Failed to compute the SHA1 hash\n"); + abort(); + } +#else if (git_odb_hash(&oid, data, size, GIT_OBJECT_BLOB) < 0) { fprintf(stderr, "Failed to compute the SHA1 hash\n"); abort(); } - if (git_indexer_append(indexer, &oid, sizeof(oid), &stats) < 0) { +#endif + + if (git_indexer_append(indexer, &oid.id, GIT_OID_SHA1_SIZE, &stats) < 0) { goto cleanup; } } diff --git a/vendor/libgit2/fuzzers/revparse_fuzzer.c b/vendor/libgit2/fuzzers/revparse_fuzzer.c new file mode 100644 index 00000000..37c22e22 --- /dev/null +++ b/vendor/libgit2/fuzzers/revparse_fuzzer.c @@ -0,0 +1,52 @@ +/* + * libgit2 revparse fuzzer target. + * + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include + +#include "git2.h" + +#include "standalone_driver.h" +#include "fuzzer_utils.h" + +#define UNUSED(x) (void)(x) + +static git_repository *repo; + +int LLVMFuzzerInitialize(int *argc, char ***argv) +{ + UNUSED(argc); + UNUSED(argv); + + if (git_libgit2_init() < 0) + abort(); + + if (git_libgit2_opts(GIT_OPT_SET_PACK_MAX_OBJECTS, 10000000) < 0) + abort(); + + repo = fuzzer_repo_init(); + return 0; +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + git_object *obj = NULL; + char *c; + + if ((c = calloc(1, size + 1)) == NULL) + abort(); + + memcpy(c, data, size); + + git_revparse_single(&obj, repo, c); + git_object_free(obj); + free(c); + + return 0; +} diff --git a/vendor/libgit2/include/git2.h b/vendor/libgit2/include/git2.h index 2961cc3e..3457e5f0 100644 --- a/vendor/libgit2/include/git2.h +++ b/vendor/libgit2/include/git2.h @@ -28,6 +28,7 @@ #include "git2/diff.h" #include "git2/email.h" #include "git2/errors.h" +#include "git2/experimental.h" #include "git2/filter.h" #include "git2/global.h" #include "git2/graph.h" diff --git a/vendor/libgit2/include/git2/attr.h b/vendor/libgit2/include/git2/attr.h index 0c838727..69929b3d 100644 --- a/vendor/libgit2/include/git2/attr.h +++ b/vendor/libgit2/include/git2/attr.h @@ -116,14 +116,12 @@ GIT_EXTERN(git_attr_value_t) git_attr_value(const char *attr); */ #define GIT_ATTR_CHECK_FILE_THEN_INDEX 0 #define GIT_ATTR_CHECK_INDEX_THEN_FILE 1 -#define GIT_ATTR_CHECK_INDEX_ONLY 2 +#define GIT_ATTR_CHECK_INDEX_ONLY 2 /** * Check attribute flags: controlling extended attribute behavior. * * Normally, attribute checks include looking in the /etc (or system - * equivalent) directory for a `gitattributes` file. Passing this - * flag will cause attribute checks to ignore that file. * equivalent) directory for a `gitattributes` file. Passing the * `GIT_ATTR_CHECK_NO_SYSTEM` flag will cause attribute checks to * ignore that file. diff --git a/vendor/libgit2/include/git2/branch.h b/vendor/libgit2/include/git2/branch.h index 36a393d1..27c6fa15 100644 --- a/vendor/libgit2/include/git2/branch.h +++ b/vendor/libgit2/include/git2/branch.h @@ -129,8 +129,8 @@ GIT_EXTERN(void) git_branch_iterator_free(git_branch_iterator *iter); * See `git_tag_create()` for rules about valid names. * * Note that if the move succeeds, the old reference object will not - + be valid anymore, and should be freed immediately by the user using - + `git_reference_free()`. + * be valid anymore, and should be freed immediately by the user using + * `git_reference_free()`. * * @param out New reference object for the updated name. * diff --git a/vendor/libgit2/include/git2/commit.h b/vendor/libgit2/include/git2/commit.h index 67170cb9..88c21e0c 100644 --- a/vendor/libgit2/include/git2/commit.h +++ b/vendor/libgit2/include/git2/commit.h @@ -394,6 +394,49 @@ GIT_EXTERN(int) git_commit_create_v( size_t parent_count, ...); +typedef struct { + unsigned int version; + + /** + * Flags for creating the commit. + * + * If `allow_empty_commit` is specified, a commit with no changes + * from the prior commit (and "empty" commit) is allowed. Otherwise, + * commit creation will be stopped. + */ + unsigned int allow_empty_commit : 1; + + /** The commit author, or NULL for the default. */ + const git_signature *author; + + /** The committer, or NULL for the default. */ + const git_signature *committer; + + /** Encoding for the commit message; leave NULL for default. */ + const char *message_encoding; +} git_commit_create_options; + +#define GIT_COMMIT_CREATE_OPTIONS_VERSION 1 +#define GIT_COMMIT_CREATE_OPTIONS_INIT { GIT_COMMIT_CREATE_OPTIONS_VERSION } + +/** + * Commits the staged changes in the repository; this is a near analog to + * `git commit -m message`. + * + * By default, empty commits are not allowed. + * + * @param id pointer to store the new commit's object id + * @param repo repository to commit changes in + * @param message the commit message + * @param opts options for creating the commit + * @return 0 on success, GIT_EUNCHANGED if there were no changes to commit, or an error code + */ +GIT_EXTERN(int) git_commit_create_from_stage( + git_oid *id, + git_repository *repo, + const char *message, + const git_commit_create_options *opts); + /** * Amend an existing commit by replacing only non-NULL values. * @@ -541,6 +584,24 @@ typedef int (*git_commit_create_cb)( const git_commit *parents[], void *payload); +/** An array of commits returned from the library */ +typedef struct git_commitarray { + git_commit *const *commits; + size_t count; +} git_commitarray; + +/** + * Free the commits contained in a commit array. This method should + * be called on `git_commitarray` objects that were provided by the + * library. Not doing so will result in a memory leak. + * + * This does not free the `git_commitarray` itself, since the library + * will never allocate that object directly itself. + * + * @param array The git_commitarray that contains commits to free + */ +GIT_EXTERN(void) git_commitarray_dispose(git_commitarray *array); + /** @} */ GIT_END_DECL #endif diff --git a/vendor/libgit2/include/git2/common.h b/vendor/libgit2/include/git2/common.h index b8c4ad53..b7cf20b3 100644 --- a/vendor/libgit2/include/git2/common.h +++ b/vendor/libgit2/include/git2/common.h @@ -105,11 +105,6 @@ GIT_BEGIN_DECL */ #define GIT_PATH_MAX 4096 -/** - * The string representation of the null object ID. - */ -#define GIT_OID_HEX_ZERO "0000000000000000000000000000000000000000" - /** * Return the version of the libgit2 library * being currently used. @@ -121,6 +116,17 @@ GIT_BEGIN_DECL */ GIT_EXTERN(int) git_libgit2_version(int *major, int *minor, int *rev); +/** + * Return the prerelease state of the libgit2 library currently being + * used. For nightly builds during active development, this will be + * "alpha". Releases may have a "beta" or release candidate ("rc1", + * "rc2", etc) prerelease. For a final release, this function returns + * NULL. + * + * @return the name of the prerelease state or NULL + */ +GIT_EXTERN(const char *) git_libgit2_prerelease(void); + /** * Combinations of these values describe the features with which libgit2 * was compiled @@ -216,7 +222,15 @@ typedef enum { GIT_OPT_GET_EXTENSIONS, GIT_OPT_SET_EXTENSIONS, GIT_OPT_GET_OWNER_VALIDATION, - GIT_OPT_SET_OWNER_VALIDATION + GIT_OPT_SET_OWNER_VALIDATION, + GIT_OPT_GET_HOMEDIR, + GIT_OPT_SET_HOMEDIR, + GIT_OPT_SET_SERVER_CONNECT_TIMEOUT, + GIT_OPT_GET_SERVER_CONNECT_TIMEOUT, + GIT_OPT_SET_SERVER_TIMEOUT, + GIT_OPT_GET_SERVER_TIMEOUT, + GIT_OPT_SET_USER_AGENT_PRODUCT, + GIT_OPT_GET_USER_AGENT_PRODUCT } git_libgit2_opt_t; /** @@ -325,11 +339,35 @@ typedef enum { * * * opts(GIT_OPT_SET_USER_AGENT, const char *user_agent) * - * > Set the value of the User-Agent header. This value will be - * > appended to "git/1.0", for compatibility with other git clients. + * > Set the value of the comment section of the User-Agent header. + * > This can be information about your product and its version. + * > By default this is "libgit2" followed by the libgit2 version. + * > + * > This value will be appended to User-Agent _product_, which + * > is typically set to "git/2.0". + * > + * > Set to the empty string ("") to not send any information in the + * > comment section, or set to NULL to restore the default. + * + * * opts(GIT_OPT_GET_USER_AGENT, git_buf *out) + * + * > Get the value of the User-Agent header. + * > The User-Agent is written to the `out` buffer. + * + * * opts(GIT_OPT_SET_USER_AGENT_PRODUCT, const char *user_agent_product) + * + * > Set the value of the product portion of the User-Agent header. + * > This defaults to "git/2.0", for compatibility with other git + * > clients. It is recommended to keep this as git/ for + * > compatibility with servers that do user-agent detection. * > - * > - `user_agent` is the value that will be delivered as the - * > User-Agent header on HTTP requests. + * > Set to the empty string ("") to not send any user-agent string, + * > or set to NULL to restore the default. + * + * * opts(GIT_OPT_GET_USER_AGENT_PRODUCT, git_buf *out) + * + * > Get the value of the User-Agent product header. + * > The User-Agent product is written to the `out` buffer. * * * opts(GIT_OPT_SET_WINDOWS_SHAREMODE, unsigned long value) * @@ -365,11 +403,6 @@ typedef enum { * > * > - `ciphers` is the list of ciphers that are eanbled. * - * * opts(GIT_OPT_GET_USER_AGENT, git_buf *out) - * - * > Get the value of the User-Agent header. - * > The User-Agent is written to the `out` buffer. - * * * opts(GIT_OPT_ENABLE_OFS_DELTA, int enabled) * * > Enable or disable the use of "offset deltas" when creating packfiles, @@ -462,6 +495,34 @@ typedef enum { * > Set that repository directories should be owned by the current * > user. The default is to validate ownership. * + * opts(GIT_OPT_GET_HOMEDIR, git_buf *out) + * > Gets the current user's home directory, as it will be used + * > for file lookups. The path is written to the `out` buffer. + * + * opts(GIT_OPT_SET_HOMEDIR, const char *path) + * > Sets the directory used as the current user's home directory, + * > for file lookups. + * > + * > - `path` directory of home directory. + * + * opts(GIT_OPT_GET_SERVER_CONNECT_TIMEOUT, int *timeout) + * > Gets the timeout (in milliseconds) to attempt connections to + * > a remote server. + * + * opts(GIT_OPT_SET_SERVER_CONNECT_TIMEOUT, int timeout) + * > Sets the timeout (in milliseconds) to attempt connections to + * > a remote server. Set to 0 to use the system default. Note that + * > this may not be able to be configured longer than the system + * > default, typically 75 seconds. + * + * opts(GIT_OPT_GET_SERVER_TIMEOUT, int *timeout) + * > Gets the timeout (in milliseconds) for reading from and writing + * > to a remote server. + * + * opts(GIT_OPT_SET_SERVER_TIMEOUT, int timeout) + * > Sets the timeout (in milliseconds) for reading from and writing + * > to a remote server. Set to 0 to use the system default. + * * @param option Option key * @param ... value to set the option * @return 0 on success, <0 on failure diff --git a/vendor/libgit2/include/git2/config.h b/vendor/libgit2/include/git2/config.h index a5486a4c..32361431 100644 --- a/vendor/libgit2/include/git2/config.h +++ b/vendor/libgit2/include/git2/config.h @@ -22,8 +22,19 @@ GIT_BEGIN_DECL /** * Priority level of a config file. + * * These priority levels correspond to the natural escalation logic - * (from higher to lower) when searching for config entries in git.git. + * (from higher to lower) when reading or searching for config entries + * in git.git. Meaning that for the same key, the configuration in + * the local configuration is preferred over the configuration in + * the system configuration file. + * + * Callers can add their own custom configuration, beginning at the + * `GIT_CONFIG_LEVEL_APP` level. + * + * Writes, by default, occur in the highest priority level backend + * that is writable. This ordering can be overridden with + * `git_config_set_writeorder`. * * git_config_open_default() and git_repository_config() honor those * priority levels as well. @@ -48,9 +59,13 @@ typedef enum { */ GIT_CONFIG_LEVEL_LOCAL = 5, + /** Worktree specific configuration file; $GIT_DIR/config.worktree + */ + GIT_CONFIG_LEVEL_WORKTREE = 6, + /** Application specific configuration file; freely defined by applications */ - GIT_CONFIG_LEVEL_APP = 6, + GIT_CONFIG_LEVEL_APP = 7, /** Represents the highest level available config file (i.e. the most * specific config file available that actually is loaded) @@ -62,12 +77,32 @@ typedef enum { * An entry in a configuration file */ typedef struct git_config_entry { - const char *name; /**< Name of the entry (normalised) */ - const char *value; /**< String value of the entry */ - unsigned int include_depth; /**< Depth of includes where this variable was found */ - git_config_level_t level; /**< Which config file this was found in */ - void GIT_CALLBACK(free)(struct git_config_entry *entry); /**< Free function for this entry */ - void *payload; /**< Opaque value for the free function. Do not read or write */ + /** Name of the configuration entry (normalized) */ + const char *name; + + /** Literal (string) value of the entry */ + const char *value; + + /** The type of backend that this entry exists in (eg, "file") */ + const char *backend_type; + + /** + * The path to the origin of this entry. For config files, this is + * the path to the file. + */ + const char *origin_path; + + /** Depth of includes where this variable was found */ + unsigned int include_depth; + + /** Configuration level for the file this was found in */ + git_config_level_t level; + + /** + * Free function for this entry; for internal purposes. Callers + * should call `git_config_entry_free` to free data. + */ + void GIT_CALLBACK(free)(struct git_config_entry *entry); } git_config_entry; /** @@ -122,7 +157,7 @@ typedef struct { * global configuration file. * * This method will not guess the path to the xdg compatible - * config file (.config/git/config). + * config file (`.config/git/config`). * * @param out Pointer to a user-allocated git_buf in which to store the path * @return 0 if a global configuration file has been found. Its path will be stored in `out`. @@ -149,8 +184,8 @@ GIT_EXTERN(int) git_config_find_xdg(git_buf *out); /** * Locate the path to the system configuration file * - * If /etc/gitconfig doesn't exist, it will look for - * %PROGRAMFILES%\Git\etc\gitconfig. + * If `/etc/gitconfig` doesn't exist, it will look for + * `%PROGRAMFILES%\Git\etc\gitconfig`. * * @param out Pointer to a user-allocated git_buf in which to store the path * @return 0 if a system configuration file has been @@ -161,7 +196,7 @@ GIT_EXTERN(int) git_config_find_system(git_buf *out); /** * Locate the path to the configuration file in ProgramData * - * Look for the file in %PROGRAMDATA%\Git\config used by portable git. + * Look for the file in `%PROGRAMDATA%\Git\config` used by portable git. * * @param out Pointer to a user-allocated git_buf in which to store the path * @return 0 if a ProgramData configuration file has been @@ -276,6 +311,11 @@ GIT_EXTERN(int) git_config_open_level( */ GIT_EXTERN(int) git_config_open_global(git_config **out, git_config *config); +GIT_EXTERN(int) git_config_set_writeorder( + git_config *cfg, + git_config_level_t *levels, + size_t len); + /** * Create a snapshot of the configuration * @@ -449,8 +489,8 @@ GIT_EXTERN(int) git_config_multivar_iterator_new(git_config_iterator **out, cons /** * Return the current entry and advance the iterator * - * The pointers returned by this function are valid until the iterator - * is freed. + * The pointers returned by this function are valid until the next call + * to `git_config_next` or until the iterator is freed. * * @param entry pointer to store the entry * @param iter the iterator diff --git a/vendor/libgit2/include/git2/deprecated.h b/vendor/libgit2/include/git2/deprecated.h index f73d7da6..52864ebe 100644 --- a/vendor/libgit2/include/git2/deprecated.h +++ b/vendor/libgit2/include/git2/deprecated.h @@ -436,6 +436,8 @@ GIT_EXTERN(int) git_diff_format_email_options_init( #define GITERR_WORKTREE GIT_ERROR_WORKTREE #define GITERR_SHA1 GIT_ERROR_SHA1 +#define GIT_ERROR_SHA1 GIT_ERROR_SHA + /** * Return the last `git_error` object that was generated for the * current thread. This is an alias of `git_error_last` and is @@ -775,6 +777,12 @@ typedef git_trace_cb git_trace_callback; */ /**@{*/ +#ifndef GIT_EXPERIMENTAL_SHA256 +# define GIT_OID_RAWSZ GIT_OID_SHA1_SIZE +# define GIT_OID_HEXSZ GIT_OID_SHA1_HEXSIZE +# define GIT_OID_HEX_ZERO GIT_OID_SHA1_HEXZERO +#endif + GIT_EXTERN(int) git_oid_iszero(const git_oid *id); /**@}*/ diff --git a/vendor/libgit2/include/git2/diff.h b/vendor/libgit2/include/git2/diff.h index 3839f003..384b6e74 100644 --- a/vendor/libgit2/include/git2/diff.h +++ b/vendor/libgit2/include/git2/diff.h @@ -274,7 +274,7 @@ typedef struct { /** * Represents the known length of the `id` field, when - * converted to a hex string. It is generally `GIT_OID_HEXSZ`, unless this + * converted to a hex string. It is generally `GIT_OID_SHA1_HEXSIZE`, unless this * delta was created from reading a patch file, in which case it may be * abbreviated to something reasonable, like 7 characters. */ @@ -421,6 +421,22 @@ typedef struct { */ uint32_t interhunk_lines; + /** + * The object ID type to emit in diffs; this is used by functions + * that operate without a repository - namely `git_diff_buffers`, + * or `git_diff_blobs` and `git_diff_blob_to_buffer` when one blob + * is `NULL`. + * + * This may be omitted (set to `0`). If a repository is available, + * the object ID format of the repository will be used. If no + * repository is available then the default is `GIT_OID_SHA`. + * + * If this is specified and a repository is available, then the + * specified `oid_type` must match the repository's object ID + * format. + */ + git_oid_t oid_type; + /** * The abbreviation length to use when formatting object ids. * Defaults to the value of 'core.abbrev' from the config, or 7 if unset. @@ -1153,9 +1169,8 @@ GIT_EXTERN(int) git_diff_to_buf( /**@}*/ - /* - * Misc + * Low-level file comparison, invoking callbacks per difference. */ /** @@ -1271,6 +1286,25 @@ GIT_EXTERN(int) git_diff_buffers( git_diff_line_cb line_cb, void *payload); +/* Patch file parsing. */ + +/** + * Options for parsing a diff / patch file. + */ +typedef struct { + unsigned int version; + git_oid_t oid_type; +} git_diff_parse_options; + +/* The current version of the diff parse options structure */ +#define GIT_DIFF_PARSE_OPTIONS_VERSION 1 + +/* Stack initializer for diff parse options. Alternatively use + * `git_diff_parse_options_init` programmatic initialization. + */ +#define GIT_DIFF_PARSE_OPTIONS_INIT \ + { GIT_DIFF_PARSE_OPTIONS_VERSION, GIT_OID_DEFAULT } + /** * Read the contents of a git patch file into a `git_diff` object. * @@ -1293,7 +1327,11 @@ GIT_EXTERN(int) git_diff_buffers( GIT_EXTERN(int) git_diff_from_buffer( git_diff **out, const char *content, - size_t content_len); + size_t content_len +#ifdef GIT_EXPERIMENTAL_SHA256 + , git_diff_parse_options *opts +#endif + ); /** * This is an opaque structure which is allocated by `git_diff_get_stats`. diff --git a/vendor/libgit2/include/git2/email.h b/vendor/libgit2/include/git2/email.h index 20393653..3389353e 100644 --- a/vendor/libgit2/include/git2/email.h +++ b/vendor/libgit2/include/git2/email.h @@ -8,6 +8,7 @@ #define INCLUDE_git_email_h__ #include "common.h" +#include "diff.h" /** * @file git2/email.h diff --git a/vendor/libgit2/include/git2/errors.h b/vendor/libgit2/include/git2/errors.h index 16712f98..52fa5f07 100644 --- a/vendor/libgit2/include/git2/errors.h +++ b/vendor/libgit2/include/git2/errors.h @@ -19,20 +19,20 @@ GIT_BEGIN_DECL /** Generic return codes */ typedef enum { - GIT_OK = 0, /**< No error */ + GIT_OK = 0, /**< No error */ - GIT_ERROR = -1, /**< Generic error */ - GIT_ENOTFOUND = -3, /**< Requested object could not be found */ - GIT_EEXISTS = -4, /**< Object exists preventing operation */ - GIT_EAMBIGUOUS = -5, /**< More than one object matches */ - GIT_EBUFS = -6, /**< Output buffer too short to hold data */ + GIT_ERROR = -1, /**< Generic error */ + GIT_ENOTFOUND = -3, /**< Requested object could not be found */ + GIT_EEXISTS = -4, /**< Object exists preventing operation */ + GIT_EAMBIGUOUS = -5, /**< More than one object matches */ + GIT_EBUFS = -6, /**< Output buffer too short to hold data */ /** * GIT_EUSER is a special error that is never generated by libgit2 * code. You can return it from a callback (e.g to stop an iteration) * to know that it was generated by the callback and not by libgit2. */ - GIT_EUSER = -7, + GIT_EUSER = -7, GIT_EBAREREPO = -8, /**< Operation not allowed on bare repository */ GIT_EUNBORNBRANCH = -9, /**< HEAD refers to branch with no commits */ @@ -58,7 +58,11 @@ typedef enum { GIT_EMISMATCH = -33, /**< Hashsum mismatch in object */ GIT_EINDEXDIRTY = -34, /**< Unsaved changes in the index would be overwritten */ GIT_EAPPLYFAIL = -35, /**< Patch application failed */ - GIT_EOWNER = -36 /**< The object is not owned by the current user */ + GIT_EOWNER = -36, /**< The object is not owned by the current user */ + GIT_TIMEOUT = -37, /**< The operation timed out */ + GIT_EUNCHANGED = -38, /**< There were no changes */ + GIT_ENOTSUPPORTED = -39, /**< An option is not supported */ + GIT_EREADONLY = -40 /**< The subject is read-only */ } git_error_code; /** @@ -107,58 +111,32 @@ typedef enum { GIT_ERROR_FILESYSTEM, GIT_ERROR_PATCH, GIT_ERROR_WORKTREE, - GIT_ERROR_SHA1, + GIT_ERROR_SHA, GIT_ERROR_HTTP, - GIT_ERROR_INTERNAL + GIT_ERROR_INTERNAL, + GIT_ERROR_GRAFTS } git_error_t; /** * Return the last `git_error` object that was generated for the * current thread. * - * The default behaviour of this function is to return NULL if no previous error has occurred. - * However, libgit2's error strings are not cleared aggressively, so a prior - * (unrelated) error may be returned. This can be avoided by only calling - * this function if the prior call to a libgit2 API returned an error. + * This function will never return NULL. * - * @return A git_error object. - */ -GIT_EXTERN(const git_error *) git_error_last(void); - -/** - * Clear the last library error that occurred for this thread. - */ -GIT_EXTERN(void) git_error_clear(void); - -/** - * Set the error message string for this thread. + * Callers should not rely on this to determine whether an error has + * occurred. For error checking, callers should examine the return + * codes of libgit2 functions. * - * This function is public so that custom ODB backends and the like can - * relay an error message through libgit2. Most regular users of libgit2 - * will never need to call this function -- actually, calling it in most - * circumstances (for example, calling from within a callback function) - * will just end up having the value overwritten by libgit2 internals. + * This call can only reliably report error messages when an error + * has occurred. (It may contain stale information if it is called + * after a different function that succeeds.) * - * This error message is stored in thread-local storage and only applies - * to the particular thread that this libgit2 call is made from. + * The memory for this object is managed by libgit2. It should not + * be freed. * - * @param error_class One of the `git_error_t` enum above describing the - * general subsystem that is responsible for the error. - * @param string The formatted error message to keep - * @return 0 on success or -1 on failure - */ -GIT_EXTERN(int) git_error_set_str(int error_class, const char *string); - -/** - * Set the error message to a special value for memory allocation failure. - * - * The normal `git_error_set_str()` function attempts to `strdup()` the - * string that is passed in. This is not a good idea when the error in - * question is a memory allocation failure. That circumstance has a - * special setter function that sets the error string to a known and - * statically allocated internal value. + * @return A git_error object. */ -GIT_EXTERN(void) git_error_set_oom(void); +GIT_EXTERN(const git_error *) git_error_last(void); /** @} */ GIT_END_DECL diff --git a/vendor/libgit2/include/git2/experimental.h b/vendor/libgit2/include/git2/experimental.h new file mode 100644 index 00000000..06435f9a --- /dev/null +++ b/vendor/libgit2/include/git2/experimental.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_experimental_h__ +#define INCLUDE_experimental_h__ + +/* + * This file exists to support users who build libgit2 with a bespoke + * build system and do not use our cmake configuration. Normally, cmake + * will create `experimental.h` from the `experimental.h.in` file and + * will include the generated file instead of this one. For non-cmake + * users, we bundle this `experimental.h` file which will be used + * instead. + */ + +#endif diff --git a/vendor/libgit2/include/git2/index.h b/vendor/libgit2/include/git2/index.h index 981535da..6e806371 100644 --- a/vendor/libgit2/include/git2/index.h +++ b/vendor/libgit2/include/git2/index.h @@ -184,7 +184,12 @@ typedef enum { * @param index_path the path to the index file in disk * @return 0 or an error code */ + +#ifdef GIT_EXPERIMENTAL_SHA256 +GIT_EXTERN(int) git_index_open(git_index **out, const char *index_path, git_oid_t oid_type); +#else GIT_EXTERN(int) git_index_open(git_index **out, const char *index_path); +#endif /** * Create an in-memory index object. @@ -197,7 +202,11 @@ GIT_EXTERN(int) git_index_open(git_index **out, const char *index_path); * @param out the pointer for the new index * @return 0 or an error code */ +#ifdef GIT_EXPERIMENTAL_SHA256 +GIT_EXTERN(int) git_index_new(git_index **out, git_oid_t oid_type); +#else GIT_EXTERN(int) git_index_new(git_index **out); +#endif /** * Free an existing index object. diff --git a/vendor/libgit2/include/git2/indexer.h b/vendor/libgit2/include/git2/indexer.h index ffe9bf36..630eef93 100644 --- a/vendor/libgit2/include/git2/indexer.h +++ b/vendor/libgit2/include/git2/indexer.h @@ -62,6 +62,19 @@ typedef int GIT_CALLBACK(git_indexer_progress_cb)(const git_indexer_progress *st typedef struct git_indexer_options { unsigned int version; +#ifdef GIT_EXPERIMENTAL_SHA256 + /** permissions to use creating packfile or 0 for defaults */ + unsigned int mode; + + /** + * object database from which to read base objects when + * fixing thin packs. This can be NULL if there are no thin + * packs; if a thin pack is encountered, an error will be + * returned if there are bases missing. + */ + git_odb *odb; +#endif + /** progress_cb function to call with progress information */ git_indexer_progress_cb progress_cb; @@ -87,6 +100,21 @@ GIT_EXTERN(int) git_indexer_options_init( git_indexer_options *opts, unsigned int version); +#ifdef GIT_EXPERIMENTAL_SHA256 +/** + * Create a new indexer instance + * + * @param out where to store the indexer instance + * @param path to the directory where the packfile should be stored + * @param oid_type the oid type to use for objects + * @return 0 or an error code. + */ +GIT_EXTERN(int) git_indexer_new( + git_indexer **out, + const char *path, + git_oid_t oid_type, + git_indexer_options *opts); +#else /** * Create a new indexer instance * @@ -106,6 +134,7 @@ GIT_EXTERN(int) git_indexer_new( unsigned int mode, git_odb *odb, git_indexer_options *opts); +#endif /** * Add data to the indexer diff --git a/vendor/libgit2/include/git2/merge.h b/vendor/libgit2/include/git2/merge.h index e90941a4..fcce5594 100644 --- a/vendor/libgit2/include/git2/merge.h +++ b/vendor/libgit2/include/git2/merge.h @@ -603,7 +603,7 @@ GIT_EXTERN(int) git_merge_commits( * completes, resolve any conflicts and prepare a commit. * * For compatibility with git, the repository is put into a merging - * state. Once the commit is done (or if the uses wishes to abort), + * state. Once the commit is done (or if the user wishes to abort), * you should clear this state by calling * `git_repository_state_cleanup()`. * diff --git a/vendor/libgit2/include/git2/object.h b/vendor/libgit2/include/git2/object.h index 5610a476..6384aaa6 100644 --- a/vendor/libgit2/include/git2/object.h +++ b/vendor/libgit2/include/git2/object.h @@ -225,6 +225,7 @@ GIT_EXTERN(int) git_object_peel( */ GIT_EXTERN(int) git_object_dup(git_object **dest, git_object *source); +#ifdef GIT_EXPERIMENTAL_SHA256 /** * Analyzes a buffer of raw object content and determines its validity. * Tree, commit, and tag objects will be parsed and ensured that they @@ -238,14 +239,39 @@ GIT_EXTERN(int) git_object_dup(git_object **dest, git_object *source); * @param valid Output pointer to set with validity of the object content * @param buf The contents to validate * @param len The length of the buffer - * @param type The type of the object in the buffer + * @param object_type The type of the object in the buffer + * @param oid_type The object ID type for the OIDs in the given buffer * @return 0 on success or an error code */ GIT_EXTERN(int) git_object_rawcontent_is_valid( int *valid, const char *buf, size_t len, - git_object_t type); + git_object_t object_type, + git_oid_t oid_type); +#else +/** + * Analyzes a buffer of raw object content and determines its validity. + * Tree, commit, and tag objects will be parsed and ensured that they + * are valid, parseable content. (Blobs are always valid by definition.) + * An error message will be set with an informative message if the object + * is not valid. + * + * @warning This function is experimental and its signature may change in + * the future. + * + * @param valid Output pointer to set with validity of the object content + * @param buf The contents to validate + * @param len The length of the buffer + * @param object_type The type of the object in the buffer + * @return 0 on success or an error code + */ +GIT_EXTERN(int) git_object_rawcontent_is_valid( + int *valid, + const char *buf, + size_t len, + git_object_t object_type); +#endif /** @} */ GIT_END_DECL diff --git a/vendor/libgit2/include/git2/odb.h b/vendor/libgit2/include/git2/odb.h index 0ffe3f32..c7d6a894 100644 --- a/vendor/libgit2/include/git2/odb.h +++ b/vendor/libgit2/include/git2/odb.h @@ -38,6 +38,25 @@ typedef enum { */ typedef int GIT_CALLBACK(git_odb_foreach_cb)(const git_oid *id, void *payload); +/** Options for configuring a loose object backend. */ +typedef struct { + unsigned int version; /**< version for the struct */ + + /** + * Type of object IDs to use for this object database, or + * 0 for default (currently SHA1). + */ + git_oid_t oid_type; +} git_odb_options; + +/* The current version of the diff options structure */ +#define GIT_ODB_OPTIONS_VERSION 1 + +/* Stack initializer for odb options. Alternatively use + * `git_odb_options_init` programmatic initialization. + */ +#define GIT_ODB_OPTIONS_INIT { GIT_ODB_OPTIONS_VERSION } + /** * Create a new object database with no backends. * @@ -46,9 +65,14 @@ typedef int GIT_CALLBACK(git_odb_foreach_cb)(const git_oid *id, void *payload); * * @param out location to store the database pointer, if opened. * Set to NULL if the open failed. + * @param opts the options for this object database or NULL for defaults * @return 0 or an error code */ +#ifdef GIT_EXPERIMENTAL_SHA256 +GIT_EXTERN(int) git_odb_new(git_odb **out, const git_odb_options *opts); +#else GIT_EXTERN(int) git_odb_new(git_odb **out); +#endif /** * Create a new object database and automatically add @@ -64,9 +88,17 @@ GIT_EXTERN(int) git_odb_new(git_odb **out); * @param out location to store the database pointer, if opened. * Set to NULL if the open failed. * @param objects_dir path of the backends' "objects" directory. + * @param opts the options for this object database or NULL for defaults * @return 0 or an error code */ +#ifdef GIT_EXPERIMENTAL_SHA256 +GIT_EXTERN(int) git_odb_open( + git_odb **out, + const char *objects_dir, + const git_odb_options *opts); +#else GIT_EXTERN(int) git_odb_open(git_odb **out, const char *objects_dir); +#endif /** * Add an on-disk alternate to an existing Object DB. @@ -117,7 +149,7 @@ GIT_EXTERN(int) git_odb_read(git_odb_object **out, git_odb *db, const git_oid *i * This method queries all available ODB backends * trying to match the 'len' first hexadecimal * characters of the 'short_id'. - * The remaining (GIT_OID_HEXSZ-len)*4 bits of + * The remaining (GIT_OID_SHA1_HEXSIZE-len)*4 bits of * 'short_id' must be 0s. * 'len' must be at least GIT_OID_MINPREFIXLEN, * and the prefix must be long enough to identify @@ -218,7 +250,7 @@ typedef struct git_odb_expand_id { * * The given array will be updated in place: for each abbreviated ID that is * unique in the database, and of the given type (if specified), - * the full object ID, object ID length (`GIT_OID_HEXSZ`) and type will be + * the full object ID, object ID length (`GIT_OID_SHA1_HEXSIZE`) and type will be * written back to the array. For IDs that are not found (or are ambiguous), * the array entry will be zeroed. * @@ -435,18 +467,28 @@ GIT_EXTERN(int) git_odb_write_multi_pack_index( git_odb *db); /** - * Determine the object-ID (sha1 hash) of a data buffer + * Determine the object-ID (sha1 or sha256 hash) of a data buffer * - * The resulting SHA-1 OID will be the identifier for the data - * buffer as if the data buffer it were to written to the ODB. + * The resulting OID will be the identifier for the data buffer as if + * the data buffer it were to written to the ODB. * * @param out the resulting object-ID. * @param data data to hash * @param len size of the data - * @param type of the data to hash + * @param object_type of the data to hash + * @param oid_type the oid type to hash to * @return 0 or an error code */ +#ifdef GIT_EXPERIMENTAL_SHA256 +GIT_EXTERN(int) git_odb_hash( + git_oid *out, + const void *data, + size_t len, + git_object_t object_type, + git_oid_t oid_type); +#else GIT_EXTERN(int) git_odb_hash(git_oid *out, const void *data, size_t len, git_object_t type); +#endif /** * Read a file from disk and fill a git_oid with the object id @@ -458,10 +500,19 @@ GIT_EXTERN(int) git_odb_hash(git_oid *out, const void *data, size_t len, git_obj * * @param out oid structure the result is written into. * @param path file to read and determine object id for - * @param type the type of the object that will be hashed + * @param object_type of the data to hash + * @param oid_type the oid type to hash to * @return 0 or an error code */ +#ifdef GIT_EXPERIMENTAL_SHA256 +GIT_EXTERN(int) git_odb_hashfile( + git_oid *out, + const char *path, + git_object_t object_type, + git_oid_t oid_type); +#else GIT_EXTERN(int) git_odb_hashfile(git_oid *out, const char *path, git_object_t type); +#endif /** * Create a copy of an odb_object diff --git a/vendor/libgit2/include/git2/odb_backend.h b/vendor/libgit2/include/git2/odb_backend.h index 5ad777b1..12dd0fd3 100644 --- a/vendor/libgit2/include/git2/odb_backend.h +++ b/vendor/libgit2/include/git2/odb_backend.h @@ -24,6 +24,26 @@ GIT_BEGIN_DECL * Constructors for in-box ODB backends. */ +/** Options for configuring a packfile object backend. */ +typedef struct { + unsigned int version; /**< version for the struct */ + + /** + * Type of object IDs to use for this object database, or + * 0 for default (currently SHA1). + */ + git_oid_t oid_type; +} git_odb_backend_pack_options; + +/* The current version of the diff options structure */ +#define GIT_ODB_BACKEND_PACK_OPTIONS_VERSION 1 + +/* Stack initializer for odb pack backend options. Alternatively use + * `git_odb_backend_pack_options_init` programmatic initialization. + */ +#define GIT_ODB_BACKEND_PACK_OPTIONS_INIT \ + { GIT_ODB_BACKEND_PACK_OPTIONS_VERSION } + /** * Create a backend for the packfiles. * @@ -32,20 +52,96 @@ GIT_BEGIN_DECL * * @return 0 or an error code */ -GIT_EXTERN(int) git_odb_backend_pack(git_odb_backend **out, const char *objects_dir); +#ifdef GIT_EXPERIMENTAL_SHA256 +GIT_EXTERN(int) git_odb_backend_pack( + git_odb_backend **out, + const char *objects_dir, + const git_odb_backend_pack_options *opts); +#else +GIT_EXTERN(int) git_odb_backend_pack( + git_odb_backend **out, + const char *objects_dir); +#endif + +/** + * Create a backend out of a single packfile + * + * This can be useful for inspecting the contents of a single + * packfile. + * + * @param out location to store the odb backend pointer + * @param index_file path to the packfile's .idx file + * + * @return 0 or an error code + */ +#ifdef GIT_EXPERIMENTAL_SHA256 +GIT_EXTERN(int) git_odb_backend_one_pack( + git_odb_backend **out, + const char *index_file, + const git_odb_backend_pack_options *opts); +#else +GIT_EXTERN(int) git_odb_backend_one_pack( + git_odb_backend **out, + const char *index_file); +#endif + +typedef enum { + GIT_ODB_BACKEND_LOOSE_FSYNC = (1 << 0) +} git_odb_backend_loose_flag_t; + +/** Options for configuring a loose object backend. */ +typedef struct { + unsigned int version; /**< version for the struct */ + + /** A combination of the `git_odb_backend_loose_flag_t` types. */ + uint32_t flags; + + /** + * zlib compression level to use (0-9), where 1 is the fastest + * at the expense of larger files, and 9 produces the best + * compression at the expense of speed. 0 indicates that no + * compression should be performed. -1 is the default (currently + * optimizing for speed). + */ + int compression_level; + + /** Permissions to use creating a directory or 0 for defaults */ + unsigned int dir_mode; + + /** Permissions to use creating a file or 0 for defaults */ + unsigned int file_mode; + + /** + * Type of object IDs to use for this object database, or + * 0 for default (currently SHA1). + */ + git_oid_t oid_type; +} git_odb_backend_loose_options; + +/* The current version of the diff options structure */ +#define GIT_ODB_BACKEND_LOOSE_OPTIONS_VERSION 1 + +/* Stack initializer for odb loose backend options. Alternatively use + * `git_odb_backend_loose_options_init` programmatic initialization. + */ +#define GIT_ODB_BACKEND_LOOSE_OPTIONS_INIT \ + { GIT_ODB_BACKEND_LOOSE_OPTIONS_VERSION, 0, -1 } /** * Create a backend for loose objects * * @param out location to store the odb backend pointer * @param objects_dir the Git repository's objects directory - * @param compression_level zlib compression level to use - * @param do_fsync whether to do an fsync() after writing - * @param dir_mode permissions to use creating a directory or 0 for defaults - * @param file_mode permissions to use creating a file or 0 for defaults + * @param opts options for the loose object backend or NULL * * @return 0 or an error code */ +#ifdef GIT_EXPERIMENTAL_SHA256 +GIT_EXTERN(int) git_odb_backend_loose( + git_odb_backend **out, + const char *objects_dir, + git_odb_backend_loose_options *opts); +#else GIT_EXTERN(int) git_odb_backend_loose( git_odb_backend **out, const char *objects_dir, @@ -53,19 +149,7 @@ GIT_EXTERN(int) git_odb_backend_loose( int do_fsync, unsigned int dir_mode, unsigned int file_mode); - -/** - * Create a backend out of a single packfile - * - * This can be useful for inspecting the contents of a single - * packfile. - * - * @param out location to store the odb backend pointer - * @param index_file path to the packfile's .idx file - * - * @return 0 or an error code - */ -GIT_EXTERN(int) git_odb_backend_one_pack(git_odb_backend **out, const char *index_file); +#endif /** Streaming mode */ typedef enum { @@ -87,6 +171,10 @@ struct git_odb_stream { unsigned int mode; void *hash_ctx; +#ifdef GIT_EXPERIMENTAL_SHA256 + git_oid_t oid_type; +#endif + git_object_size_t declared_size; git_object_size_t received_bytes; diff --git a/vendor/libgit2/include/git2/oid.h b/vendor/libgit2/include/git2/oid.h index 549df4ea..35b43ef1 100644 --- a/vendor/libgit2/include/git2/oid.h +++ b/vendor/libgit2/include/git2/oid.h @@ -9,6 +9,7 @@ #include "common.h" #include "types.h" +#include "experimental.h" /** * @file git2/oid.h @@ -19,11 +20,76 @@ */ GIT_BEGIN_DECL -/** Size (in bytes) of a raw/binary oid */ -#define GIT_OID_RAWSZ 20 +/** The type of object id. */ +typedef enum { -/** Size (in bytes) of a hex formatted oid */ -#define GIT_OID_HEXSZ (GIT_OID_RAWSZ * 2) +#ifdef GIT_EXPERIMENTAL_SHA256 + GIT_OID_SHA1 = 1, /**< SHA1 */ + GIT_OID_SHA256 = 2 /**< SHA256 */ +#else + GIT_OID_SHA1 = 1 /**< SHA1 */ +#endif + +} git_oid_t; + +/* + * SHA1 is currently the only supported object ID type. + */ + +/** SHA1 is currently libgit2's default oid type. */ +#define GIT_OID_DEFAULT GIT_OID_SHA1 + +/** Size (in bytes) of a raw/binary sha1 oid */ +#define GIT_OID_SHA1_SIZE 20 +/** Size (in bytes) of a hex formatted sha1 oid */ +#define GIT_OID_SHA1_HEXSIZE (GIT_OID_SHA1_SIZE * 2) + +/** + * The binary representation of the null sha1 object ID. + */ +#ifndef GIT_EXPERIMENTAL_SHA256 +# define GIT_OID_SHA1_ZERO { { 0 } } +#else +# define GIT_OID_SHA1_ZERO { GIT_OID_SHA1, { 0 } } +#endif + +/** + * The string representation of the null sha1 object ID. + */ +#define GIT_OID_SHA1_HEXZERO "0000000000000000000000000000000000000000" + +/* + * Experimental SHA256 support is a breaking change to the API. + * This exists for application compatibility testing. + */ + +#ifdef GIT_EXPERIMENTAL_SHA256 + +/** Size (in bytes) of a raw/binary sha256 oid */ +# define GIT_OID_SHA256_SIZE 32 +/** Size (in bytes) of a hex formatted sha256 oid */ +# define GIT_OID_SHA256_HEXSIZE (GIT_OID_SHA256_SIZE * 2) + +/** + * The binary representation of the null sha256 object ID. + */ +# define GIT_OID_SHA256_ZERO { GIT_OID_SHA256, { 0 } } + +/** + * The string representation of the null sha256 object ID. + */ +# define GIT_OID_SHA256_HEXZERO "0000000000000000000000000000000000000000000000000000000000000000" + +#endif + +/* Maximum possible object ID size in raw / hex string format. */ +#ifndef GIT_EXPERIMENTAL_SHA256 +# define GIT_OID_MAX_SIZE GIT_OID_SHA1_SIZE +# define GIT_OID_MAX_HEXSIZE GIT_OID_SHA1_HEXSIZE +#else +# define GIT_OID_MAX_SIZE GIT_OID_SHA256_SIZE +# define GIT_OID_MAX_HEXSIZE GIT_OID_SHA256_HEXSIZE +#endif /** Minimum length (in number of hex characters, * i.e. packets of 4 bits) of an oid prefix */ @@ -31,29 +97,50 @@ GIT_BEGIN_DECL /** Unique identity of any object (commit, tree, blob, tag). */ typedef struct git_oid { + +#ifdef GIT_EXPERIMENTAL_SHA256 + /** type of object id */ + unsigned char type; +#endif + /** raw binary formatted id */ - unsigned char id[GIT_OID_RAWSZ]; + unsigned char id[GIT_OID_MAX_SIZE]; } git_oid; /** * Parse a hex formatted object id into a git_oid. * + * The appropriate number of bytes for the given object ID type will + * be read from the string - 40 bytes for SHA1, 64 bytes for SHA256. + * The given string need not be NUL terminated. + * * @param out oid structure the result is written into. * @param str input hex string; must be pointing at the start of * the hex sequence and have at least the number of bytes - * needed for an oid encoded in hex (40 bytes). + * needed for an oid encoded in hex (40 bytes for sha1, + * 256 bytes for sha256). + * @param type the type of object id * @return 0 or an error code */ +#ifdef GIT_EXPERIMENTAL_SHA256 +GIT_EXTERN(int) git_oid_fromstr(git_oid *out, const char *str, git_oid_t type); +#else GIT_EXTERN(int) git_oid_fromstr(git_oid *out, const char *str); +#endif /** - * Parse a hex formatted null-terminated string into a git_oid. + * Parse a hex formatted NUL-terminated string into a git_oid. * * @param out oid structure the result is written into. * @param str input hex string; must be null-terminated. + * @param type the type of object id * @return 0 or an error code */ +#ifdef GIT_EXPERIMENTAL_SHA256 +GIT_EXTERN(int) git_oid_fromstrp(git_oid *out, const char *str, git_oid_t type); +#else GIT_EXTERN(int) git_oid_fromstrp(git_oid *out, const char *str); +#endif /** * Parse N characters of a hex formatted object id into a git_oid. @@ -64,9 +151,14 @@ GIT_EXTERN(int) git_oid_fromstrp(git_oid *out, const char *str); * @param out oid structure the result is written into. * @param str input hex string of at least size `length` * @param length length of the input string + * @param type the type of object id * @return 0 or an error code */ +#ifdef GIT_EXPERIMENTAL_SHA256 +GIT_EXTERN(int) git_oid_fromstrn(git_oid *out, const char *str, size_t length, git_oid_t type); +#else GIT_EXTERN(int) git_oid_fromstrn(git_oid *out, const char *str, size_t length); +#endif /** * Copy an already raw oid into a git_oid structure. @@ -75,16 +167,21 @@ GIT_EXTERN(int) git_oid_fromstrn(git_oid *out, const char *str, size_t length); * @param raw the raw input bytes to be copied. * @return 0 on success or error code */ +#ifdef GIT_EXPERIMENTAL_SHA256 +GIT_EXTERN(int) git_oid_fromraw(git_oid *out, const unsigned char *raw, git_oid_t type); +#else GIT_EXTERN(int) git_oid_fromraw(git_oid *out, const unsigned char *raw); +#endif /** * Format a git_oid into a hex string. * * @param out output hex string; must be pointing at the start of * the hex sequence and have at least the number of bytes - * needed for an oid encoded in hex (40 bytes). Only the - * oid digits are written; a '\\0' terminator must be added - * by the caller if it is required. + * needed for an oid encoded in hex (40 bytes for SHA1, + * 64 bytes for SHA256). Only the oid digits are written; + * a '\\0' terminator must be added by the caller if it is + * required. * @param id oid structure to format. * @return 0 on success or error code */ @@ -94,7 +191,7 @@ GIT_EXTERN(int) git_oid_fmt(char *out, const git_oid *id); * Format a git_oid into a partial hex string. * * @param out output hex string; you say how many bytes to write. - * If the number of bytes is > GIT_OID_HEXSZ, extra bytes + * If the number of bytes is > GIT_OID_SHA1_HEXSIZE, extra bytes * will be zeroed; if not, a '\0' terminator is NOT added. * @param n number of characters to write into out string * @param id oid structure to format. @@ -110,9 +207,10 @@ GIT_EXTERN(int) git_oid_nfmt(char *out, size_t n, const git_oid *id); * * @param out output hex string; must be pointing at the start of * the hex sequence and have at least the number of bytes - * needed for an oid encoded in hex (41 bytes). Only the - * oid digits are written; a '\\0' terminator must be added - * by the caller if it is required. + * needed for an oid encoded in hex (41 bytes for SHA1, + * 65 bytes for SHA256). Only the oid digits are written; + * a '\\0' terminator must be added by the caller if it + * is required. * @param id oid structure to format. * @return 0 on success, non-zero callback return value, or error code */ @@ -127,14 +225,16 @@ GIT_EXTERN(int) git_oid_pathfmt(char *out, const git_oid *id); * concurrent calls of the function. * * @param oid The oid structure to format - * @return the c-string + * @return the c-string or NULL on failure */ GIT_EXTERN(char *) git_oid_tostr_s(const git_oid *oid); /** * Format a git_oid into a buffer as a hex format c-string. * - * If the buffer is smaller than GIT_OID_HEXSZ+1, then the resulting + * If the buffer is smaller than the size of a hex-formatted oid string + * plus an additional byte (GIT_OID_SHA_HEXSIZE + 1 for SHA1 or + * GIT_OID_SHA256_HEXSIZE + 1 for SHA256), then the resulting * oid c-string will be truncated to n-1 characters (but will still be * NUL-byte terminated). * diff --git a/vendor/libgit2/include/git2/refspec.h b/vendor/libgit2/include/git2/refspec.h index eaf77474..e7087132 100644 --- a/vendor/libgit2/include/git2/refspec.h +++ b/vendor/libgit2/include/git2/refspec.h @@ -58,7 +58,7 @@ GIT_EXTERN(const char *) git_refspec_dst(const git_refspec *refspec); * Get the refspec's string * * @param refspec the refspec - * @returns the refspec's original string + * @return the refspec's original string */ GIT_EXTERN(const char *) git_refspec_string(const git_refspec *refspec); diff --git a/vendor/libgit2/include/git2/remote.h b/vendor/libgit2/include/git2/remote.h index 8c9c26f3..5505f6c3 100644 --- a/vendor/libgit2/include/git2/remote.h +++ b/vendor/libgit2/include/git2/remote.h @@ -76,6 +76,17 @@ typedef enum { GIT_REMOTE_CREATE_SKIP_DEFAULT_FETCHSPEC = (1 << 1) } git_remote_create_flags; +/** + * How to handle reference updates. + */ +typedef enum { + /* Write the fetch results to FETCH_HEAD. */ + GIT_REMOTE_UPDATE_FETCHHEAD = (1 << 0), + + /* Report unchanged tips in the update_tips callback. */ + GIT_REMOTE_UPDATE_REPORT_UNCHANGED = (1 << 1) +} git_remote_update_flags; + /** * Remote creation options structure * @@ -702,6 +713,15 @@ typedef enum { GIT_REMOTE_DOWNLOAD_TAGS_ALL } git_remote_autotag_option_t; +/** Constants for fetch depth (shallowness of fetch). */ +typedef enum { + /** The fetch is "full" (not shallow). This is the default. */ + GIT_FETCH_DEPTH_FULL = 0, + + /** The fetch should "unshallow" and fetch missing data. */ + GIT_FETCH_DEPTH_UNSHALLOW = 2147483647 +} git_fetch_depth_t; + /** * Fetch options structure. * @@ -724,10 +744,9 @@ typedef struct { git_fetch_prune_t prune; /** - * Whether to write the results to FETCH_HEAD. Defaults to - * on. Leave this default in order to behave like git. + * How to handle reference updates; see `git_remote_update_flags`. */ - int update_fetchhead; + unsigned int update_fetchhead; /** * Determines how to behave regarding tags on the remote, such @@ -743,6 +762,15 @@ typedef struct { */ git_proxy_options proxy_opts; + /** + * Depth of the fetch to perform, or `GIT_FETCH_DEPTH_FULL` + * (or `0`) for full history, or `GIT_FETCH_DEPTH_UNSHALLOW` + * to "unshallow" a shallow repository. + * + * The default is full (`GIT_FETCH_DEPTH_FULL` or `0`). + */ + int depth; + /** * Whether to allow off-site redirects. If this is not * specified, the `http.followRedirects` configuration setting @@ -757,8 +785,13 @@ typedef struct { } git_fetch_options; #define GIT_FETCH_OPTIONS_VERSION 1 -#define GIT_FETCH_OPTIONS_INIT { GIT_FETCH_OPTIONS_VERSION, GIT_REMOTE_CALLBACKS_INIT, GIT_FETCH_PRUNE_UNSPECIFIED, 1, \ - GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, GIT_PROXY_OPTIONS_INIT } +#define GIT_FETCH_OPTIONS_INIT { \ + GIT_FETCH_OPTIONS_VERSION, \ + GIT_REMOTE_CALLBACKS_INIT, \ + GIT_FETCH_PRUNE_UNSPECIFIED, \ + GIT_REMOTE_UPDATE_FETCHHEAD, \ + GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, \ + GIT_PROXY_OPTIONS_INIT } /** * Initialize git_fetch_options structure @@ -812,6 +845,11 @@ typedef struct { * Extra headers for this push operation */ git_strarray custom_headers; + + /** + * "Push options" to deliver to the remote. + */ + git_strarray remote_push_options; } git_push_options; #define GIT_PUSH_OPTIONS_VERSION 1 @@ -983,7 +1021,7 @@ GIT_EXTERN(int) git_remote_upload( * the name of the remote (or its url, for in-memory remotes). This * parameter is ignored when pushing. * @param callbacks pointer to the callback structure to use or NULL - * @param update_fetchhead whether to write to FETCH_HEAD. Pass 1 to behave like git. + * @param update_flags the git_remote_update_flags for these tips. * @param download_tags what the behaviour for downloading tags is for this fetch. This is * ignored for push. This must be the same value passed to `git_remote_download()`. * @return 0 or an error code @@ -991,7 +1029,7 @@ GIT_EXTERN(int) git_remote_upload( GIT_EXTERN(int) git_remote_update_tips( git_remote *remote, const git_remote_callbacks *callbacks, - int update_fetchhead, + unsigned int update_flags, git_remote_autotag_option_t download_tags, const char *reflog_message); diff --git a/vendor/libgit2/include/git2/repository.h b/vendor/libgit2/include/git2/repository.h index c87f3c96..0afda72d 100644 --- a/vendor/libgit2/include/git2/repository.h +++ b/vendor/libgit2/include/git2/repository.h @@ -11,6 +11,7 @@ #include "types.h" #include "oid.h" #include "buffer.h" +#include "commit.h" /** * @file git2/repository.h @@ -56,9 +57,19 @@ GIT_EXTERN(int) git_repository_open_from_worktree(git_repository **out, git_work * * @param out pointer to the repo * @param odb the object database to wrap + * @param oid_type the oid type of the object database * @return 0 or an error code */ -GIT_EXTERN(int) git_repository_wrap_odb(git_repository **out, git_odb *odb); +#ifdef GIT_EXPERIMENTAL_SHA256 +GIT_EXTERN(int) git_repository_wrap_odb( + git_repository **out, + git_odb *odb, + git_oid_t oid_type); +#else +GIT_EXTERN(int) git_repository_wrap_odb( + git_repository **out, + git_odb *odb); +#endif /** * Look for a git repository and copy its path in the given buffer. @@ -351,6 +362,15 @@ typedef struct { * pointing to this URL. */ const char *origin_url; + +#ifdef GIT_EXPERIMENTAL_SHA256 + /** + * + * Type of object IDs to use for this repository, or 0 for + * default (currently SHA1). + */ + git_oid_t oid_type; +#endif } git_repository_init_options; #define GIT_REPOSITORY_INIT_OPTIONS_VERSION 1 @@ -456,7 +476,9 @@ GIT_EXTERN(int) git_repository_head_unborn(git_repository *repo); * Check if a repository is empty * * An empty repository has just been initialized and contains no references - * apart from HEAD, which must be pointing to the unborn master branch. + * apart from HEAD, which must be pointing to the unborn master branch, + * or the branch specified for the repository in the `init.defaultBranch` + * configuration variable. * * @param repo Repo to test * @return 1 if the repository is empty, 0 if it isn't, error code @@ -482,6 +504,7 @@ typedef enum { GIT_REPOSITORY_ITEM_LOGS, GIT_REPOSITORY_ITEM_MODULES, GIT_REPOSITORY_ITEM_WORKTREES, + GIT_REPOSITORY_ITEM_WORKTREE_CONFIG, GIT_REPOSITORY_ITEM__LAST } git_repository_item_t; @@ -525,7 +548,7 @@ GIT_EXTERN(const char *) git_repository_workdir(const git_repository *repo); /** * Get the path of the shared common directory for this repository. - * + * * If the repository is bare, it is the root directory for the repository. * If the repository is a worktree, it is the parent repo's gitdir. * Otherwise, it is the gitdir. @@ -949,6 +972,25 @@ GIT_EXTERN(int) git_repository_ident(const char **name, const char **email, cons */ GIT_EXTERN(int) git_repository_set_ident(git_repository *repo, const char *name, const char *email); +/** + * Gets the object type used by this repository. + * + * @param repo the repository + * @return the object id type + */ +GIT_EXTERN(git_oid_t) git_repository_oid_type(git_repository *repo); + +/** + * Gets the parents of the next commit, given the current repository state. + * Generally, this is the HEAD commit, except when performing a merge, in + * which case it is two or more commits. + * + * @param commits a `git_commitarray` that will contain the commit parents + * @param repo the repository + * @return 0 or an error code + */ +GIT_EXTERN(int) git_repository_commit_parents(git_commitarray *commits, git_repository *repo); + /** @} */ GIT_END_DECL #endif diff --git a/vendor/libgit2/include/git2/stash.h b/vendor/libgit2/include/git2/stash.h index 32e6f957..dcfc013d 100644 --- a/vendor/libgit2/include/git2/stash.h +++ b/vendor/libgit2/include/git2/stash.h @@ -44,7 +44,12 @@ typedef enum { * All ignored files are also stashed and then cleaned up from * the working directory */ - GIT_STASH_INCLUDE_IGNORED = (1 << 2) + GIT_STASH_INCLUDE_IGNORED = (1 << 2), + + /** + * All changes in the index and working directory are left intact + */ + GIT_STASH_KEEP_ALL = (1 << 3) } git_stash_flags; /** @@ -52,15 +57,10 @@ typedef enum { * * @param out Object id of the commit containing the stashed state. * This commit is also the target of the direct reference refs/stash. - * * @param repo The owning repository. - * * @param stasher The identity of the person performing the stashing. - * * @param message Optional description along with the stashed state. - * * @param flags Flags to control the stashing process. (see GIT_STASH_* above) - * * @return 0 on success, GIT_ENOTFOUND where there's nothing to stash, * or error code. */ @@ -71,6 +71,60 @@ GIT_EXTERN(int) git_stash_save( const char *message, uint32_t flags); +/** + * Stash save options structure + * + * Initialize with `GIT_STASH_SAVE_OPTIONS_INIT`. Alternatively, you can + * use `git_stash_save_options_init`. + * + */ +typedef struct git_stash_save_options { + unsigned int version; + + /** Flags to control the stashing process. (see GIT_STASH_* above) */ + uint32_t flags; + + /** The identity of the person performing the stashing. */ + const git_signature *stasher; + + /** Optional description along with the stashed state. */ + const char *message; + + /** Optional paths that control which files are stashed. */ + git_strarray paths; +} git_stash_save_options; + +#define GIT_STASH_SAVE_OPTIONS_VERSION 1 +#define GIT_STASH_SAVE_OPTIONS_INIT { GIT_STASH_SAVE_OPTIONS_VERSION } + +/** + * Initialize git_stash_save_options structure + * + * Initializes a `git_stash_save_options` with default values. Equivalent to + * creating an instance with `GIT_STASH_SAVE_OPTIONS_INIT`. + * + * @param opts The `git_stash_save_options` struct to initialize. + * @param version The struct version; pass `GIT_STASH_SAVE_OPTIONS_VERSION`. + * @return Zero on success; -1 on failure. + */ +GIT_EXTERN(int) git_stash_save_options_init( + git_stash_save_options *opts, unsigned int version); + +/** + * Save the local modifications to a new stash, with options. + * + * @param out Object id of the commit containing the stashed state. + * This commit is also the target of the direct reference refs/stash. + * @param repo The owning repository. + * @param opts The stash options. + * @return 0 on success, GIT_ENOTFOUND where there's nothing to stash, + * or error code. + */ +GIT_EXTERN(int) git_stash_save_with_opts( + git_oid *out, + git_repository *repo, + const git_stash_save_options *opts); + /** Stash application flags. */ typedef enum { GIT_STASH_APPLY_DEFAULT = 0, diff --git a/vendor/libgit2/include/git2/status.h b/vendor/libgit2/include/git2/status.h index d8f9663b..bb28e875 100644 --- a/vendor/libgit2/include/git2/status.h +++ b/vendor/libgit2/include/git2/status.h @@ -227,13 +227,16 @@ typedef struct { /** * The `show` value is one of the `git_status_show_t` constants that - * control which files to scan and in what order. + * control which files to scan and in what order. The default is + * `GIT_STATUS_SHOW_INDEX_AND_WORKDIR`. */ git_status_show_t show; /** * The `flags` value is an OR'ed combination of the - * `git_status_opt_t` values above. + * `git_status_opt_t` values above. The default is + * `GIT_STATUS_OPT_DEFAULTS`, which matches git's default + * behavior. */ unsigned int flags; diff --git a/vendor/libgit2/include/git2/strarray.h b/vendor/libgit2/include/git2/strarray.h index 0f657e6c..03d93f8f 100644 --- a/vendor/libgit2/include/git2/strarray.h +++ b/vendor/libgit2/include/git2/strarray.h @@ -36,19 +36,6 @@ typedef struct git_strarray { */ GIT_EXTERN(void) git_strarray_dispose(git_strarray *array); -/** - * Copy a string array object from source to target. - * - * Note: target is overwritten and hence should be empty, otherwise its - * contents are leaked. Call git_strarray_free() if necessary. - * - * @param tgt target - * @param src source - * @return 0 on success, < 0 on allocation failure - */ -GIT_EXTERN(int) git_strarray_copy(git_strarray *tgt, const git_strarray *src); - - /** @} */ GIT_END_DECL diff --git a/vendor/libgit2/include/git2/sys/alloc.h b/vendor/libgit2/include/git2/sys/alloc.h index c295807b..e7f85b89 100644 --- a/vendor/libgit2/include/git2/sys/alloc.h +++ b/vendor/libgit2/include/git2/sys/alloc.h @@ -24,28 +24,6 @@ typedef struct { /** Allocate `n` bytes of memory */ void * GIT_CALLBACK(gmalloc)(size_t n, const char *file, int line); - /** - * Allocate memory for an array of `nelem` elements, where each element - * has a size of `elsize`. Returned memory shall be initialized to - * all-zeroes - */ - void * GIT_CALLBACK(gcalloc)(size_t nelem, size_t elsize, const char *file, int line); - - /** Allocate memory for the string `str` and duplicate its contents. */ - char * GIT_CALLBACK(gstrdup)(const char *str, const char *file, int line); - - /** - * Equivalent to the `gstrdup` function, but only duplicating at most - * `n + 1` bytes - */ - char * GIT_CALLBACK(gstrndup)(const char *str, size_t n, const char *file, int line); - - /** - * Equivalent to `gstrndup`, but will always duplicate exactly `n` bytes - * of `str`. Thus, out of bounds reads at `str` may happen. - */ - char * GIT_CALLBACK(gsubstrdup)(const char *str, size_t n, const char *file, int line); - /** * This function shall deallocate the old object `ptr` and return a * pointer to a new object that has the size specified by `size`. In @@ -53,18 +31,6 @@ typedef struct { */ void * GIT_CALLBACK(grealloc)(void *ptr, size_t size, const char *file, int line); - /** - * This function shall be equivalent to `grealloc`, but allocating - * `neleme * elsize` bytes. - */ - void * GIT_CALLBACK(greallocarray)(void *ptr, size_t nelem, size_t elsize, const char *file, int line); - - /** - * This function shall allocate a new array of `nelem` elements, where - * each element has a size of `elsize` bytes. - */ - void * GIT_CALLBACK(gmallocarray)(size_t nelem, size_t elsize, const char *file, int line); - /** * This function shall free the memory pointed to by `ptr`. In case * `ptr` is `NULL`, this shall be a no-op. diff --git a/vendor/libgit2/include/git2/sys/commit_graph.h b/vendor/libgit2/include/git2/sys/commit_graph.h index 823c7ed5..06e045fc 100644 --- a/vendor/libgit2/include/git2/sys/commit_graph.h +++ b/vendor/libgit2/include/git2/sys/commit_graph.h @@ -28,7 +28,13 @@ GIT_BEGIN_DECL * @param objects_dir the path to a git objects directory. * @return Zero on success; -1 on failure. */ -GIT_EXTERN(int) git_commit_graph_open(git_commit_graph **cgraph_out, const char *objects_dir); +GIT_EXTERN(int) git_commit_graph_open( + git_commit_graph **cgraph_out, + const char *objects_dir +#ifdef GIT_EXPERIMENTAL_SHA256 + , git_oid_t oid_type +#endif + ); /** * Frees commit-graph data. This should only be called when memory allocated @@ -50,7 +56,11 @@ GIT_EXTERN(void) git_commit_graph_free(git_commit_graph *cgraph); */ GIT_EXTERN(int) git_commit_graph_writer_new( git_commit_graph_writer **out, - const char *objects_info_dir); + const char *objects_info_dir +#ifdef GIT_EXPERIMENTAL_SHA256 + , git_oid_t oid_type +#endif + ); /** * Free the commit-graph writer and its resources. diff --git a/vendor/libgit2/include/git2/sys/config.h b/vendor/libgit2/include/git2/sys/config.h index 0a9005e3..75d20758 100644 --- a/vendor/libgit2/include/git2/sys/config.h +++ b/vendor/libgit2/include/git2/sys/config.h @@ -125,6 +125,57 @@ GIT_EXTERN(int) git_config_add_backend( const git_repository *repo, int force); +/** Options for in-memory configuration backends. */ +typedef struct { + unsigned int version; + + /** + * The type of this backend (eg, "command line"). If this is + * NULL, then this will be "in-memory". + */ + const char *backend_type; + + /** + * The path to the origin; if this is NULL then it will be + * left unset in the resulting configuration entries. + */ + const char *origin_path; +} git_config_backend_memory_options; + +#define GIT_CONFIG_BACKEND_MEMORY_OPTIONS_VERSION 1 +#define GIT_CONFIG_BACKEND_MEMORY_OPTIONS_INIT { GIT_CONFIG_BACKEND_MEMORY_OPTIONS_VERSION } + + +/** + * Create an in-memory configuration backend from a string in standard + * git configuration file format. + * + * @param out the new backend + * @param cfg the configuration that is to be parsed + * @param len the length of the string pointed to by `cfg` + * @param opts the options to initialize this backend with, or NULL + */ +extern int git_config_backend_from_string( + git_config_backend **out, + const char *cfg, + size_t len, + git_config_backend_memory_options *opts); + +/** + * Create an in-memory configuration backend from a list of name/value + * pairs. + * + * @param out the new backend + * @param values the configuration values to set (in "key=value" format) + * @param len the length of the values array + * @param opts the options to initialize this backend with, or NULL + */ +extern int git_config_backend_from_values( + git_config_backend **out, + const char **values, + size_t len, + git_config_backend_memory_options *opts); + /** @} */ GIT_END_DECL #endif diff --git a/vendor/libgit2/include/git2/sys/email.h b/vendor/libgit2/include/git2/sys/email.h index 6f4a2866..5029f9a5 100644 --- a/vendor/libgit2/include/git2/sys/email.h +++ b/vendor/libgit2/include/git2/sys/email.h @@ -7,6 +7,11 @@ #ifndef INCLUDE_sys_git_email_h__ #define INCLUDE_sys_git_email_h__ +#include "git2/common.h" +#include "git2/diff.h" +#include "git2/email.h" +#include "git2/types.h" + /** * @file git2/sys/email.h * @brief Advanced git email creation routines diff --git a/vendor/libgit2/include/git2/sys/errors.h b/vendor/libgit2/include/git2/sys/errors.h new file mode 100644 index 00000000..3ae12152 --- /dev/null +++ b/vendor/libgit2/include/git2/sys/errors.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_sys_git_errors_h__ +#define INCLUDE_sys_git_errors_h__ + +#include "git2/common.h" + +GIT_BEGIN_DECL + +/** + * Clear the last library error that occurred for this thread. + */ +GIT_EXTERN(void) git_error_clear(void); + +/** + * Set the error message string for this thread, using `printf`-style + * formatting. + * + * This function is public so that custom ODB backends and the like can + * relay an error message through libgit2. Most regular users of libgit2 + * will never need to call this function -- actually, calling it in most + * circumstances (for example, calling from within a callback function) + * will just end up having the value overwritten by libgit2 internals. + * + * This error message is stored in thread-local storage and only applies + * to the particular thread that this libgit2 call is made from. + * + * @param error_class One of the `git_error_t` enum above describing the + * general subsystem that is responsible for the error. + * @param fmt The `printf`-style format string; subsequent arguments must + * be the arguments for the format string. + */ +GIT_EXTERN(void) git_error_set(int error_class, const char *fmt, ...) + GIT_FORMAT_PRINTF(2, 3); + +/** + * Set the error message string for this thread. This function is like + * `git_error_set` but takes a static string instead of a `printf`-style + * format. + * + * @param error_class One of the `git_error_t` enum above describing the + * general subsystem that is responsible for the error. + * @param string The error message to keep + * @return 0 on success or -1 on failure + */ +GIT_EXTERN(int) git_error_set_str(int error_class, const char *string); + +/** + * Set the error message to a special value for memory allocation failure. + * + * The normal `git_error_set_str()` function attempts to `strdup()` the + * string that is passed in. This is not a good idea when the error in + * question is a memory allocation failure. That circumstance has a + * special setter function that sets the error string to a known and + * statically allocated internal value. + */ +GIT_EXTERN(void) git_error_set_oom(void); + +GIT_END_DECL + +#endif diff --git a/vendor/libgit2/include/git2/sys/midx.h b/vendor/libgit2/include/git2/sys/midx.h index e3d74982..3a87484d 100644 --- a/vendor/libgit2/include/git2/sys/midx.h +++ b/vendor/libgit2/include/git2/sys/midx.h @@ -29,7 +29,11 @@ GIT_BEGIN_DECL */ GIT_EXTERN(int) git_midx_writer_new( git_midx_writer **out, - const char *pack_dir); + const char *pack_dir +#ifdef GIT_EXPERIMENTAL_SHA256 + , git_oid_t oid_type +#endif + ); /** * Free the multi-pack-index writer and its resources. diff --git a/vendor/libgit2/include/git2/sys/odb_backend.h b/vendor/libgit2/include/git2/sys/odb_backend.h index 8598f94e..c42abd37 100644 --- a/vendor/libgit2/include/git2/sys/odb_backend.h +++ b/vendor/libgit2/include/git2/sys/odb_backend.h @@ -36,7 +36,7 @@ struct git_odb_backend { void **, size_t *, git_object_t *, git_odb_backend *, const git_oid *); /* To find a unique object given a prefix of its oid. The oid given - * must be so that the remaining (GIT_OID_HEXSZ - len)*4 bits are 0s. + * must be so that the remaining (GIT_OID_SHA1_HEXSIZE - len)*4 bits are 0s. */ int GIT_CALLBACK(read_prefix)( git_oid *, void **, size_t *, git_object_t *, diff --git a/vendor/libgit2/include/git2/sys/remote.h b/vendor/libgit2/include/git2/sys/remote.h index dd243ca5..58950e1e 100644 --- a/vendor/libgit2/include/git2/sys/remote.h +++ b/vendor/libgit2/include/git2/sys/remote.h @@ -8,6 +8,8 @@ #ifndef INCLUDE_sys_git_remote_h #define INCLUDE_sys_git_remote_h +#include "git2/remote.h" + /** * @file git2/sys/remote.h * @brief Low-level remote functionality for custom transports @@ -18,14 +20,33 @@ GIT_BEGIN_DECL +/** + * A remote's capabilities. + */ typedef enum { /** Remote supports fetching an advertised object by ID. */ GIT_REMOTE_CAPABILITY_TIP_OID = (1 << 0), /** Remote supports fetching an individual reachable object. */ GIT_REMOTE_CAPABILITY_REACHABLE_OID = (1 << 1), + + /** Remote supports push options. */ + GIT_REMOTE_CAPABILITY_PUSH_OPTIONS = (1 << 2), } git_remote_capability_t; +/** + * Disposes libgit2-initialized fields from a git_remote_connect_options. + * This should only be used for git_remote_connect_options returned by + * git_transport_remote_connect_options. + * + * Note that this does not free the `git_remote_connect_options` itself, just + * the memory pointed to by it. + * + * @param opts The `git_remote_connect_options` struct to dispose. + */ +GIT_EXTERN(void) git_remote_connect_options_dispose( + git_remote_connect_options *opts); + /** @} */ GIT_END_DECL #endif diff --git a/vendor/libgit2/include/git2/sys/repository.h b/vendor/libgit2/include/git2/sys/repository.h index 892be669..080a404c 100644 --- a/vendor/libgit2/include/git2/sys/repository.h +++ b/vendor/libgit2/include/git2/sys/repository.h @@ -9,6 +9,7 @@ #include "git2/common.h" #include "git2/types.h" +#include "git2/oid.h" /** * @file git2/sys/repository.h @@ -32,7 +33,11 @@ GIT_BEGIN_DECL * @param out The blank repository * @return 0 on success, or an error code */ +#ifdef GIT_EXPERIMENTAL_SHA256 +GIT_EXTERN(int) git_repository_new(git_repository **out, git_oid_t oid_type); +#else GIT_EXTERN(int) git_repository_new(git_repository **out); +#endif /** * Reset all the internal state in a repository. diff --git a/vendor/libgit2/include/git2/sys/stream.h b/vendor/libgit2/include/git2/sys/stream.h index e0e03a2d..3277088c 100644 --- a/vendor/libgit2/include/git2/sys/stream.h +++ b/vendor/libgit2/include/git2/sys/stream.h @@ -29,8 +29,22 @@ GIT_BEGIN_DECL typedef struct git_stream { int version; - int encrypted; - int proxy_support; + unsigned int encrypted : 1, + proxy_support : 1; + + /** + * Timeout for read and write operations; can be set to `0` to + * block indefinitely. + */ + int timeout; + + /** + * Timeout to connect to the remote server; can be set to `0` + * to use the system defaults. This can be shorter than the + * system default - often 75 seconds - but cannot be longer. + */ + int connect_timeout; + int GIT_CALLBACK(connect)(struct git_stream *); int GIT_CALLBACK(certificate)(git_cert **, struct git_stream *); int GIT_CALLBACK(set_proxy)(struct git_stream *, const git_proxy_options *proxy_opts); diff --git a/vendor/libgit2/include/git2/sys/transport.h b/vendor/libgit2/include/git2/sys/transport.h index f0c2a3ea..370ca45d 100644 --- a/vendor/libgit2/include/git2/sys/transport.h +++ b/vendor/libgit2/include/git2/sys/transport.h @@ -9,10 +9,12 @@ #define INCLUDE_sys_git_transport_h #include "git2/net.h" +#include "git2/oidarray.h" +#include "git2/proxy.h" +#include "git2/remote.h" +#include "git2/strarray.h" #include "git2/transport.h" #include "git2/types.h" -#include "git2/strarray.h" -#include "git2/proxy.h" /** * @file git2/sys/transport.h @@ -24,6 +26,14 @@ GIT_BEGIN_DECL +typedef struct { + const git_remote_head * const *refs; + size_t refs_len; + git_oid *shallow_roots; + size_t shallow_roots_len; + int depth; +} git_fetch_negotiation; + struct git_transport { unsigned int version; /**< The struct version */ @@ -56,6 +66,18 @@ struct git_transport { unsigned int *capabilities, git_transport *transport); +#ifdef GIT_EXPERIMENTAL_SHA256 + /** + * Gets the object type for the remote repository. + * + * This function may be called after a successful call to + * `connect()`. + */ + int GIT_CALLBACK(oid_type)( + git_oid_t *object_type, + git_transport *transport); +#endif + /** * Get the list of available references in the remote repository. * @@ -83,8 +105,17 @@ struct git_transport { int GIT_CALLBACK(negotiate_fetch)( git_transport *transport, git_repository *repo, - const git_remote_head * const *refs, - size_t count); + const git_fetch_negotiation *fetch_data); + + /** + * Return the shallow roots of the remote. + * + * This function may be called after a successful call to + * `negotiate_fetch`. + */ + int GIT_CALLBACK(shallow_roots)( + git_oidarray *out, + git_transport *transport); /** * Start downloading the packfile from the remote repository. @@ -261,14 +292,17 @@ GIT_EXTERN(int) git_transport_smart_certificate_check(git_transport *transport, GIT_EXTERN(int) git_transport_smart_credentials(git_credential **out, git_transport *transport, const char *user, int methods); /** - * Get a copy of the proxy options + * Get a copy of the remote connect options * - * The url is copied and must be freed by the caller. + * All data is copied and must be freed by the caller by calling + * `git_remote_connect_options_dispose`. * * @param out options struct to fill * @param transport the transport to extract the data from. */ -GIT_EXTERN(int) git_transport_smart_proxy_options(git_proxy_options *out, git_transport *transport); +GIT_EXTERN(int) git_transport_remote_connect_options( + git_remote_connect_options *out, + git_transport *transport); /* *** End of base transport interface *** diff --git a/vendor/libgit2/include/git2/version.h b/vendor/libgit2/include/git2/version.h index 980f70b6..540bf286 100644 --- a/vendor/libgit2/include/git2/version.h +++ b/vendor/libgit2/include/git2/version.h @@ -7,12 +7,37 @@ #ifndef INCLUDE_git_version_h__ #define INCLUDE_git_version_h__ -#define LIBGIT2_VERSION "1.4.3" -#define LIBGIT2_VER_MAJOR 1 -#define LIBGIT2_VER_MINOR 4 -#define LIBGIT2_VER_REVISION 3 -#define LIBGIT2_VER_PATCH 0 +/** + * The version string for libgit2. This string follows semantic + * versioning (v2) guidelines. + */ +#define LIBGIT2_VERSION "1.8.5" + +/** The major version number for this version of libgit2. */ +#define LIBGIT2_VER_MAJOR 1 + +/** The minor version number for this version of libgit2. */ +#define LIBGIT2_VER_MINOR 8 + +/** The revision ("teeny") version number for this version of libgit2. */ +#define LIBGIT2_VER_REVISION 5 -#define LIBGIT2_SOVERSION "1.4" +/** The Windows DLL patch number for this version of libgit2. */ +#define LIBGIT2_VER_PATCH 0 + +/** + * The prerelease string for this version of libgit2. For development + * (nightly) builds, this will be "alpha". For prereleases, this will be + * a prerelease name like "beta" or "rc1". For final releases, this will + * be `NULL`. + */ +#define LIBGIT2_VER_PRERELEASE NULL + +/** + * The library ABI soversion for this version of libgit2. This should + * only be changed when the library has a breaking ABI change, and so + * may trail the library's version number. + */ +#define LIBGIT2_SOVERSION "1.8" #endif diff --git a/vendor/libgit2/include/git2/worktree.h b/vendor/libgit2/include/git2/worktree.h index bb024dc9..a6e5d17c 100644 --- a/vendor/libgit2/include/git2/worktree.h +++ b/vendor/libgit2/include/git2/worktree.h @@ -11,6 +11,7 @@ #include "buffer.h" #include "types.h" #include "strarray.h" +#include "checkout.h" /** * @file git2/worktrees.h @@ -85,8 +86,9 @@ GIT_EXTERN(int) git_worktree_validate(const git_worktree *wt); typedef struct git_worktree_add_options { unsigned int version; - int lock; /**< lock newly created worktree */ - git_reference *ref; /**< reference to use for the new worktree HEAD */ + int lock; /**< lock newly created worktree */ + int checkout_existing; /**< allow checkout of existing branch matching worktree name */ + git_reference *ref; /**< reference to use for the new worktree HEAD */ /** * Options for the checkout. @@ -95,7 +97,8 @@ typedef struct git_worktree_add_options { } git_worktree_add_options; #define GIT_WORKTREE_ADD_OPTIONS_VERSION 1 -#define GIT_WORKTREE_ADD_OPTIONS_INIT {GIT_WORKTREE_ADD_OPTIONS_VERSION,0,NULL,GIT_CHECKOUT_OPTIONS_INIT} +#define GIT_WORKTREE_ADD_OPTIONS_INIT { GIT_WORKTREE_ADD_OPTIONS_VERSION, \ + 0, 0, NULL, GIT_CHECKOUT_OPTIONS_INIT } /** * Initialize git_worktree_add_options structure @@ -237,7 +240,9 @@ GIT_EXTERN(int) git_worktree_prune_options_init( * * If the worktree is not valid and not locked or if the above * flags have been passed in, this function will return a - * positive value. + * positive value. If the worktree is not prunable, an error + * message will be set (visible in `giterr_last`) with details about + * why. * * @param wt Worktree to check. * @param opts The prunable options. diff --git a/vendor/libgit2/package.json b/vendor/libgit2/package.json index 5caa47ae..0e6e66ef 100644 --- a/vendor/libgit2/package.json +++ b/vendor/libgit2/package.json @@ -1,6 +1,6 @@ { "name": "libgit2", - "version": "1.4.3", + "version": "1.8.5", "repo": "https://github.com/libgit2/libgit2", "description": " A cross-platform, linkable library implementation of Git that you can use in your application.", "install": "mkdir build && cd build && cmake .. && cmake --build ." diff --git a/vendor/libgit2/script/valgrind.sh b/vendor/libgit2/script/valgrind.sh index b5deed2b..aacd767a 100755 --- a/vendor/libgit2/script/valgrind.sh +++ b/vendor/libgit2/script/valgrind.sh @@ -1,2 +1,2 @@ #!/bin/bash -exec valgrind --leak-check=full --show-reachable=yes --error-exitcode=125 --num-callers=50 --suppressions="$(dirname "${BASH_SOURCE[0]}")/valgrind.supp" "$@" +exec valgrind --leak-check=full --show-reachable=yes --child-silent-after-fork=yes --error-exitcode=125 --num-callers=50 --suppressions="$(dirname "${BASH_SOURCE[0]}")/valgrind.supp" "$@" diff --git a/vendor/libgit2/script/valgrind.supp b/vendor/libgit2/script/valgrind.supp index 8c4549f6..79e8378f 100644 --- a/vendor/libgit2/script/valgrind.supp +++ b/vendor/libgit2/script/valgrind.supp @@ -80,6 +80,13 @@ fun:__check_pf } +{ + ignore-glibc-getaddrinfo-fn + Memcheck:Leak + ... + fun:getaddrinfo +} + { ignore-curl-global-init Memcheck:Leak @@ -191,6 +198,16 @@ ... } +{ + ignore-openssl-undefined-in-connect + Memcheck:Cond + ... + obj:*libcrypto.so* + ... + fun:openssl_connect + ... +} + { ignore-libssh2-rsa-sha1-sign Memcheck:Leak diff --git a/vendor/libgit2/src/CMakeLists.txt b/vendor/libgit2/src/CMakeLists.txt index e7b54d03..ed3f4a51 100644 --- a/vendor/libgit2/src/CMakeLists.txt +++ b/vendor/libgit2/src/CMakeLists.txt @@ -1,12 +1,22 @@ -add_library(git2internal OBJECT) -set_target_properties(git2internal PROPERTIES C_STANDARD 90) -set_target_properties(git2internal PROPERTIES C_EXTENSIONS OFF) +# The main libgit2 source tree: this CMakeLists.txt identifies platform +# support and includes the subprojects that make up core libgit2 support. +# +# Optional build configuration settings +# if(DEPRECATE_HARD) add_definitions(-DGIT_DEPRECATE_HARD) endif() +if(USE_LEAK_CHECKER STREQUAL "valgrind") + add_definitions(-DVALGRIND) +endif() + +# +# Optional debugging functionality +# + if(DEBUG_POOL) set(GIT_DEBUG_POOL 1) endif() @@ -22,102 +32,145 @@ if(DEBUG_STRICT_OPEN) endif() add_feature_info(debugopen GIT_DEBUG_STRICT_OPEN "path validation in open") +# +# Optional feature enablement +# -include(PkgBuildConfig) -include(SanitizeBool) +include(SelectGSSAPI) +include(SelectHTTPSBackend) +include(SelectHashes) +include(SelectHTTPParser) +include(SelectRegex) +include(SelectXdiff) +include(SelectSSH) +include(SelectZlib) -# This variable will contain the libraries we need to put into -# libgit2.pc's Requires.private. That is, what we're linking to or -# what someone who's statically linking us needs to link to. -set(LIBGIT2_PC_REQUIRES "") -# This will be set later if we use the system's http-parser library or -# use iconv (OSX) and will be written to the Libs.private field in the -# pc file. -set(LIBGIT2_PC_LIBS "") +# +# Platform support +# -set(LIBGIT2_INCLUDES - "${CMAKE_CURRENT_BINARY_DIR}" - "${PROJECT_SOURCE_DIR}/src" - "${PROJECT_SOURCE_DIR}/include") +# futimes/futimens if(HAVE_FUTIMENS) set(GIT_USE_FUTIMENS 1) endif () add_feature_info(futimens GIT_USE_FUTIMENS "futimens support") -check_prototype_definition(qsort_r - "void qsort_r(void *base, size_t nmemb, size_t size, void *thunk, int (*compar)(void *, const void *, const void *))" - "" "stdlib.h" GIT_QSORT_R_BSD) +# qsort + +# old-style FreeBSD qsort_r() has the 'context' parameter as the first argument +# of the comparison function: +check_prototype_definition_safe(qsort_r + "void (qsort_r)(void *base, size_t nmemb, size_t size, void *context, int (*compar)(void *, const void *, const void *))" + "" "stdlib.h" GIT_QSORT_BSD) -check_prototype_definition(qsort_r - "void qsort_r(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *arg)" - "" "stdlib.h" GIT_QSORT_R_GNU) +# GNU or POSIX qsort_r() has the 'context' parameter as the last argument of the +# comparison function: +check_prototype_definition_safe(qsort_r + "void (qsort_r)(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *context)" + "" "stdlib.h" GIT_QSORT_GNU) -check_function_exists(qsort_s GIT_QSORT_S) +# C11 qsort_s() has the 'context' parameter as the last argument of the +# comparison function, and returns an error status: +check_prototype_definition_safe(qsort_s + "errno_t (qsort_s)(void *base, rsize_t nmemb, rsize_t size, int (*compar)(const void *, const void *, void *), void *context)" + "0" "stdlib.h" GIT_QSORT_C11) -check_function_exists(getentropy GIT_RAND_GETENTROPY) +# MSC qsort_s() has the 'context' parameter as the first argument of the +# comparison function, and as the last argument of qsort_s(): +check_prototype_definition_safe(qsort_s + "void (qsort_s)(void *base, size_t num, size_t width, int (*compare )(void *, const void *, const void *), void *context)" + "" "stdlib.h" GIT_QSORT_MSC) -# Find required dependencies +# random / entropy data + +check_symbol_exists(getentropy unistd.h GIT_RAND_GETENTROPY) +check_symbol_exists(getloadavg stdlib.h GIT_RAND_GETLOADAVG) + +# poll if(WIN32) - list(APPEND LIBGIT2_SYSTEM_LIBS ws2_32) -elseif(CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)") - list(APPEND LIBGIT2_SYSTEM_LIBS socket nsl) - list(APPEND LIBGIT2_PC_LIBS "-lsocket" "-lnsl") -elseif(CMAKE_SYSTEM_NAME MATCHES "Haiku") - list(APPEND LIBGIT2_SYSTEM_LIBS network) - list(APPEND LIBGIT2_PC_LIBS "-lnetwork") + set(GIT_IO_WSAPOLL 1) +else() + check_symbol_exists(poll poll.h GIT_IO_POLL) + check_symbol_exists(select sys/select.h GIT_IO_SELECT) +endif() + +# determine architecture of the machine + +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(GIT_ARCH_64 1) +elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) + set(GIT_ARCH_32 1) +elseif(CMAKE_SIZEOF_VOID_P) + message(FATAL_ERROR "Unsupported architecture (pointer size is ${CMAKE_SIZEOF_VOID_P} bytes)") +else() + message(FATAL_ERROR "Unsupported architecture (CMAKE_SIZEOF_VOID_P is unset)") +endif() + +# nanosecond mtime/ctime support + +if(USE_NSEC) + set(GIT_USE_NSEC 1) endif() +# high-resolution stat support + +if(HAVE_STRUCT_STAT_ST_MTIM) + set(GIT_USE_STAT_MTIM 1) +elseif(HAVE_STRUCT_STAT_ST_MTIMESPEC) + set(GIT_USE_STAT_MTIMESPEC 1) +elseif(HAVE_STRUCT_STAT_ST_MTIME_NSEC) + set(GIT_USE_STAT_MTIME_NSEC 1) +endif() + +# realtime support + check_library_exists(rt clock_gettime "time.h" NEED_LIBRT) if(NEED_LIBRT) list(APPEND LIBGIT2_SYSTEM_LIBS rt) list(APPEND LIBGIT2_PC_LIBS "-lrt") endif() -if(USE_THREADS) - list(APPEND LIBGIT2_SYSTEM_LIBS ${CMAKE_THREAD_LIBS_INIT}) - list(APPEND LIBGIT2_PC_LIBS ${CMAKE_THREAD_LIBS_INIT}) +# platform libraries + +if(WIN32) + list(APPEND LIBGIT2_SYSTEM_LIBS "ws2_32" "secur32") + list(APPEND LIBGIT2_PC_LIBS "-lws2_32" "-lsecur32") endif() -add_feature_info(threadsafe USE_THREADS "threadsafe support") +if(CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)") + list(APPEND LIBGIT2_SYSTEM_LIBS socket nsl) + list(APPEND LIBGIT2_PC_LIBS "-lsocket" "-lnsl") +endif() -if(WIN32 AND EMBED_SSH_PATH) - file(GLOB SRC_SSH "${EMBED_SSH_PATH}/src/*.c") - list(SORT SRC_SSH) - target_sources(git2internal PRIVATE ${SRC_SSH}) +if(CMAKE_SYSTEM_NAME MATCHES "Haiku") + list(APPEND LIBGIT2_SYSTEM_LIBS gnu network) + list(APPEND LIBGIT2_PC_LIBS "-lgnu -lnetwork") +endif() - list(APPEND LIBGIT2_SYSTEM_INCLUDES "${EMBED_SSH_PATH}/include") - file(WRITE "${EMBED_SSH_PATH}/src/libssh2_config.h" "#define HAVE_WINCNG\n#define LIBSSH2_WINCNG\n#include \"../win32/libssh2_config.h\"") - set(GIT_SSH 1) +if(AMIGA) + add_definitions(-DNO_ADDRINFO -DNO_READDIR_R -DNO_MMAP) endif() -include(SelectHTTPSBackend) -include(SelectHashes) -include(SelectHTTPParser) -include(SelectRegex) -include(SelectSSH) -include(SelectWinHTTP) -include(SelectZlib) +# threads +if(USE_THREADS) + if(NOT WIN32) + find_package(Threads REQUIRED) + list(APPEND LIBGIT2_SYSTEM_LIBS ${CMAKE_THREAD_LIBS_INIT}) + list(APPEND LIBGIT2_PC_LIBS ${CMAKE_THREAD_LIBS_INIT}) + endif() -if(USE_SHA1 STREQUAL "CollisionDetection") - file(GLOB SRC_SHA1 hash/sha1/collisiondetect.* hash/sha1/sha1dc/*) -elseif(USE_SHA1 STREQUAL "OpenSSL") - file(GLOB SRC_SHA1 hash/sha1/openssl.*) -elseif(USE_SHA1 STREQUAL "CommonCrypto") - file(GLOB SRC_SHA1 hash/sha1/common_crypto.*) -elseif(USE_SHA1 STREQUAL "mbedTLS") - file(GLOB SRC_SHA1 hash/sha1/mbedtls.*) -elseif(USE_SHA1 STREQUAL "Win32") - file(GLOB SRC_SHA1 hash/sha1/win32.*) -elseif(USE_SHA1 STREQUAL "Generic") - file(GLOB SRC_SHA1 hash/sha1/generic.*) + set(GIT_THREADS 1) endif() -list(APPEND SRC_SHA1 "hash/sha1.h") -target_sources(git2internal PRIVATE ${SRC_SHA1}) +add_feature_info(threadsafe USE_THREADS "threadsafe support") + +# +# Optional bundled features +# -# Optional external dependency: ntlmclient +# ntlmclient if(USE_NTLMCLIENT) set(GIT_NTLM 1) add_subdirectory("${PROJECT_SOURCE_DIR}/deps/ntlmclient" "${PROJECT_BINARY_DIR}/deps/ntlmclient") @@ -126,13 +179,12 @@ if(USE_NTLMCLIENT) endif() add_feature_info(ntlmclient GIT_NTLM "NTLM authentication support for Unix") -# Optional external dependency: GSSAPI +# +# Optional external dependencies -include(SelectGSSAPI) - -# Optional external dependency: iconv +# iconv if(USE_ICONV) - find_package(Iconv) + find_package(IntlIconv) endif() if(ICONV_FOUND) set(GIT_USE_ICONV 1) @@ -142,166 +194,22 @@ if(ICONV_FOUND) endif() add_feature_info(iconv GIT_USE_ICONV "iconv encoding conversion support") +# +# Include child projects +# -if(USE_THREADS) - if(NOT WIN32) - find_package(Threads REQUIRED) - endif() - - set(GIT_THREADS 1) -endif() - -if(USE_NSEC) - set(GIT_USE_NSEC 1) -endif() - -if(HAVE_STRUCT_STAT_ST_MTIM) - set(GIT_USE_STAT_MTIM 1) -elseif(HAVE_STRUCT_STAT_ST_MTIMESPEC) - set(GIT_USE_STAT_MTIMESPEC 1) -elseif(HAVE_STRUCT_STAT_ST_MTIME_NSEC) - set(GIT_USE_STAT_MTIME_NSEC 1) -endif() - -target_compile_definitions(git2internal PRIVATE _FILE_OFFSET_BITS=64) - -# Collect sourcefiles -file(GLOB SRC_H - "${PROJECT_SOURCE_DIR}/include/git2.h" - "${PROJECT_SOURCE_DIR}/include/git2/*.h" - "${PROJECT_SOURCE_DIR}/include/git2/sys/*.h") -list(SORT SRC_H) -target_sources(git2internal PRIVATE ${SRC_H}) - -# On Windows use specific platform sources -if(WIN32 AND NOT CYGWIN) - set(WIN_RC "win32/git2.rc") - - file(GLOB SRC_OS win32/*.c win32/*.h) - list(SORT SRC_OS) - target_sources(git2internal PRIVATE ${SRC_OS}) -elseif(AMIGA) - target_compile_definitions(git2internal PRIVATE NO_ADDRINFO NO_READDIR_R NO_MMAP) -else() - file(GLOB SRC_OS unix/*.c unix/*.h) - list(SORT SRC_OS) - target_sources(git2internal PRIVATE ${SRC_OS}) -endif() - -if(USE_LEAK_CHECKER STREQUAL "valgrind") - target_compile_definitions(git2internal PRIVATE VALGRIND) -endif() - -file(GLOB SRC_GIT2 *.c *.h - allocators/*.c allocators/*.h - streams/*.c streams/*.h - transports/*.c transports/*.h - xdiff/*.c xdiff/*.h) -list(SORT SRC_GIT2) -target_sources(git2internal PRIVATE ${SRC_GIT2}) - -if(APPLE) - # The old Secure Transport API has been deprecated in macOS 10.15. - set_source_files_properties(streams/stransport.c PROPERTIES COMPILE_FLAGS -Wno-deprecated) -endif() +add_subdirectory(libgit2) +add_subdirectory(util) -# the xdiff dependency is not (yet) warning-free, disable warnings as -# errors for the xdiff sources until we've sorted them out -if(MSVC) - set_source_files_properties(xdiff/xdiffi.c PROPERTIES COMPILE_FLAGS -WX-) - set_source_files_properties(xdiff/xemit.c PROPERTIES COMPILE_FLAGS -WX-) - set_source_files_properties(xdiff/xhistogram.c PROPERTIES COMPILE_FLAGS -WX-) - set_source_files_properties(xdiff/xmerge.c PROPERTIES COMPILE_FLAGS -WX-) - set_source_files_properties(xdiff/xutils.c PROPERTIES COMPILE_FLAGS -WX-) - set_source_files_properties(xdiff/xpatience.c PROPERTIES COMPILE_FLAGS -WX-) -else() - set_source_files_properties(xdiff/xdiffi.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare -Wno-unused-parameter") - set_source_files_properties(xdiff/xemit.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare -Wno-unused-parameter") - set_source_files_properties(xdiff/xhistogram.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare") - set_source_files_properties(xdiff/xutils.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare") - set_source_files_properties(xdiff/xpatience.c PROPERTIES COMPILE_FLAGS "-Wno-sign-compare") +if(BUILD_CLI) + add_subdirectory(cli) endif() -# Determine architecture of the machine -if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(GIT_ARCH_64 1) -elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) - set(GIT_ARCH_32 1) -elseif(CMAKE_SIZEOF_VOID_P) - message(FATAL_ERROR "Unsupported architecture (pointer size is ${CMAKE_SIZEOF_VOID_P} bytes)") -else() - message(FATAL_ERROR "Unsupported architecture (CMAKE_SIZEOF_VOID_P is unset)") -endif() - -configure_file(features.h.in git2/sys/features.h) - -ide_split_sources(git2internal) -list(APPEND LIBGIT2_OBJECTS $ ${LIBGIT2_DEPENDENCY_OBJECTS}) - -target_include_directories(git2internal PRIVATE ${LIBGIT2_INCLUDES} ${LIBGIT2_DEPENDENCY_INCLUDES} PUBLIC ${PROJECT_SOURCE_DIR}/include) -target_include_directories(git2internal SYSTEM PRIVATE ${LIBGIT2_SYSTEM_INCLUDES}) - +# re-export these to the root so that peer projects (tests, fuzzers, +# examples) can use them set(LIBGIT2_INCLUDES ${LIBGIT2_INCLUDES} PARENT_SCOPE) set(LIBGIT2_OBJECTS ${LIBGIT2_OBJECTS} PARENT_SCOPE) set(LIBGIT2_DEPENDENCY_INCLUDES ${LIBGIT2_DEPENDENCY_INCLUDES} PARENT_SCOPE) set(LIBGIT2_DEPENDENCY_OBJECTS ${LIBGIT2_DEPENDENCY_OBJECTS} PARENT_SCOPE) set(LIBGIT2_SYSTEM_INCLUDES ${LIBGIT2_SYSTEM_INCLUDES} PARENT_SCOPE) set(LIBGIT2_SYSTEM_LIBS ${LIBGIT2_SYSTEM_LIBS} PARENT_SCOPE) - -if(XCODE_VERSION) - # This is required for Xcode to actually link the libgit2 library - # when using only object libraries. - file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy.c "") - list(APPEND LIBGIT2_OBJECTS ${CMAKE_CURRENT_BINARY_DIR}/dummy.c) -endif() - -# Compile and link libgit2 -add_library(git2 ${WIN_RC} ${LIBGIT2_OBJECTS}) -target_link_libraries(git2 ${LIBGIT2_SYSTEM_LIBS}) - -set_target_properties(git2 PROPERTIES C_STANDARD 90) -set_target_properties(git2 PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) -set_target_properties(git2 PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) -set_target_properties(git2 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) - -# Workaround for Cmake bug #0011240 (see http://public.kitware.com/Bug/view.php?id=11240) -# Win64+MSVC+static libs = linker error -if(MSVC AND GIT_ARCH_64 AND NOT BUILD_SHARED_LIBS) - set_target_properties(git2 PROPERTIES STATIC_LIBRARY_FLAGS "/MACHINE:x64") -endif() - -ide_split_sources(git2) - -if(SONAME) - set_target_properties(git2 PROPERTIES VERSION ${libgit2_VERSION}) - set_target_properties(git2 PROPERTIES SOVERSION "${libgit2_VERSION_MAJOR}.${libgit2_VERSION_MINOR}") - if(LIBGIT2_FILENAME) - target_compile_definitions(git2 PRIVATE LIBGIT2_FILENAME=\"${LIBGIT2_FILENAME}\") - set_target_properties(git2 PROPERTIES OUTPUT_NAME ${LIBGIT2_FILENAME}) - elseif(DEFINED LIBGIT2_PREFIX) - set_target_properties(git2 PROPERTIES PREFIX "${LIBGIT2_PREFIX}") - endif() -endif() - -pkg_build_config(NAME libgit2 - VERSION ${libgit2_VERSION} - DESCRIPTION "The git library, take 2" - LIBS_SELF git2 - PRIVATE_LIBS ${LIBGIT2_PC_LIBS} - REQUIRES ${LIBGIT2_PC_REQUIRES} -) - -if(MSVC_IDE) - # Precompiled headers - set_target_properties(git2 PROPERTIES COMPILE_FLAGS "/Yuprecompiled.h /FIprecompiled.h") - set_source_files_properties(win32/precompiled.c COMPILE_FLAGS "/Ycprecompiled.h") -endif() - -# Install -install(TARGETS git2 - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} -) -install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/git2 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) -install(FILES ${PROJECT_SOURCE_DIR}/include/git2.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/vendor/libgit2/src/README.md b/vendor/libgit2/src/README.md new file mode 100644 index 00000000..10b86c1d --- /dev/null +++ b/vendor/libgit2/src/README.md @@ -0,0 +1,12 @@ +# libgit2 sources + +This is the source that makes up the core of libgit2 and its related +projects. + +* `cli` + A git-compatible command-line interface that uses libgit2. +* `libgit2` + This is the libgit2 project, a cross-platform, linkable library + implementation of Git that you can use in your application. +* `util` + A shared utility library for these projects. diff --git a/vendor/libgit2/src/alloc.c b/vendor/libgit2/src/alloc.c deleted file mode 100644 index 2820d84a..00000000 --- a/vendor/libgit2/src/alloc.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "alloc.h" -#include "runtime.h" - -#include "allocators/failalloc.h" -#include "allocators/stdalloc.h" -#include "allocators/win32_leakcheck.h" - -/* Fail any allocation until git_libgit2_init is called. */ -git_allocator git__allocator = { - git_failalloc_malloc, - git_failalloc_calloc, - git_failalloc_strdup, - git_failalloc_strndup, - git_failalloc_substrdup, - git_failalloc_realloc, - git_failalloc_reallocarray, - git_failalloc_mallocarray, - git_failalloc_free -}; - -static int setup_default_allocator(void) -{ -#if defined(GIT_WIN32_LEAKCHECK) - return git_win32_leakcheck_init_allocator(&git__allocator); -#else - return git_stdalloc_init_allocator(&git__allocator); -#endif -} - -int git_allocator_global_init(void) -{ - /* - * We don't want to overwrite any allocator which has been set - * before the init function is called. - */ - if (git__allocator.gmalloc != git_failalloc_malloc) - return 0; - - return setup_default_allocator(); -} - -int git_allocator_setup(git_allocator *allocator) -{ - if (!allocator) - return setup_default_allocator(); - - memcpy(&git__allocator, allocator, sizeof(*allocator)); - return 0; -} diff --git a/vendor/libgit2/src/alloc.h b/vendor/libgit2/src/alloc.h deleted file mode 100644 index 04fb7e10..00000000 --- a/vendor/libgit2/src/alloc.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#ifndef INCLUDE_alloc_h__ -#define INCLUDE_alloc_h__ - -#include "git2/sys/alloc.h" - -extern git_allocator git__allocator; - -#define git__malloc(len) git__allocator.gmalloc(len, __FILE__, __LINE__) -#define git__calloc(nelem, elsize) git__allocator.gcalloc(nelem, elsize, __FILE__, __LINE__) -#define git__strdup(str) git__allocator.gstrdup(str, __FILE__, __LINE__) -#define git__strndup(str, n) git__allocator.gstrndup(str, n, __FILE__, __LINE__) -#define git__substrdup(str, n) git__allocator.gsubstrdup(str, n, __FILE__, __LINE__) -#define git__realloc(ptr, size) git__allocator.grealloc(ptr, size, __FILE__, __LINE__) -#define git__reallocarray(ptr, nelem, elsize) git__allocator.greallocarray(ptr, nelem, elsize, __FILE__, __LINE__) -#define git__mallocarray(nelem, elsize) git__allocator.gmallocarray(nelem, elsize, __FILE__, __LINE__) -#define git__free git__allocator.gfree - -/** - * This function is being called by our global setup routines to - * initialize the standard allocator. - */ -int git_allocator_global_init(void); - -/** - * Switch out libgit2's global memory allocator - * - * @param allocator The new allocator that should be used. All function pointers - * of it need to be set correctly. - * @return An error code or 0. - */ -int git_allocator_setup(git_allocator *allocator); - -#endif diff --git a/vendor/libgit2/src/allocators/failalloc.c b/vendor/libgit2/src/allocators/failalloc.c deleted file mode 100644 index 5257d1de..00000000 --- a/vendor/libgit2/src/allocators/failalloc.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "failalloc.h" - -void *git_failalloc_malloc(size_t len, const char *file, int line) -{ - GIT_UNUSED(len); - GIT_UNUSED(file); - GIT_UNUSED(line); - - return NULL; -} - -void *git_failalloc_calloc(size_t nelem, size_t elsize, const char *file, int line) -{ - GIT_UNUSED(nelem); - GIT_UNUSED(elsize); - GIT_UNUSED(file); - GIT_UNUSED(line); - - return NULL; -} - -char *git_failalloc_strdup(const char *str, const char *file, int line) -{ - GIT_UNUSED(str); - GIT_UNUSED(file); - GIT_UNUSED(line); - - return NULL; -} - -char *git_failalloc_strndup(const char *str, size_t n, const char *file, int line) -{ - GIT_UNUSED(str); - GIT_UNUSED(n); - GIT_UNUSED(file); - GIT_UNUSED(line); - - return NULL; -} - -char *git_failalloc_substrdup(const char *start, size_t n, const char *file, int line) -{ - GIT_UNUSED(start); - GIT_UNUSED(n); - GIT_UNUSED(file); - GIT_UNUSED(line); - - return NULL; -} - -void *git_failalloc_realloc(void *ptr, size_t size, const char *file, int line) -{ - GIT_UNUSED(ptr); - GIT_UNUSED(size); - GIT_UNUSED(file); - GIT_UNUSED(line); - - return NULL; -} - -void *git_failalloc_reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line) -{ - GIT_UNUSED(ptr); - GIT_UNUSED(nelem); - GIT_UNUSED(elsize); - GIT_UNUSED(file); - GIT_UNUSED(line); - - return NULL; -} - -void *git_failalloc_mallocarray(size_t nelem, size_t elsize, const char *file, int line) -{ - GIT_UNUSED(nelem); - GIT_UNUSED(elsize); - GIT_UNUSED(file); - GIT_UNUSED(line); - - return NULL; -} - -void git_failalloc_free(void *ptr) -{ - GIT_UNUSED(ptr); -} diff --git a/vendor/libgit2/src/allocators/failalloc.h b/vendor/libgit2/src/allocators/failalloc.h deleted file mode 100644 index 6115e51e..00000000 --- a/vendor/libgit2/src/allocators/failalloc.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#ifndef INCLUDE_allocators_failalloc_h__ -#define INCLUDE_allocators_failalloc_h__ - -#include "common.h" - -extern void *git_failalloc_malloc(size_t len, const char *file, int line); -extern void *git_failalloc_calloc(size_t nelem, size_t elsize, const char *file, int line); -extern char *git_failalloc_strdup(const char *str, const char *file, int line); -extern char *git_failalloc_strndup(const char *str, size_t n, const char *file, int line); -extern char *git_failalloc_substrdup(const char *start, size_t n, const char *file, int line); -extern void *git_failalloc_realloc(void *ptr, size_t size, const char *file, int line); -extern void *git_failalloc_reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line); -extern void *git_failalloc_mallocarray(size_t nelem, size_t elsize, const char *file, int line); -extern void git_failalloc_free(void *ptr); - -#endif diff --git a/vendor/libgit2/src/allocators/stdalloc.c b/vendor/libgit2/src/allocators/stdalloc.c deleted file mode 100644 index 2b36d9f3..00000000 --- a/vendor/libgit2/src/allocators/stdalloc.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "stdalloc.h" - -static void *stdalloc__malloc(size_t len, const char *file, int line) -{ - void *ptr; - - GIT_UNUSED(file); - GIT_UNUSED(line); - -#ifdef GIT_DEBUG_STRICT_ALLOC - if (!len) - return NULL; -#endif - - ptr = malloc(len); - - if (!ptr) - git_error_set_oom(); - - return ptr; -} - -static void *stdalloc__calloc(size_t nelem, size_t elsize, const char *file, int line) -{ - void *ptr; - - GIT_UNUSED(file); - GIT_UNUSED(line); - -#ifdef GIT_DEBUG_STRICT_ALLOC - if (!elsize || !nelem) - return NULL; -#endif - - ptr = calloc(nelem, elsize); - - if (!ptr) - git_error_set_oom(); - - return ptr; -} - -static char *stdalloc__strdup(const char *str, const char *file, int line) -{ - char *ptr; - - GIT_UNUSED(file); - GIT_UNUSED(line); - - ptr = strdup(str); - - if (!ptr) - git_error_set_oom(); - - return ptr; -} - -static char *stdalloc__strndup(const char *str, size_t n, const char *file, int line) -{ - size_t length = 0, alloclength; - char *ptr; - - length = p_strnlen(str, n); - - if (GIT_ADD_SIZET_OVERFLOW(&alloclength, length, 1) || - !(ptr = stdalloc__malloc(alloclength, file, line))) - return NULL; - - if (length) - memcpy(ptr, str, length); - - ptr[length] = '\0'; - - return ptr; -} - -static char *stdalloc__substrdup(const char *start, size_t n, const char *file, int line) -{ - char *ptr; - size_t alloclen; - - if (GIT_ADD_SIZET_OVERFLOW(&alloclen, n, 1) || - !(ptr = stdalloc__malloc(alloclen, file, line))) - return NULL; - - memcpy(ptr, start, n); - ptr[n] = '\0'; - return ptr; -} - -static void *stdalloc__realloc(void *ptr, size_t size, const char *file, int line) -{ - void *new_ptr; - - GIT_UNUSED(file); - GIT_UNUSED(line); - -#ifdef GIT_DEBUG_STRICT_ALLOC - if (!size) - return NULL; -#endif - - new_ptr = realloc(ptr, size); - - if (!new_ptr) - git_error_set_oom(); - - return new_ptr; -} - -static void *stdalloc__reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line) -{ - size_t newsize; - - if (GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize)) - return NULL; - - return stdalloc__realloc(ptr, newsize, file, line); -} - -static void *stdalloc__mallocarray(size_t nelem, size_t elsize, const char *file, int line) -{ - return stdalloc__reallocarray(NULL, nelem, elsize, file, line); -} - -static void stdalloc__free(void *ptr) -{ - free(ptr); -} - -int git_stdalloc_init_allocator(git_allocator *allocator) -{ - allocator->gmalloc = stdalloc__malloc; - allocator->gcalloc = stdalloc__calloc; - allocator->gstrdup = stdalloc__strdup; - allocator->gstrndup = stdalloc__strndup; - allocator->gsubstrdup = stdalloc__substrdup; - allocator->grealloc = stdalloc__realloc; - allocator->greallocarray = stdalloc__reallocarray; - allocator->gmallocarray = stdalloc__mallocarray; - allocator->gfree = stdalloc__free; - return 0; -} diff --git a/vendor/libgit2/src/allocators/win32_leakcheck.c b/vendor/libgit2/src/allocators/win32_leakcheck.c deleted file mode 100644 index fe06a14a..00000000 --- a/vendor/libgit2/src/allocators/win32_leakcheck.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "win32_leakcheck.h" - -#if defined(GIT_WIN32_LEAKCHECK) - -#include "win32/w32_leakcheck.h" - -static void *leakcheck_malloc(size_t len, const char *file, int line) -{ - void *ptr = _malloc_dbg(len, _NORMAL_BLOCK, git_win32_leakcheck_stacktrace(1,file), line); - if (!ptr) git_error_set_oom(); - return ptr; -} - -static void *leakcheck_calloc(size_t nelem, size_t elsize, const char *file, int line) -{ - void *ptr = _calloc_dbg(nelem, elsize, _NORMAL_BLOCK, git_win32_leakcheck_stacktrace(1,file), line); - if (!ptr) git_error_set_oom(); - return ptr; -} - -static char *leakcheck_strdup(const char *str, const char *file, int line) -{ - char *ptr = _strdup_dbg(str, _NORMAL_BLOCK, git_win32_leakcheck_stacktrace(1,file), line); - if (!ptr) git_error_set_oom(); - return ptr; -} - -static char *leakcheck_strndup(const char *str, size_t n, const char *file, int line) -{ - size_t length = 0, alloclength; - char *ptr; - - length = p_strnlen(str, n); - - if (GIT_ADD_SIZET_OVERFLOW(&alloclength, length, 1) || - !(ptr = leakcheck_malloc(alloclength, file, line))) - return NULL; - - if (length) - memcpy(ptr, str, length); - - ptr[length] = '\0'; - - return ptr; -} - -static char *leakcheck_substrdup(const char *start, size_t n, const char *file, int line) -{ - char *ptr; - size_t alloclen; - - if (GIT_ADD_SIZET_OVERFLOW(&alloclen, n, 1) || - !(ptr = leakcheck_malloc(alloclen, file, line))) - return NULL; - - memcpy(ptr, start, n); - ptr[n] = '\0'; - return ptr; -} - -static void *leakcheck_realloc(void *ptr, size_t size, const char *file, int line) -{ - void *new_ptr = _realloc_dbg(ptr, size, _NORMAL_BLOCK, git_win32_leakcheck_stacktrace(1,file), line); - if (!new_ptr) git_error_set_oom(); - return new_ptr; -} - -static void *leakcheck_reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line) -{ - size_t newsize; - - if (GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize)) - return NULL; - - return leakcheck_realloc(ptr, newsize, file, line); -} - -static void *leakcheck_mallocarray(size_t nelem, size_t elsize, const char *file, int line) -{ - return leakcheck_reallocarray(NULL, nelem, elsize, file, line); -} - -static void leakcheck_free(void *ptr) -{ - free(ptr); -} - -int git_win32_leakcheck_init_allocator(git_allocator *allocator) -{ - allocator->gmalloc = leakcheck_malloc; - allocator->gcalloc = leakcheck_calloc; - allocator->gstrdup = leakcheck_strdup; - allocator->gstrndup = leakcheck_strndup; - allocator->gsubstrdup = leakcheck_substrdup; - allocator->grealloc = leakcheck_realloc; - allocator->greallocarray = leakcheck_reallocarray; - allocator->gmallocarray = leakcheck_mallocarray; - allocator->gfree = leakcheck_free; - return 0; -} - -#else - -int git_win32_leakcheck_init_allocator(git_allocator *allocator) -{ - GIT_UNUSED(allocator); - git_error_set(GIT_EINVALID, "leakcheck memory allocator not available"); - return -1; -} - -#endif diff --git a/vendor/libgit2/src/blob.c b/vendor/libgit2/src/blob.c deleted file mode 100644 index 19ce8b3b..00000000 --- a/vendor/libgit2/src/blob.c +++ /dev/null @@ -1,528 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "blob.h" - -#include "git2/common.h" -#include "git2/object.h" -#include "git2/repository.h" -#include "git2/odb_backend.h" - -#include "buf.h" -#include "filebuf.h" -#include "filter.h" - -const void *git_blob_rawcontent(const git_blob *blob) -{ - GIT_ASSERT_ARG_WITH_RETVAL(blob, NULL); - - if (blob->raw) - return blob->data.raw.data; - else - return git_odb_object_data(blob->data.odb); -} - -git_object_size_t git_blob_rawsize(const git_blob *blob) -{ - GIT_ASSERT_ARG(blob); - - if (blob->raw) - return blob->data.raw.size; - else - return (git_object_size_t)git_odb_object_size(blob->data.odb); -} - -int git_blob__getbuf(git_str *buffer, git_blob *blob) -{ - git_object_size_t size = git_blob_rawsize(blob); - - GIT_ERROR_CHECK_BLOBSIZE(size); - return git_str_set(buffer, git_blob_rawcontent(blob), (size_t)size); -} - -void git_blob__free(void *_blob) -{ - git_blob *blob = (git_blob *) _blob; - if (!blob->raw) - git_odb_object_free(blob->data.odb); - git__free(blob); -} - -int git_blob__parse_raw(void *_blob, const char *data, size_t size) -{ - git_blob *blob = (git_blob *) _blob; - - GIT_ASSERT_ARG(blob); - - blob->raw = 1; - blob->data.raw.data = data; - blob->data.raw.size = size; - return 0; -} - -int git_blob__parse(void *_blob, git_odb_object *odb_obj) -{ - git_blob *blob = (git_blob *) _blob; - - GIT_ASSERT_ARG(blob); - - git_cached_obj_incref((git_cached_obj *)odb_obj); - blob->raw = 0; - blob->data.odb = odb_obj; - return 0; -} - -int git_blob_create_from_buffer( - git_oid *id, git_repository *repo, const void *buffer, size_t len) -{ - int error; - git_odb *odb; - git_odb_stream *stream; - - GIT_ASSERT_ARG(id); - GIT_ASSERT_ARG(repo); - - if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 || - (error = git_odb_open_wstream(&stream, odb, len, GIT_OBJECT_BLOB)) < 0) - return error; - - if ((error = git_odb_stream_write(stream, buffer, len)) == 0) - error = git_odb_stream_finalize_write(id, stream); - - git_odb_stream_free(stream); - return error; -} - -static int write_file_stream( - git_oid *id, git_odb *odb, const char *path, git_object_size_t file_size) -{ - int fd, error; - char buffer[FILEIO_BUFSIZE]; - git_odb_stream *stream = NULL; - ssize_t read_len = -1; - git_object_size_t written = 0; - - if ((error = git_odb_open_wstream( - &stream, odb, file_size, GIT_OBJECT_BLOB)) < 0) - return error; - - if ((fd = git_futils_open_ro(path)) < 0) { - git_odb_stream_free(stream); - return -1; - } - - while (!error && (read_len = p_read(fd, buffer, sizeof(buffer))) > 0) { - error = git_odb_stream_write(stream, buffer, read_len); - written += read_len; - } - - p_close(fd); - - if (written != file_size || read_len < 0) { - git_error_set(GIT_ERROR_OS, "failed to read file into stream"); - error = -1; - } - - if (!error) - error = git_odb_stream_finalize_write(id, stream); - - git_odb_stream_free(stream); - return error; -} - -static int write_file_filtered( - git_oid *id, - git_object_size_t *size, - git_odb *odb, - const char *full_path, - git_filter_list *fl, - git_repository* repo) -{ - int error; - git_str tgt = GIT_STR_INIT; - - error = git_filter_list__apply_to_file(&tgt, fl, repo, full_path); - - /* Write the file to disk if it was properly filtered */ - if (!error) { - *size = tgt.size; - - error = git_odb_write(id, odb, tgt.ptr, tgt.size, GIT_OBJECT_BLOB); - } - - git_str_dispose(&tgt); - return error; -} - -static int write_symlink( - git_oid *id, git_odb *odb, const char *path, size_t link_size) -{ - char *link_data; - ssize_t read_len; - int error; - - link_data = git__malloc(link_size); - GIT_ERROR_CHECK_ALLOC(link_data); - - read_len = p_readlink(path, link_data, link_size); - if (read_len != (ssize_t)link_size) { - git_error_set(GIT_ERROR_OS, "failed to create blob: cannot read symlink '%s'", path); - git__free(link_data); - return -1; - } - - error = git_odb_write(id, odb, (void *)link_data, link_size, GIT_OBJECT_BLOB); - git__free(link_data); - return error; -} - -int git_blob__create_from_paths( - git_oid *id, - struct stat *out_st, - git_repository *repo, - const char *content_path, - const char *hint_path, - mode_t hint_mode, - bool try_load_filters) -{ - int error; - struct stat st; - git_odb *odb = NULL; - git_object_size_t size; - mode_t mode; - git_str path = GIT_STR_INIT; - - GIT_ASSERT_ARG(hint_path || !try_load_filters); - - if (!content_path) { - if (git_repository_workdir_path(&path, repo, hint_path) < 0) - return -1; - - content_path = path.ptr; - } - - if ((error = git_fs_path_lstat(content_path, &st)) < 0 || - (error = git_repository_odb(&odb, repo)) < 0) - goto done; - - if (S_ISDIR(st.st_mode)) { - git_error_set(GIT_ERROR_ODB, "cannot create blob from '%s': it is a directory", content_path); - error = GIT_EDIRECTORY; - goto done; - } - - if (out_st) - memcpy(out_st, &st, sizeof(st)); - - size = st.st_size; - mode = hint_mode ? hint_mode : st.st_mode; - - if (S_ISLNK(mode)) { - error = write_symlink(id, odb, content_path, (size_t)size); - } else { - git_filter_list *fl = NULL; - - if (try_load_filters) - /* Load the filters for writing this file to the ODB */ - error = git_filter_list_load( - &fl, repo, NULL, hint_path, - GIT_FILTER_TO_ODB, GIT_FILTER_DEFAULT); - - if (error < 0) - /* well, that didn't work */; - else if (fl == NULL) - /* No filters need to be applied to the document: we can stream - * directly from disk */ - error = write_file_stream(id, odb, content_path, size); - else { - /* We need to apply one or more filters */ - error = write_file_filtered(id, &size, odb, content_path, fl, repo); - - git_filter_list_free(fl); - } - - /* - * TODO: eventually support streaming filtered files, for files - * which are bigger than a given threshold. This is not a priority - * because applying a filter in streaming mode changes the final - * size of the blob, and without knowing its final size, the blob - * cannot be written in stream mode to the ODB. - * - * The plan is to do streaming writes to a tempfile on disk and then - * opening streaming that file to the ODB, using - * `write_file_stream`. - * - * CAREFULLY DESIGNED APIS YO - */ - } - -done: - git_odb_free(odb); - git_str_dispose(&path); - - return error; -} - -int git_blob_create_from_workdir( - git_oid *id, git_repository *repo, const char *path) -{ - return git_blob__create_from_paths(id, NULL, repo, NULL, path, 0, true); -} - -int git_blob_create_from_disk( - git_oid *id, git_repository *repo, const char *path) -{ - int error; - git_str full_path = GIT_STR_INIT; - const char *workdir, *hintpath = NULL; - - if ((error = git_fs_path_prettify(&full_path, path, NULL)) < 0) { - git_str_dispose(&full_path); - return error; - } - - workdir = git_repository_workdir(repo); - - if (workdir && !git__prefixcmp(full_path.ptr, workdir)) - hintpath = full_path.ptr + strlen(workdir); - - error = git_blob__create_from_paths( - id, NULL, repo, git_str_cstr(&full_path), hintpath, 0, !!hintpath); - - git_str_dispose(&full_path); - return error; -} - -typedef struct { - git_writestream parent; - git_filebuf fbuf; - git_repository *repo; - char *hintpath; -} blob_writestream; - -static int blob_writestream_close(git_writestream *_stream) -{ - blob_writestream *stream = (blob_writestream *) _stream; - - git_filebuf_cleanup(&stream->fbuf); - return 0; -} - -static void blob_writestream_free(git_writestream *_stream) -{ - blob_writestream *stream = (blob_writestream *) _stream; - - git_filebuf_cleanup(&stream->fbuf); - git__free(stream->hintpath); - git__free(stream); -} - -static int blob_writestream_write(git_writestream *_stream, const char *buffer, size_t len) -{ - blob_writestream *stream = (blob_writestream *) _stream; - - return git_filebuf_write(&stream->fbuf, buffer, len); -} - -int git_blob_create_from_stream(git_writestream **out, git_repository *repo, const char *hintpath) -{ - int error; - git_str path = GIT_STR_INIT; - blob_writestream *stream; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(repo); - - stream = git__calloc(1, sizeof(blob_writestream)); - GIT_ERROR_CHECK_ALLOC(stream); - - if (hintpath) { - stream->hintpath = git__strdup(hintpath); - GIT_ERROR_CHECK_ALLOC(stream->hintpath); - } - - stream->repo = repo; - stream->parent.write = blob_writestream_write; - stream->parent.close = blob_writestream_close; - stream->parent.free = blob_writestream_free; - - if ((error = git_repository__item_path(&path, repo, GIT_REPOSITORY_ITEM_OBJECTS)) < 0 - || (error = git_str_joinpath(&path, path.ptr, "streamed")) < 0) - goto cleanup; - - if ((error = git_filebuf_open_withsize(&stream->fbuf, git_str_cstr(&path), GIT_FILEBUF_TEMPORARY, - 0666, 2 * 1024 * 1024)) < 0) - goto cleanup; - - *out = (git_writestream *) stream; - -cleanup: - if (error < 0) - blob_writestream_free((git_writestream *) stream); - - git_str_dispose(&path); - return error; -} - -int git_blob_create_from_stream_commit(git_oid *out, git_writestream *_stream) -{ - int error; - blob_writestream *stream = (blob_writestream *) _stream; - - /* - * We can make this more officient by avoiding writing to - * disk, but for now let's re-use the helper functions we - * have. - */ - if ((error = git_filebuf_flush(&stream->fbuf)) < 0) - goto cleanup; - - error = git_blob__create_from_paths(out, NULL, stream->repo, stream->fbuf.path_lock, - stream->hintpath, 0, !!stream->hintpath); - -cleanup: - blob_writestream_free(_stream); - return error; - -} - -int git_blob_is_binary(const git_blob *blob) -{ - git_str content = GIT_STR_INIT; - git_object_size_t size; - - GIT_ASSERT_ARG(blob); - - size = git_blob_rawsize(blob); - - git_str_attach_notowned(&content, git_blob_rawcontent(blob), - (size_t)min(size, GIT_FILTER_BYTES_TO_CHECK_NUL)); - return git_str_is_binary(&content); -} - -int git_blob_data_is_binary(const char *str, size_t len) -{ - git_str content = GIT_STR_INIT; - - git_str_attach_notowned(&content, str, len); - - return git_str_is_binary(&content); -} - -int git_blob_filter_options_init( - git_blob_filter_options *opts, - unsigned int version) -{ - GIT_INIT_STRUCTURE_FROM_TEMPLATE(opts, version, - git_blob_filter_options, GIT_BLOB_FILTER_OPTIONS_INIT); - return 0; -} - -int git_blob_filter( - git_buf *out, - git_blob *blob, - const char *path, - git_blob_filter_options *given_opts) -{ - git_blob_filter_options opts = GIT_BLOB_FILTER_OPTIONS_INIT; - git_filter_options filter_opts = GIT_FILTER_OPTIONS_INIT; - git_filter_list *fl = NULL; - int error = 0; - - GIT_ASSERT_ARG(blob); - GIT_ASSERT_ARG(path); - GIT_ASSERT_ARG(out); - - GIT_ERROR_CHECK_VERSION( - given_opts, GIT_BLOB_FILTER_OPTIONS_VERSION, "git_blob_filter_options"); - - if (given_opts != NULL) - memcpy(&opts, given_opts, sizeof(git_blob_filter_options)); - - if ((opts.flags & GIT_BLOB_FILTER_CHECK_FOR_BINARY) != 0 && - git_blob_is_binary(blob)) - return 0; - - if ((opts.flags & GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES) != 0) - filter_opts.flags |= GIT_FILTER_NO_SYSTEM_ATTRIBUTES; - - if ((opts.flags & GIT_BLOB_FILTER_ATTRIBUTES_FROM_HEAD) != 0) - filter_opts.flags |= GIT_FILTER_ATTRIBUTES_FROM_HEAD; - - if ((opts.flags & GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT) != 0) { - filter_opts.flags |= GIT_FILTER_ATTRIBUTES_FROM_COMMIT; - -#ifndef GIT_DEPRECATE_HARD - if (opts.commit_id) - git_oid_cpy(&filter_opts.attr_commit_id, opts.commit_id); - else -#endif - git_oid_cpy(&filter_opts.attr_commit_id, &opts.attr_commit_id); - } - - if (!(error = git_filter_list_load_ext( - &fl, git_blob_owner(blob), blob, path, - GIT_FILTER_TO_WORKTREE, &filter_opts))) { - - error = git_filter_list_apply_to_blob(out, fl, blob); - - git_filter_list_free(fl); - } - - return error; -} - -/* Deprecated functions */ - -#ifndef GIT_DEPRECATE_HARD -int git_blob_create_frombuffer( - git_oid *id, git_repository *repo, const void *buffer, size_t len) -{ - return git_blob_create_from_buffer(id, repo, buffer, len); -} - -int git_blob_create_fromworkdir(git_oid *id, git_repository *repo, const char *relative_path) -{ - return git_blob_create_from_workdir(id, repo, relative_path); -} - -int git_blob_create_fromdisk(git_oid *id, git_repository *repo, const char *path) -{ - return git_blob_create_from_disk(id, repo, path); -} - -int git_blob_create_fromstream( - git_writestream **out, - git_repository *repo, - const char *hintpath) -{ - return git_blob_create_from_stream(out, repo, hintpath); -} - -int git_blob_create_fromstream_commit( - git_oid *out, - git_writestream *stream) -{ - return git_blob_create_from_stream_commit(out, stream); -} - -int git_blob_filtered_content( - git_buf *out, - git_blob *blob, - const char *path, - int check_for_binary_data) -{ - git_blob_filter_options opts = GIT_BLOB_FILTER_OPTIONS_INIT; - - if (check_for_binary_data) - opts.flags |= GIT_BLOB_FILTER_CHECK_FOR_BINARY; - else - opts.flags &= ~GIT_BLOB_FILTER_CHECK_FOR_BINARY; - - return git_blob_filter(out, blob, path, &opts); -} -#endif diff --git a/vendor/libgit2/src/cli/CMakeLists.txt b/vendor/libgit2/src/cli/CMakeLists.txt new file mode 100644 index 00000000..97797e33 --- /dev/null +++ b/vendor/libgit2/src/cli/CMakeLists.txt @@ -0,0 +1,57 @@ +set(CLI_INCLUDES + "${libgit2_BINARY_DIR}/src/util" + "${libgit2_BINARY_DIR}/include" + "${libgit2_SOURCE_DIR}/src/util" + "${libgit2_SOURCE_DIR}/src/cli" + "${libgit2_SOURCE_DIR}/include" + "${LIBGIT2_DEPENDENCY_INCLUDES}" + "${LIBGIT2_SYSTEM_INCLUDES}") + +if(WIN32 AND NOT CYGWIN) + file(GLOB CLI_SRC_OS win32/*.c) + list(SORT CLI_SRC_OS) +else() + file(GLOB CLI_SRC_OS unix/*.c) + list(SORT CLI_SRC_OS) +endif() + +file(GLOB CLI_SRC_C *.c *.h) +list(SORT CLI_SRC_C) + +# +# The CLI currently needs to be statically linked against libgit2 because +# the utility library uses libgit2's thread-local error buffers. TODO: +# remove this dependency and allow us to dynamically link against libgit2. +# + +if(BUILD_CLI STREQUAL "dynamic") + set(CLI_LIBGIT2_LIBRARY libgit2package) +else() + set(CLI_LIBGIT2_OBJECTS $) +endif() + +# +# Compile and link the CLI +# + +add_executable(git2_cli ${CLI_SRC_C} ${CLI_SRC_OS} ${CLI_OBJECTS} + $ + ${CLI_LIBGIT2_OBJECTS} + ${LIBGIT2_DEPENDENCY_OBJECTS}) +target_link_libraries(git2_cli ${CLI_LIBGIT2_LIBRARY} ${LIBGIT2_SYSTEM_LIBS}) + +set_target_properties(git2_cli PROPERTIES C_STANDARD 90) +set_target_properties(git2_cli PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${libgit2_BINARY_DIR}) +set_target_properties(git2_cli PROPERTIES OUTPUT_NAME ${LIBGIT2_FILENAME}) + +ide_split_sources(git2_cli) + +target_include_directories(git2_cli PRIVATE ${CLI_INCLUDES}) + +if(MSVC_IDE) + # Precompiled headers + set_target_properties(git2_cli PROPERTIES COMPILE_FLAGS "/Yuprecompiled.h /FIprecompiled.h") + set_source_files_properties(win32/precompiled.c COMPILE_FLAGS "/Ycprecompiled.h") +endif() + +install(TARGETS git2_cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/vendor/libgit2/src/cli/README.md b/vendor/libgit2/src/cli/README.md new file mode 100644 index 00000000..3087c39c --- /dev/null +++ b/vendor/libgit2/src/cli/README.md @@ -0,0 +1,26 @@ +# cli + +A git-compatible command-line interface that uses libgit2. + +## Adding commands + +1. Individual commands have a `main`-like top-level entrypoint. For example: + + ```c + int cmd_help(int argc, char **argv) + ``` + + Although this is the same signature as `main`, commands are not built as + individual standalone executables, they'll be linked into the main cli. + (Though there may be an option for command executables to be built as + standalone executables in the future.) + +2. Commands are prototyped in `cmd.h` and added to `main.c`'s list of + commands (`cli_cmds[]`). Commands should be specified with their name, + entrypoint and a brief description that can be printed in `git help`. + This is done because commands are linked into the main cli. + +3. Commands should accept a `--help` option that displays their help + information. This will be shown when a user runs ` --help` and + when a user runs `help `. + diff --git a/vendor/libgit2/src/cli/cmd.c b/vendor/libgit2/src/cli/cmd.c new file mode 100644 index 00000000..0b1fafb4 --- /dev/null +++ b/vendor/libgit2/src/cli/cmd.c @@ -0,0 +1,21 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "common.h" +#include "cmd.h" + +const cli_cmd_spec *cli_cmd_spec_byname(const char *name) +{ + const cli_cmd_spec *cmd; + + for (cmd = cli_cmds; cmd->name; cmd++) { + if (!strcmp(cmd->name, name)) + return cmd; + } + + return NULL; +} diff --git a/vendor/libgit2/src/cli/cmd.h b/vendor/libgit2/src/cli/cmd.h new file mode 100644 index 00000000..bd881223 --- /dev/null +++ b/vendor/libgit2/src/cli/cmd.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef CLI_cmd_h__ +#define CLI_cmd_h__ + +/* Command definitions */ +typedef struct { + const char *name; + int (*fn)(int argc, char **argv); + const char *desc; +} cli_cmd_spec; + +/* Options that are common to all commands (eg --help, --git-dir) */ +extern const cli_opt_spec cli_common_opts[]; + +/* All the commands supported by the CLI */ +extern const cli_cmd_spec cli_cmds[]; + +/* Find a command by name */ +extern const cli_cmd_spec *cli_cmd_spec_byname(const char *name); + +/* Commands */ +extern int cmd_cat_file(int argc, char **argv); +extern int cmd_clone(int argc, char **argv); +extern int cmd_config(int argc, char **argv); +extern int cmd_hash_object(int argc, char **argv); +extern int cmd_help(int argc, char **argv); +extern int cmd_index_pack(int argc, char **argv); + +#endif /* CLI_cmd_h__ */ diff --git a/vendor/libgit2/src/cli/cmd_cat_file.c b/vendor/libgit2/src/cli/cmd_cat_file.c new file mode 100644 index 00000000..90ee6033 --- /dev/null +++ b/vendor/libgit2/src/cli/cmd_cat_file.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include "common.h" +#include "cmd.h" + +#define COMMAND_NAME "cat-file" + +typedef enum { + DISPLAY_CONTENT = 0, + DISPLAY_EXISTS, + DISPLAY_PRETTY, + DISPLAY_SIZE, + DISPLAY_TYPE +} display_t; + +static int show_help; +static int display = DISPLAY_CONTENT; +static char *type_name, *object_spec; + +static const cli_opt_spec opts[] = { + CLI_COMMON_OPT, + + { CLI_OPT_TYPE_SWITCH, NULL, 't', &display, DISPLAY_TYPE, + CLI_OPT_USAGE_REQUIRED, NULL, "display the type of the object" }, + { CLI_OPT_TYPE_SWITCH, NULL, 's', &display, DISPLAY_SIZE, + CLI_OPT_USAGE_CHOICE, NULL, "display the size of the object" }, + { CLI_OPT_TYPE_SWITCH, NULL, 'e', &display, DISPLAY_EXISTS, + CLI_OPT_USAGE_CHOICE, NULL, "displays nothing unless the object is corrupt" }, + { CLI_OPT_TYPE_SWITCH, NULL, 'p', &display, DISPLAY_PRETTY, + CLI_OPT_USAGE_CHOICE, NULL, "pretty-print the object" }, + { CLI_OPT_TYPE_ARG, "type", 0, &type_name, 0, + CLI_OPT_USAGE_CHOICE, "type", "the type of object to display" }, + { CLI_OPT_TYPE_ARG, "object", 0, &object_spec, 0, + CLI_OPT_USAGE_REQUIRED, "object", "the object to display" }, + { 0 }, +}; + +static void print_help(void) +{ + cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts); + printf("\n"); + + printf("Display the content for the given object in the repository.\n"); + printf("\n"); + + printf("Options:\n"); + + cli_opt_help_fprint(stdout, opts); +} + +static int print_odb(git_object *object, display_t display) +{ + git_odb *odb = NULL; + git_odb_object *odb_object = NULL; + const unsigned char *content; + git_object_size_t size; + int ret = 0; + + /* + * Our parsed blobs retain the raw content; all other objects are + * parsed into a working representation. To get the raw content, + * we need to do an ODB lookup. (Thankfully, this should be cached + * in-memory from our last call.) + */ + if (git_object_type(object) == GIT_OBJECT_BLOB) { + content = git_blob_rawcontent((git_blob *)object); + size = git_blob_rawsize((git_blob *)object); + } else { + if (git_repository_odb(&odb, git_object_owner(object)) < 0 || + git_odb_read(&odb_object, odb, git_object_id(object)) < 0) { + ret = cli_error_git(); + goto done; + } + + content = git_odb_object_data(odb_object); + size = git_odb_object_size(odb_object); + } + + switch (display) { + case DISPLAY_SIZE: + if (printf("%" PRIu64 "\n", size) < 0) + ret = cli_error_os(); + break; + case DISPLAY_CONTENT: + if (p_write(fileno(stdout), content, (size_t)size) < 0) + ret = cli_error_os(); + break; + default: + GIT_ASSERT(0); + } + +done: + git_odb_object_free(odb_object); + git_odb_free(odb); + return ret; +} + +static int print_type(git_object *object) +{ + if (printf("%s\n", git_object_type2string(git_object_type(object))) < 0) + return cli_error_os(); + + return 0; +} + +static int print_pretty(git_object *object) +{ + const git_tree_entry *entry; + size_t i, count; + + /* + * Only trees are stored in an unreadable format and benefit from + * pretty-printing. + */ + if (git_object_type(object) != GIT_OBJECT_TREE) + return print_odb(object, DISPLAY_CONTENT); + + for (i = 0, count = git_tree_entrycount((git_tree *)object); i < count; i++) { + entry = git_tree_entry_byindex((git_tree *)object, i); + + if (printf("%06o %s %s\t%s\n", + git_tree_entry_filemode_raw(entry), + git_object_type2string(git_tree_entry_type(entry)), + git_oid_tostr_s(git_tree_entry_id(entry)), + git_tree_entry_name(entry)) < 0) + return cli_error_os(); + } + + return 0; +} + +int cmd_cat_file(int argc, char **argv) +{ + cli_repository_open_options open_opts = { argv + 1, argc - 1}; + git_repository *repo = NULL; + git_object *object = NULL; + git_object_t type; + cli_opt invalid_opt; + int giterr, ret = 0; + + if (cli_opt_parse(&invalid_opt, opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU)) + return cli_opt_usage_error(COMMAND_NAME, opts, &invalid_opt); + + if (show_help) { + print_help(); + return 0; + } + + if (cli_repository_open(&repo, &open_opts) < 0) + return cli_error_git(); + + if ((giterr = git_revparse_single(&object, repo, object_spec)) < 0) { + if (display == DISPLAY_EXISTS && giterr == GIT_ENOTFOUND) + ret = 1; + else + ret = cli_error_git(); + + goto done; + } + + if (type_name) { + git_object *peeled; + + if ((type = git_object_string2type(type_name)) == GIT_OBJECT_INVALID) { + ret = cli_error_usage("invalid object type '%s'", type_name); + goto done; + } + + if (git_object_peel(&peeled, object, type) < 0) { + ret = cli_error_git(); + goto done; + } + + git_object_free(object); + object = peeled; + } + + switch (display) { + case DISPLAY_EXISTS: + ret = 0; + break; + case DISPLAY_TYPE: + ret = print_type(object); + break; + case DISPLAY_PRETTY: + ret = print_pretty(object); + break; + default: + ret = print_odb(object, display); + break; + } + +done: + git_object_free(object); + git_repository_free(repo); + return ret; +} diff --git a/vendor/libgit2/src/cli/cmd_clone.c b/vendor/libgit2/src/cli/cmd_clone.c new file mode 100644 index 00000000..7d9736fc --- /dev/null +++ b/vendor/libgit2/src/cli/cmd_clone.c @@ -0,0 +1,190 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include +#include "common.h" +#include "cmd.h" +#include "error.h" +#include "sighandler.h" +#include "progress.h" + +#include "fs_path.h" +#include "futils.h" + +#define COMMAND_NAME "clone" + +static char *branch, *remote_path, *local_path, *depth; +static int show_help, quiet, checkout = 1, bare; +static bool local_path_exists; +static cli_progress progress = CLI_PROGRESS_INIT; + +static const cli_opt_spec opts[] = { + CLI_COMMON_OPT, + + { CLI_OPT_TYPE_SWITCH, "quiet", 'q', &quiet, 1, + CLI_OPT_USAGE_DEFAULT, NULL, "display the type of the object" }, + { CLI_OPT_TYPE_SWITCH, "no-checkout", 'n', &checkout, 0, + CLI_OPT_USAGE_DEFAULT, NULL, "don't checkout HEAD" }, + { CLI_OPT_TYPE_SWITCH, "bare", 0, &bare, 1, + CLI_OPT_USAGE_DEFAULT, NULL, "don't create a working directory" }, + { CLI_OPT_TYPE_VALUE, "branch", 'b', &branch, 0, + CLI_OPT_USAGE_DEFAULT, "name", "branch to check out" }, + { CLI_OPT_TYPE_VALUE, "depth", 0, &depth, 0, + CLI_OPT_USAGE_DEFAULT, "depth", "commit depth to check out " }, + { CLI_OPT_TYPE_LITERAL }, + { CLI_OPT_TYPE_ARG, "repository", 0, &remote_path, 0, + CLI_OPT_USAGE_REQUIRED, "repository", "repository path" }, + { CLI_OPT_TYPE_ARG, "directory", 0, &local_path, 0, + CLI_OPT_USAGE_DEFAULT, "directory", "directory to clone into" }, + { 0 } +}; + +static void print_help(void) +{ + cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts); + printf("\n"); + + printf("Clone a repository into a new directory.\n"); + printf("\n"); + + printf("Options:\n"); + + cli_opt_help_fprint(stdout, opts); +} + +static char *compute_local_path(const char *orig_path) +{ + const char *slash; + char *local_path; + + if ((slash = strrchr(orig_path, '/')) == NULL && + (slash = strrchr(orig_path, '\\')) == NULL) + local_path = git__strdup(orig_path); + else + local_path = git__strdup(slash + 1); + + return local_path; +} + +static int compute_depth(const char *depth) +{ + int64_t i; + const char *endptr; + + if (!depth) + return 0; + + if (git__strntol64(&i, depth, strlen(depth), &endptr, 10) < 0 || i < 0 || i > INT_MAX || *endptr) { + fprintf(stderr, "fatal: depth '%s' is not valid.\n", depth); + exit(128); + } + + return (int)i; +} + +static bool validate_local_path(const char *path) +{ + if (!git_fs_path_exists(path)) + return false; + + if (!git_fs_path_isdir(path) || !git_fs_path_is_empty_dir(path)) { + fprintf(stderr, "fatal: destination path '%s' already exists and is not an empty directory.\n", + path); + exit(128); + } + + return true; +} + +static void cleanup(void) +{ + int rmdir_flags = GIT_RMDIR_REMOVE_FILES; + + cli_progress_abort(&progress); + + if (local_path_exists) + rmdir_flags |= GIT_RMDIR_SKIP_ROOT; + + if (!git_fs_path_isdir(local_path)) + return; + + git_futils_rmdir_r(local_path, NULL, rmdir_flags); +} + +static void interrupt_cleanup(void) +{ + cleanup(); + exit(130); +} + +int cmd_clone(int argc, char **argv) +{ + git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; + git_repository *repo = NULL; + cli_opt invalid_opt; + char *computed_path = NULL; + int ret = 0; + + if (cli_opt_parse(&invalid_opt, opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU)) + return cli_opt_usage_error(COMMAND_NAME, opts, &invalid_opt); + + if (show_help) { + print_help(); + return 0; + } + + if (!remote_path) { + ret = cli_error_usage("you must specify a repository to clone"); + goto done; + } + + clone_opts.bare = !!bare; + clone_opts.checkout_branch = branch; + clone_opts.fetch_opts.depth = compute_depth(depth); + + if (!checkout) + clone_opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE; + + if (!local_path) + local_path = computed_path = compute_local_path(remote_path); + + local_path_exists = validate_local_path(local_path); + + cli_sighandler_set_interrupt(interrupt_cleanup); + + if (!local_path_exists && + git_futils_mkdir(local_path, 0777, 0) < 0) { + ret = cli_error_git(); + goto done; + } + + if (!quiet) { + clone_opts.fetch_opts.callbacks.sideband_progress = cli_progress_fetch_sideband; + clone_opts.fetch_opts.callbacks.transfer_progress = cli_progress_fetch_transfer; + clone_opts.fetch_opts.callbacks.payload = &progress; + + clone_opts.checkout_opts.progress_cb = cli_progress_checkout; + clone_opts.checkout_opts.progress_payload = &progress; + + printf("Cloning into '%s'...\n", local_path); + } + + if (git_clone(&repo, remote_path, local_path, &clone_opts) < 0) { + cleanup(); + ret = cli_error_git(); + goto done; + } + + cli_progress_finish(&progress); + +done: + cli_progress_dispose(&progress); + git__free(computed_path); + git_repository_free(repo); + return ret; +} diff --git a/vendor/libgit2/src/cli/cmd_config.c b/vendor/libgit2/src/cli/cmd_config.c new file mode 100644 index 00000000..6b9d373c --- /dev/null +++ b/vendor/libgit2/src/cli/cmd_config.c @@ -0,0 +1,242 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include + +#include "common.h" +#include "cmd.h" + +#define COMMAND_NAME "config" + +typedef enum { + ACTION_NONE = 0, + ACTION_GET, + ACTION_ADD, + ACTION_REPLACE_ALL, + ACTION_LIST +} action_t; + +static action_t action = ACTION_NONE; +static int show_origin; +static int show_scope; +static int show_help; +static int null_separator; +static int config_level; +static char *config_filename; +static char *name, *value, *value_pattern; + +static const cli_opt_spec opts[] = { + CLI_COMMON_OPT, \ + + { CLI_OPT_TYPE_SWITCH, "null", 'z', &null_separator, 1, + 0, NULL, "use NUL as a separator" }, + + { CLI_OPT_TYPE_SWITCH, "system", 0, &config_level, GIT_CONFIG_LEVEL_SYSTEM, + 0, NULL, "read/write to system configuration" }, + { CLI_OPT_TYPE_SWITCH, "global", 0, &config_level, GIT_CONFIG_LEVEL_GLOBAL, + CLI_OPT_USAGE_CHOICE, NULL, "read/write to global configuration" }, + { CLI_OPT_TYPE_SWITCH, "local", 0, &config_level, GIT_CONFIG_LEVEL_LOCAL, + CLI_OPT_USAGE_CHOICE, NULL, "read/write to local configuration" }, + { CLI_OPT_TYPE_VALUE, "file", 0, &config_filename, 0, + CLI_OPT_USAGE_CHOICE, "filename", "read/write to specified configuration file" }, + + { CLI_OPT_TYPE_SWITCH, "get", 0, &action, ACTION_GET, + CLI_OPT_USAGE_REQUIRED, NULL, "get a configuration value" }, + { CLI_OPT_TYPE_SWITCH, "add", 0, &action, ACTION_ADD, + CLI_OPT_USAGE_CHOICE, NULL, "add a configuration value" }, + { CLI_OPT_TYPE_SWITCH, "replace-all", 0, &action, ACTION_REPLACE_ALL, + CLI_OPT_USAGE_CHOICE, NULL, "add a configuration value, replacing any old values" }, + { CLI_OPT_TYPE_SWITCH, "list", 'l', &action, ACTION_LIST, + CLI_OPT_USAGE_CHOICE | CLI_OPT_USAGE_SHOW_LONG, + NULL, "list all configuration entries" }, + { CLI_OPT_TYPE_SWITCH, "show-origin", 0, &show_origin, 1, + 0, NULL, "show origin of configuration" }, + { CLI_OPT_TYPE_SWITCH, "show-scope", 0, &show_scope, 1, + 0, NULL, "show scope of configuration" }, + { CLI_OPT_TYPE_ARG, "name", 0, &name, 0, + 0, "name", "name of configuration entry" }, + { CLI_OPT_TYPE_ARG, "value", 0, &value, 0, + 0, "value", "value of configuration entry" }, + { CLI_OPT_TYPE_ARG, "regexp", 0, &value_pattern, 0, + 0, "regexp", "regular expression of values to replace" }, + { 0 }, +}; + +static void print_help(void) +{ + cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts); + printf("\n"); + + printf("Query and set configuration options.\n"); + printf("\n"); + + printf("Options:\n"); + + cli_opt_help_fprint(stdout, opts); +} + +static int get_config(git_config *config) +{ + git_buf value = GIT_BUF_INIT; + char sep = null_separator ? '\0' : '\n'; + int error; + + error = git_config_get_string_buf(&value, config, name); + + if (error && error != GIT_ENOTFOUND) + return cli_error_git(); + + else if (error == GIT_ENOTFOUND) + return 1; + + printf("%s%c", value.ptr, sep); + return 0; +} + +static int add_config(git_config *config) +{ + if (git_config_set_multivar(config, name, "$^", value) < 0) + return cli_error_git(); + + return 0; +} + +static int replace_all_config(git_config *config) +{ + if (git_config_set_multivar(config, name, value_pattern ? value_pattern : ".*", value) < 0) + return cli_error_git(); + + return 0; +} + +static const char *level_name(git_config_level_t level) +{ + switch (level) { + case GIT_CONFIG_LEVEL_PROGRAMDATA: + return "programdata"; + case GIT_CONFIG_LEVEL_SYSTEM: + return "system"; + case GIT_CONFIG_LEVEL_XDG: + return "global"; + case GIT_CONFIG_LEVEL_GLOBAL: + return "global"; + case GIT_CONFIG_LEVEL_LOCAL: + return "local"; + case GIT_CONFIG_LEVEL_APP: + return "command"; + default: + return "unknown"; + } +} + +static int list_config(git_config *config) +{ + git_config_iterator *iterator; + git_config_entry *entry; + char data_separator = null_separator ? '\0' : '\t'; + char kv_separator = null_separator ? '\n' : '='; + char entry_separator = null_separator ? '\0' : '\n'; + int error; + + if (git_config_iterator_new(&iterator, config) < 0) + return cli_error_git(); + + while ((error = git_config_next(&entry, iterator)) == 0) { + if (show_scope) + printf("%s%c", + level_name(entry->level), + data_separator); + + if (show_origin) + printf("%s%s%s%c", + entry->backend_type ? entry->backend_type : "", + entry->backend_type && entry->origin_path ? ":" : "", + entry->origin_path ? entry->origin_path : "", + data_separator); + + printf("%s%c%s%c", entry->name, kv_separator, entry->value, + entry_separator); + } + + if (error != GIT_ITEROVER) + return cli_error_git(); + + git_config_iterator_free(iterator); + return 0; +} + +int cmd_config(int argc, char **argv) +{ + git_repository *repo = NULL; + git_config *config = NULL; + cli_repository_open_options open_opts = { argv + 1, argc - 1}; + cli_opt invalid_opt; + int ret = 0; + + if (cli_opt_parse(&invalid_opt, opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU)) + return cli_opt_usage_error(COMMAND_NAME, opts, &invalid_opt); + + if (show_help) { + print_help(); + return 0; + } + + if (config_filename) { + if (git_config_new(&config) < 0 || + git_config_add_file_ondisk(config, config_filename, + GIT_CONFIG_LEVEL_APP, NULL, 0) < 0) { + ret = cli_error_git(); + goto done; + } + } else { + if (cli_repository_open(&repo, &open_opts) < 0 || + git_repository_config(&config, repo) < 0) { + ret = cli_error_git(); + goto done; + } + + if (config_level && + git_config_open_level(&config, config, config_level) < 0) { + ret = cli_error_git(); + goto done; + } + } + + switch (action) { + case ACTION_ADD: + if (!name || !value || value_pattern) + ret = cli_error_usage("%s --add requires two arguments", COMMAND_NAME); + else + ret = add_config(config); + break; + case ACTION_REPLACE_ALL: + if (!name || !value) + ret = cli_error_usage("%s --replace-all requires two or three arguments", COMMAND_NAME); + else + ret = replace_all_config(config); + break; + case ACTION_GET: + if (!name) + ret = cli_error_usage("%s --get requires an argument", COMMAND_NAME); + else + ret = get_config(config); + break; + case ACTION_LIST: + if (name) + ret = cli_error_usage("%s --list does not take an argument", COMMAND_NAME); + else + ret = list_config(config); + break; + default: + ret = cli_error_usage("unknown action"); + } + +done: + git_config_free(config); + git_repository_free(repo); + return ret; +} diff --git a/vendor/libgit2/src/cli/cmd_hash_object.c b/vendor/libgit2/src/cli/cmd_hash_object.c new file mode 100644 index 00000000..741debbe --- /dev/null +++ b/vendor/libgit2/src/cli/cmd_hash_object.c @@ -0,0 +1,153 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include "common.h" +#include "cmd.h" + +#include "futils.h" + +#define COMMAND_NAME "hash-object" + +static int show_help; +static char *type_name; +static int write_object, read_stdin, literally; +static char **filenames; + +static const cli_opt_spec opts[] = { + CLI_COMMON_OPT, + + { CLI_OPT_TYPE_VALUE, NULL, 't', &type_name, 0, + CLI_OPT_USAGE_DEFAULT, "type", "the type of object to hash (default: \"blob\")" }, + { CLI_OPT_TYPE_SWITCH, NULL, 'w', &write_object, 1, + CLI_OPT_USAGE_DEFAULT, NULL, "write the object to the object database" }, + { CLI_OPT_TYPE_SWITCH, "literally", 0, &literally, 1, + CLI_OPT_USAGE_DEFAULT, NULL, "do not validate the object contents" }, + { CLI_OPT_TYPE_SWITCH, "stdin", 0, &read_stdin, 1, + CLI_OPT_USAGE_REQUIRED, NULL, "read content from stdin" }, + { CLI_OPT_TYPE_ARGS, "file", 0, &filenames, 0, + CLI_OPT_USAGE_CHOICE, "file", "the file (or files) to read and hash" }, + { 0 }, +}; + +static void print_help(void) +{ + cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts); + printf("\n"); + + printf("Compute the object ID for a given file and optionally write that file\nto the object database.\n"); + printf("\n"); + + printf("Options:\n"); + + cli_opt_help_fprint(stdout, opts); +} + +static int hash_buf( + git_odb *odb, + git_str *buf, + git_object_t object_type, + git_oid_t oid_type) +{ + git_oid oid; + + if (!literally) { + int valid = 0; + +#ifdef GIT_EXPERIMENTAL_SHA256 + if (git_object_rawcontent_is_valid(&valid, buf->ptr, buf->size, object_type, oid_type) < 0 || !valid) + return cli_error_git(); +#else + GIT_UNUSED(oid_type); + + if (git_object_rawcontent_is_valid(&valid, buf->ptr, buf->size, object_type) < 0 || !valid) + return cli_error_git(); +#endif + } + + if (write_object) { + if (git_odb_write(&oid, odb, buf->ptr, buf->size, object_type) < 0) + return cli_error_git(); + } else { +#ifdef GIT_EXPERIMENTAL_SHA256 + if (git_odb_hash(&oid, buf->ptr, buf->size, object_type, GIT_OID_SHA1) < 0) + return cli_error_git(); +#else + if (git_odb_hash(&oid, buf->ptr, buf->size, object_type) < 0) + return cli_error_git(); +#endif + } + + if (printf("%s\n", git_oid_tostr_s(&oid)) < 0) + return cli_error_os(); + + return 0; +} + +int cmd_hash_object(int argc, char **argv) +{ + cli_repository_open_options open_opts = { argv + 1, argc - 1}; + git_repository *repo = NULL; + git_odb *odb = NULL; + git_oid_t oid_type; + git_str buf = GIT_STR_INIT; + cli_opt invalid_opt; + git_object_t object_type = GIT_OBJECT_BLOB; + char **filename; + int ret = 0; + + if (cli_opt_parse(&invalid_opt, opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU)) + return cli_opt_usage_error(COMMAND_NAME, opts, &invalid_opt); + + if (show_help) { + print_help(); + return 0; + } + + if (type_name && (object_type = git_object_string2type(type_name)) == GIT_OBJECT_INVALID) + return cli_error_usage("invalid object type '%s'", type_name); + + if (write_object && + (cli_repository_open(&repo, &open_opts) < 0 || + git_repository_odb(&odb, repo) < 0)) { + ret = cli_error_git(); + goto done; + } + + oid_type = git_repository_oid_type(repo); + + /* + * TODO: we're reading blobs, we shouldn't pull them all into main + * memory, we should just stream them into the odb instead. + * (Or create a `git_odb_writefile` API.) + */ + if (read_stdin) { + if (git_futils_readbuffer_fd_full(&buf, fileno(stdin)) < 0) { + ret = cli_error_git(); + goto done; + } + + if ((ret = hash_buf(odb, &buf, object_type, oid_type)) != 0) + goto done; + } else { + for (filename = filenames; *filename; filename++) { + if (git_futils_readbuffer(&buf, *filename) < 0) { + ret = cli_error_git(); + goto done; + } + + if ((ret = hash_buf(odb, &buf, object_type, oid_type)) != 0) + goto done; + } + } + +done: + git_str_dispose(&buf); + git_odb_free(odb); + git_repository_free(repo); + return ret; +} diff --git a/vendor/libgit2/src/cli/cmd_help.c b/vendor/libgit2/src/cli/cmd_help.c new file mode 100644 index 00000000..5e877e06 --- /dev/null +++ b/vendor/libgit2/src/cli/cmd_help.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include +#include "common.h" +#include "cmd.h" + +#define COMMAND_NAME "help" + +static char *command; +static int show_help; + +static const cli_opt_spec opts[] = { + CLI_COMMON_OPT, + + { CLI_OPT_TYPE_ARG, "command", 0, &command, 0, + CLI_OPT_USAGE_DEFAULT, "command", "the command to show help for" }, + { 0 }, +}; + +static int print_help(void) +{ + cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts); + printf("\n"); + + printf("Display help information about %s. If a command is specified, help\n", PROGRAM_NAME); + printf("about that command will be shown. Otherwise, general information about\n"); + printf("%s will be shown, including the commands available.\n", PROGRAM_NAME); + + return 0; +} + +static int print_commands(void) +{ + const cli_cmd_spec *cmd; + + cli_opt_usage_fprint(stdout, PROGRAM_NAME, NULL, cli_common_opts); + printf("\n"); + + printf("These are the %s commands available:\n\n", PROGRAM_NAME); + + for (cmd = cli_cmds; cmd->name; cmd++) + printf(" %-11s %s\n", cmd->name, cmd->desc); + + printf("\nSee '%s help ' for more information on a specific command.\n", PROGRAM_NAME); + + return 0; +} + +int cmd_help(int argc, char **argv) +{ + char *fake_args[2]; + const cli_cmd_spec *cmd; + cli_opt invalid_opt; + + if (cli_opt_parse(&invalid_opt, opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU)) + return cli_opt_usage_error(COMMAND_NAME, opts, &invalid_opt); + + /* Show the meta-help */ + if (show_help) + return print_help(); + + /* We were not asked to show help for a specific command. */ + if (!command) + return print_commands(); + + /* + * If we were asked for help for a command (eg, `help `), + * delegate back to that command's `--help` option. This lets + * commands own their help. Emulate the command-line arguments + * that would invoke ` --help` and invoke that command. + */ + fake_args[0] = command; + fake_args[1] = "--help"; + + if ((cmd = cli_cmd_spec_byname(command)) == NULL) + return cli_error("'%s' is not a %s command. See '%s help'.", + command, PROGRAM_NAME, PROGRAM_NAME); + + return cmd->fn(2, fake_args); +} diff --git a/vendor/libgit2/src/cli/cmd_index_pack.c b/vendor/libgit2/src/cli/cmd_index_pack.c new file mode 100644 index 00000000..09685c5d --- /dev/null +++ b/vendor/libgit2/src/cli/cmd_index_pack.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include "common.h" +#include "cmd.h" +#include "progress.h" + +#define COMMAND_NAME "index-pack" + +#define BUFFER_SIZE (1024 * 1024) + +static int show_help, verbose, read_stdin; +static char *filename; +static cli_progress progress = CLI_PROGRESS_INIT; + +static const cli_opt_spec opts[] = { + { CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, + CLI_OPT_USAGE_HIDDEN | CLI_OPT_USAGE_STOP_PARSING, NULL, + "display help about the " COMMAND_NAME " command" }, + + { CLI_OPT_TYPE_SWITCH, "verbose", 'v', &verbose, 1, + CLI_OPT_USAGE_DEFAULT, NULL, "display progress output" }, + + { CLI_OPT_TYPE_LITERAL }, + + { CLI_OPT_TYPE_SWITCH, "stdin", 0, &read_stdin, 1, + CLI_OPT_USAGE_REQUIRED, NULL, "read from stdin" }, + { CLI_OPT_TYPE_ARG, "pack-file", 0, &filename, 0, + CLI_OPT_USAGE_CHOICE, "pack-file", "packfile path" }, + + { 0 }, +}; + +static void print_help(void) +{ + cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts); + printf("\n"); + + printf("Indexes a packfile and writes the index to disk.\n"); + printf("\n"); + + printf("Options:\n"); + + cli_opt_help_fprint(stdout, opts); +} + +int cmd_index_pack(int argc, char **argv) +{ + cli_opt invalid_opt; + git_indexer *idx = NULL; + git_indexer_options idx_opts = GIT_INDEXER_OPTIONS_INIT; + git_indexer_progress stats = {0}; + char buf[BUFFER_SIZE]; + ssize_t read_len; + int fd, ret; + + if (cli_opt_parse(&invalid_opt, opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU)) + return cli_opt_usage_error(COMMAND_NAME, opts, &invalid_opt); + + if (show_help) { + print_help(); + return 0; + } + + if (verbose) { + idx_opts.progress_cb = cli_progress_indexer; + idx_opts.progress_cb_payload = &progress; + } + + if (read_stdin) { + fd = fileno(stdin); + } else if ((fd = p_open(filename, O_RDONLY)) < 0) { + ret = cli_error_git(); + goto done; + } + +#ifdef GIT_EXPERIMENTAL_SHA256 + ret = git_indexer_new(&idx, ".", GIT_OID_SHA1, &idx_opts); +#else + ret = git_indexer_new(&idx, ".", 0, NULL, &idx_opts); +#endif + + if (ret < 0) { + ret = cli_error_git(); + goto done; + } + + while ((read_len = p_read(fd, buf, sizeof(buf))) > 0) { + if (git_indexer_append(idx, buf, (size_t)read_len, &stats) < 0) { + ret = cli_error_git(); + goto done; + } + } + + if (git_indexer_commit(idx, &stats) < 0) { + ret = cli_error_git(); + goto done; + } + + cli_progress_finish(&progress); + +done: + if (!read_stdin && fd >= 0) + p_close(fd); + + cli_progress_dispose(&progress); + git_indexer_free(idx); + return ret; +} diff --git a/vendor/libgit2/src/cli/common.c b/vendor/libgit2/src/cli/common.c new file mode 100644 index 00000000..60b03586 --- /dev/null +++ b/vendor/libgit2/src/cli/common.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include + +#include "git2_util.h" +#include "vector.h" + +#include "common.h" +#include "error.h" + +static int parse_option(cli_opt *opt, void *data) +{ + git_str kv = GIT_STR_INIT, env = GIT_STR_INIT; + git_vector *cmdline_config = data; + int error = 0; + + if (opt->spec && opt->spec->alias == 'c') { + if (git_str_puts(&kv, opt->value) < 0) { + error = cli_error_git(); + goto done; + } + } + + else if (opt->spec && !strcmp(opt->spec->name, "config-env")) { + char *val = strchr(opt->value, '='); + + if (val == NULL || *(val + 1) == '\0') { + error = cli_error("invalid config format: '%s'", opt->value); + goto done; + } + + if (git_str_put(&kv, opt->value, (val - opt->value)) < 0) { + error = cli_error_git(); + goto done; + } + + val++; + + if ((error = git__getenv(&env, val)) == GIT_ENOTFOUND) { + error = cli_error("missing environment variable '%s' for configuration '%s'", val, kv.ptr); + goto done; + } else if (error) { + error = cli_error_git(); + goto done; + } + + if (git_str_putc(&kv, '=') < 0 || + git_str_puts(&kv, env.ptr) < 0) { + error = cli_error_git(); + goto done; + } + } + + if (kv.size > 0 && + git_vector_insert(cmdline_config, git_str_detach(&kv)) < 0) + error = cli_error_git(); + +done: + git_str_dispose(&env); + git_str_dispose(&kv); + return error; +} + +static int parse_common_options( + git_repository *repo, + cli_repository_open_options *opts) +{ + cli_opt_spec common_opts[] = { + { CLI_COMMON_OPT_CONFIG }, + { CLI_COMMON_OPT_CONFIG_ENV }, + { 0 } + }; + git_config_backend_memory_options config_opts = + GIT_CONFIG_BACKEND_MEMORY_OPTIONS_INIT; + git_vector cmdline = GIT_VECTOR_INIT; + git_config *config = NULL; + git_config_backend *backend = NULL; + int error = 0; + + config_opts.backend_type = "command line"; + + if ((error = cli_opt_foreach(common_opts, opts->args, + opts->args_len, CLI_OPT_PARSE_GNU, parse_option, + &cmdline)) < 0) + goto done; + + if (git_vector_length(&cmdline) == 0) + goto done; + + if (git_repository_config(&config, repo) < 0 || + git_config_backend_from_values(&backend, + (const char **)cmdline.contents, cmdline.length, + &config_opts) < 0 || + git_config_add_backend(config, backend, GIT_CONFIG_LEVEL_APP, + repo, 0) < 0) + error = cli_error_git(); + +done: + if (error && backend) + backend->free(backend); + git_config_free(config); + git_vector_free_deep(&cmdline); + return error; +} + +int cli_repository_open( + git_repository **out, + cli_repository_open_options *opts) +{ + git_repository *repo; + + if (git_repository_open_ext(&repo, ".", GIT_REPOSITORY_OPEN_FROM_ENV, NULL) < 0) + return -1; + + if (opts && parse_common_options(repo, opts) < 0) + return -1; + + *out = repo; + return 0; +} diff --git a/vendor/libgit2/src/cli/common.h b/vendor/libgit2/src/cli/common.h new file mode 100644 index 00000000..3aed8ad8 --- /dev/null +++ b/vendor/libgit2/src/cli/common.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef CLI_common_h__ +#define CLI_common_h__ + +#define PROGRAM_NAME "git2" + +#include "git2_util.h" + +#include "error.h" +#include "opt.h" +#include "opt_usage.h" + +/* + * Common command arguments. + */ + +#define CLI_COMMON_OPT_HELP \ + CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, \ + CLI_OPT_USAGE_HIDDEN | CLI_OPT_USAGE_STOP_PARSING +#define CLI_COMMON_OPT_CONFIG \ + CLI_OPT_TYPE_VALUE, NULL, 'c', NULL, 0, \ + CLI_OPT_USAGE_HIDDEN +#define CLI_COMMON_OPT_CONFIG_ENV \ + CLI_OPT_TYPE_VALUE, "config-env", 0, NULL, 0, \ + CLI_OPT_USAGE_HIDDEN + +#define CLI_COMMON_OPT \ + { CLI_COMMON_OPT_HELP }, \ + { CLI_COMMON_OPT_CONFIG }, \ + { CLI_COMMON_OPT_CONFIG_ENV } + +typedef struct { + char **args; + int args_len; +} cli_repository_open_options; + +extern int cli_repository_open( + git_repository **out, + cli_repository_open_options *opts); + +/* + * Common command arguments. + */ + +#define CLI_COMMON_OPT_HELP \ + CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, \ + CLI_OPT_USAGE_HIDDEN | CLI_OPT_USAGE_STOP_PARSING +#define CLI_COMMON_OPT_CONFIG \ + CLI_OPT_TYPE_VALUE, NULL, 'c', NULL, 0, \ + CLI_OPT_USAGE_HIDDEN +#define CLI_COMMON_OPT_CONFIG_ENV \ + CLI_OPT_TYPE_VALUE, "config-env", 0, NULL, 0, \ + CLI_OPT_USAGE_HIDDEN + +#define CLI_COMMON_OPT \ + { CLI_COMMON_OPT_HELP }, \ + { CLI_COMMON_OPT_CONFIG }, \ + { CLI_COMMON_OPT_CONFIG_ENV } + +#endif /* CLI_common_h__ */ diff --git a/vendor/libgit2/src/cli/error.h b/vendor/libgit2/src/cli/error.h new file mode 100644 index 00000000..abf8a516 --- /dev/null +++ b/vendor/libgit2/src/cli/error.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef CLI_error_h__ +#define CLI_error_h__ + +#include "common.h" +#include + +#define CLI_EXIT_OK 0 +#define CLI_EXIT_ERROR 1 +#define CLI_EXIT_OS 128 +#define CLI_EXIT_GIT 128 +#define CLI_EXIT_USAGE 129 + +#define cli_error__print(fmt) do { \ + va_list ap; \ + va_start(ap, fmt); \ + fprintf(stderr, "%s: ", PROGRAM_NAME); \ + vfprintf(stderr, fmt, ap); \ + fprintf(stderr, "\n"); \ + va_end(ap); \ + } while(0) + +GIT_INLINE(int) cli_error(const char *fmt, ...) +{ + cli_error__print(fmt); + return CLI_EXIT_ERROR; +} + +GIT_INLINE(int) cli_error_usage(const char *fmt, ...) +{ + cli_error__print(fmt); + return CLI_EXIT_USAGE; +} + +GIT_INLINE(int) cli_error_git(void) +{ + const git_error *err = git_error_last(); + fprintf(stderr, "%s: %s\n", PROGRAM_NAME, + err ? err->message : "unknown error"); + return CLI_EXIT_GIT; +} + +#define cli_error_os() (perror(PROGRAM_NAME), CLI_EXIT_OS) + +#endif /* CLI_error_h__ */ diff --git a/vendor/libgit2/src/cli/main.c b/vendor/libgit2/src/cli/main.c new file mode 100644 index 00000000..c7a6fcfc --- /dev/null +++ b/vendor/libgit2/src/cli/main.c @@ -0,0 +1,120 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include +#include "common.h" +#include "cmd.h" + +static int show_help = 0; +static int show_version = 0; +static char *command = NULL; +static char **args = NULL; + +const cli_opt_spec cli_common_opts[] = { + { CLI_OPT_TYPE_SWITCH, "help", 0, &show_help, 1, + CLI_OPT_USAGE_DEFAULT, NULL, "display help information" }, + { CLI_OPT_TYPE_VALUE, NULL, 'c', NULL, 0, + CLI_OPT_USAGE_DEFAULT, "key=value", "add configuration value" }, + { CLI_OPT_TYPE_VALUE, "config-env", 0, NULL, 0, + CLI_OPT_USAGE_DEFAULT, "key=value", "set configuration value to environment variable" }, + { CLI_OPT_TYPE_SWITCH, "version", 0, &show_version, 1, + CLI_OPT_USAGE_DEFAULT, NULL, "display the version" }, + { CLI_OPT_TYPE_ARG, "command", 0, &command, 0, + CLI_OPT_USAGE_REQUIRED, "command", "the command to run" }, + { CLI_OPT_TYPE_ARGS, "args", 0, &args, 0, + CLI_OPT_USAGE_DEFAULT, "args", "arguments for the command" }, + { 0 } +}; + +const cli_cmd_spec cli_cmds[] = { + { "cat-file", cmd_cat_file, "Display an object in the repository" }, + { "clone", cmd_clone, "Clone a repository into a new directory" }, + { "config", cmd_config, "View or set configuration values " }, + { "hash-object", cmd_hash_object, "Hash a raw object and product its object ID" }, + { "help", cmd_help, "Display help information" }, + { "index-pack", cmd_index_pack, "Create an index for a packfile" }, + { NULL } +}; + +/* + * Reorder the argv as it was given, since git has the notion of global + * options (like `--help` or `-c key=val`) that we want to pass to the + * subcommand, and that can appear early in the arguments, before the + * command name. Put the command-name in argv[1] to allow easier parsing. + */ +static void reorder_args(char **argv, size_t first) +{ + char *tmp; + size_t i; + + if (first == 1) + return; + + tmp = argv[first]; + + for (i = first; i > 1; i--) + argv[i] = argv[i - 1]; + + argv[1] = tmp; +} + +int main(int argc, char **argv) +{ + const cli_cmd_spec *cmd; + cli_opt_parser optparser; + cli_opt opt; + int ret = 0; + + if (git_libgit2_init() < 0) { + cli_error("failed to initialize libgit2"); + exit(CLI_EXIT_GIT); + } + + cli_opt_parser_init(&optparser, cli_common_opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU); + + /* Parse the top-level (common) options and command information */ + while (cli_opt_parser_next(&opt, &optparser)) { + if (!opt.spec) { + cli_opt_status_fprint(stderr, PROGRAM_NAME, &opt); + cli_opt_usage_fprint(stderr, PROGRAM_NAME, NULL, cli_common_opts); + ret = CLI_EXIT_USAGE; + goto done; + } + + /* + * When we see a command, stop parsing and capture the + * remaining arguments as args for the command itself. + */ + if (command) { + reorder_args(argv, optparser.idx); + break; + } + } + + if (show_version) { + printf("%s version %s\n", PROGRAM_NAME, LIBGIT2_VERSION); + goto done; + } + + if (!command) { + ret = cmd_help(argc, argv); + goto done; + } + + if ((cmd = cli_cmd_spec_byname(command)) == NULL) { + ret = cli_error("'%s' is not a %s command. See '%s help'.", + command, PROGRAM_NAME, PROGRAM_NAME); + goto done; + } + + ret = cmd->fn(argc - 1, &argv[1]); + +done: + git_libgit2_shutdown(); + return ret; +} diff --git a/vendor/libgit2/src/cli/opt.c b/vendor/libgit2/src/cli/opt.c new file mode 100644 index 00000000..9242e220 --- /dev/null +++ b/vendor/libgit2/src/cli/opt.c @@ -0,0 +1,695 @@ +/* + * Copyright (c), Edward Thomson + * All rights reserved. + * + * This file is part of adopt, distributed under the MIT license. + * For full terms and conditions, see the included LICENSE file. + * + * THIS FILE IS AUTOMATICALLY GENERATED; DO NOT EDIT. + * + * This file was produced by using the `rename.pl` script included with + * adopt. The command-line specified was: + * + * ./rename.pl cli_opt --filename=opt --include=common.h --inline=GIT_INLINE --header-guard=CLI_opt_h__ --lowercase-status --without-usage + */ + +#include +#include +#include +#include +#include + +#if defined(__sun) || defined(__illumos__) +# include +#endif + +#include "common.h" +#include "opt.h" + +#ifdef _WIN32 +# include +#else +# include +# include +#endif + +#ifdef _MSC_VER +# define alloca _alloca +#endif + +#define spec_is_option_type(x) \ + ((x)->type == CLI_OPT_TYPE_BOOL || \ + (x)->type == CLI_OPT_TYPE_SWITCH || \ + (x)->type == CLI_OPT_TYPE_VALUE) + +GIT_INLINE(const cli_opt_spec *) spec_for_long( + int *is_negated, + int *has_value, + const char **value, + const cli_opt_parser *parser, + const char *arg) +{ + const cli_opt_spec *spec; + char *eql; + size_t eql_pos; + + eql = strchr(arg, '='); + eql_pos = (eql = strchr(arg, '=')) ? (size_t)(eql - arg) : strlen(arg); + + for (spec = parser->specs; spec->type; ++spec) { + /* Handle -- (everything after this is literal) */ + if (spec->type == CLI_OPT_TYPE_LITERAL && arg[0] == '\0') + return spec; + + /* Handle --no-option arguments for bool types */ + if (spec->type == CLI_OPT_TYPE_BOOL && + strncmp(arg, "no-", 3) == 0 && + strcmp(arg + 3, spec->name) == 0) { + *is_negated = 1; + return spec; + } + + /* Handle the typical --option arguments */ + if (spec_is_option_type(spec) && + spec->name && + strcmp(arg, spec->name) == 0) + return spec; + + /* Handle --option=value arguments */ + if (spec->type == CLI_OPT_TYPE_VALUE && + spec->name && eql && + strncmp(arg, spec->name, eql_pos) == 0 && + spec->name[eql_pos] == '\0') { + *has_value = 1; + *value = arg[eql_pos + 1] ? &arg[eql_pos + 1] : NULL; + return spec; + } + } + + return NULL; +} + +GIT_INLINE(const cli_opt_spec *) spec_for_short( + const char **value, + const cli_opt_parser *parser, + const char *arg) +{ + const cli_opt_spec *spec; + + for (spec = parser->specs; spec->type; ++spec) { + /* Handle -svalue short options with a value */ + if (spec->type == CLI_OPT_TYPE_VALUE && + arg[0] == spec->alias && + arg[1] != '\0') { + *value = &arg[1]; + return spec; + } + + /* Handle typical -s short options */ + if (arg[0] == spec->alias) { + *value = NULL; + return spec; + } + } + + return NULL; +} + +GIT_INLINE(const cli_opt_spec *) spec_for_arg(cli_opt_parser *parser) +{ + const cli_opt_spec *spec; + size_t args = 0; + + for (spec = parser->specs; spec->type; ++spec) { + if (spec->type == CLI_OPT_TYPE_ARG) { + if (args == parser->arg_idx) { + parser->arg_idx++; + return spec; + } + + args++; + } + + if (spec->type == CLI_OPT_TYPE_ARGS && args == parser->arg_idx) + return spec; + } + + return NULL; +} + +GIT_INLINE(int) spec_is_choice(const cli_opt_spec *spec) +{ + return ((spec + 1)->type && + ((spec + 1)->usage & CLI_OPT_USAGE_CHOICE)); +} + +/* + * If we have a choice with switches and bare arguments, and we see + * the switch, then we no longer expect the bare argument. + */ +GIT_INLINE(void) consume_choices(const cli_opt_spec *spec, cli_opt_parser *parser) +{ + /* back up to the beginning of the choices */ + while (spec->type && (spec->usage & CLI_OPT_USAGE_CHOICE)) + --spec; + + if (!spec_is_choice(spec)) + return; + + do { + if (spec->type == CLI_OPT_TYPE_ARG) + parser->arg_idx++; + ++spec; + } while(spec->type && (spec->usage & CLI_OPT_USAGE_CHOICE)); +} + +static cli_opt_status_t parse_long(cli_opt *opt, cli_opt_parser *parser) +{ + const cli_opt_spec *spec; + char *arg = parser->args[parser->idx++]; + const char *value = NULL; + int is_negated = 0, has_value = 0; + + opt->arg = arg; + + if ((spec = spec_for_long(&is_negated, &has_value, &value, parser, &arg[2])) == NULL) { + opt->spec = NULL; + opt->status = CLI_OPT_STATUS_UNKNOWN_OPTION; + goto done; + } + + opt->spec = spec; + + /* Future options parsed as literal */ + if (spec->type == CLI_OPT_TYPE_LITERAL) + parser->in_literal = 1; + + /* --bool or --no-bool */ + else if (spec->type == CLI_OPT_TYPE_BOOL && spec->value) + *((int *)spec->value) = !is_negated; + + /* --accumulate */ + else if (spec->type == CLI_OPT_TYPE_ACCUMULATOR && spec->value) + *((int *)spec->value) += spec->switch_value ? spec->switch_value : 1; + + /* --switch */ + else if (spec->type == CLI_OPT_TYPE_SWITCH && spec->value) + *((int *)spec->value) = spec->switch_value; + + /* Parse values as "--foo=bar" or "--foo bar" */ + else if (spec->type == CLI_OPT_TYPE_VALUE) { + if (has_value) + opt->value = (char *)value; + else if ((parser->idx + 1) <= parser->args_len) + opt->value = parser->args[parser->idx++]; + + if (spec->value) + *((char **)spec->value) = opt->value; + } + + /* Required argument was not provided */ + if (spec->type == CLI_OPT_TYPE_VALUE && + !opt->value && + !(spec->usage & CLI_OPT_USAGE_VALUE_OPTIONAL)) + opt->status = CLI_OPT_STATUS_MISSING_VALUE; + else + opt->status = CLI_OPT_STATUS_OK; + + consume_choices(opt->spec, parser); + +done: + return opt->status; +} + +static cli_opt_status_t parse_short(cli_opt *opt, cli_opt_parser *parser) +{ + const cli_opt_spec *spec; + char *arg = parser->args[parser->idx++]; + const char *value; + + opt->arg = arg; + + if ((spec = spec_for_short(&value, parser, &arg[1 + parser->in_short])) == NULL) { + opt->spec = NULL; + opt->status = CLI_OPT_STATUS_UNKNOWN_OPTION; + goto done; + } + + opt->spec = spec; + + if (spec->type == CLI_OPT_TYPE_BOOL && spec->value) + *((int *)spec->value) = 1; + + else if (spec->type == CLI_OPT_TYPE_ACCUMULATOR && spec->value) + *((int *)spec->value) += spec->switch_value ? spec->switch_value : 1; + + else if (spec->type == CLI_OPT_TYPE_SWITCH && spec->value) + *((int *)spec->value) = spec->switch_value; + + /* Parse values as "-ifoo" or "-i foo" */ + else if (spec->type == CLI_OPT_TYPE_VALUE) { + if (value) + opt->value = (char *)value; + else if ((parser->idx + 1) <= parser->args_len) + opt->value = parser->args[parser->idx++]; + + if (spec->value) + *((char **)spec->value) = opt->value; + } + + /* + * Handle compressed short arguments, like "-fbcd"; see if there's + * another character after the one we processed. If not, advance + * the parser index. + */ + if (spec->type != CLI_OPT_TYPE_VALUE && arg[2 + parser->in_short] != '\0') { + parser->in_short++; + parser->idx--; + } else { + parser->in_short = 0; + } + + /* Required argument was not provided */ + if (spec->type == CLI_OPT_TYPE_VALUE && !opt->value) + opt->status = CLI_OPT_STATUS_MISSING_VALUE; + else + opt->status = CLI_OPT_STATUS_OK; + + consume_choices(opt->spec, parser); + +done: + return opt->status; +} + +static cli_opt_status_t parse_arg(cli_opt *opt, cli_opt_parser *parser) +{ + const cli_opt_spec *spec = spec_for_arg(parser); + + opt->spec = spec; + opt->arg = parser->args[parser->idx]; + + if (!spec) { + parser->idx++; + opt->status = CLI_OPT_STATUS_UNKNOWN_OPTION; + } else if (spec->type == CLI_OPT_TYPE_ARGS) { + if (spec->value) + *((char ***)spec->value) = &parser->args[parser->idx]; + + /* + * We have started a list of arguments; the remainder of + * given arguments need not be examined. + */ + parser->in_args = (parser->args_len - parser->idx); + parser->idx = parser->args_len; + opt->args_len = parser->in_args; + opt->status = CLI_OPT_STATUS_OK; + } else { + if (spec->value) + *((char **)spec->value) = parser->args[parser->idx]; + + parser->idx++; + opt->status = CLI_OPT_STATUS_OK; + } + + return opt->status; +} + +static int support_gnu_style(unsigned int flags) +{ + if ((flags & CLI_OPT_PARSE_FORCE_GNU) != 0) + return 1; + + if ((flags & CLI_OPT_PARSE_GNU) == 0) + return 0; + + /* TODO: Windows */ +#if defined(_WIN32) && defined(UNICODE) + if (_wgetenv(L"POSIXLY_CORRECT") != NULL) + return 0; +#else + if (getenv("POSIXLY_CORRECT") != NULL) + return 0; +#endif + + return 1; +} + +void cli_opt_parser_init( + cli_opt_parser *parser, + const cli_opt_spec specs[], + char **args, + size_t args_len, + unsigned int flags) +{ + assert(parser); + + memset(parser, 0x0, sizeof(cli_opt_parser)); + + parser->specs = specs; + parser->args = args; + parser->args_len = args_len; + parser->flags = flags; + + parser->needs_sort = support_gnu_style(flags); +} + +GIT_INLINE(const cli_opt_spec *) spec_for_sort( + int *needs_value, + const cli_opt_parser *parser, + const char *arg) +{ + int is_negated, has_value = 0; + const char *value; + const cli_opt_spec *spec = NULL; + size_t idx = 0; + + *needs_value = 0; + + if (strncmp(arg, "--", 2) == 0) { + spec = spec_for_long(&is_negated, &has_value, &value, parser, &arg[2]); + *needs_value = !has_value; + } + + else if (strncmp(arg, "-", 1) == 0) { + spec = spec_for_short(&value, parser, &arg[1]); + + /* + * Advance through compressed short arguments to see if + * the last one has a value, eg "-xvffilename". + */ + while (spec && !value && arg[1 + ++idx] != '\0') + spec = spec_for_short(&value, parser, &arg[1 + idx]); + + *needs_value = (value == NULL); + } + + return spec; +} + +/* + * Some parsers allow for handling arguments like "file1 --help file2"; + * this is done by re-sorting the arguments in-place; emulate that. + */ +static int sort_gnu_style(cli_opt_parser *parser) +{ + size_t i, j, insert_idx = parser->idx, offset; + const cli_opt_spec *spec; + char *option, *value; + int needs_value, changed = 0; + + parser->needs_sort = 0; + + for (i = parser->idx; i < parser->args_len; i++) { + spec = spec_for_sort(&needs_value, parser, parser->args[i]); + + /* Not a "-" or "--" prefixed option. No change. */ + if (!spec) + continue; + + /* A "--" alone means remaining args are literal. */ + if (spec->type == CLI_OPT_TYPE_LITERAL) + break; + + option = parser->args[i]; + + /* + * If the argument is a value type and doesn't already + * have a value (eg "--foo=bar" or "-fbar") then we need + * to copy the next argument as its value. + */ + if (spec->type == CLI_OPT_TYPE_VALUE && needs_value) { + /* + * A required value is not provided; set parser + * index to this value so that we fail on it. + */ + if (i + 1 >= parser->args_len) { + parser->idx = i; + return 1; + } + + value = parser->args[i + 1]; + offset = 1; + } else { + value = NULL; + offset = 0; + } + + /* Caller error if args[0] is an option. */ + if (i == 0) + return 0; + + /* Shift args up one (or two) and insert the option */ + for (j = i; j > insert_idx; j--) + parser->args[j + offset] = parser->args[j - 1]; + + parser->args[insert_idx] = option; + + if (value) + parser->args[insert_idx + 1] = value; + + insert_idx += (1 + offset); + i += offset; + + changed = 1; + } + + return changed; +} + +cli_opt_status_t cli_opt_parser_next(cli_opt *opt, cli_opt_parser *parser) +{ + assert(opt && parser); + + memset(opt, 0x0, sizeof(cli_opt)); + + if (parser->idx >= parser->args_len) { + opt->args_len = parser->in_args; + return CLI_OPT_STATUS_DONE; + } + + /* Handle options in long form, those beginning with "--" */ + if (strncmp(parser->args[parser->idx], "--", 2) == 0 && + !parser->in_short && + !parser->in_literal) + return parse_long(opt, parser); + + /* Handle options in short form, those beginning with "-" */ + else if (parser->in_short || + (strncmp(parser->args[parser->idx], "-", 1) == 0 && + !parser->in_literal)) + return parse_short(opt, parser); + + /* + * We've reached the first "bare" argument. In POSIX mode, all + * remaining items on the command line are arguments. In GNU + * mode, there may be long or short options after this. Sort any + * options up to this position then re-parse the current position. + */ + if (parser->needs_sort && sort_gnu_style(parser)) + return cli_opt_parser_next(opt, parser); + + return parse_arg(opt, parser); +} + +GIT_INLINE(int) spec_included(const cli_opt_spec **specs, const cli_opt_spec *spec) +{ + const cli_opt_spec **i; + + for (i = specs; *i; ++i) { + if (spec == *i) + return 1; + } + + return 0; +} + +static cli_opt_status_t validate_required( + cli_opt *opt, + const cli_opt_spec specs[], + const cli_opt_spec **given_specs) +{ + const cli_opt_spec *spec, *required; + int given; + + /* + * Iterate over the possible specs to identify requirements and + * ensure that those have been given on the command-line. + * Note that we can have required *choices*, where one in a + * list of choices must be specified. + */ + for (spec = specs, required = NULL, given = 0; spec->type; ++spec) { + if (!required && (spec->usage & CLI_OPT_USAGE_REQUIRED)) { + required = spec; + given = 0; + } else if (!required) { + continue; + } + + if (!given) + given = spec_included(given_specs, spec); + + /* + * Validate the requirement unless we're in a required + * choice. In that case, keep the required state and + * validate at the end of the choice list. + */ + if (!spec_is_choice(spec)) { + if (!given) { + opt->spec = required; + opt->status = CLI_OPT_STATUS_MISSING_ARGUMENT; + break; + } + + required = NULL; + given = 0; + } + } + + return opt->status; +} + +cli_opt_status_t cli_opt_parse( + cli_opt *opt, + const cli_opt_spec specs[], + char **args, + size_t args_len, + unsigned int flags) +{ + cli_opt_parser parser; + const cli_opt_spec **given_specs; + size_t given_idx = 0; + + cli_opt_parser_init(&parser, specs, args, args_len, flags); + + given_specs = alloca(sizeof(const cli_opt_spec *) * (args_len + 1)); + + while (cli_opt_parser_next(opt, &parser)) { + if (opt->status != CLI_OPT_STATUS_OK && + opt->status != CLI_OPT_STATUS_DONE) + return opt->status; + + if ((opt->spec->usage & CLI_OPT_USAGE_STOP_PARSING)) + return (opt->status = CLI_OPT_STATUS_DONE); + + given_specs[given_idx++] = opt->spec; + } + + given_specs[given_idx] = NULL; + + return validate_required(opt, specs, given_specs); +} + +int cli_opt_foreach( + const cli_opt_spec specs[], + char **args, + size_t args_len, + unsigned int flags, + int (*callback)(cli_opt *, void *), + void *callback_data) +{ + cli_opt_parser parser; + cli_opt opt; + int ret; + + cli_opt_parser_init(&parser, specs, args, args_len, flags); + + while (cli_opt_parser_next(&opt, &parser)) { + if ((ret = callback(&opt, callback_data)) != 0) + return ret; + } + + return 0; +} + +static int spec_name_fprint(FILE *file, const cli_opt_spec *spec) +{ + int error; + + if (spec->type == CLI_OPT_TYPE_ARG) + error = fprintf(file, "%s", spec->value_name); + else if (spec->type == CLI_OPT_TYPE_ARGS) + error = fprintf(file, "%s", spec->value_name); + else if (spec->alias && !(spec->usage & CLI_OPT_USAGE_SHOW_LONG)) + error = fprintf(file, "-%c", spec->alias); + else + error = fprintf(file, "--%s", spec->name); + + return error; +} + +int cli_opt_status_fprint( + FILE *file, + const char *command, + const cli_opt *opt) +{ + const cli_opt_spec *choice; + int error; + + if (command && (error = fprintf(file, "%s: ", command)) < 0) + return error; + + switch (opt->status) { + case CLI_OPT_STATUS_DONE: + error = fprintf(file, "finished processing arguments (no error)\n"); + break; + case CLI_OPT_STATUS_OK: + error = fprintf(file, "no error\n"); + break; + case CLI_OPT_STATUS_UNKNOWN_OPTION: + error = fprintf(file, "unknown option: %s\n", opt->arg); + break; + case CLI_OPT_STATUS_MISSING_VALUE: + if ((error = fprintf(file, "argument '")) < 0 || + (error = spec_name_fprint(file, opt->spec)) < 0 || + (error = fprintf(file, "' requires a value.\n")) < 0) + break; + break; + case CLI_OPT_STATUS_MISSING_ARGUMENT: + if (spec_is_choice(opt->spec)) { + int is_choice = 1; + + if (spec_is_choice((opt->spec)+1)) + error = fprintf(file, "one of"); + else + error = fprintf(file, "either"); + + if (error < 0) + break; + + for (choice = opt->spec; is_choice; ++choice) { + is_choice = spec_is_choice(choice); + + if (!is_choice) + error = fprintf(file, " or"); + else if (choice != opt->spec) + error = fprintf(file, ","); + + if ((error < 0) || + (error = fprintf(file, " '")) < 0 || + (error = spec_name_fprint(file, choice)) < 0 || + (error = fprintf(file, "'")) < 0) + break; + + if (!spec_is_choice(choice)) + break; + } + + if ((error < 0) || + (error = fprintf(file, " is required.\n")) < 0) + break; + } else { + if ((error = fprintf(file, "argument '")) < 0 || + (error = spec_name_fprint(file, opt->spec)) < 0 || + (error = fprintf(file, "' is required.\n")) < 0) + break; + } + + break; + default: + error = fprintf(file, "unknown status: %d\n", opt->status); + break; + } + + return error; +} + diff --git a/vendor/libgit2/src/cli/opt.h b/vendor/libgit2/src/cli/opt.h new file mode 100644 index 00000000..226f74db --- /dev/null +++ b/vendor/libgit2/src/cli/opt.h @@ -0,0 +1,367 @@ +/* + * Copyright (c), Edward Thomson + * All rights reserved. + * + * This file is part of adopt, distributed under the MIT license. + * For full terms and conditions, see the included LICENSE file. + * + * THIS FILE IS AUTOMATICALLY GENERATED; DO NOT EDIT. + * + * This file was produced by using the `rename.pl` script included with + * adopt. The command-line specified was: + * + * ./rename.pl cli_opt --filename=opt --include=common.h --inline=GIT_INLINE --header-guard=CLI_opt_h__ --lowercase-status --without-usage + */ + +#ifndef CLI_opt_h__ +#define CLI_opt_h__ + +#include +#include + +/** + * The type of argument to be parsed. + */ +typedef enum { + CLI_OPT_TYPE_NONE = 0, + + /** + * An option that, when specified, sets a given value to true. + * This is useful for options like "--debug". A negation + * option (beginning with "no-") is implicitly specified; for + * example "--no-debug". The `value` pointer in the returned + * option will be set to `1` when this is specified, and set to + * `0` when the negation "no-" option is specified. + */ + CLI_OPT_TYPE_BOOL, + + /** + * An option that, when specified, sets the given `value` pointer + * to the specified `switch_value`. This is useful for booleans + * where you do not want the implicit negation that comes with an + * `CLI_OPT_TYPE_BOOL`, or for switches that multiplex a value, like + * setting a mode. For example, `--read` may set the `value` to + * `MODE_READ` and `--write` may set the `value` to `MODE_WRITE`. + */ + CLI_OPT_TYPE_SWITCH, + + /** + * An option that, when specified, increments the given + * `value` by the given `switch_value`. This can be specified + * multiple times to continue to increment the `value`. + * (For example, "-vvv" to set verbosity to 3.) + */ + CLI_OPT_TYPE_ACCUMULATOR, + + /** + * An option that takes a value, for example `-n value`, + * `-nvalue`, `--name value` or `--name=value`. + */ + CLI_OPT_TYPE_VALUE, + + /** + * A bare "--" that indicates that arguments following this are + * literal. This allows callers to specify things that might + * otherwise look like options, for example to operate on a file + * named "-rf" then you can invoke "program -- -rf" to treat + * "-rf" as an argument not an option. + */ + CLI_OPT_TYPE_LITERAL, + + /** + * A single argument, not an option. When options are exhausted, + * arguments will be matches in the order that they're specified + * in the spec list. For example, if two `CLI_OPT_TYPE_ARGS` are + * specified, `input_file` and `output_file`, then the first bare + * argument on the command line will be `input_file` and the + * second will be `output_file`. + */ + CLI_OPT_TYPE_ARG, + + /** + * A collection of arguments. This is useful when you want to take + * a list of arguments, for example, multiple paths. When specified, + * the value will be set to the first argument in the list. + */ + CLI_OPT_TYPE_ARGS, +} cli_opt_type_t; + +/** + * Additional information about an option, including parsing + * restrictions and usage information to be displayed to the end-user. + */ +typedef enum { + /** Defaults for the argument. */ + CLI_OPT_USAGE_DEFAULT = 0, + + /** This argument is required. */ + CLI_OPT_USAGE_REQUIRED = (1u << 0), + + /** + * This is a multiple choice argument, combined with the previous + * argument. For example, when the previous argument is `-f` and + * this optional is applied to an argument of type `-b` then one + * of `-f` or `-b` may be specified. + */ + CLI_OPT_USAGE_CHOICE = (1u << 1), + + /** + * This argument short-circuits the remainder of parsing. + * Useful for arguments like `--help`. + */ + CLI_OPT_USAGE_STOP_PARSING = (1u << 2), + + /** The argument's value is optional ("-n" or "-n foo") */ + CLI_OPT_USAGE_VALUE_OPTIONAL = (1u << 3), + + /** This argument should not be displayed in usage. */ + CLI_OPT_USAGE_HIDDEN = (1u << 4), + + /** In usage, show the long format instead of the abbreviated format. */ + CLI_OPT_USAGE_SHOW_LONG = (1u << 5), +} cli_opt_usage_t; + +typedef enum { + /** Default parsing behavior. */ + CLI_OPT_PARSE_DEFAULT = 0, + + /** + * Parse with GNU `getopt_long` style behavior, where options can + * be intermixed with arguments at any position (for example, + * "file1 --help file2".) Like `getopt_long`, this can mutate the + * arguments given. + */ + CLI_OPT_PARSE_GNU = (1u << 0), + + /** + * Force GNU `getopt_long` style behavior; the `POSIXLY_CORRECT` + * environment variable is ignored. + */ + CLI_OPT_PARSE_FORCE_GNU = (1u << 1), +} cli_opt_flag_t; + +/** Specification for an available option. */ +typedef struct cli_opt_spec { + /** Type of option expected. */ + cli_opt_type_t type; + + /** Name of the long option. */ + const char *name; + + /** The alias is the short (one-character) option alias. */ + const char alias; + + /** + * If this spec is of type `CLI_OPT_TYPE_BOOL`, this is a pointer + * to an `int` that will be set to `1` if the option is specified. + * + * If this spec is of type `CLI_OPT_TYPE_SWITCH`, this is a pointer + * to an `int` that will be set to the opt's `switch_value` (below) + * when this option is specified. + * + * If this spec is of type `CLI_OPT_TYPE_ACCUMULATOR`, this is a + * pointer to an `int` that will be incremented by the opt's + * `switch_value` (below). If no `switch_value` is provided then + * the value will be incremented by 1. + * + * If this spec is of type `CLI_OPT_TYPE_VALUE`, + * `CLI_OPT_TYPE_VALUE_OPTIONAL`, or `CLI_OPT_TYPE_ARG`, this is + * a pointer to a `char *` that will be set to the value + * specified on the command line. + * + * If this spec is of type `CLI_OPT_TYPE_ARGS`, this is a pointer + * to a `char **` that will be set to the remaining values + * specified on the command line. + */ + void *value; + + /** + * If this spec is of type `CLI_OPT_TYPE_SWITCH`, this is the value + * to set in the option's `value` pointer when it is specified. If + * this spec is of type `CLI_OPT_TYPE_ACCUMULATOR`, this is the value + * to increment in the option's `value` pointer when it is + * specified. This is ignored for other opt types. + */ + int switch_value; + + /** + * Optional usage flags that change parsing behavior and how + * usage information is shown to the end-user. + */ + uint32_t usage; + + /** + * The name of the value, provided when creating usage information. + * This is required only for the functions that display usage + * information and only when a spec is of type `CLI_OPT_TYPE_VALUE, + * `CLI_OPT_TYPE_ARG` or `CLI_OPT_TYPE_ARGS``. + */ + const char *value_name; + + /** + * Optional short description of the option to display to the + * end-user. This is only used when creating usage information. + */ + const char *help; +} cli_opt_spec; + +/** Return value for `cli_opt_parser_next`. */ +typedef enum { + /** Parsing is complete; there are no more arguments. */ + CLI_OPT_STATUS_DONE = 0, + + /** + * This argument was parsed correctly; the `opt` structure is + * populated and the value pointer has been set. + */ + CLI_OPT_STATUS_OK = 1, + + /** + * The argument could not be parsed correctly, it does not match + * any of the specifications provided. + */ + CLI_OPT_STATUS_UNKNOWN_OPTION = 2, + + /** + * The argument matched a spec of type `CLI_OPT_VALUE`, but no value + * was provided. + */ + CLI_OPT_STATUS_MISSING_VALUE = 3, + + /** A required argument was not provided. */ + CLI_OPT_STATUS_MISSING_ARGUMENT = 4, +} cli_opt_status_t; + +/** An option provided on the command-line. */ +typedef struct cli_opt { + /** The status of parsing the most recent argument. */ + cli_opt_status_t status; + + /** + * The specification that was provided on the command-line, or + * `NULL` if the argument did not match an `cli_opt_spec`. + */ + const cli_opt_spec *spec; + + /** + * The argument as it was specified on the command-line, including + * dashes, eg, `-f` or `--foo`. + */ + char *arg; + + /** + * If the spec is of type `CLI_OPT_VALUE` or `CLI_OPT_VALUE_OPTIONAL`, + * this is the value provided to the argument. + */ + char *value; + + /** + * If the argument is of type `CLI_OPT_ARGS`, this is the number of + * arguments remaining. This value is persisted even when parsing + * is complete and `status` == `CLI_OPT_STATUS_DONE`. + */ + size_t args_len; +} cli_opt; + +/* The internal parser state. Callers should not modify this structure. */ +typedef struct cli_opt_parser { + const cli_opt_spec *specs; + char **args; + size_t args_len; + unsigned int flags; + + /* Parser state */ + size_t idx; + size_t arg_idx; + size_t in_args; + size_t in_short; + unsigned int needs_sort : 1, + in_literal : 1; +} cli_opt_parser; + +/** + * Parses all the command-line arguments and updates all the options using + * the pointers provided. Parsing stops on any invalid argument and + * information about the failure will be provided in the opt argument. + * + * This is the simplest way to parse options; it handles the initialization + * (`parser_init`) and looping (`parser_next`). + * + * @param opt The The `cli_opt` information that failed parsing + * @param specs A NULL-terminated array of `cli_opt_spec`s that can be parsed + * @param args The arguments that will be parsed + * @param args_len The length of arguments to be parsed + * @param flags The `cli_opt_flag_t flags for parsing + */ +cli_opt_status_t cli_opt_parse( + cli_opt *opt, + const cli_opt_spec specs[], + char **args, + size_t args_len, + unsigned int flags); + +/** + * Quickly executes the given callback for each argument. + * + * @param specs A NULL-terminated array of `cli_opt_spec`s that can be parsed + * @param args The arguments that will be parsed + * @param args_len The length of arguments to be parsed + * @param flags The `cli_opt_flag_t flags for parsing + * @param callback The callback to invoke for each specified option + * @param callback_data Data to be provided to the callback + */ +int cli_opt_foreach( + const cli_opt_spec specs[], + char **args, + size_t args_len, + unsigned int flags, + int (*callback)(cli_opt *, void *), + void *callback_data); + +/** + * Initializes a parser that parses the given arguments according to the + * given specifications. + * + * @param parser The `cli_opt_parser` that will be initialized + * @param specs A NULL-terminated array of `cli_opt_spec`s that can be parsed + * @param args The arguments that will be parsed + * @param args_len The length of arguments to be parsed + * @param flags The `cli_opt_flag_t flags for parsing + */ +void cli_opt_parser_init( + cli_opt_parser *parser, + const cli_opt_spec specs[], + char **args, + size_t args_len, + unsigned int flags); + +/** + * Parses the next command-line argument and places the information about + * the argument into the given `opt` data. + * + * @param opt The `cli_opt` information parsed from the argument + * @param parser An `cli_opt_parser` that has been initialized with + * `cli_opt_parser_init` + * @return true if the caller should continue iterating, or 0 if there are + * no arguments left to process. + */ +cli_opt_status_t cli_opt_parser_next( + cli_opt *opt, + cli_opt_parser *parser); + +/** + * Prints the status after parsing the most recent argument. This is + * useful for printing an error message when an unknown argument was + * specified, or when an argument was specified without a value. + * + * @param file The file to print information to + * @param command The name of the command to use when printing (optional) + * @param opt The option that failed to parse + * @return 0 on success, -1 on failure + */ +int cli_opt_status_fprint( + FILE *file, + const char *command, + const cli_opt *opt); + +#endif /* CLI_opt_h__ */ diff --git a/vendor/libgit2/src/cli/opt_usage.c b/vendor/libgit2/src/cli/opt_usage.c new file mode 100644 index 00000000..8374f515 --- /dev/null +++ b/vendor/libgit2/src/cli/opt_usage.c @@ -0,0 +1,194 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "common.h" +#include "str.h" + +static int print_spec_name(git_str *out, const cli_opt_spec *spec) +{ + if (spec->type == CLI_OPT_TYPE_VALUE && spec->alias && + !(spec->usage & CLI_OPT_USAGE_VALUE_OPTIONAL) && + !(spec->usage & CLI_OPT_USAGE_SHOW_LONG)) + return git_str_printf(out, "-%c <%s>", spec->alias, spec->value_name); + if (spec->type == CLI_OPT_TYPE_VALUE && spec->alias && + !(spec->usage & CLI_OPT_USAGE_SHOW_LONG)) + return git_str_printf(out, "-%c [<%s>]", spec->alias, spec->value_name); + if (spec->type == CLI_OPT_TYPE_VALUE && + !(spec->usage & CLI_OPT_USAGE_VALUE_OPTIONAL)) + return git_str_printf(out, "--%s[=<%s>]", spec->name, spec->value_name); + if (spec->type == CLI_OPT_TYPE_VALUE) + return git_str_printf(out, "--%s=<%s>", spec->name, spec->value_name); + if (spec->type == CLI_OPT_TYPE_ARG) + return git_str_printf(out, "<%s>", spec->value_name); + if (spec->type == CLI_OPT_TYPE_ARGS) + return git_str_printf(out, "<%s>...", spec->value_name); + if (spec->type == CLI_OPT_TYPE_LITERAL) + return git_str_printf(out, "--"); + if (spec->alias && !(spec->usage & CLI_OPT_USAGE_SHOW_LONG)) + return git_str_printf(out, "-%c", spec->alias); + if (spec->name) + return git_str_printf(out, "--%s", spec->name); + + GIT_ASSERT(0); +} + +/* + * This is similar to adopt's function, but modified to understand + * that we have a command ("git") and a "subcommand" ("checkout"). + * It also understands a terminal's line length and wrap appropriately, + * using a `git_str` for storage. + */ +int cli_opt_usage_fprint( + FILE *file, + const char *command, + const char *subcommand, + const cli_opt_spec specs[]) +{ + git_str usage = GIT_BUF_INIT, opt = GIT_BUF_INIT; + const cli_opt_spec *spec; + size_t i, prefixlen, linelen; + bool choice = false, next_choice = false, optional = false; + int error; + + /* TODO: query actual console width. */ + int console_width = 80; + + if ((error = git_str_printf(&usage, "usage: %s", command)) < 0) + goto done; + + if (subcommand && + (error = git_str_printf(&usage, " %s", subcommand)) < 0) + goto done; + + linelen = git_str_len(&usage); + prefixlen = linelen + 1; + + for (spec = specs; spec->type; ++spec) { + if (!choice) + optional = !(spec->usage & CLI_OPT_USAGE_REQUIRED); + + next_choice = !!((spec + 1)->usage & CLI_OPT_USAGE_CHOICE); + + if (spec->usage & CLI_OPT_USAGE_HIDDEN) + continue; + + if (choice) + git_str_putc(&opt, '|'); + else + git_str_clear(&opt); + + if (optional && !choice) + git_str_putc(&opt, '['); + if (!optional && !choice && next_choice) + git_str_putc(&opt, '('); + + if ((error = print_spec_name(&opt, spec)) < 0) + goto done; + + if (!optional && choice && !next_choice) + git_str_putc(&opt, ')'); + else if (optional && !next_choice) + git_str_putc(&opt, ']'); + + if ((choice = next_choice)) + continue; + + if (git_str_oom(&opt)) { + error = -1; + goto done; + } + + if (linelen > prefixlen && + console_width > 0 && + linelen + git_str_len(&opt) + 1 > (size_t)console_width) { + git_str_putc(&usage, '\n'); + + for (i = 0; i < prefixlen; i++) + git_str_putc(&usage, ' '); + + linelen = prefixlen; + } else { + git_str_putc(&usage, ' '); + linelen += git_str_len(&opt) + 1; + } + + git_str_puts(&usage, git_str_cstr(&opt)); + + if (git_str_oom(&usage)) { + error = -1; + goto done; + } + } + + error = fprintf(file, "%s\n", git_str_cstr(&usage)); + +done: + error = (error < 0) ? -1 : 0; + + git_str_dispose(&usage); + git_str_dispose(&opt); + return error; +} + +int cli_opt_usage_error( + const char *subcommand, + const cli_opt_spec specs[], + const cli_opt *invalid_opt) +{ + cli_opt_status_fprint(stderr, PROGRAM_NAME, invalid_opt); + cli_opt_usage_fprint(stderr, PROGRAM_NAME, subcommand, specs); + return CLI_EXIT_USAGE; +} + +int cli_opt_help_fprint( + FILE *file, + const cli_opt_spec specs[]) +{ + git_str help = GIT_BUF_INIT; + const cli_opt_spec *spec; + int error = 0; + + /* Display required arguments first */ + for (spec = specs; spec->type; ++spec) { + if (! (spec->usage & CLI_OPT_USAGE_REQUIRED) || + (spec->usage & CLI_OPT_USAGE_HIDDEN)) + continue; + + git_str_printf(&help, " "); + + if ((error = print_spec_name(&help, spec)) < 0) + goto done; + + git_str_printf(&help, ": %s\n", spec->help); + } + + /* Display the remaining arguments */ + for (spec = specs; spec->type; ++spec) { + if ((spec->usage & CLI_OPT_USAGE_REQUIRED) || + (spec->usage & CLI_OPT_USAGE_HIDDEN)) + continue; + + git_str_printf(&help, " "); + + if ((error = print_spec_name(&help, spec)) < 0) + goto done; + + git_str_printf(&help, ": %s\n", spec->help); + + } + + if (git_str_oom(&help) || + p_write(fileno(file), help.ptr, help.size) < 0) + error = -1; + +done: + error = (error < 0) ? -1 : 0; + + git_str_dispose(&help); + return error; +} + diff --git a/vendor/libgit2/src/cli/opt_usage.h b/vendor/libgit2/src/cli/opt_usage.h new file mode 100644 index 00000000..c752494e --- /dev/null +++ b/vendor/libgit2/src/cli/opt_usage.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef CLI_opt_usage_h__ +#define CLI_opt_usage_h__ + +/** + * Prints usage information to the given file handle. + * + * @param file The file to print information to + * @param command The name of the command to use when printing + * @param subcommand The name of the subcommand (eg "checkout") to use when printing, or NULL to skip + * @param specs The specifications allowed by the command + * @return 0 on success, -1 on failure + */ +int cli_opt_usage_fprint( + FILE *file, + const char *command, + const char *subcommand, + const cli_opt_spec specs[]); + +int cli_opt_usage_error( + const char *subcommand, + const cli_opt_spec specs[], + const cli_opt *invalid_opt); + +int cli_opt_help_fprint( + FILE *file, + const cli_opt_spec specs[]); + +#endif /* CLI_opt_usage_h__ */ diff --git a/vendor/libgit2/src/cli/progress.c b/vendor/libgit2/src/cli/progress.c new file mode 100644 index 00000000..d975b095 --- /dev/null +++ b/vendor/libgit2/src/cli/progress.c @@ -0,0 +1,395 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include +#include + +#include "progress.h" +#include "error.h" + +/* + * Show updates to the percentage and number of objects received + * separately from the throughput to give an accurate progress while + * avoiding too much noise on the screen. (In milliseconds.) + */ +#define PROGRESS_UPDATE_TIME 60 +#define THROUGHPUT_UPDATE_TIME 500 + +#define is_nl(c) ((c) == '\r' || (c) == '\n') + +#define return_os_error(msg) do { \ + git_error_set(GIT_ERROR_OS, "%s", msg); return -1; } while(0) + +GIT_INLINE(size_t) no_nl_len(const char *str, size_t len) +{ + size_t i = 0; + + while (i < len && !is_nl(str[i])) + i++; + + return i; +} + +GIT_INLINE(size_t) nl_len(bool *has_nl, const char *str, size_t len) +{ + size_t i = no_nl_len(str, len); + + *has_nl = false; + + while (i < len && is_nl(str[i])) { + *has_nl = true; + i++; + } + + return i; +} + +static int progress_write(cli_progress *progress, bool force, git_str *line) +{ + bool has_nl; + size_t no_nl = no_nl_len(line->ptr, line->size); + size_t nl = nl_len(&has_nl, line->ptr + no_nl, line->size - no_nl); + uint64_t now = git_time_monotonic(); + size_t i; + + /* Avoid spamming the console with progress updates */ + if (!force && line->ptr[line->size - 1] != '\n' && progress->last_update) { + if (now - progress->last_update < PROGRESS_UPDATE_TIME) { + git_str_clear(&progress->deferred); + git_str_put(&progress->deferred, line->ptr, line->size); + return git_str_oom(&progress->deferred) ? -1 : 0; + } + } + + /* + * If there's something on this line already (eg, a progress line + * with only a trailing `\r` that we'll print over) then we need + * to really print over it in case we're writing a shorter line. + */ + if (printf("%.*s", (int)no_nl, line->ptr) < 0) + return_os_error("could not print status"); + + if (progress->onscreen.size) { + for (i = no_nl; i < progress->onscreen.size; i++) { + if (printf(" ") < 0) + return_os_error("could not print status"); + } + } + + if (printf("%.*s", (int)nl, line->ptr + no_nl) < 0 || + fflush(stdout) != 0) + return_os_error("could not print status"); + + git_str_clear(&progress->onscreen); + + if (line->ptr[line->size - 1] == '\n') { + progress->last_update = 0; + } else { + git_str_put(&progress->onscreen, line->ptr, line->size); + progress->last_update = now; + } + + git_str_clear(&progress->deferred); + return git_str_oom(&progress->onscreen) ? -1 : 0; +} + +static int progress_printf(cli_progress *progress, bool force, const char *fmt, ...) + GIT_FORMAT_PRINTF(3, 4); + +int progress_printf(cli_progress *progress, bool force, const char *fmt, ...) +{ + git_str buf = GIT_BUF_INIT; + va_list ap; + int error; + + va_start(ap, fmt); + error = git_str_vprintf(&buf, fmt, ap); + va_end(ap); + + if (error < 0) + return error; + + error = progress_write(progress, force, &buf); + + git_str_dispose(&buf); + return error; +} + +static int progress_complete(cli_progress *progress) +{ + if (progress->deferred.size) + progress_write(progress, true, &progress->deferred); + + if (progress->onscreen.size) + if (printf("\n") < 0) + return_os_error("could not print status"); + + git_str_clear(&progress->deferred); + git_str_clear(&progress->onscreen); + progress->last_update = 0; + progress->action_start = 0; + progress->action_finish = 0; + + return 0; +} + +GIT_INLINE(int) percent(size_t completed, size_t total) +{ + if (total == 0) + return (completed == 0) ? 100 : 0; + + return (int)(((double)completed / (double)total) * 100); +} + +int cli_progress_fetch_sideband(const char *str, int len, void *payload) +{ + cli_progress *progress = (cli_progress *)payload; + size_t remain; + + if (len <= 0) + return 0; + + /* Accumulate the sideband data, then print it line-at-a-time. */ + if (git_str_put(&progress->sideband, str, len) < 0) + return -1; + + str = progress->sideband.ptr; + remain = progress->sideband.size; + + while (remain) { + bool has_nl; + size_t line_len = nl_len(&has_nl, str, remain); + + if (!has_nl) + break; + + if (line_len < INT_MAX) { + int error = progress_printf(progress, true, + "remote: %.*s", (int)line_len, str); + + if (error < 0) + return error; + } + + str += line_len; + remain -= line_len; + } + + git_str_consume_bytes(&progress->sideband, (progress->sideband.size - remain)); + + return 0; +} + +static int fetch_receiving( + cli_progress *progress, + const git_indexer_progress *stats) +{ + char *recv_units[] = { "B", "KiB", "MiB", "GiB", "TiB", NULL }; + char *rate_units[] = { "B/s", "KiB/s", "MiB/s", "GiB/s", "TiB/s", NULL }; + uint64_t now, elapsed; + + double recv_len, rate; + size_t recv_unit_idx = 0, rate_unit_idx = 0; + bool done = (stats->received_objects == stats->total_objects); + + if (!progress->action_start) + progress->action_start = git_time_monotonic(); + + if (done && progress->action_finish) + now = progress->action_finish; + else if (done) + progress->action_finish = now = git_time_monotonic(); + else + now = git_time_monotonic(); + + if (progress->throughput_update && + now - progress->throughput_update < THROUGHPUT_UPDATE_TIME) { + elapsed = progress->throughput_update - + progress->action_start; + recv_len = progress->throughput_bytes; + } else { + elapsed = now - progress->action_start; + recv_len = (double)stats->received_bytes; + + progress->throughput_update = now; + progress->throughput_bytes = recv_len; + } + + rate = elapsed ? recv_len / elapsed : 0; + + while (recv_len > 1024 && recv_units[recv_unit_idx+1]) { + recv_len /= 1024; + recv_unit_idx++; + } + + while (rate > 1024 && rate_units[rate_unit_idx+1]) { + rate /= 1024; + rate_unit_idx++; + } + + return progress_printf(progress, false, + "Receiving objects: %3d%% (%d/%d), %.2f %s | %.2f %s%s\r", + percent(stats->received_objects, stats->total_objects), + stats->received_objects, + stats->total_objects, + recv_len, recv_units[recv_unit_idx], + rate, rate_units[rate_unit_idx], + done ? ", done." : ""); +} + +static int indexer_indexing( + cli_progress *progress, + const git_indexer_progress *stats) +{ + bool done = (stats->received_objects == stats->total_objects); + + return progress_printf(progress, false, + "Indexing objects: %3d%% (%d/%d)%s\r", + percent(stats->received_objects, stats->total_objects), + stats->received_objects, + stats->total_objects, + done ? ", done." : ""); +} + +static int indexer_resolving( + cli_progress *progress, + const git_indexer_progress *stats) +{ + bool done = (stats->indexed_deltas == stats->total_deltas); + + return progress_printf(progress, false, + "Resolving deltas: %3d%% (%d/%d)%s\r", + percent(stats->indexed_deltas, stats->total_deltas), + stats->indexed_deltas, stats->total_deltas, + done ? ", done." : ""); +} + +int cli_progress_fetch_transfer(const git_indexer_progress *stats, void *payload) +{ + cli_progress *progress = (cli_progress *)payload; + int error = 0; + + switch (progress->action) { + case CLI_PROGRESS_NONE: + progress->action = CLI_PROGRESS_RECEIVING; + /* fall through */ + + case CLI_PROGRESS_RECEIVING: + if ((error = fetch_receiving(progress, stats)) < 0) + break; + + /* + * Upgrade from receiving to resolving; do this after the + * final call to cli_progress_fetch_receiving (above) to + * ensure that we've printed a final "done" string after + * any sideband data. + */ + if (!stats->indexed_deltas) + break; + + progress_complete(progress); + progress->action = CLI_PROGRESS_RESOLVING; + /* fall through */ + + case CLI_PROGRESS_RESOLVING: + error = indexer_resolving(progress, stats); + break; + + default: + /* should not be reached */ + GIT_ASSERT(!"unexpected progress state"); + } + + return error; +} + +int cli_progress_indexer( + const git_indexer_progress *stats, + void *payload) +{ + cli_progress *progress = (cli_progress *)payload; + int error = 0; + + switch (progress->action) { + case CLI_PROGRESS_NONE: + progress->action = CLI_PROGRESS_INDEXING; + /* fall through */ + + case CLI_PROGRESS_INDEXING: + if ((error = indexer_indexing(progress, stats)) < 0) + break; + + if (stats->indexed_deltas == stats->total_deltas) + break; + + progress_complete(progress); + progress->action = CLI_PROGRESS_RESOLVING; + /* fall through */ + + case CLI_PROGRESS_RESOLVING: + error = indexer_resolving(progress, stats); + break; + + default: + /* should not be reached */ + GIT_ASSERT(!"unexpected progress state"); + } + + return error; +} + +void cli_progress_checkout( + const char *path, + size_t completed_steps, + size_t total_steps, + void *payload) +{ + cli_progress *progress = (cli_progress *)payload; + bool done = (completed_steps == total_steps); + + GIT_UNUSED(path); + + if (progress->action != CLI_PROGRESS_CHECKING_OUT) { + progress_complete(progress); + progress->action = CLI_PROGRESS_CHECKING_OUT; + } + + progress_printf(progress, false, + "Checking out files: %3d%% (%" PRIuZ "/%" PRIuZ ")%s\r", + percent(completed_steps, total_steps), + completed_steps, total_steps, + done ? ", done." : ""); +} + +int cli_progress_abort(cli_progress *progress) +{ + if (progress->onscreen.size > 0 && printf("\n") < 0) + return_os_error("could not print status"); + + return 0; +} + +int cli_progress_finish(cli_progress *progress) +{ + int error = progress->action ? progress_complete(progress) : 0; + + progress->action = 0; + return error; +} + +void cli_progress_dispose(cli_progress *progress) +{ + if (progress == NULL) + return; + + git_str_dispose(&progress->sideband); + git_str_dispose(&progress->onscreen); + git_str_dispose(&progress->deferred); + + memset(progress, 0, sizeof(cli_progress)); +} diff --git a/vendor/libgit2/src/cli/progress.h b/vendor/libgit2/src/cli/progress.h new file mode 100644 index 00000000..f08d68f1 --- /dev/null +++ b/vendor/libgit2/src/cli/progress.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef CLI_progress_h__ +#define CLI_progress_h__ + +#include +#include "str.h" + +/* + * A general purpose set of progress printing functions. An individual + * `cli_progress` object is capable of displaying progress for a single + * function, even if that function displays multiple pieces of progress + * (like `git_clone`). `cli_progress_finish` should be called after + * any function invocation to re-set state. + */ + +typedef enum { + CLI_PROGRESS_NONE, + CLI_PROGRESS_RECEIVING, + CLI_PROGRESS_INDEXING, + CLI_PROGRESS_RESOLVING, + CLI_PROGRESS_CHECKING_OUT +} cli_progress_t; + +typedef struct { + cli_progress_t action; + + /* Actions may time themselves (eg fetch) but are not required to */ + uint64_t action_start; + uint64_t action_finish; + + /* Last console update, avoid too frequent updates. */ + uint64_t last_update; + + /* Accumulators for partial output and deferred updates. */ + git_str sideband; + git_str onscreen; + git_str deferred; + + /* Last update about throughput */ + uint64_t throughput_update; + double throughput_bytes; +} cli_progress; + +#define CLI_PROGRESS_INIT { 0 } + +/** + * Prints sideband data from fetch to the console. Suitable for a + * `sideband_progress` callback for `git_fetch_options`. + * + * @param str The sideband string + * @param len The length of the sideband string + * @param payload A pointer to the cli_progress + * @return 0 on success, -1 on failure + */ +extern int cli_progress_fetch_sideband( + const char *str, + int len, + void *payload); + +/** + * Prints fetch transfer statistics to the console. Suitable for a + * `transfer_progress` callback for `git_fetch_options`. + * + * @param stats The indexer stats + * @param payload A pointer to the cli_progress + * @return 0 on success, -1 on failure + */ +extern int cli_progress_fetch_transfer( + const git_indexer_progress *stats, + void *payload); + +/** + * Prints indexer progress to the console. Suitable for a + * `progress_cb` callback for `git_indexer_options`. + * + * @param stats The indexer stats + * @param payload A pointer to the cli_progress + */ +extern int cli_progress_indexer( + const git_indexer_progress *stats, + void *payload); + +/** + * Prints checkout progress to the console. Suitable for a + * `progress_cb` callback for `git_checkout_options`. + * + * @param path The path being written + * @param completed_steps The completed checkout steps + * @param total_steps The total number of checkout steps + * @param payload A pointer to the cli_progress + */ +extern void cli_progress_checkout( + const char *path, + size_t completed_steps, + size_t total_steps, + void *payload); + +/** + * Stop displaying progress quickly; suitable for stopping an application + * quickly. Does not display any lines that were buffered, just gets the + * console back to a sensible place. + * + * @param progress The progress information + * @return 0 on success, -1 on failure + */ +extern int cli_progress_abort(cli_progress *progress); + +/** + * Finishes displaying progress; flushes any buffered output. + * + * @param progress The progress information + * @return 0 on success, -1 on failure + */ +extern int cli_progress_finish(cli_progress *progress); + +/** + * Disposes the progress information. + * + * @param progress The progress information + */ +extern void cli_progress_dispose(cli_progress *progress); + +#endif /* CLI_progress_h__ */ diff --git a/vendor/libgit2/src/cli/sighandler.h b/vendor/libgit2/src/cli/sighandler.h new file mode 100644 index 00000000..877223e0 --- /dev/null +++ b/vendor/libgit2/src/cli/sighandler.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef CLI_sighandler_h__ +#define CLI_sighandler_h__ + +/** + * Sets up a signal handler that will run when the process is interrupted + * (via SIGINT on POSIX or Control-C or Control-Break on Windows). + * + * @param handler The function to run on interrupt + * @return 0 on success, -1 on failure + */ +int cli_sighandler_set_interrupt(void (*handler)(void)); + +#endif /* CLI_sighandler_h__ */ diff --git a/vendor/libgit2/src/cli/unix/sighandler.c b/vendor/libgit2/src/cli/unix/sighandler.c new file mode 100644 index 00000000..05ac8672 --- /dev/null +++ b/vendor/libgit2/src/cli/unix/sighandler.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include +#include "git2_util.h" +#include "common.h" +#include "sighandler.h" + +static void (*interrupt_handler)(void) = NULL; + +static void interrupt_proxy(int signal) +{ + GIT_UNUSED(signal); + interrupt_handler(); +} + +int cli_sighandler_set_interrupt(void (*handler)(void)) +{ + void (*result)(int); + + if ((interrupt_handler = handler) != NULL) + result = signal(SIGINT, interrupt_proxy); + else + result = signal(SIGINT, SIG_DFL); + + if (result == SIG_ERR) { + git_error_set(GIT_ERROR_OS, "could not set signal handler"); + return -1; + } + + return 0; +} diff --git a/vendor/libgit2/src/win32/precompiled.c b/vendor/libgit2/src/cli/win32/precompiled.c similarity index 100% rename from vendor/libgit2/src/win32/precompiled.c rename to vendor/libgit2/src/cli/win32/precompiled.c diff --git a/vendor/libgit2/src/cli/win32/precompiled.h b/vendor/libgit2/src/cli/win32/precompiled.h new file mode 100644 index 00000000..031370e8 --- /dev/null +++ b/vendor/libgit2/src/cli/win32/precompiled.h @@ -0,0 +1,3 @@ +#include + +#include "common.h" diff --git a/vendor/libgit2/src/cli/win32/sighandler.c b/vendor/libgit2/src/cli/win32/sighandler.c new file mode 100644 index 00000000..05a67fb1 --- /dev/null +++ b/vendor/libgit2/src/cli/win32/sighandler.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "git2_util.h" +#include + +#include "sighandler.h" + +static void (*interrupt_handler)(void) = NULL; + +static BOOL WINAPI interrupt_proxy(DWORD signal) +{ + GIT_UNUSED(signal); + interrupt_handler(); + return TRUE; +} + +int cli_sighandler_set_interrupt(void (*handler)(void)) +{ + BOOL result; + + if ((interrupt_handler = handler) != NULL) + result = SetConsoleCtrlHandler(interrupt_proxy, FALSE); + else + result = SetConsoleCtrlHandler(NULL, FALSE); + + if (!result) { + git_error_set(GIT_ERROR_OS, "could not set control control handler"); + return -1; + } + + return 0; +} diff --git a/vendor/libgit2/src/clone.c b/vendor/libgit2/src/clone.c deleted file mode 100644 index 1843875f..00000000 --- a/vendor/libgit2/src/clone.c +++ /dev/null @@ -1,655 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "clone.h" - -#include "git2/clone.h" -#include "git2/remote.h" -#include "git2/revparse.h" -#include "git2/branch.h" -#include "git2/config.h" -#include "git2/checkout.h" -#include "git2/commit.h" -#include "git2/tree.h" - -#include "remote.h" -#include "futils.h" -#include "refs.h" -#include "fs_path.h" -#include "repository.h" -#include "odb.h" - -static int clone_local_into(git_repository *repo, git_remote *remote, const git_fetch_options *fetch_opts, const git_checkout_options *co_opts, const char *branch, int link); - -static int create_branch( - git_reference **branch, - git_repository *repo, - const git_oid *target, - const char *name, - const char *log_message) -{ - git_commit *head_obj = NULL; - git_reference *branch_ref = NULL; - git_str refname = GIT_STR_INIT; - int error; - - /* Find the target commit */ - if ((error = git_commit_lookup(&head_obj, repo, target)) < 0) - return error; - - /* Create the new branch */ - if ((error = git_str_printf(&refname, GIT_REFS_HEADS_DIR "%s", name)) < 0) - return error; - - error = git_reference_create(&branch_ref, repo, git_str_cstr(&refname), target, 0, log_message); - git_str_dispose(&refname); - git_commit_free(head_obj); - - if (!error) - *branch = branch_ref; - else - git_reference_free(branch_ref); - - return error; -} - -static int setup_tracking_config( - git_repository *repo, - const char *branch_name, - const char *remote_name, - const char *merge_target) -{ - git_config *cfg; - git_str remote_key = GIT_STR_INIT, merge_key = GIT_STR_INIT; - int error = -1; - - if (git_repository_config__weakptr(&cfg, repo) < 0) - return -1; - - if (git_str_printf(&remote_key, "branch.%s.remote", branch_name) < 0) - goto cleanup; - - if (git_str_printf(&merge_key, "branch.%s.merge", branch_name) < 0) - goto cleanup; - - if (git_config_set_string(cfg, git_str_cstr(&remote_key), remote_name) < 0) - goto cleanup; - - if (git_config_set_string(cfg, git_str_cstr(&merge_key), merge_target) < 0) - goto cleanup; - - error = 0; - -cleanup: - git_str_dispose(&remote_key); - git_str_dispose(&merge_key); - return error; -} - -static int create_tracking_branch( - git_reference **branch, - git_repository *repo, - const git_oid *target, - const char *branch_name, - const char *log_message) -{ - int error; - - if ((error = create_branch(branch, repo, target, branch_name, log_message)) < 0) - return error; - - return setup_tracking_config( - repo, - branch_name, - GIT_REMOTE_ORIGIN, - git_reference_name(*branch)); -} - -static int update_head_to_new_branch( - git_repository *repo, - const git_oid *target, - const char *name, - const char *reflog_message) -{ - git_reference *tracking_branch = NULL; - int error; - - if (!git__prefixcmp(name, GIT_REFS_HEADS_DIR)) - name += strlen(GIT_REFS_HEADS_DIR); - - error = create_tracking_branch(&tracking_branch, repo, target, name, - reflog_message); - - if (!error) - error = git_repository_set_head( - repo, git_reference_name(tracking_branch)); - - git_reference_free(tracking_branch); - - /* if it already existed, then the user's refspec created it for us, ignore it' */ - if (error == GIT_EEXISTS) - error = 0; - - return error; -} - -static int update_head_to_default(git_repository *repo) -{ - git_str initialbranch = GIT_STR_INIT; - const char *branch_name; - int error = 0; - - if ((error = git_repository_initialbranch(&initialbranch, repo)) < 0) - goto done; - - if (git__prefixcmp(initialbranch.ptr, GIT_REFS_HEADS_DIR) != 0) { - git_error_set(GIT_ERROR_INVALID, "invalid initial branch '%s'", initialbranch.ptr); - error = -1; - goto done; - } - - branch_name = initialbranch.ptr + strlen(GIT_REFS_HEADS_DIR); - - error = setup_tracking_config(repo, branch_name, GIT_REMOTE_ORIGIN, - initialbranch.ptr); - -done: - git_str_dispose(&initialbranch); - return error; -} - -static int update_remote_head( - git_repository *repo, - git_remote *remote, - git_str *target, - const char *reflog_message) -{ - git_refspec *refspec; - git_reference *remote_head = NULL; - git_str remote_head_name = GIT_STR_INIT; - git_str remote_branch_name = GIT_STR_INIT; - int error; - - /* Determine the remote tracking ref name from the local branch */ - refspec = git_remote__matching_refspec(remote, git_str_cstr(target)); - - if (refspec == NULL) { - git_error_set(GIT_ERROR_NET, "the remote's default branch does not fit the refspec configuration"); - error = GIT_EINVALIDSPEC; - goto cleanup; - } - - if ((error = git_refspec__transform( - &remote_branch_name, - refspec, - git_str_cstr(target))) < 0) - goto cleanup; - - if ((error = git_str_printf(&remote_head_name, - "%s%s/%s", - GIT_REFS_REMOTES_DIR, - git_remote_name(remote), - GIT_HEAD_FILE)) < 0) - goto cleanup; - - error = git_reference_symbolic_create( - &remote_head, - repo, - git_str_cstr(&remote_head_name), - git_str_cstr(&remote_branch_name), - true, - reflog_message); - -cleanup: - git_reference_free(remote_head); - git_str_dispose(&remote_branch_name); - git_str_dispose(&remote_head_name); - return error; -} - -static int update_head_to_remote( - git_repository *repo, - git_remote *remote, - const char *reflog_message) -{ - int error = 0; - size_t refs_len; - const git_remote_head *remote_head, **refs; - const git_oid *remote_head_id; - git_str branch = GIT_STR_INIT; - - if ((error = git_remote_ls(&refs, &refs_len, remote)) < 0) - return error; - - /* We cloned an empty repository or one with an unborn HEAD */ - if (refs_len == 0 || strcmp(refs[0]->name, GIT_HEAD_FILE)) - return update_head_to_default(repo); - - /* We know we have HEAD, let's see where it points */ - remote_head = refs[0]; - GIT_ASSERT(remote_head); - - remote_head_id = &remote_head->oid; - - error = git_remote__default_branch(&branch, remote); - if (error == GIT_ENOTFOUND) { - error = git_repository_set_head_detached( - repo, remote_head_id); - goto cleanup; - } - - if ((error = update_remote_head(repo, remote, &branch, reflog_message)) < 0) - goto cleanup; - - error = update_head_to_new_branch( - repo, - remote_head_id, - git_str_cstr(&branch), - reflog_message); - -cleanup: - git_str_dispose(&branch); - - return error; -} - -static int update_head_to_branch( - git_repository *repo, - git_remote *remote, - const char *branch, - const char *reflog_message) -{ - int retcode; - git_str remote_branch_name = GIT_STR_INIT; - git_reference *remote_ref = NULL; - git_str default_branch = GIT_STR_INIT; - - GIT_ASSERT_ARG(remote); - GIT_ASSERT_ARG(branch); - - if ((retcode = git_str_printf(&remote_branch_name, GIT_REFS_REMOTES_DIR "%s/%s", - git_remote_name(remote), branch)) < 0 ) - goto cleanup; - - if ((retcode = git_reference_lookup(&remote_ref, repo, git_str_cstr(&remote_branch_name))) < 0) - goto cleanup; - - if ((retcode = update_head_to_new_branch(repo, git_reference_target(remote_ref), branch, - reflog_message)) < 0) - goto cleanup; - - if ((retcode = git_remote__default_branch(&default_branch, remote)) < 0) - goto cleanup; - - if (!git_remote__matching_refspec(remote, git_str_cstr(&default_branch))) - goto cleanup; - - retcode = update_remote_head(repo, remote, &default_branch, reflog_message); - -cleanup: - git_reference_free(remote_ref); - git_str_dispose(&remote_branch_name); - git_str_dispose(&default_branch); - return retcode; -} - -static int default_repository_create(git_repository **out, const char *path, int bare, void *payload) -{ - GIT_UNUSED(payload); - - return git_repository_init(out, path, bare); -} - -static int default_remote_create( - git_remote **out, - git_repository *repo, - const char *name, - const char *url, - void *payload) -{ - GIT_UNUSED(payload); - - return git_remote_create(out, repo, name, url); -} - -/* - * submodules? - */ - -static int create_and_configure_origin( - git_remote **out, - git_repository *repo, - const char *url, - const git_clone_options *options) -{ - int error; - git_remote *origin = NULL; - char buf[GIT_PATH_MAX]; - git_remote_create_cb remote_create = options->remote_cb; - void *payload = options->remote_cb_payload; - - /* If the path exists and is a dir, the url should be the absolute path */ - if (git_fs_path_root(url) < 0 && git_fs_path_exists(url) && git_fs_path_isdir(url)) { - if (p_realpath(url, buf) == NULL) - return -1; - - url = buf; - } - - if (!remote_create) { - remote_create = default_remote_create; - payload = NULL; - } - - if ((error = remote_create(&origin, repo, "origin", url, payload)) < 0) - goto on_error; - - *out = origin; - return 0; - -on_error: - git_remote_free(origin); - return error; -} - -static bool should_checkout( - git_repository *repo, - bool is_bare, - const git_checkout_options *opts) -{ - if (is_bare) - return false; - - if (!opts) - return false; - - if (opts->checkout_strategy == GIT_CHECKOUT_NONE) - return false; - - return !git_repository_head_unborn(repo); -} - -static int checkout_branch(git_repository *repo, git_remote *remote, const git_checkout_options *co_opts, const char *branch, const char *reflog_message) -{ - int error; - - if (branch) - error = update_head_to_branch(repo, remote, branch, reflog_message); - /* Point HEAD to the same ref as the remote's head */ - else - error = update_head_to_remote(repo, remote, reflog_message); - - if (!error && should_checkout(repo, git_repository_is_bare(repo), co_opts)) - error = git_checkout_head(repo, co_opts); - - return error; -} - -static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch_options *opts, const git_checkout_options *co_opts, const char *branch) -{ - int error; - git_str reflog_message = GIT_STR_INIT; - git_fetch_options fetch_opts; - git_remote *remote; - - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(_remote); - - if (!git_repository_is_empty(repo)) { - git_error_set(GIT_ERROR_INVALID, "the repository is not empty"); - return -1; - } - - if ((error = git_remote_dup(&remote, _remote)) < 0) - return error; - - memcpy(&fetch_opts, opts, sizeof(git_fetch_options)); - fetch_opts.update_fetchhead = 0; - fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL; - git_str_printf(&reflog_message, "clone: from %s", git_remote_url(remote)); - - if ((error = git_remote_fetch(remote, NULL, &fetch_opts, git_str_cstr(&reflog_message))) != 0) - goto cleanup; - - error = checkout_branch(repo, remote, co_opts, branch, git_str_cstr(&reflog_message)); - -cleanup: - git_remote_free(remote); - git_str_dispose(&reflog_message); - - return error; -} - -int git_clone__should_clone_local(const char *url_or_path, git_clone_local_t local) -{ - git_str fromurl = GIT_STR_INIT; - const char *path = url_or_path; - bool is_url, is_local; - - if (local == GIT_CLONE_NO_LOCAL) - return 0; - - if ((is_url = git_fs_path_is_local_file_url(url_or_path)) != 0) { - if (git_fs_path_fromurl(&fromurl, url_or_path) < 0) { - is_local = -1; - goto done; - } - - path = fromurl.ptr; - } - - is_local = (!is_url || local != GIT_CLONE_LOCAL_AUTO) && - git_fs_path_isdir(path); - -done: - git_str_dispose(&fromurl); - return is_local; -} - -static int git__clone( - git_repository **out, - const char *url, - const char *local_path, - const git_clone_options *_options, - int use_existing) -{ - int error = 0; - git_repository *repo = NULL; - git_remote *origin; - git_clone_options options = GIT_CLONE_OPTIONS_INIT; - uint32_t rmdir_flags = GIT_RMDIR_REMOVE_FILES; - git_repository_create_cb repository_cb; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(url); - GIT_ASSERT_ARG(local_path); - - if (_options) - memcpy(&options, _options, sizeof(git_clone_options)); - - GIT_ERROR_CHECK_VERSION(&options, GIT_CLONE_OPTIONS_VERSION, "git_clone_options"); - - /* Only clone to a new directory or an empty directory */ - if (git_fs_path_exists(local_path) && !use_existing && !git_fs_path_is_empty_dir(local_path)) { - git_error_set(GIT_ERROR_INVALID, - "'%s' exists and is not an empty directory", local_path); - return GIT_EEXISTS; - } - - /* Only remove the root directory on failure if we create it */ - if (git_fs_path_exists(local_path)) - rmdir_flags |= GIT_RMDIR_SKIP_ROOT; - - if (options.repository_cb) - repository_cb = options.repository_cb; - else - repository_cb = default_repository_create; - - if ((error = repository_cb(&repo, local_path, options.bare, options.repository_cb_payload)) < 0) - return error; - - if (!(error = create_and_configure_origin(&origin, repo, url, &options))) { - int clone_local = git_clone__should_clone_local(url, options.local); - int link = options.local != GIT_CLONE_LOCAL_NO_LINKS; - - if (clone_local == 1) - error = clone_local_into( - repo, origin, &options.fetch_opts, &options.checkout_opts, - options.checkout_branch, link); - else if (clone_local == 0) - error = clone_into( - repo, origin, &options.fetch_opts, &options.checkout_opts, - options.checkout_branch); - else - error = -1; - - git_remote_free(origin); - } - - if (error != 0) { - git_error_state last_error = {0}; - git_error_state_capture(&last_error, error); - - git_repository_free(repo); - repo = NULL; - - (void)git_futils_rmdir_r(local_path, NULL, rmdir_flags); - - git_error_state_restore(&last_error); - } - - *out = repo; - return error; -} - -int git_clone( - git_repository **out, - const char *url, - const char *local_path, - const git_clone_options *_options) -{ - return git__clone(out, url, local_path, _options, 0); -} - -int git_clone__submodule( - git_repository **out, - const char *url, - const char *local_path, - const git_clone_options *_options) -{ - return git__clone(out, url, local_path, _options, 1); -} - -int git_clone_options_init(git_clone_options *opts, unsigned int version) -{ - GIT_INIT_STRUCTURE_FROM_TEMPLATE( - opts, version, git_clone_options, GIT_CLONE_OPTIONS_INIT); - return 0; -} - -#ifndef GIT_DEPRECATE_HARD -int git_clone_init_options(git_clone_options *opts, unsigned int version) -{ - return git_clone_options_init(opts, version); -} -#endif - -static bool can_link(const char *src, const char *dst, int link) -{ -#ifdef GIT_WIN32 - GIT_UNUSED(src); - GIT_UNUSED(dst); - GIT_UNUSED(link); - return false; -#else - - struct stat st_src, st_dst; - - if (!link) - return false; - - if (p_stat(src, &st_src) < 0) - return false; - - if (p_stat(dst, &st_dst) < 0) - return false; - - return st_src.st_dev == st_dst.st_dev; -#endif -} - -static int clone_local_into(git_repository *repo, git_remote *remote, const git_fetch_options *fetch_opts, const git_checkout_options *co_opts, const char *branch, int link) -{ - int error, flags; - git_repository *src; - git_str src_odb = GIT_STR_INIT, dst_odb = GIT_STR_INIT, src_path = GIT_STR_INIT; - git_str reflog_message = GIT_STR_INIT; - - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(remote); - - if (!git_repository_is_empty(repo)) { - git_error_set(GIT_ERROR_INVALID, "the repository is not empty"); - return -1; - } - - /* - * Let's figure out what path we should use for the source - * repo, if it's not rooted, the path should be relative to - * the repository's worktree/gitdir. - */ - if ((error = git_fs_path_from_url_or_path(&src_path, git_remote_url(remote))) < 0) - return error; - - /* Copy .git/objects/ from the source to the target */ - if ((error = git_repository_open(&src, git_str_cstr(&src_path))) < 0) { - git_str_dispose(&src_path); - return error; - } - - if (git_repository__item_path(&src_odb, src, GIT_REPOSITORY_ITEM_OBJECTS) < 0 || - git_repository__item_path(&dst_odb, repo, GIT_REPOSITORY_ITEM_OBJECTS) < 0) { - error = -1; - goto cleanup; - } - - flags = 0; - if (can_link(git_repository_path(src), git_repository_path(repo), link)) - flags |= GIT_CPDIR_LINK_FILES; - - error = git_futils_cp_r(git_str_cstr(&src_odb), git_str_cstr(&dst_odb), - flags, GIT_OBJECT_DIR_MODE); - - /* - * can_link() doesn't catch all variations, so if we hit an - * error and did want to link, let's try again without trying - * to link. - */ - if (error < 0 && link) { - flags &= ~GIT_CPDIR_LINK_FILES; - error = git_futils_cp_r(git_str_cstr(&src_odb), git_str_cstr(&dst_odb), - flags, GIT_OBJECT_DIR_MODE); - } - - if (error < 0) - goto cleanup; - - git_str_printf(&reflog_message, "clone: from %s", git_remote_url(remote)); - - if ((error = git_remote_fetch(remote, NULL, fetch_opts, git_str_cstr(&reflog_message))) != 0) - goto cleanup; - - error = checkout_branch(repo, remote, co_opts, branch, git_str_cstr(&reflog_message)); - -cleanup: - git_str_dispose(&reflog_message); - git_str_dispose(&src_path); - git_str_dispose(&src_odb); - git_str_dispose(&dst_odb); - git_repository_free(src); - return error; -} diff --git a/vendor/libgit2/src/commit.c b/vendor/libgit2/src/commit.c deleted file mode 100644 index b137463f..00000000 --- a/vendor/libgit2/src/commit.c +++ /dev/null @@ -1,1042 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "commit.h" - -#include "git2/common.h" -#include "git2/object.h" -#include "git2/repository.h" -#include "git2/signature.h" -#include "git2/mailmap.h" -#include "git2/sys/commit.h" - -#include "buf.h" -#include "odb.h" -#include "commit.h" -#include "signature.h" -#include "refs.h" -#include "object.h" -#include "array.h" -#include "oidarray.h" - -void git_commit__free(void *_commit) -{ - git_commit *commit = _commit; - - git_array_clear(commit->parent_ids); - - git_signature_free(commit->author); - git_signature_free(commit->committer); - - git__free(commit->raw_header); - git__free(commit->raw_message); - git__free(commit->message_encoding); - git__free(commit->summary); - git__free(commit->body); - - git__free(commit); -} - -static int git_commit__create_buffer_internal( - git_str *out, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_oid *tree, - git_array_oid_t *parents) -{ - size_t i = 0; - const git_oid *parent; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(tree); - - git_oid__writebuf(out, "tree ", tree); - - for (i = 0; i < git_array_size(*parents); i++) { - parent = git_array_get(*parents, i); - git_oid__writebuf(out, "parent ", parent); - } - - git_signature__writebuf(out, "author ", author); - git_signature__writebuf(out, "committer ", committer); - - if (message_encoding != NULL) - git_str_printf(out, "encoding %s\n", message_encoding); - - git_str_putc(out, '\n'); - - if (git_str_puts(out, message) < 0) - goto on_error; - - return 0; - -on_error: - git_str_dispose(out); - return -1; -} - -static int validate_tree_and_parents(git_array_oid_t *parents, git_repository *repo, const git_oid *tree, - git_commit_parent_callback parent_cb, void *parent_payload, - const git_oid *current_id, bool validate) -{ - size_t i; - int error; - git_oid *parent_cpy; - const git_oid *parent; - - if (validate && !git_object__is_valid(repo, tree, GIT_OBJECT_TREE)) - return -1; - - i = 0; - while ((parent = parent_cb(i, parent_payload)) != NULL) { - if (validate && !git_object__is_valid(repo, parent, GIT_OBJECT_COMMIT)) { - error = -1; - goto on_error; - } - - parent_cpy = git_array_alloc(*parents); - GIT_ERROR_CHECK_ALLOC(parent_cpy); - - git_oid_cpy(parent_cpy, parent); - i++; - } - - if (current_id && (parents->size == 0 || git_oid_cmp(current_id, git_array_get(*parents, 0)))) { - git_error_set(GIT_ERROR_OBJECT, "failed to create commit: current tip is not the first parent"); - error = GIT_EMODIFIED; - goto on_error; - } - - return 0; - -on_error: - git_array_clear(*parents); - return error; -} - -static int git_commit__create_internal( - git_oid *id, - git_repository *repo, - const char *update_ref, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_oid *tree, - git_commit_parent_callback parent_cb, - void *parent_payload, - bool validate) -{ - int error; - git_odb *odb; - git_reference *ref = NULL; - git_str buf = GIT_STR_INIT; - const git_oid *current_id = NULL; - git_array_oid_t parents = GIT_ARRAY_INIT; - - if (update_ref) { - error = git_reference_lookup_resolved(&ref, repo, update_ref, 10); - if (error < 0 && error != GIT_ENOTFOUND) - return error; - } - git_error_clear(); - - if (ref) - current_id = git_reference_target(ref); - - if ((error = validate_tree_and_parents(&parents, repo, tree, parent_cb, parent_payload, current_id, validate)) < 0) - goto cleanup; - - error = git_commit__create_buffer_internal(&buf, author, committer, - message_encoding, message, tree, - &parents); - - if (error < 0) - goto cleanup; - - if (git_repository_odb__weakptr(&odb, repo) < 0) - goto cleanup; - - if (git_odb__freshen(odb, tree) < 0) - goto cleanup; - - if (git_odb_write(id, odb, buf.ptr, buf.size, GIT_OBJECT_COMMIT) < 0) - goto cleanup; - - - if (update_ref != NULL) { - error = git_reference__update_for_commit( - repo, ref, update_ref, id, "commit"); - goto cleanup; - } - -cleanup: - git_array_clear(parents); - git_reference_free(ref); - git_str_dispose(&buf); - return error; -} - -int git_commit_create_from_callback( - git_oid *id, - git_repository *repo, - const char *update_ref, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_oid *tree, - git_commit_parent_callback parent_cb, - void *parent_payload) -{ - return git_commit__create_internal( - id, repo, update_ref, author, committer, message_encoding, message, - tree, parent_cb, parent_payload, true); -} - -typedef struct { - size_t total; - va_list args; -} commit_parent_varargs; - -static const git_oid *commit_parent_from_varargs(size_t curr, void *payload) -{ - commit_parent_varargs *data = payload; - const git_commit *commit; - if (curr >= data->total) - return NULL; - commit = va_arg(data->args, const git_commit *); - return commit ? git_commit_id(commit) : NULL; -} - -int git_commit_create_v( - git_oid *id, - git_repository *repo, - const char *update_ref, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_tree *tree, - size_t parent_count, - ...) -{ - int error = 0; - commit_parent_varargs data; - - GIT_ASSERT_ARG(tree); - GIT_ASSERT_ARG(git_tree_owner(tree) == repo); - - data.total = parent_count; - va_start(data.args, parent_count); - - error = git_commit__create_internal( - id, repo, update_ref, author, committer, - message_encoding, message, git_tree_id(tree), - commit_parent_from_varargs, &data, false); - - va_end(data.args); - return error; -} - -typedef struct { - size_t total; - const git_oid **parents; -} commit_parent_oids; - -static const git_oid *commit_parent_from_ids(size_t curr, void *payload) -{ - commit_parent_oids *data = payload; - return (curr < data->total) ? data->parents[curr] : NULL; -} - -int git_commit_create_from_ids( - git_oid *id, - git_repository *repo, - const char *update_ref, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_oid *tree, - size_t parent_count, - const git_oid *parents[]) -{ - commit_parent_oids data = { parent_count, parents }; - - return git_commit__create_internal( - id, repo, update_ref, author, committer, - message_encoding, message, tree, - commit_parent_from_ids, &data, true); -} - -typedef struct { - size_t total; - const git_commit **parents; - git_repository *repo; -} commit_parent_data; - -static const git_oid *commit_parent_from_array(size_t curr, void *payload) -{ - commit_parent_data *data = payload; - const git_commit *commit; - if (curr >= data->total) - return NULL; - commit = data->parents[curr]; - if (git_commit_owner(commit) != data->repo) - return NULL; - return git_commit_id(commit); -} - -int git_commit_create( - git_oid *id, - git_repository *repo, - const char *update_ref, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_tree *tree, - size_t parent_count, - const git_commit *parents[]) -{ - commit_parent_data data = { parent_count, parents, repo }; - - GIT_ASSERT_ARG(tree); - GIT_ASSERT_ARG(git_tree_owner(tree) == repo); - - return git_commit__create_internal( - id, repo, update_ref, author, committer, - message_encoding, message, git_tree_id(tree), - commit_parent_from_array, &data, false); -} - -static const git_oid *commit_parent_for_amend(size_t curr, void *payload) -{ - const git_commit *commit_to_amend = payload; - if (curr >= git_array_size(commit_to_amend->parent_ids)) - return NULL; - return git_array_get(commit_to_amend->parent_ids, curr); -} - -int git_commit_amend( - git_oid *id, - const git_commit *commit_to_amend, - const char *update_ref, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_tree *tree) -{ - git_repository *repo; - git_oid tree_id; - git_reference *ref; - int error; - - GIT_ASSERT_ARG(id); - GIT_ASSERT_ARG(commit_to_amend); - - repo = git_commit_owner(commit_to_amend); - - if (!author) - author = git_commit_author(commit_to_amend); - if (!committer) - committer = git_commit_committer(commit_to_amend); - if (!message_encoding) - message_encoding = git_commit_message_encoding(commit_to_amend); - if (!message) - message = git_commit_message(commit_to_amend); - - if (!tree) { - git_tree *old_tree; - GIT_ERROR_CHECK_ERROR( git_commit_tree(&old_tree, commit_to_amend) ); - git_oid_cpy(&tree_id, git_tree_id(old_tree)); - git_tree_free(old_tree); - } else { - GIT_ASSERT_ARG(git_tree_owner(tree) == repo); - git_oid_cpy(&tree_id, git_tree_id(tree)); - } - - if (update_ref) { - if ((error = git_reference_lookup_resolved(&ref, repo, update_ref, 5)) < 0) - return error; - - if (git_oid_cmp(git_commit_id(commit_to_amend), git_reference_target(ref))) { - git_reference_free(ref); - git_error_set(GIT_ERROR_REFERENCE, "commit to amend is not the tip of the given branch"); - return -1; - } - } - - error = git_commit__create_internal( - id, repo, NULL, author, committer, message_encoding, message, - &tree_id, commit_parent_for_amend, (void *)commit_to_amend, false); - - if (!error && update_ref) { - error = git_reference__update_for_commit( - repo, ref, NULL, id, "commit"); - git_reference_free(ref); - } - - return error; -} - -static int commit_parse(git_commit *commit, const char *data, size_t size, unsigned int flags) -{ - const char *buffer_start = data, *buffer; - const char *buffer_end = buffer_start + size; - git_oid parent_id; - size_t header_len; - git_signature dummy_sig; - int error; - - GIT_ASSERT_ARG(commit); - GIT_ASSERT_ARG(data); - - buffer = buffer_start; - - /* Allocate for one, which will allow not to realloc 90% of the time */ - git_array_init_to_size(commit->parent_ids, 1); - GIT_ERROR_CHECK_ARRAY(commit->parent_ids); - - /* The tree is always the first field */ - if (!(flags & GIT_COMMIT_PARSE_QUICK)) { - if (git_oid__parse(&commit->tree_id, &buffer, buffer_end, "tree ") < 0) - goto bad_buffer; - } else { - size_t tree_len = strlen("tree ") + GIT_OID_HEXSZ + 1; - if (buffer + tree_len > buffer_end) - goto bad_buffer; - buffer += tree_len; - } - - /* - * TODO: commit grafts! - */ - - while (git_oid__parse(&parent_id, &buffer, buffer_end, "parent ") == 0) { - git_oid *new_id = git_array_alloc(commit->parent_ids); - GIT_ERROR_CHECK_ALLOC(new_id); - - git_oid_cpy(new_id, &parent_id); - } - - if (!(flags & GIT_COMMIT_PARSE_QUICK)) { - commit->author = git__malloc(sizeof(git_signature)); - GIT_ERROR_CHECK_ALLOC(commit->author); - - if ((error = git_signature__parse(commit->author, &buffer, buffer_end, "author ", '\n')) < 0) - return error; - } - - /* Some tools create multiple author fields, ignore the extra ones */ - while (!git__prefixncmp(buffer, buffer_end - buffer, "author ")) { - if ((error = git_signature__parse(&dummy_sig, &buffer, buffer_end, "author ", '\n')) < 0) - return error; - - git__free(dummy_sig.name); - git__free(dummy_sig.email); - } - - /* Always parse the committer; we need the commit time */ - commit->committer = git__malloc(sizeof(git_signature)); - GIT_ERROR_CHECK_ALLOC(commit->committer); - - if ((error = git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n')) < 0) - return error; - - if (flags & GIT_COMMIT_PARSE_QUICK) - return 0; - - /* Parse add'l header entries */ - while (buffer < buffer_end) { - const char *eoln = buffer; - if (buffer[-1] == '\n' && buffer[0] == '\n') - break; - - while (eoln < buffer_end && *eoln != '\n') - ++eoln; - - if (git__prefixncmp(buffer, buffer_end - buffer, "encoding ") == 0) { - buffer += strlen("encoding "); - - commit->message_encoding = git__strndup(buffer, eoln - buffer); - GIT_ERROR_CHECK_ALLOC(commit->message_encoding); - } - - if (eoln < buffer_end && *eoln == '\n') - ++eoln; - buffer = eoln; - } - - header_len = buffer - buffer_start; - commit->raw_header = git__strndup(buffer_start, header_len); - GIT_ERROR_CHECK_ALLOC(commit->raw_header); - - /* point "buffer" to data after header, +1 for the final LF */ - buffer = buffer_start + header_len + 1; - - /* extract commit message */ - if (buffer <= buffer_end) - commit->raw_message = git__strndup(buffer, buffer_end - buffer); - else - commit->raw_message = git__strdup(""); - GIT_ERROR_CHECK_ALLOC(commit->raw_message); - - return 0; - -bad_buffer: - git_error_set(GIT_ERROR_OBJECT, "failed to parse bad commit object"); - return GIT_EINVALID; -} - -int git_commit__parse_raw(void *commit, const char *data, size_t size) -{ - return commit_parse(commit, data, size, 0); -} - -int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned int flags) -{ - return commit_parse(commit, git_odb_object_data(odb_obj), git_odb_object_size(odb_obj), flags); -} - -int git_commit__parse(void *_commit, git_odb_object *odb_obj) -{ - return git_commit__parse_ext(_commit, odb_obj, 0); -} - -#define GIT_COMMIT_GETTER(_rvalue, _name, _return, _invalid) \ - _rvalue git_commit_##_name(const git_commit *commit) \ - {\ - GIT_ASSERT_ARG_WITH_RETVAL(commit, _invalid); \ - return _return; \ - } - -GIT_COMMIT_GETTER(const git_signature *, author, commit->author, NULL) -GIT_COMMIT_GETTER(const git_signature *, committer, commit->committer, NULL) -GIT_COMMIT_GETTER(const char *, message_raw, commit->raw_message, NULL) -GIT_COMMIT_GETTER(const char *, message_encoding, commit->message_encoding, NULL) -GIT_COMMIT_GETTER(const char *, raw_header, commit->raw_header, NULL) -GIT_COMMIT_GETTER(git_time_t, time, commit->committer->when.time, INT64_MIN) -GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset, -1) -GIT_COMMIT_GETTER(unsigned int, parentcount, (unsigned int)git_array_size(commit->parent_ids), 0) -GIT_COMMIT_GETTER(const git_oid *, tree_id, &commit->tree_id, NULL) - -const char *git_commit_message(const git_commit *commit) -{ - const char *message; - - GIT_ASSERT_ARG_WITH_RETVAL(commit, NULL); - - message = commit->raw_message; - - /* trim leading newlines from raw message */ - while (*message && *message == '\n') - ++message; - - return message; -} - -const char *git_commit_summary(git_commit *commit) -{ - git_str summary = GIT_STR_INIT; - const char *msg, *space, *next; - bool space_contains_newline = false; - - GIT_ASSERT_ARG_WITH_RETVAL(commit, NULL); - - if (!commit->summary) { - for (msg = git_commit_message(commit), space = NULL; *msg; ++msg) { - char next_character = msg[0]; - /* stop processing at the end of the first paragraph */ - if (next_character == '\n') { - if (!msg[1]) - break; - if (msg[1] == '\n') - break; - /* stop processing if next line contains only whitespace */ - next = msg + 1; - while (*next && git__isspace_nonlf(*next)) { - ++next; - } - if (!*next || *next == '\n') - break; - } - /* record the beginning of contiguous whitespace runs */ - if (git__isspace(next_character)) { - if(space == NULL) { - space = msg; - space_contains_newline = false; - } - space_contains_newline |= next_character == '\n'; - } - /* the next character is non-space */ - else { - /* process any recorded whitespace */ - if (space) { - if(space_contains_newline) - git_str_putc(&summary, ' '); /* if the space contains a newline, collapse to ' ' */ - else - git_str_put(&summary, space, (msg - space)); /* otherwise copy it */ - space = NULL; - } - /* copy the next character */ - git_str_putc(&summary, next_character); - } - } - - commit->summary = git_str_detach(&summary); - if (!commit->summary) - commit->summary = git__strdup(""); - } - - return commit->summary; -} - -const char *git_commit_body(git_commit *commit) -{ - const char *msg, *end; - - GIT_ASSERT_ARG_WITH_RETVAL(commit, NULL); - - if (!commit->body) { - /* search for end of summary */ - for (msg = git_commit_message(commit); *msg; ++msg) - if (msg[0] == '\n' && (!msg[1] || msg[1] == '\n')) - break; - - /* trim leading and trailing whitespace */ - for (; *msg; ++msg) - if (!git__isspace(*msg)) - break; - for (end = msg + strlen(msg) - 1; msg <= end; --end) - if (!git__isspace(*end)) - break; - - if (*msg) - commit->body = git__strndup(msg, end - msg + 1); - } - - return commit->body; -} - -int git_commit_tree(git_tree **tree_out, const git_commit *commit) -{ - GIT_ASSERT_ARG(commit); - return git_tree_lookup(tree_out, commit->object.repo, &commit->tree_id); -} - -const git_oid *git_commit_parent_id( - const git_commit *commit, unsigned int n) -{ - GIT_ASSERT_ARG_WITH_RETVAL(commit, NULL); - - return git_array_get(commit->parent_ids, n); -} - -int git_commit_parent( - git_commit **parent, const git_commit *commit, unsigned int n) -{ - const git_oid *parent_id; - GIT_ASSERT_ARG(commit); - - parent_id = git_commit_parent_id(commit, n); - if (parent_id == NULL) { - git_error_set(GIT_ERROR_INVALID, "parent %u does not exist", n); - return GIT_ENOTFOUND; - } - - return git_commit_lookup(parent, commit->object.repo, parent_id); -} - -int git_commit_nth_gen_ancestor( - git_commit **ancestor, - const git_commit *commit, - unsigned int n) -{ - git_commit *current, *parent = NULL; - int error; - - GIT_ASSERT_ARG(ancestor); - GIT_ASSERT_ARG(commit); - - if (git_commit_dup(¤t, (git_commit *)commit) < 0) - return -1; - - if (n == 0) { - *ancestor = current; - return 0; - } - - while (n--) { - error = git_commit_parent(&parent, current, 0); - - git_commit_free(current); - - if (error < 0) - return error; - - current = parent; - } - - *ancestor = parent; - return 0; -} - -int git_commit_header_field( - git_buf *out, - const git_commit *commit, - const char *field) -{ - GIT_BUF_WRAP_PRIVATE(out, git_commit__header_field, commit, field); -} - -int git_commit__header_field( - git_str *out, - const git_commit *commit, - const char *field) -{ - const char *eol, *buf = commit->raw_header; - - git_str_clear(out); - - while ((eol = strchr(buf, '\n'))) { - /* We can skip continuations here */ - if (buf[0] == ' ') { - buf = eol + 1; - continue; - } - - /* Skip until we find the field we're after */ - if (git__prefixcmp(buf, field)) { - buf = eol + 1; - continue; - } - - buf += strlen(field); - /* Check that we're not matching a prefix but the field itself */ - if (buf[0] != ' ') { - buf = eol + 1; - continue; - } - - buf++; /* skip the SP */ - - git_str_put(out, buf, eol - buf); - if (git_str_oom(out)) - goto oom; - - /* If the next line starts with SP, it's multi-line, we must continue */ - while (eol[1] == ' ') { - git_str_putc(out, '\n'); - buf = eol + 2; - eol = strchr(buf, '\n'); - if (!eol) - goto malformed; - - git_str_put(out, buf, eol - buf); - } - - if (git_str_oom(out)) - goto oom; - - return 0; - } - - git_error_set(GIT_ERROR_OBJECT, "no such field '%s'", field); - return GIT_ENOTFOUND; - -malformed: - git_error_set(GIT_ERROR_OBJECT, "malformed header"); - return -1; -oom: - git_error_set_oom(); - return -1; -} - -int git_commit_extract_signature( - git_buf *signature_out, - git_buf *signed_data_out, - git_repository *repo, - git_oid *commit_id, - const char *field) -{ - git_str signature = GIT_STR_INIT, signed_data = GIT_STR_INIT; - int error; - - if ((error = git_buf_tostr(&signature, signature_out)) < 0 || - (error = git_buf_tostr(&signed_data, signed_data_out)) < 0 || - (error = git_commit__extract_signature(&signature, &signed_data, repo, commit_id, field)) < 0 || - (error = git_buf_fromstr(signature_out, &signature)) < 0 || - (error = git_buf_fromstr(signed_data_out, &signed_data)) < 0) - goto done; - -done: - git_str_dispose(&signature); - git_str_dispose(&signed_data); - return error; -} - -int git_commit__extract_signature( - git_str *signature, - git_str *signed_data, - git_repository *repo, - git_oid *commit_id, - const char *field) -{ - git_odb_object *obj; - git_odb *odb; - const char *buf; - const char *h, *eol; - int error; - - git_str_clear(signature); - git_str_clear(signed_data); - - if (!field) - field = "gpgsig"; - - if ((error = git_repository_odb__weakptr(&odb, repo)) < 0) - return error; - - if ((error = git_odb_read(&obj, odb, commit_id)) < 0) - return error; - - if (obj->cached.type != GIT_OBJECT_COMMIT) { - git_error_set(GIT_ERROR_INVALID, "the requested type does not match the type in the ODB"); - error = GIT_ENOTFOUND; - goto cleanup; - } - - buf = git_odb_object_data(obj); - - while ((h = strchr(buf, '\n')) && h[1] != '\0') { - h++; - if (git__prefixcmp(buf, field)) { - if (git_str_put(signed_data, buf, h - buf) < 0) - return -1; - - buf = h; - continue; - } - - h = buf; - h += strlen(field); - eol = strchr(h, '\n'); - if (h[0] != ' ') { - buf = h; - continue; - } - if (!eol) - goto malformed; - - h++; /* skip the SP */ - - git_str_put(signature, h, eol - h); - if (git_str_oom(signature)) - goto oom; - - /* If the next line starts with SP, it's multi-line, we must continue */ - while (eol[1] == ' ') { - git_str_putc(signature, '\n'); - h = eol + 2; - eol = strchr(h, '\n'); - if (!eol) - goto malformed; - - git_str_put(signature, h, eol - h); - } - - if (git_str_oom(signature)) - goto oom; - - error = git_str_puts(signed_data, eol+1); - git_odb_object_free(obj); - return error; - } - - git_error_set(GIT_ERROR_OBJECT, "this commit is not signed"); - error = GIT_ENOTFOUND; - goto cleanup; - -malformed: - git_error_set(GIT_ERROR_OBJECT, "malformed header"); - error = -1; - goto cleanup; -oom: - git_error_set_oom(); - error = -1; - goto cleanup; - -cleanup: - git_odb_object_free(obj); - git_str_clear(signature); - git_str_clear(signed_data); - return error; -} - -int git_commit_create_buffer( - git_buf *out, - git_repository *repo, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_tree *tree, - size_t parent_count, - const git_commit *parents[]) -{ - GIT_BUF_WRAP_PRIVATE(out, git_commit__create_buffer, repo, - author, committer, message_encoding, message, - tree, parent_count, parents); -} - -int git_commit__create_buffer( - git_str *out, - git_repository *repo, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_tree *tree, - size_t parent_count, - const git_commit *parents[]) -{ - int error; - commit_parent_data data = { parent_count, parents, repo }; - git_array_oid_t parents_arr = GIT_ARRAY_INIT; - const git_oid *tree_id; - - GIT_ASSERT_ARG(tree); - GIT_ASSERT_ARG(git_tree_owner(tree) == repo); - - tree_id = git_tree_id(tree); - - if ((error = validate_tree_and_parents(&parents_arr, repo, tree_id, commit_parent_from_array, &data, NULL, true)) < 0) - return error; - - error = git_commit__create_buffer_internal( - out, author, committer, - message_encoding, message, tree_id, - &parents_arr); - - git_array_clear(parents_arr); - return error; -} - -/** - * Append to 'out' properly marking continuations when there's a newline in 'content' - */ -static int format_header_field(git_str *out, const char *field, const char *content) -{ - const char *lf; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(field); - GIT_ASSERT_ARG(content); - - git_str_puts(out, field); - git_str_putc(out, ' '); - - while ((lf = strchr(content, '\n')) != NULL) { - git_str_put(out, content, lf - content); - git_str_puts(out, "\n "); - content = lf + 1; - } - - git_str_puts(out, content); - git_str_putc(out, '\n'); - - return git_str_oom(out) ? -1 : 0; -} - -static const git_oid *commit_parent_from_commit(size_t n, void *payload) -{ - const git_commit *commit = (const git_commit *) payload; - - return git_array_get(commit->parent_ids, n); - -} - -int git_commit_create_with_signature( - git_oid *out, - git_repository *repo, - const char *commit_content, - const char *signature, - const char *signature_field) -{ - git_odb *odb; - int error = 0; - const char *field; - const char *header_end; - git_str commit = GIT_STR_INIT; - git_commit *parsed; - git_array_oid_t parents = GIT_ARRAY_INIT; - - /* The first step is to verify that all the tree and parents exist */ - parsed = git__calloc(1, sizeof(git_commit)); - GIT_ERROR_CHECK_ALLOC(parsed); - if (commit_parse(parsed, commit_content, strlen(commit_content), 0) < 0) { - error = -1; - goto cleanup; - } - - if ((error = validate_tree_and_parents(&parents, repo, &parsed->tree_id, commit_parent_from_commit, parsed, NULL, true)) < 0) - goto cleanup; - - git_array_clear(parents); - - /* Then we start appending by identifying the end of the commit header */ - header_end = strstr(commit_content, "\n\n"); - if (!header_end) { - git_error_set(GIT_ERROR_INVALID, "malformed commit contents"); - error = -1; - goto cleanup; - } - - /* The header ends after the first LF */ - header_end++; - git_str_put(&commit, commit_content, header_end - commit_content); - - if (signature != NULL) { - field = signature_field ? signature_field : "gpgsig"; - - if ((error = format_header_field(&commit, field, signature)) < 0) - goto cleanup; - } - - git_str_puts(&commit, header_end); - - if (git_str_oom(&commit)) - return -1; - - if ((error = git_repository_odb__weakptr(&odb, repo)) < 0) - goto cleanup; - - if ((error = git_odb_write(out, odb, commit.ptr, commit.size, GIT_OBJECT_COMMIT)) < 0) - goto cleanup; - -cleanup: - git_commit__free(parsed); - git_str_dispose(&commit); - return error; -} - -int git_commit_committer_with_mailmap( - git_signature **out, const git_commit *commit, const git_mailmap *mailmap) -{ - return git_mailmap_resolve_signature(out, mailmap, commit->committer); -} - -int git_commit_author_with_mailmap( - git_signature **out, const git_commit *commit, const git_mailmap *mailmap) -{ - return git_mailmap_resolve_signature(out, mailmap, commit->author); -} diff --git a/vendor/libgit2/src/commit.h b/vendor/libgit2/src/commit.h deleted file mode 100644 index 7a2454e6..00000000 --- a/vendor/libgit2/src/commit.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_commit_h__ -#define INCLUDE_commit_h__ - -#include "common.h" - -#include "git2/commit.h" -#include "tree.h" -#include "repository.h" -#include "array.h" - -#include - -struct git_commit { - git_object object; - - git_array_t(git_oid) parent_ids; - git_oid tree_id; - - git_signature *author; - git_signature *committer; - - char *message_encoding; - char *raw_message; - char *raw_header; - - char *summary; - char *body; -}; - -int git_commit__header_field( - git_str *out, - const git_commit *commit, - const char *field); - -int git_commit__extract_signature( - git_str *signature, - git_str *signed_data, - git_repository *repo, - git_oid *commit_id, - const char *field); - -int git_commit__create_buffer( - git_str *out, - git_repository *repo, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_tree *tree, - size_t parent_count, - const git_commit *parents[]); - -void git_commit__free(void *commit); -int git_commit__parse(void *commit, git_odb_object *obj); -int git_commit__parse_raw(void *commit, const char *data, size_t size); - -typedef enum { - GIT_COMMIT_PARSE_QUICK = (1 << 0) /**< Only parse parents and committer info */ -} git_commit__parse_flags; - -int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned int flags); - -#endif diff --git a/vendor/libgit2/src/common.h b/vendor/libgit2/src/common.h deleted file mode 100644 index 549bddb5..00000000 --- a/vendor/libgit2/src/common.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_common_h__ -#define INCLUDE_common_h__ - -#ifndef LIBGIT2_NO_FEATURES_H -# include "git2/sys/features.h" -#endif - -#include "git2/common.h" -#include "cc-compat.h" - -/** Declare a function as always inlined. */ -#if defined(_MSC_VER) -# define GIT_INLINE(type) static __inline type -#elif defined(__GNUC__) -# define GIT_INLINE(type) static __inline__ type -#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) -# define GIT_INLINE(type) static inline type -#else -# define GIT_INLINE(type) static type -#endif - -/** Support for gcc/clang __has_builtin intrinsic */ -#ifndef __has_builtin -# define __has_builtin(x) 0 -#endif - -/** - * Declare that a function's return value must be used. - * - * Used mostly to guard against potential silent bugs at runtime. This is - * recommended to be added to functions that: - * - * - Allocate / reallocate memory. This prevents memory leaks or errors where - * buffers are expected to have grown to a certain size, but could not be - * resized. - * - Acquire locks. When a lock cannot be acquired, that will almost certainly - * cause a data race / undefined behavior. - */ -#if defined(__GNUC__) -# define GIT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) -#else -# define GIT_WARN_UNUSED_RESULT -#endif - -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef GIT_WIN32 - -# include -# include -# include -# include -# include -# include "win32/msvc-compat.h" -# include "win32/mingw-compat.h" -# include "win32/w32_common.h" -# include "win32/win32-compat.h" -# include "win32/error.h" -# include "win32/version.h" -# ifdef GIT_THREADS -# include "win32/thread.h" -# endif - -#else - -# include -# include -# ifdef GIT_THREADS -# include -# include -# endif - -#define GIT_LIBGIT2_CALL -#define GIT_SYSTEM_CALL - -#ifdef GIT_USE_STAT_ATIMESPEC -# define st_atim st_atimespec -# define st_ctim st_ctimespec -# define st_mtim st_mtimespec -#endif - -# include - -#endif - -#include "git2/types.h" -#include "git2/errors.h" -#include "errors.h" -#include "thread.h" -#include "integer.h" -#include "assert_safe.h" -#include "utf8.h" - -/* - * Include the declarations for deprecated functions; this ensures - * that they're decorated with the proper extern/visibility attributes. - */ -#include "git2/deprecated.h" - -#include "posix.h" - -#define DEFAULT_BUFSIZE 65536 -#define FILEIO_BUFSIZE DEFAULT_BUFSIZE -#define FILTERIO_BUFSIZE DEFAULT_BUFSIZE -#define NETIO_BUFSIZE DEFAULT_BUFSIZE - -/** - * Check a pointer allocation result, returning -1 if it failed. - */ -#define GIT_ERROR_CHECK_ALLOC(ptr) do { \ - if ((ptr) == NULL) { return -1; } \ - } while(0) - -/** - * Check a string buffer allocation result, returning -1 if it failed. - */ -#define GIT_ERROR_CHECK_ALLOC_STR(buf) do { \ - if ((void *)(buf) == NULL || git_str_oom(buf)) { return -1; } \ - } while(0) - -/** - * Check a return value and propagate result if non-zero. - */ -#define GIT_ERROR_CHECK_ERROR(code) \ - do { int _err = (code); if (_err) return _err; } while (0) - -/** - * Check a versioned structure for validity - */ -GIT_INLINE(int) git_error__check_version(const void *structure, unsigned int expected_max, const char *name) -{ - unsigned int actual; - - if (!structure) - return 0; - - actual = *(const unsigned int*)structure; - if (actual > 0 && actual <= expected_max) - return 0; - - git_error_set(GIT_ERROR_INVALID, "invalid version %d on %s", actual, name); - return -1; -} -#define GIT_ERROR_CHECK_VERSION(S,V,N) if (git_error__check_version(S,V,N) < 0) return -1 - -/** - * Initialize a structure with a version. - */ -GIT_INLINE(void) git__init_structure(void *structure, size_t len, unsigned int version) -{ - memset(structure, 0, len); - *((int*)structure) = version; -} -#define GIT_INIT_STRUCTURE(S,V) git__init_structure(S, sizeof(*S), V) - -#define GIT_INIT_STRUCTURE_FROM_TEMPLATE(PTR,VERSION,TYPE,TPL) do { \ - TYPE _tmpl = TPL; \ - GIT_ERROR_CHECK_VERSION(&(VERSION), _tmpl.version, #TYPE); \ - memcpy((PTR), &_tmpl, sizeof(_tmpl)); } while (0) - - -/** Check for additive overflow, setting an error if would occur. */ -#define GIT_ADD_SIZET_OVERFLOW(out, one, two) \ - (git__add_sizet_overflow(out, one, two) ? (git_error_set_oom(), 1) : 0) - -/** Check for additive overflow, setting an error if would occur. */ -#define GIT_MULTIPLY_SIZET_OVERFLOW(out, nelem, elsize) \ - (git__multiply_sizet_overflow(out, nelem, elsize) ? (git_error_set_oom(), 1) : 0) - -/** Check for additive overflow, failing if it would occur. */ -#define GIT_ERROR_CHECK_ALLOC_ADD(out, one, two) \ - if (GIT_ADD_SIZET_OVERFLOW(out, one, two)) { return -1; } - -#define GIT_ERROR_CHECK_ALLOC_ADD3(out, one, two, three) \ - if (GIT_ADD_SIZET_OVERFLOW(out, one, two) || \ - GIT_ADD_SIZET_OVERFLOW(out, *(out), three)) { return -1; } - -#define GIT_ERROR_CHECK_ALLOC_ADD4(out, one, two, three, four) \ - if (GIT_ADD_SIZET_OVERFLOW(out, one, two) || \ - GIT_ADD_SIZET_OVERFLOW(out, *(out), three) || \ - GIT_ADD_SIZET_OVERFLOW(out, *(out), four)) { return -1; } - -#define GIT_ERROR_CHECK_ALLOC_ADD5(out, one, two, three, four, five) \ - if (GIT_ADD_SIZET_OVERFLOW(out, one, two) || \ - GIT_ADD_SIZET_OVERFLOW(out, *(out), three) || \ - GIT_ADD_SIZET_OVERFLOW(out, *(out), four) || \ - GIT_ADD_SIZET_OVERFLOW(out, *(out), five)) { return -1; } - -/** Check for multiplicative overflow, failing if it would occur. */ -#define GIT_ERROR_CHECK_ALLOC_MULTIPLY(out, nelem, elsize) \ - if (GIT_MULTIPLY_SIZET_OVERFLOW(out, nelem, elsize)) { return -1; } - -/* NOTE: other git_error functions are in the public errors.h header file */ - -/* Forward declare git_str */ -typedef struct git_str git_str; - -#include "util.h" - -#endif diff --git a/vendor/libgit2/src/config.c b/vendor/libgit2/src/config.c deleted file mode 100644 index 6bd59f2a..00000000 --- a/vendor/libgit2/src/config.c +++ /dev/null @@ -1,1570 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "config.h" - -#include "git2/config.h" -#include "git2/sys/config.h" - -#include "buf.h" -#include "config_backend.h" -#include "regexp.h" -#include "sysdir.h" -#include "transaction.h" -#include "vector.h" -#if GIT_WIN32 -# include -#endif - -#include - -void git_config_entry_free(git_config_entry *entry) -{ - if (!entry) - return; - - entry->free(entry); -} - -typedef struct { - git_refcount rc; - - git_config_backend *backend; - git_config_level_t level; -} backend_internal; - -static void backend_internal_free(backend_internal *internal) -{ - git_config_backend *backend; - - backend = internal->backend; - backend->free(backend); - git__free(internal); -} - -static void config_free(git_config *cfg) -{ - size_t i; - backend_internal *internal; - - for (i = 0; i < cfg->backends.length; ++i) { - internal = git_vector_get(&cfg->backends, i); - GIT_REFCOUNT_DEC(internal, backend_internal_free); - } - - git_vector_free(&cfg->backends); - - git__memzero(cfg, sizeof(*cfg)); - git__free(cfg); -} - -void git_config_free(git_config *cfg) -{ - if (cfg == NULL) - return; - - GIT_REFCOUNT_DEC(cfg, config_free); -} - -static int config_backend_cmp(const void *a, const void *b) -{ - const backend_internal *bk_a = (const backend_internal *)(a); - const backend_internal *bk_b = (const backend_internal *)(b); - - return bk_b->level - bk_a->level; -} - -int git_config_new(git_config **out) -{ - git_config *cfg; - - cfg = git__malloc(sizeof(git_config)); - GIT_ERROR_CHECK_ALLOC(cfg); - - memset(cfg, 0x0, sizeof(git_config)); - - if (git_vector_init(&cfg->backends, 3, config_backend_cmp) < 0) { - git__free(cfg); - return -1; - } - - *out = cfg; - GIT_REFCOUNT_INC(cfg); - return 0; -} - -int git_config_add_file_ondisk( - git_config *cfg, - const char *path, - git_config_level_t level, - const git_repository *repo, - int force) -{ - git_config_backend *file = NULL; - struct stat st; - int res; - - GIT_ASSERT_ARG(cfg); - GIT_ASSERT_ARG(path); - - res = p_stat(path, &st); - if (res < 0 && errno != ENOENT && errno != ENOTDIR) { - git_error_set(GIT_ERROR_CONFIG, "failed to stat '%s'", path); - return -1; - } - - if (git_config_backend_from_file(&file, path) < 0) - return -1; - - if ((res = git_config_add_backend(cfg, file, level, repo, force)) < 0) { - /* - * free manually; the file is not owned by the config - * instance yet and will not be freed on cleanup - */ - file->free(file); - return res; - } - - return 0; -} - -int git_config_open_ondisk(git_config **out, const char *path) -{ - int error; - git_config *config; - - *out = NULL; - - if (git_config_new(&config) < 0) - return -1; - - if ((error = git_config_add_file_ondisk(config, path, GIT_CONFIG_LEVEL_LOCAL, NULL, 0)) < 0) - git_config_free(config); - else - *out = config; - - return error; -} - -int git_config_snapshot(git_config **out, git_config *in) -{ - int error = 0; - size_t i; - backend_internal *internal; - git_config *config; - - *out = NULL; - - if (git_config_new(&config) < 0) - return -1; - - git_vector_foreach(&in->backends, i, internal) { - git_config_backend *b; - - if ((error = internal->backend->snapshot(&b, internal->backend)) < 0) - break; - - if ((error = git_config_add_backend(config, b, internal->level, NULL, 0)) < 0) { - b->free(b); - break; - } - } - - if (error < 0) - git_config_free(config); - else - *out = config; - - return error; -} - -static int find_backend_by_level( - backend_internal **out, - const git_config *cfg, - git_config_level_t level) -{ - int pos = -1; - backend_internal *internal; - size_t i; - - /* when passing GIT_CONFIG_HIGHEST_LEVEL, the idea is to get the config backend - * which has the highest level. As config backends are stored in a vector - * sorted by decreasing order of level, getting the backend at position 0 - * will do the job. - */ - if (level == GIT_CONFIG_HIGHEST_LEVEL) { - pos = 0; - } else { - git_vector_foreach(&cfg->backends, i, internal) { - if (internal->level == level) - pos = (int)i; - } - } - - if (pos == -1) { - git_error_set(GIT_ERROR_CONFIG, - "no configuration exists for the given level '%i'", (int)level); - return GIT_ENOTFOUND; - } - - *out = git_vector_get(&cfg->backends, pos); - - return 0; -} - -static int duplicate_level(void **old_raw, void *new_raw) -{ - backend_internal **old = (backend_internal **)old_raw; - - GIT_UNUSED(new_raw); - - git_error_set(GIT_ERROR_CONFIG, "there already exists a configuration for the given level (%i)", (int)(*old)->level); - return GIT_EEXISTS; -} - -static void try_remove_existing_backend( - git_config *cfg, - git_config_level_t level) -{ - int pos = -1; - backend_internal *internal; - size_t i; - - git_vector_foreach(&cfg->backends, i, internal) { - if (internal->level == level) - pos = (int)i; - } - - if (pos == -1) - return; - - internal = git_vector_get(&cfg->backends, pos); - - if (git_vector_remove(&cfg->backends, pos) < 0) - return; - - GIT_REFCOUNT_DEC(internal, backend_internal_free); -} - -static int git_config__add_internal( - git_config *cfg, - backend_internal *internal, - git_config_level_t level, - int force) -{ - int result; - - /* delete existing config backend for level if it exists */ - if (force) - try_remove_existing_backend(cfg, level); - - if ((result = git_vector_insert_sorted(&cfg->backends, - internal, &duplicate_level)) < 0) - return result; - - git_vector_sort(&cfg->backends); - internal->backend->cfg = cfg; - - GIT_REFCOUNT_INC(internal); - - return 0; -} - -int git_config_open_global(git_config **cfg_out, git_config *cfg) -{ - if (!git_config_open_level(cfg_out, cfg, GIT_CONFIG_LEVEL_XDG)) - return 0; - - return git_config_open_level(cfg_out, cfg, GIT_CONFIG_LEVEL_GLOBAL); -} - -int git_config_open_level( - git_config **cfg_out, - const git_config *cfg_parent, - git_config_level_t level) -{ - git_config *cfg; - backend_internal *internal; - int res; - - if ((res = find_backend_by_level(&internal, cfg_parent, level)) < 0) - return res; - - if ((res = git_config_new(&cfg)) < 0) - return res; - - if ((res = git_config__add_internal(cfg, internal, level, true)) < 0) { - git_config_free(cfg); - return res; - } - - *cfg_out = cfg; - - return 0; -} - -int git_config_add_backend( - git_config *cfg, - git_config_backend *backend, - git_config_level_t level, - const git_repository *repo, - int force) -{ - backend_internal *internal; - int result; - - GIT_ASSERT_ARG(cfg); - GIT_ASSERT_ARG(backend); - - GIT_ERROR_CHECK_VERSION(backend, GIT_CONFIG_BACKEND_VERSION, "git_config_backend"); - - if ((result = backend->open(backend, level, repo)) < 0) - return result; - - internal = git__malloc(sizeof(backend_internal)); - GIT_ERROR_CHECK_ALLOC(internal); - - memset(internal, 0x0, sizeof(backend_internal)); - - internal->backend = backend; - internal->level = level; - - if ((result = git_config__add_internal(cfg, internal, level, force)) < 0) { - git__free(internal); - return result; - } - - return 0; -} - -/* - * Loop over all the variables - */ - -typedef struct { - git_config_iterator parent; - git_config_iterator *current; - const git_config *cfg; - git_regexp regex; - size_t i; -} all_iter; - -static int find_next_backend(size_t *out, const git_config *cfg, size_t i) -{ - backend_internal *internal; - - for (; i > 0; --i) { - internal = git_vector_get(&cfg->backends, i - 1); - if (!internal || !internal->backend) - continue; - - *out = i; - return 0; - } - - return -1; -} - -static int all_iter_next(git_config_entry **entry, git_config_iterator *_iter) -{ - all_iter *iter = (all_iter *) _iter; - backend_internal *internal; - git_config_backend *backend; - size_t i; - int error = 0; - - if (iter->current != NULL && - (error = iter->current->next(entry, iter->current)) == 0) { - return 0; - } - - if (error < 0 && error != GIT_ITEROVER) - return error; - - do { - if (find_next_backend(&i, iter->cfg, iter->i) < 0) - return GIT_ITEROVER; - - internal = git_vector_get(&iter->cfg->backends, i - 1); - backend = internal->backend; - iter->i = i - 1; - - if (iter->current) - iter->current->free(iter->current); - - iter->current = NULL; - error = backend->iterator(&iter->current, backend); - if (error == GIT_ENOTFOUND) - continue; - - if (error < 0) - return error; - - error = iter->current->next(entry, iter->current); - /* If this backend is empty, then keep going */ - if (error == GIT_ITEROVER) - continue; - - return error; - - } while(1); - - return GIT_ITEROVER; -} - -static int all_iter_glob_next(git_config_entry **entry, git_config_iterator *_iter) -{ - int error; - all_iter *iter = (all_iter *) _iter; - - /* - * We use the "normal" function to grab the next one across - * backends and then apply the regex - */ - while ((error = all_iter_next(entry, _iter)) == 0) { - /* skip non-matching keys if regexp was provided */ - if (git_regexp_match(&iter->regex, (*entry)->name) != 0) - continue; - - /* and simply return if we like the entry's name */ - return 0; - } - - return error; -} - -static void all_iter_free(git_config_iterator *_iter) -{ - all_iter *iter = (all_iter *) _iter; - - if (iter->current) - iter->current->free(iter->current); - - git__free(iter); -} - -static void all_iter_glob_free(git_config_iterator *_iter) -{ - all_iter *iter = (all_iter *) _iter; - - git_regexp_dispose(&iter->regex); - all_iter_free(_iter); -} - -int git_config_iterator_new(git_config_iterator **out, const git_config *cfg) -{ - all_iter *iter; - - iter = git__calloc(1, sizeof(all_iter)); - GIT_ERROR_CHECK_ALLOC(iter); - - iter->parent.free = all_iter_free; - iter->parent.next = all_iter_next; - - iter->i = cfg->backends.length; - iter->cfg = cfg; - - *out = (git_config_iterator *) iter; - - return 0; -} - -int git_config_iterator_glob_new(git_config_iterator **out, const git_config *cfg, const char *regexp) -{ - all_iter *iter; - int result; - - if (regexp == NULL) - return git_config_iterator_new(out, cfg); - - iter = git__calloc(1, sizeof(all_iter)); - GIT_ERROR_CHECK_ALLOC(iter); - - if ((result = git_regexp_compile(&iter->regex, regexp, 0)) < 0) { - git__free(iter); - return -1; - } - - iter->parent.next = all_iter_glob_next; - iter->parent.free = all_iter_glob_free; - iter->i = cfg->backends.length; - iter->cfg = cfg; - - *out = (git_config_iterator *) iter; - - return 0; -} - -int git_config_foreach( - const git_config *cfg, git_config_foreach_cb cb, void *payload) -{ - return git_config_foreach_match(cfg, NULL, cb, payload); -} - -int git_config_backend_foreach_match( - git_config_backend *backend, - const char *regexp, - git_config_foreach_cb cb, - void *payload) -{ - git_config_entry *entry; - git_config_iterator *iter; - git_regexp regex; - int error = 0; - - GIT_ASSERT_ARG(backend); - GIT_ASSERT_ARG(cb); - - if (regexp && git_regexp_compile(®ex, regexp, 0) < 0) - return -1; - - if ((error = backend->iterator(&iter, backend)) < 0) { - iter = NULL; - return -1; - } - - while (!(iter->next(&entry, iter) < 0)) { - /* skip non-matching keys if regexp was provided */ - if (regexp && git_regexp_match(®ex, entry->name) != 0) - continue; - - /* abort iterator on non-zero return value */ - if ((error = cb(entry, payload)) != 0) { - git_error_set_after_callback(error); - break; - } - } - - if (regexp != NULL) - git_regexp_dispose(®ex); - - iter->free(iter); - - return error; -} - -int git_config_foreach_match( - const git_config *cfg, - const char *regexp, - git_config_foreach_cb cb, - void *payload) -{ - int error; - git_config_iterator *iter; - git_config_entry *entry; - - if ((error = git_config_iterator_glob_new(&iter, cfg, regexp)) < 0) - return error; - - while (!(error = git_config_next(&entry, iter))) { - if ((error = cb(entry, payload)) != 0) { - git_error_set_after_callback(error); - break; - } - } - - git_config_iterator_free(iter); - - if (error == GIT_ITEROVER) - error = 0; - - return error; -} - -/************** - * Setters - **************/ - -typedef enum { - BACKEND_USE_SET, - BACKEND_USE_DELETE -} backend_use; - -static const char *uses[] = { - "set", - "delete" -}; - -static int get_backend_for_use(git_config_backend **out, - git_config *cfg, const char *name, backend_use use) -{ - size_t i; - backend_internal *backend; - - *out = NULL; - - if (git_vector_length(&cfg->backends) == 0) { - git_error_set(GIT_ERROR_CONFIG, - "cannot %s value for '%s' when no config backends exist", - uses[use], name); - return GIT_ENOTFOUND; - } - - git_vector_foreach(&cfg->backends, i, backend) { - if (!backend->backend->readonly) { - *out = backend->backend; - return 0; - } - } - - git_error_set(GIT_ERROR_CONFIG, - "cannot %s value for '%s' when all config backends are readonly", - uses[use], name); - return GIT_ENOTFOUND; -} - -int git_config_delete_entry(git_config *cfg, const char *name) -{ - git_config_backend *backend; - - if (get_backend_for_use(&backend, cfg, name, BACKEND_USE_DELETE) < 0) - return GIT_ENOTFOUND; - - return backend->del(backend, name); -} - -int git_config_set_int64(git_config *cfg, const char *name, int64_t value) -{ - char str_value[32]; /* All numbers should fit in here */ - p_snprintf(str_value, sizeof(str_value), "%" PRId64, value); - return git_config_set_string(cfg, name, str_value); -} - -int git_config_set_int32(git_config *cfg, const char *name, int32_t value) -{ - return git_config_set_int64(cfg, name, (int64_t)value); -} - -int git_config_set_bool(git_config *cfg, const char *name, int value) -{ - return git_config_set_string(cfg, name, value ? "true" : "false"); -} - -int git_config_set_string(git_config *cfg, const char *name, const char *value) -{ - int error; - git_config_backend *backend; - - if (!value) { - git_error_set(GIT_ERROR_CONFIG, "the value to set cannot be NULL"); - return -1; - } - - if (get_backend_for_use(&backend, cfg, name, BACKEND_USE_SET) < 0) - return GIT_ENOTFOUND; - - error = backend->set(backend, name, value); - - if (!error && GIT_REFCOUNT_OWNER(cfg) != NULL) - git_repository__configmap_lookup_cache_clear(GIT_REFCOUNT_OWNER(cfg)); - - return error; -} - -int git_config__update_entry( - git_config *config, - const char *key, - const char *value, - bool overwrite_existing, - bool only_if_existing) -{ - int error = 0; - git_config_entry *ce = NULL; - - if ((error = git_config__lookup_entry(&ce, config, key, false)) < 0) - return error; - - if (!ce && only_if_existing) /* entry doesn't exist */ - return 0; - if (ce && !overwrite_existing) /* entry would be overwritten */ - return 0; - if (value && ce && ce->value && !strcmp(ce->value, value)) /* no change */ - return 0; - if (!value && (!ce || !ce->value)) /* asked to delete absent entry */ - return 0; - - if (!value) - error = git_config_delete_entry(config, key); - else - error = git_config_set_string(config, key, value); - - git_config_entry_free(ce); - return error; -} - -/*********** - * Getters - ***********/ - -static int config_error_notfound(const char *name) -{ - git_error_set(GIT_ERROR_CONFIG, "config value '%s' was not found", name); - return GIT_ENOTFOUND; -} - -enum { - GET_ALL_ERRORS = 0, - GET_NO_MISSING = 1, - GET_NO_ERRORS = 2 -}; - -static int get_entry( - git_config_entry **out, - const git_config *cfg, - const char *name, - bool normalize_name, - int want_errors) -{ - int res = GIT_ENOTFOUND; - const char *key = name; - char *normalized = NULL; - size_t i; - backend_internal *internal; - - *out = NULL; - - if (normalize_name) { - if ((res = git_config__normalize_name(name, &normalized)) < 0) - goto cleanup; - key = normalized; - } - - res = GIT_ENOTFOUND; - git_vector_foreach(&cfg->backends, i, internal) { - if (!internal || !internal->backend) - continue; - - res = internal->backend->get(internal->backend, key, out); - if (res != GIT_ENOTFOUND) - break; - } - - git__free(normalized); - -cleanup: - if (res == GIT_ENOTFOUND) - res = (want_errors > GET_ALL_ERRORS) ? 0 : config_error_notfound(name); - else if (res && (want_errors == GET_NO_ERRORS)) { - git_error_clear(); - res = 0; - } - - return res; -} - -int git_config_get_entry( - git_config_entry **out, const git_config *cfg, const char *name) -{ - return get_entry(out, cfg, name, true, GET_ALL_ERRORS); -} - -int git_config__lookup_entry( - git_config_entry **out, - const git_config *cfg, - const char *key, - bool no_errors) -{ - return get_entry( - out, cfg, key, false, no_errors ? GET_NO_ERRORS : GET_NO_MISSING); -} - -int git_config_get_mapped( - int *out, - const git_config *cfg, - const char *name, - const git_configmap *maps, - size_t map_n) -{ - git_config_entry *entry; - int ret; - - if ((ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS)) < 0) - return ret; - - ret = git_config_lookup_map_value(out, maps, map_n, entry->value); - git_config_entry_free(entry); - - return ret; -} - -int git_config_get_int64(int64_t *out, const git_config *cfg, const char *name) -{ - git_config_entry *entry; - int ret; - - if ((ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS)) < 0) - return ret; - - ret = git_config_parse_int64(out, entry->value); - git_config_entry_free(entry); - - return ret; -} - -int git_config_get_int32(int32_t *out, const git_config *cfg, const char *name) -{ - git_config_entry *entry; - int ret; - - if ((ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS)) < 0) - return ret; - - ret = git_config_parse_int32(out, entry->value); - git_config_entry_free(entry); - - return ret; -} - -int git_config_get_bool(int *out, const git_config *cfg, const char *name) -{ - git_config_entry *entry; - int ret; - - if ((ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS)) < 0) - return ret; - - ret = git_config_parse_bool(out, entry->value); - git_config_entry_free(entry); - - return ret; -} - -static int is_readonly(const git_config *cfg) -{ - size_t i; - backend_internal *internal; - - git_vector_foreach(&cfg->backends, i, internal) { - if (!internal || !internal->backend) - continue; - - if (!internal->backend->readonly) - return 0; - } - - return 1; -} - -static int git_config__parse_path(git_str *out, const char *value) -{ - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(value); - - if (value[0] == '~') { - if (value[1] != '\0' && value[1] != '/') { - git_error_set(GIT_ERROR_CONFIG, "retrieving a homedir by name is not supported"); - return -1; - } - - return git_sysdir_expand_global_file(out, value[1] ? &value[2] : NULL); - } - - return git_str_sets(out, value); -} - -int git_config_parse_path(git_buf *out, const char *value) -{ - GIT_BUF_WRAP_PRIVATE(out, git_config__parse_path, value); -} - -int git_config_get_path( - git_buf *out, - const git_config *cfg, - const char *name) -{ - GIT_BUF_WRAP_PRIVATE(out, git_config__get_path, cfg, name); -} - -int git_config__get_path( - git_str *out, - const git_config *cfg, - const char *name) -{ - git_config_entry *entry; - int error; - - if ((error = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS)) < 0) - return error; - - error = git_config__parse_path(out, entry->value); - git_config_entry_free(entry); - - return error; -} - -int git_config_get_string( - const char **out, const git_config *cfg, const char *name) -{ - git_config_entry *entry; - int ret; - - if (!is_readonly(cfg)) { - git_error_set(GIT_ERROR_CONFIG, "get_string called on a live config object"); - return -1; - } - - ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS); - *out = !ret ? (entry->value ? entry->value : "") : NULL; - - git_config_entry_free(entry); - - return ret; -} - -int git_config_get_string_buf( - git_buf *out, const git_config *cfg, const char *name) -{ - GIT_BUF_WRAP_PRIVATE(out, git_config__get_string_buf, cfg, name); -} - -int git_config__get_string_buf( - git_str *out, const git_config *cfg, const char *name) -{ - git_config_entry *entry; - int ret; - const char *str; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(cfg); - - ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS); - str = !ret ? (entry->value ? entry->value : "") : NULL; - - if (str) - ret = git_str_puts(out, str); - - git_config_entry_free(entry); - - return ret; -} - -char *git_config__get_string_force( - const git_config *cfg, const char *key, const char *fallback_value) -{ - git_config_entry *entry; - char *ret; - - get_entry(&entry, cfg, key, false, GET_NO_ERRORS); - ret = (entry && entry->value) ? git__strdup(entry->value) : fallback_value ? git__strdup(fallback_value) : NULL; - git_config_entry_free(entry); - - return ret; -} - -int git_config__get_bool_force( - const git_config *cfg, const char *key, int fallback_value) -{ - int val = fallback_value; - git_config_entry *entry; - - get_entry(&entry, cfg, key, false, GET_NO_ERRORS); - - if (entry && git_config_parse_bool(&val, entry->value) < 0) - git_error_clear(); - - git_config_entry_free(entry); - return val; -} - -int git_config__get_int_force( - const git_config *cfg, const char *key, int fallback_value) -{ - int32_t val = (int32_t)fallback_value; - git_config_entry *entry; - - get_entry(&entry, cfg, key, false, GET_NO_ERRORS); - - if (entry && git_config_parse_int32(&val, entry->value) < 0) - git_error_clear(); - - git_config_entry_free(entry); - return (int)val; -} - -int git_config_get_multivar_foreach( - const git_config *cfg, const char *name, const char *regexp, - git_config_foreach_cb cb, void *payload) -{ - int err, found; - git_config_iterator *iter; - git_config_entry *entry; - - if ((err = git_config_multivar_iterator_new(&iter, cfg, name, regexp)) < 0) - return err; - - found = 0; - while ((err = iter->next(&entry, iter)) == 0) { - found = 1; - - if ((err = cb(entry, payload)) != 0) { - git_error_set_after_callback(err); - break; - } - } - - iter->free(iter); - if (err == GIT_ITEROVER) - err = 0; - - if (found == 0 && err == 0) - err = config_error_notfound(name); - - return err; -} - -typedef struct { - git_config_iterator parent; - git_config_iterator *iter; - char *name; - git_regexp regex; - int have_regex; -} multivar_iter; - -static int multivar_iter_next(git_config_entry **entry, git_config_iterator *_iter) -{ - multivar_iter *iter = (multivar_iter *) _iter; - int error = 0; - - while ((error = iter->iter->next(entry, iter->iter)) == 0) { - if (git__strcmp(iter->name, (*entry)->name)) - continue; - - if (!iter->have_regex) - return 0; - - if (git_regexp_match(&iter->regex, (*entry)->value) == 0) - return 0; - } - - return error; -} - -static void multivar_iter_free(git_config_iterator *_iter) -{ - multivar_iter *iter = (multivar_iter *) _iter; - - iter->iter->free(iter->iter); - - git__free(iter->name); - if (iter->have_regex) - git_regexp_dispose(&iter->regex); - git__free(iter); -} - -int git_config_multivar_iterator_new(git_config_iterator **out, const git_config *cfg, const char *name, const char *regexp) -{ - multivar_iter *iter = NULL; - git_config_iterator *inner = NULL; - int error; - - if ((error = git_config_iterator_new(&inner, cfg)) < 0) - return error; - - iter = git__calloc(1, sizeof(multivar_iter)); - GIT_ERROR_CHECK_ALLOC(iter); - - if ((error = git_config__normalize_name(name, &iter->name)) < 0) - goto on_error; - - if (regexp != NULL) { - if ((error = git_regexp_compile(&iter->regex, regexp, 0)) < 0) - goto on_error; - - iter->have_regex = 1; - } - - iter->iter = inner; - iter->parent.free = multivar_iter_free; - iter->parent.next = multivar_iter_next; - - *out = (git_config_iterator *) iter; - - return 0; - -on_error: - - inner->free(inner); - git__free(iter); - return error; -} - -int git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value) -{ - git_config_backend *backend; - - if (get_backend_for_use(&backend, cfg, name, BACKEND_USE_DELETE) < 0) - return GIT_ENOTFOUND; - - return backend->set_multivar(backend, name, regexp, value); -} - -int git_config_delete_multivar(git_config *cfg, const char *name, const char *regexp) -{ - git_config_backend *backend; - - if (get_backend_for_use(&backend, cfg, name, BACKEND_USE_DELETE) < 0) - return GIT_ENOTFOUND; - - return backend->del_multivar(backend, name, regexp); -} - -int git_config_next(git_config_entry **entry, git_config_iterator *iter) -{ - return iter->next(entry, iter); -} - -void git_config_iterator_free(git_config_iterator *iter) -{ - if (iter == NULL) - return; - - iter->free(iter); -} - -int git_config_find_global(git_buf *path) -{ - GIT_BUF_WRAP_PRIVATE(path, git_sysdir_find_global_file, GIT_CONFIG_FILENAME_GLOBAL); -} - -int git_config__find_global(git_str *path) -{ - return git_sysdir_find_global_file(path, GIT_CONFIG_FILENAME_GLOBAL); -} - -int git_config_find_xdg(git_buf *path) -{ - GIT_BUF_WRAP_PRIVATE(path, git_sysdir_find_global_file, GIT_CONFIG_FILENAME_XDG); -} - -int git_config__find_xdg(git_str *path) -{ - return git_sysdir_find_xdg_file(path, GIT_CONFIG_FILENAME_XDG); -} - -int git_config_find_system(git_buf *path) -{ - GIT_BUF_WRAP_PRIVATE(path, git_sysdir_find_global_file, GIT_CONFIG_FILENAME_SYSTEM); -} - -int git_config__find_system(git_str *path) -{ - return git_sysdir_find_system_file(path, GIT_CONFIG_FILENAME_SYSTEM); -} - -int git_config_find_programdata(git_buf *path) -{ - git_str str = GIT_STR_INIT; - int error; - - if ((error = git_buf_tostr(&str, path)) == 0 && - (error = git_config__find_programdata(&str)) == 0) - error = git_buf_fromstr(path, &str); - - git_str_dispose(&str); - return error; -} - -int git_config__find_programdata(git_str *path) -{ - bool is_safe; - - if (git_sysdir_find_programdata_file(path, GIT_CONFIG_FILENAME_PROGRAMDATA) < 0 || - git_fs_path_owner_is_system_or_current_user(&is_safe, path->ptr) < 0) - return -1; - - if (!is_safe) { - git_error_set(GIT_ERROR_CONFIG, "programdata path has invalid ownership"); - return -1; - } - - return 0; -} - -int git_config__global_location(git_str *buf) -{ - const git_str *paths; - const char *sep, *start; - - if (git_sysdir_get(&paths, GIT_SYSDIR_GLOBAL) < 0) - return -1; - - /* no paths, so give up */ - if (!paths || !git_str_len(paths)) - return -1; - - /* find unescaped separator or end of string */ - for (sep = start = git_str_cstr(paths); *sep; ++sep) { - if (*sep == GIT_PATH_LIST_SEPARATOR && - (sep <= start || sep[-1] != '\\')) - break; - } - - if (git_str_set(buf, start, (size_t)(sep - start)) < 0) - return -1; - - return git_str_joinpath(buf, buf->ptr, GIT_CONFIG_FILENAME_GLOBAL); -} - -int git_config_open_default(git_config **out) -{ - int error; - git_config *cfg = NULL; - git_str buf = GIT_STR_INIT; - - if ((error = git_config_new(&cfg)) < 0) - return error; - - if (!git_config__find_global(&buf) || - !git_config__global_location(&buf)) { - error = git_config_add_file_ondisk(cfg, buf.ptr, - GIT_CONFIG_LEVEL_GLOBAL, NULL, 0); - } - - if (!error && !git_config__find_xdg(&buf)) - error = git_config_add_file_ondisk(cfg, buf.ptr, - GIT_CONFIG_LEVEL_XDG, NULL, 0); - - if (!error && !git_config__find_system(&buf)) - error = git_config_add_file_ondisk(cfg, buf.ptr, - GIT_CONFIG_LEVEL_SYSTEM, NULL, 0); - - if (!error && !git_config__find_programdata(&buf)) - error = git_config_add_file_ondisk(cfg, buf.ptr, - GIT_CONFIG_LEVEL_PROGRAMDATA, NULL, 0); - - git_str_dispose(&buf); - - if (error) { - git_config_free(cfg); - cfg = NULL; - } - - *out = cfg; - - return error; -} - -int git_config_lock(git_transaction **out, git_config *cfg) -{ - int error; - git_config_backend *backend; - backend_internal *internal; - - GIT_ASSERT_ARG(cfg); - - internal = git_vector_get(&cfg->backends, 0); - if (!internal || !internal->backend) { - git_error_set(GIT_ERROR_CONFIG, "cannot lock; the config has no backends"); - return -1; - } - backend = internal->backend; - - if ((error = backend->lock(backend)) < 0) - return error; - - return git_transaction_config_new(out, cfg); -} - -int git_config_unlock(git_config *cfg, int commit) -{ - git_config_backend *backend; - backend_internal *internal; - - GIT_ASSERT_ARG(cfg); - - internal = git_vector_get(&cfg->backends, 0); - if (!internal || !internal->backend) { - git_error_set(GIT_ERROR_CONFIG, "cannot lock; the config has no backends"); - return -1; - } - - backend = internal->backend; - - return backend->unlock(backend, commit); -} - -/*********** - * Parsers - ***********/ - -int git_config_lookup_map_value( - int *out, - const git_configmap *maps, - size_t map_n, - const char *value) -{ - size_t i; - - for (i = 0; i < map_n; ++i) { - const git_configmap *m = maps + i; - - switch (m->type) { - case GIT_CONFIGMAP_FALSE: - case GIT_CONFIGMAP_TRUE: { - int bool_val; - - if (git_config_parse_bool(&bool_val, value) == 0 && - bool_val == (int)m->type) { - *out = m->map_value; - return 0; - } - break; - } - - case GIT_CONFIGMAP_INT32: - if (git_config_parse_int32(out, value) == 0) - return 0; - break; - - case GIT_CONFIGMAP_STRING: - if (value && strcasecmp(value, m->str_match) == 0) { - *out = m->map_value; - return 0; - } - break; - } - } - - git_error_set(GIT_ERROR_CONFIG, "failed to map '%s'", value); - return -1; -} - -int git_config_lookup_map_enum(git_configmap_t *type_out, const char **str_out, - const git_configmap *maps, size_t map_n, int enum_val) -{ - size_t i; - - for (i = 0; i < map_n; i++) { - const git_configmap *m = &maps[i]; - - if (m->map_value != enum_val) - continue; - - *type_out = m->type; - *str_out = m->str_match; - return 0; - } - - git_error_set(GIT_ERROR_CONFIG, "invalid enum value"); - return GIT_ENOTFOUND; -} - -int git_config_parse_bool(int *out, const char *value) -{ - if (git__parse_bool(out, value) == 0) - return 0; - - if (git_config_parse_int32(out, value) == 0) { - *out = !!(*out); - return 0; - } - - git_error_set(GIT_ERROR_CONFIG, "failed to parse '%s' as a boolean value", value); - return -1; -} - -int git_config_parse_int64(int64_t *out, const char *value) -{ - const char *num_end; - int64_t num; - - if (!value || git__strntol64(&num, value, strlen(value), &num_end, 0) < 0) - goto fail_parse; - - switch (*num_end) { - case 'g': - case 'G': - num *= 1024; - /* fallthrough */ - - case 'm': - case 'M': - num *= 1024; - /* fallthrough */ - - case 'k': - case 'K': - num *= 1024; - - /* check that that there are no more characters after the - * given modifier suffix */ - if (num_end[1] != '\0') - return -1; - - /* fallthrough */ - - case '\0': - *out = num; - return 0; - - default: - goto fail_parse; - } - -fail_parse: - git_error_set(GIT_ERROR_CONFIG, "failed to parse '%s' as an integer", value ? value : "(null)"); - return -1; -} - -int git_config_parse_int32(int32_t *out, const char *value) -{ - int64_t tmp; - int32_t truncate; - - if (git_config_parse_int64(&tmp, value) < 0) - goto fail_parse; - - truncate = tmp & 0xFFFFFFFF; - if (truncate != tmp) - goto fail_parse; - - *out = truncate; - return 0; - -fail_parse: - git_error_set(GIT_ERROR_CONFIG, "failed to parse '%s' as a 32-bit integer", value ? value : "(null)"); - return -1; -} - -static int normalize_section(char *start, char *end) -{ - char *scan; - - if (start == end) - return GIT_EINVALIDSPEC; - - /* Validate and downcase range */ - for (scan = start; *scan; ++scan) { - if (end && scan >= end) - break; - if (isalnum(*scan)) - *scan = (char)git__tolower(*scan); - else if (*scan != '-' || scan == start) - return GIT_EINVALIDSPEC; - } - - if (scan == start) - return GIT_EINVALIDSPEC; - - return 0; -} - - -/* Take something the user gave us and make it nice for our hash function */ -int git_config__normalize_name(const char *in, char **out) -{ - char *name, *fdot, *ldot; - - GIT_ASSERT_ARG(in); - GIT_ASSERT_ARG(out); - - name = git__strdup(in); - GIT_ERROR_CHECK_ALLOC(name); - - fdot = strchr(name, '.'); - ldot = strrchr(name, '.'); - - if (fdot == NULL || fdot == name || ldot == NULL || !ldot[1]) - goto invalid; - - /* Validate and downcase up to first dot and after last dot */ - if (normalize_section(name, fdot) < 0 || - normalize_section(ldot + 1, NULL) < 0) - goto invalid; - - /* If there is a middle range, make sure it doesn't have newlines */ - while (fdot < ldot) - if (*fdot++ == '\n') - goto invalid; - - *out = name; - return 0; - -invalid: - git__free(name); - git_error_set(GIT_ERROR_CONFIG, "invalid config item name '%s'", in); - return GIT_EINVALIDSPEC; -} - -struct rename_data { - git_config *config; - git_str *name; - size_t old_len; -}; - -static int rename_config_entries_cb( - const git_config_entry *entry, - void *payload) -{ - int error = 0; - struct rename_data *data = (struct rename_data *)payload; - size_t base_len = git_str_len(data->name); - - if (base_len > 0 && - !(error = git_str_puts(data->name, entry->name + data->old_len))) - { - error = git_config_set_string( - data->config, git_str_cstr(data->name), entry->value); - - git_str_truncate(data->name, base_len); - } - - if (!error) - error = git_config_delete_entry(data->config, entry->name); - - return error; -} - -int git_config_rename_section( - git_repository *repo, - const char *old_section_name, - const char *new_section_name) -{ - git_config *config; - git_str pattern = GIT_STR_INIT, replace = GIT_STR_INIT; - int error = 0; - struct rename_data data; - - git_str_puts_escape_regex(&pattern, old_section_name); - - if ((error = git_str_puts(&pattern, "\\..+")) < 0) - goto cleanup; - - if ((error = git_repository_config__weakptr(&config, repo)) < 0) - goto cleanup; - - data.config = config; - data.name = &replace; - data.old_len = strlen(old_section_name) + 1; - - if ((error = git_str_join(&replace, '.', new_section_name, "")) < 0) - goto cleanup; - - if (new_section_name != NULL && - (error = normalize_section(replace.ptr, strchr(replace.ptr, '.'))) < 0) - { - git_error_set( - GIT_ERROR_CONFIG, "invalid config section '%s'", new_section_name); - goto cleanup; - } - - error = git_config_foreach_match( - config, git_str_cstr(&pattern), rename_config_entries_cb, &data); - -cleanup: - git_str_dispose(&pattern); - git_str_dispose(&replace); - - return error; -} - -int git_config_init_backend(git_config_backend *backend, unsigned int version) -{ - GIT_INIT_STRUCTURE_FROM_TEMPLATE( - backend, version, git_config_backend, GIT_CONFIG_BACKEND_INIT); - return 0; -} diff --git a/vendor/libgit2/src/config_entries.c b/vendor/libgit2/src/config_entries.c deleted file mode 100644 index 66aae096..00000000 --- a/vendor/libgit2/src/config_entries.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "config_entries.h" - -typedef struct config_entry_list { - struct config_entry_list *next; - struct config_entry_list *last; - git_config_entry *entry; -} config_entry_list; - -typedef struct { - git_config_entry *entry; - bool multivar; -} config_entry_map_head; - -typedef struct config_entries_iterator { - git_config_iterator parent; - git_config_entries *entries; - config_entry_list *head; -} config_entries_iterator; - -struct git_config_entries { - git_refcount rc; - git_strmap *map; - config_entry_list *list; -}; - -int git_config_entries_new(git_config_entries **out) -{ - git_config_entries *entries; - int error; - - entries = git__calloc(1, sizeof(git_config_entries)); - GIT_ERROR_CHECK_ALLOC(entries); - GIT_REFCOUNT_INC(entries); - - if ((error = git_strmap_new(&entries->map)) < 0) - git__free(entries); - else - *out = entries; - - return error; -} - -int git_config_entries_dup_entry(git_config_entries *entries, const git_config_entry *entry) -{ - git_config_entry *duplicated; - int error; - - duplicated = git__calloc(1, sizeof(git_config_entry)); - GIT_ERROR_CHECK_ALLOC(duplicated); - - duplicated->name = git__strdup(entry->name); - GIT_ERROR_CHECK_ALLOC(duplicated->name); - - if (entry->value) { - duplicated->value = git__strdup(entry->value); - GIT_ERROR_CHECK_ALLOC(duplicated->value); - } - duplicated->level = entry->level; - duplicated->include_depth = entry->include_depth; - - if ((error = git_config_entries_append(entries, duplicated)) < 0) - goto out; - -out: - if (error && duplicated) { - git__free((char *) duplicated->name); - git__free((char *) duplicated->value); - git__free(duplicated); - } - return error; -} - -int git_config_entries_dup(git_config_entries **out, git_config_entries *entries) -{ - git_config_entries *result = NULL; - config_entry_list *head; - int error; - - if ((error = git_config_entries_new(&result)) < 0) - goto out; - - for (head = entries->list; head; head = head->next) - if ((git_config_entries_dup_entry(result, head->entry)) < 0) - goto out; - - *out = result; - result = NULL; - -out: - git_config_entries_free(result); - return error; -} - -void git_config_entries_incref(git_config_entries *entries) -{ - GIT_REFCOUNT_INC(entries); -} - -static void config_entries_free(git_config_entries *entries) -{ - config_entry_list *list = NULL, *next; - config_entry_map_head *head; - - git_strmap_foreach_value(entries->map, head, - git__free((char *) head->entry->name); git__free(head) - ); - git_strmap_free(entries->map); - - list = entries->list; - while (list != NULL) { - next = list->next; - git__free((char *) list->entry->value); - git__free(list->entry); - git__free(list); - list = next; - } - - git__free(entries); -} - -void git_config_entries_free(git_config_entries *entries) -{ - if (entries) - GIT_REFCOUNT_DEC(entries, config_entries_free); -} - -int git_config_entries_append(git_config_entries *entries, git_config_entry *entry) -{ - config_entry_list *list_head; - config_entry_map_head *map_head; - - if ((map_head = git_strmap_get(entries->map, entry->name)) != NULL) { - map_head->multivar = true; - /* - * This is a micro-optimization for configuration files - * with a lot of same keys. As for multivars the entry's - * key will be the same for all entries, we can just free - * all except the first entry's name and just re-use it. - */ - git__free((char *) entry->name); - entry->name = map_head->entry->name; - } else { - map_head = git__calloc(1, sizeof(*map_head)); - if ((git_strmap_set(entries->map, entry->name, map_head)) < 0) - return -1; - } - map_head->entry = entry; - - list_head = git__calloc(1, sizeof(config_entry_list)); - GIT_ERROR_CHECK_ALLOC(list_head); - list_head->entry = entry; - - if (entries->list) - entries->list->last->next = list_head; - else - entries->list = list_head; - entries->list->last = list_head; - - return 0; -} - -int git_config_entries_get(git_config_entry **out, git_config_entries *entries, const char *key) -{ - config_entry_map_head *entry; - if ((entry = git_strmap_get(entries->map, key)) == NULL) - return GIT_ENOTFOUND; - *out = entry->entry; - return 0; -} - -int git_config_entries_get_unique(git_config_entry **out, git_config_entries *entries, const char *key) -{ - config_entry_map_head *entry; - - if ((entry = git_strmap_get(entries->map, key)) == NULL) - return GIT_ENOTFOUND; - - if (entry->multivar) { - git_error_set(GIT_ERROR_CONFIG, "entry is not unique due to being a multivar"); - return -1; - } - - if (entry->entry->include_depth) { - git_error_set(GIT_ERROR_CONFIG, "entry is not unique due to being included"); - return -1; - } - - *out = entry->entry; - - return 0; -} - -static void config_iterator_free(git_config_iterator *iter) -{ - config_entries_iterator *it = (config_entries_iterator *) iter; - git_config_entries_free(it->entries); - git__free(it); -} - -static int config_iterator_next( - git_config_entry **entry, - git_config_iterator *iter) -{ - config_entries_iterator *it = (config_entries_iterator *) iter; - - if (!it->head) - return GIT_ITEROVER; - - *entry = it->head->entry; - it->head = it->head->next; - - return 0; -} - -int git_config_entries_iterator_new(git_config_iterator **out, git_config_entries *entries) -{ - config_entries_iterator *it; - - it = git__calloc(1, sizeof(config_entries_iterator)); - GIT_ERROR_CHECK_ALLOC(it); - it->parent.next = config_iterator_next; - it->parent.free = config_iterator_free; - it->head = entries->list; - it->entries = entries; - - git_config_entries_incref(entries); - *out = &it->parent; - - return 0; -} diff --git a/vendor/libgit2/src/config_entries.h b/vendor/libgit2/src/config_entries.h deleted file mode 100644 index 832379e7..00000000 --- a/vendor/libgit2/src/config_entries.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "common.h" - -#include "git2/sys/config.h" -#include "config.h" - -typedef struct git_config_entries git_config_entries; - -int git_config_entries_new(git_config_entries **out); -int git_config_entries_dup(git_config_entries **out, git_config_entries *entries); -int git_config_entries_dup_entry(git_config_entries *entries, const git_config_entry *entry); -void git_config_entries_incref(git_config_entries *entries); -void git_config_entries_free(git_config_entries *entries); -/* Add or append the new config option */ -int git_config_entries_append(git_config_entries *entries, git_config_entry *entry); -int git_config_entries_get(git_config_entry **out, git_config_entries *entries, const char *key); -int git_config_entries_get_unique(git_config_entry **out, git_config_entries *entries, const char *key); -int git_config_entries_iterator_new(git_config_iterator **out, git_config_entries *entries); diff --git a/vendor/libgit2/src/config_mem.c b/vendor/libgit2/src/config_mem.c deleted file mode 100644 index 560229cf..00000000 --- a/vendor/libgit2/src/config_mem.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "config.h" - -#include "config_backend.h" -#include "config_parse.h" -#include "config_entries.h" - -typedef struct { - git_config_backend parent; - git_config_entries *entries; - git_str cfg; -} config_memory_backend; - -typedef struct { - git_config_entries *entries; - git_config_level_t level; -} config_memory_parse_data; - -static int config_error_readonly(void) -{ - git_error_set(GIT_ERROR_CONFIG, "this backend is read-only"); - return -1; -} - -static int read_variable_cb( - git_config_parser *reader, - const char *current_section, - const char *var_name, - const char *var_value, - const char *line, - size_t line_len, - void *payload) -{ - config_memory_parse_data *parse_data = (config_memory_parse_data *) payload; - git_str buf = GIT_STR_INIT; - git_config_entry *entry; - const char *c; - int result; - - GIT_UNUSED(reader); - GIT_UNUSED(line); - GIT_UNUSED(line_len); - - if (current_section) { - /* TODO: Once warnings land, we should likely warn - * here. Git appears to warn in most cases if it sees - * un-namespaced config options. - */ - git_str_puts(&buf, current_section); - git_str_putc(&buf, '.'); - } - - for (c = var_name; *c; c++) - git_str_putc(&buf, git__tolower(*c)); - - if (git_str_oom(&buf)) - return -1; - - entry = git__calloc(1, sizeof(git_config_entry)); - GIT_ERROR_CHECK_ALLOC(entry); - entry->name = git_str_detach(&buf); - entry->value = var_value ? git__strdup(var_value) : NULL; - entry->level = parse_data->level; - entry->include_depth = 0; - - if ((result = git_config_entries_append(parse_data->entries, entry)) < 0) - return result; - - return result; -} - -static int config_memory_open(git_config_backend *backend, git_config_level_t level, const git_repository *repo) -{ - config_memory_backend *memory_backend = (config_memory_backend *) backend; - git_config_parser parser = GIT_PARSE_CTX_INIT; - config_memory_parse_data parse_data; - int error; - - GIT_UNUSED(repo); - - if ((error = git_config_parser_init(&parser, "in-memory", memory_backend->cfg.ptr, - memory_backend->cfg.size)) < 0) - goto out; - parse_data.entries = memory_backend->entries; - parse_data.level = level; - - if ((error = git_config_parse(&parser, NULL, read_variable_cb, NULL, NULL, &parse_data)) < 0) - goto out; - -out: - git_config_parser_dispose(&parser); - return error; -} - -static int config_memory_get(git_config_backend *backend, const char *key, git_config_entry **out) -{ - config_memory_backend *memory_backend = (config_memory_backend *) backend; - return git_config_entries_get(out, memory_backend->entries, key); -} - -static int config_memory_iterator( - git_config_iterator **iter, - git_config_backend *backend) -{ - config_memory_backend *memory_backend = (config_memory_backend *) backend; - git_config_entries *entries; - int error; - - if ((error = git_config_entries_dup(&entries, memory_backend->entries)) < 0) - goto out; - - if ((error = git_config_entries_iterator_new(iter, entries)) < 0) - goto out; - -out: - /* Let iterator delete duplicated entries when it's done */ - git_config_entries_free(entries); - return error; -} - -static int config_memory_set(git_config_backend *backend, const char *name, const char *value) -{ - GIT_UNUSED(backend); - GIT_UNUSED(name); - GIT_UNUSED(value); - return config_error_readonly(); -} - -static int config_memory_set_multivar( - git_config_backend *backend, const char *name, const char *regexp, const char *value) -{ - GIT_UNUSED(backend); - GIT_UNUSED(name); - GIT_UNUSED(regexp); - GIT_UNUSED(value); - return config_error_readonly(); -} - -static int config_memory_delete(git_config_backend *backend, const char *name) -{ - GIT_UNUSED(backend); - GIT_UNUSED(name); - return config_error_readonly(); -} - -static int config_memory_delete_multivar(git_config_backend *backend, const char *name, const char *regexp) -{ - GIT_UNUSED(backend); - GIT_UNUSED(name); - GIT_UNUSED(regexp); - return config_error_readonly(); -} - -static int config_memory_lock(git_config_backend *backend) -{ - GIT_UNUSED(backend); - return config_error_readonly(); -} - -static int config_memory_unlock(git_config_backend *backend, int success) -{ - GIT_UNUSED(backend); - GIT_UNUSED(success); - return config_error_readonly(); -} - -static void config_memory_free(git_config_backend *_backend) -{ - config_memory_backend *backend = (config_memory_backend *)_backend; - - if (backend == NULL) - return; - - git_config_entries_free(backend->entries); - git_str_dispose(&backend->cfg); - git__free(backend); -} - -int git_config_backend_from_string(git_config_backend **out, const char *cfg, size_t len) -{ - config_memory_backend *backend; - - backend = git__calloc(1, sizeof(config_memory_backend)); - GIT_ERROR_CHECK_ALLOC(backend); - - if (git_config_entries_new(&backend->entries) < 0) { - git__free(backend); - return -1; - } - - if (git_str_set(&backend->cfg, cfg, len) < 0) { - git_config_entries_free(backend->entries); - git__free(backend); - return -1; - } - - backend->parent.version = GIT_CONFIG_BACKEND_VERSION; - backend->parent.readonly = 1; - backend->parent.open = config_memory_open; - backend->parent.get = config_memory_get; - backend->parent.set = config_memory_set; - backend->parent.set_multivar = config_memory_set_multivar; - backend->parent.del = config_memory_delete; - backend->parent.del_multivar = config_memory_delete_multivar; - backend->parent.iterator = config_memory_iterator; - backend->parent.lock = config_memory_lock; - backend->parent.unlock = config_memory_unlock; - backend->parent.snapshot = git_config_backend_snapshot; - backend->parent.free = config_memory_free; - - *out = (git_config_backend *)backend; - - return 0; -} diff --git a/vendor/libgit2/src/errors.c b/vendor/libgit2/src/errors.c deleted file mode 100644 index 3614b9ce..00000000 --- a/vendor/libgit2/src/errors.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "common.h" - -#include "threadstate.h" -#include "posix.h" -#include "str.h" -#include "libgit2.h" - -/******************************************** - * New error handling - ********************************************/ - -static git_error g_git_oom_error = { - "Out of memory", - GIT_ERROR_NOMEMORY -}; - -static git_error g_git_uninitialized_error = { - "libgit2 has not been initialized; you must call git_libgit2_init", - GIT_ERROR_INVALID -}; - -static void set_error_from_buffer(int error_class) -{ - git_error *error = &GIT_THREADSTATE->error_t; - git_str *buf = &GIT_THREADSTATE->error_buf; - - error->message = buf->ptr; - error->klass = error_class; - - GIT_THREADSTATE->last_error = error; -} - -static void set_error(int error_class, char *string) -{ - git_str *buf = &GIT_THREADSTATE->error_buf; - - git_str_clear(buf); - if (string) { - git_str_puts(buf, string); - git__free(string); - } - - set_error_from_buffer(error_class); -} - -void git_error_set_oom(void) -{ - GIT_THREADSTATE->last_error = &g_git_oom_error; -} - -void git_error_set(int error_class, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - git_error_vset(error_class, fmt, ap); - va_end(ap); -} - -void git_error_vset(int error_class, const char *fmt, va_list ap) -{ -#ifdef GIT_WIN32 - DWORD win32_error_code = (error_class == GIT_ERROR_OS) ? GetLastError() : 0; -#endif - int error_code = (error_class == GIT_ERROR_OS) ? errno : 0; - git_str *buf = &GIT_THREADSTATE->error_buf; - - git_str_clear(buf); - if (fmt) { - git_str_vprintf(buf, fmt, ap); - if (error_class == GIT_ERROR_OS) - git_str_PUTS(buf, ": "); - } - - if (error_class == GIT_ERROR_OS) { -#ifdef GIT_WIN32 - char * win32_error = git_win32_get_error_message(win32_error_code); - if (win32_error) { - git_str_puts(buf, win32_error); - git__free(win32_error); - - SetLastError(0); - } - else -#endif - if (error_code) - git_str_puts(buf, strerror(error_code)); - - if (error_code) - errno = 0; - } - - if (!git_str_oom(buf)) - set_error_from_buffer(error_class); -} - -int git_error_set_str(int error_class, const char *string) -{ - git_str *buf = &GIT_THREADSTATE->error_buf; - - GIT_ASSERT_ARG(string); - - git_str_clear(buf); - git_str_puts(buf, string); - - if (git_str_oom(buf)) - return -1; - - set_error_from_buffer(error_class); - return 0; -} - -void git_error_clear(void) -{ - if (GIT_THREADSTATE->last_error != NULL) { - set_error(0, NULL); - GIT_THREADSTATE->last_error = NULL; - } - - errno = 0; -#ifdef GIT_WIN32 - SetLastError(0); -#endif -} - -const git_error *git_error_last(void) -{ - /* If the library is not initialized, return a static error. */ - if (!git_libgit2_init_count()) - return &g_git_uninitialized_error; - - return GIT_THREADSTATE->last_error; -} - -int git_error_state_capture(git_error_state *state, int error_code) -{ - git_error *error = GIT_THREADSTATE->last_error; - git_str *error_buf = &GIT_THREADSTATE->error_buf; - - memset(state, 0, sizeof(git_error_state)); - - if (!error_code) - return 0; - - state->error_code = error_code; - state->oom = (error == &g_git_oom_error); - - if (error) { - state->error_msg.klass = error->klass; - - if (state->oom) - state->error_msg.message = g_git_oom_error.message; - else - state->error_msg.message = git_str_detach(error_buf); - } - - git_error_clear(); - return error_code; -} - -int git_error_state_restore(git_error_state *state) -{ - int ret = 0; - - git_error_clear(); - - if (state && state->error_msg.message) { - if (state->oom) - git_error_set_oom(); - else - set_error(state->error_msg.klass, state->error_msg.message); - - ret = state->error_code; - memset(state, 0, sizeof(git_error_state)); - } - - return ret; -} - -void git_error_state_free(git_error_state *state) -{ - if (!state) - return; - - if (!state->oom) - git__free(state->error_msg.message); - - memset(state, 0, sizeof(git_error_state)); -} - -int git_error_system_last(void) -{ -#ifdef GIT_WIN32 - return GetLastError(); -#else - return errno; -#endif -} - -void git_error_system_set(int code) -{ -#ifdef GIT_WIN32 - SetLastError(code); -#else - errno = code; -#endif -} - -/* Deprecated error values and functions */ - -#ifndef GIT_DEPRECATE_HARD -const git_error *giterr_last(void) -{ - return git_error_last(); -} - -void giterr_clear(void) -{ - git_error_clear(); -} - -void giterr_set_str(int error_class, const char *string) -{ - git_error_set_str(error_class, string); -} - -void giterr_set_oom(void) -{ - git_error_set_oom(); -} -#endif diff --git a/vendor/libgit2/src/errors.h b/vendor/libgit2/src/errors.h deleted file mode 100644 index a2f60f75..00000000 --- a/vendor/libgit2/src/errors.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#ifndef INCLUDE_errors_h__ -#define INCLUDE_errors_h__ - -#include "common.h" - -/* - * Set the error message for this thread, formatting as needed. - */ -void git_error_set(int error_class, const char *fmt, ...) GIT_FORMAT_PRINTF(2, 3); -void git_error_vset(int error_class, const char *fmt, va_list ap); - -/** - * Set error message for user callback if needed. - * - * If the error code in non-zero and no error message is set, this - * sets a generic error message. - * - * @return This always returns the `error_code` parameter. - */ -GIT_INLINE(int) git_error_set_after_callback_function( - int error_code, const char *action) -{ - if (error_code) { - const git_error *e = git_error_last(); - if (!e || !e->message) - git_error_set(e ? e->klass : GIT_ERROR_CALLBACK, - "%s callback returned %d", action, error_code); - } - return error_code; -} - -#ifdef GIT_WIN32 -#define git_error_set_after_callback(code) \ - git_error_set_after_callback_function((code), __FUNCTION__) -#else -#define git_error_set_after_callback(code) \ - git_error_set_after_callback_function((code), __func__) -#endif - -/** - * Gets the system error code for this thread. - */ -int git_error_system_last(void); - -/** - * Sets the system error code for this thread. - */ -void git_error_system_set(int code); - -/** - * Structure to preserve libgit2 error state - */ -typedef struct { - int error_code; - unsigned int oom : 1; - git_error error_msg; -} git_error_state; - -/** - * Capture current error state to restore later, returning error code. - * If `error_code` is zero, this does not clear the current error state. - * You must either restore this error state, or free it. - */ -extern int git_error_state_capture(git_error_state *state, int error_code); - -/** - * Restore error state to a previous value, returning saved error code. - */ -extern int git_error_state_restore(git_error_state *state); - -/** Free an error state. */ -extern void git_error_state_free(git_error_state *state); - -#endif diff --git a/vendor/libgit2/src/features.h.in b/vendor/libgit2/src/features.h.in deleted file mode 100644 index f920135d..00000000 --- a/vendor/libgit2/src/features.h.in +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef INCLUDE_features_h__ -#define INCLUDE_features_h__ - -#cmakedefine GIT_DEBUG_POOL 1 -#cmakedefine GIT_DEBUG_STRICT_ALLOC 1 -#cmakedefine GIT_DEBUG_STRICT_OPEN 1 - -#cmakedefine GIT_THREADS 1 -#cmakedefine GIT_WIN32_LEAKCHECK 1 - -#cmakedefine GIT_ARCH_64 1 -#cmakedefine GIT_ARCH_32 1 - -#cmakedefine GIT_USE_ICONV 1 -#cmakedefine GIT_USE_NSEC 1 -#cmakedefine GIT_USE_STAT_MTIM 1 -#cmakedefine GIT_USE_STAT_MTIMESPEC 1 -#cmakedefine GIT_USE_STAT_MTIME_NSEC 1 -#cmakedefine GIT_USE_FUTIMENS 1 - -#cmakedefine GIT_REGEX_REGCOMP_L -#cmakedefine GIT_REGEX_REGCOMP -#cmakedefine GIT_REGEX_PCRE -#cmakedefine GIT_REGEX_PCRE2 -#cmakedefine GIT_REGEX_BUILTIN 1 - -#cmakedefine GIT_QSORT_R_BSD -#cmakedefine GIT_QSORT_R_GNU -#cmakedefine GIT_QSORT_S - -#cmakedefine GIT_SSH 1 -#cmakedefine GIT_SSH_MEMORY_CREDENTIALS 1 - -#cmakedefine GIT_NTLM 1 -#cmakedefine GIT_GSSAPI 1 -#cmakedefine GIT_GSSFRAMEWORK 1 - -#cmakedefine GIT_WINHTTP 1 -#cmakedefine GIT_HTTPS 1 -#cmakedefine GIT_OPENSSL 1 -#cmakedefine GIT_OPENSSL_DYNAMIC 1 -#cmakedefine GIT_SECURE_TRANSPORT 1 -#cmakedefine GIT_MBEDTLS 1 - -#cmakedefine GIT_SHA1_COLLISIONDETECT 1 -#cmakedefine GIT_SHA1_WIN32 1 -#cmakedefine GIT_SHA1_COMMON_CRYPTO 1 -#cmakedefine GIT_SHA1_OPENSSL 1 -#cmakedefine GIT_SHA1_MBEDTLS 1 - -#cmakedefine GIT_RAND_GETENTROPY 1 - -#endif diff --git a/vendor/libgit2/src/fetch.c b/vendor/libgit2/src/fetch.c deleted file mode 100644 index e9f30d9b..00000000 --- a/vendor/libgit2/src/fetch.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "fetch.h" - -#include "git2/oid.h" -#include "git2/refs.h" -#include "git2/revwalk.h" -#include "git2/transport.h" -#include "git2/sys/remote.h" - -#include "remote.h" -#include "refspec.h" -#include "pack.h" -#include "netops.h" -#include "repository.h" -#include "refs.h" - -static int maybe_want(git_remote *remote, git_remote_head *head, git_refspec *tagspec, git_remote_autotag_option_t tagopt) -{ - int match = 0, valid; - - if (git_reference_name_is_valid(&valid, head->name) < 0) - return -1; - - if (!valid) - return 0; - - if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_ALL) { - /* - * If tagopt is --tags, always request tags - * in addition to the remote's refspecs - */ - if (git_refspec_src_matches(tagspec, head->name)) - match = 1; - } - - if (!match && git_remote__matching_refspec(remote, head->name)) - match = 1; - - if (!match) - return 0; - - return git_vector_insert(&remote->refs, head); -} - -static int mark_local(git_remote *remote) -{ - git_remote_head *head; - git_odb *odb; - size_t i; - - if (git_repository_odb__weakptr(&odb, remote->repo) < 0) - return -1; - - git_vector_foreach(&remote->refs, i, head) { - /* If we have the object, mark it so we don't ask for it */ - if (git_odb_exists(odb, &head->oid)) - head->local = 1; - else - remote->need_pack = 1; - } - - return 0; -} - -static int maybe_want_oid(git_remote *remote, git_refspec *spec) -{ - git_remote_head *oid_head; - - oid_head = git__calloc(1, sizeof(git_remote_head)); - GIT_ERROR_CHECK_ALLOC(oid_head); - - git_oid_fromstr(&oid_head->oid, spec->src); - - if (spec->dst) { - oid_head->name = git__strdup(spec->dst); - GIT_ERROR_CHECK_ALLOC(oid_head->name); - } - - if (git_vector_insert(&remote->local_heads, oid_head) < 0 || - git_vector_insert(&remote->refs, oid_head) < 0) - return -1; - - return 0; -} - -static int filter_wants(git_remote *remote, const git_fetch_options *opts) -{ - git_remote_head **heads; - git_refspec tagspec, head, *spec; - int error = 0; - git_odb *odb; - size_t i, heads_len; - unsigned int remote_caps; - unsigned int oid_mask = GIT_REMOTE_CAPABILITY_TIP_OID | - GIT_REMOTE_CAPABILITY_REACHABLE_OID; - git_remote_autotag_option_t tagopt = remote->download_tags; - - if (opts && opts->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED) - tagopt = opts->download_tags; - - git_vector_clear(&remote->refs); - if ((error = git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true)) < 0) - return error; - - /* - * The fetch refspec can be NULL, and what this means is that the - * user didn't specify one. This is fine, as it means that we're - * not interested in any particular branch but just the remote's - * HEAD, which will be stored in FETCH_HEAD after the fetch. - */ - if (remote->active_refspecs.length == 0) { - if ((error = git_refspec__parse(&head, "HEAD", true)) < 0) - goto cleanup; - - error = git_refspec__dwim_one(&remote->active_refspecs, &head, &remote->refs); - git_refspec__dispose(&head); - - if (error < 0) - goto cleanup; - } - - if ((error = git_repository_odb__weakptr(&odb, remote->repo)) < 0) - goto cleanup; - - if ((error = git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote)) < 0 || - (error = git_remote_capabilities(&remote_caps, remote)) < 0) - goto cleanup; - - /* Handle remote heads */ - for (i = 0; i < heads_len; i++) { - if ((error = maybe_want(remote, heads[i], &tagspec, tagopt)) < 0) - goto cleanup; - } - - /* Handle explicitly specified OID specs */ - git_vector_foreach(&remote->active_refspecs, i, spec) { - if (!git_oid__is_hexstr(spec->src)) - continue; - - if (!(remote_caps & oid_mask)) { - git_error_set(GIT_ERROR_INVALID, "cannot fetch a specific object from the remote repository"); - error = -1; - goto cleanup; - } - - if ((error = maybe_want_oid(remote, spec)) < 0) - goto cleanup; - } - - error = mark_local(remote); - -cleanup: - git_refspec__dispose(&tagspec); - - return error; -} - -/* - * In this first version, we push all our refs in and start sending - * them out. When we get an ACK we hide that commit and continue - * traversing until we're done - */ -int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts) -{ - git_transport *t = remote->transport; - - remote->need_pack = 0; - - if (filter_wants(remote, opts) < 0) - return -1; - - /* Don't try to negotiate when we don't want anything */ - if (!remote->need_pack) - return 0; - - /* - * Now we have everything set up so we can start tell the - * server what we want and what we have. - */ - return t->negotiate_fetch(t, - remote->repo, - (const git_remote_head * const *)remote->refs.contents, - remote->refs.length); -} - -int git_fetch_download_pack(git_remote *remote) -{ - git_transport *t = remote->transport; - - if (!remote->need_pack) - return 0; - - return t->download_pack(t, remote->repo, &remote->stats); -} - -int git_fetch_options_init(git_fetch_options *opts, unsigned int version) -{ - GIT_INIT_STRUCTURE_FROM_TEMPLATE( - opts, version, git_fetch_options, GIT_FETCH_OPTIONS_INIT); - return 0; -} - -#ifndef GIT_DEPRECATE_HARD -int git_fetch_init_options(git_fetch_options *opts, unsigned int version) -{ - return git_fetch_options_init(opts, version); -} -#endif diff --git a/vendor/libgit2/src/filebuf.c b/vendor/libgit2/src/filebuf.c deleted file mode 100644 index eafcba3b..00000000 --- a/vendor/libgit2/src/filebuf.c +++ /dev/null @@ -1,595 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "filebuf.h" - -#include "futils.h" - -static const size_t WRITE_BUFFER_SIZE = (4096 * 2); - -enum buferr_t { - BUFERR_OK = 0, - BUFERR_WRITE, - BUFERR_ZLIB, - BUFERR_MEM -}; - -#define ENSURE_BUF_OK(buf) if ((buf)->last_error != BUFERR_OK) { return -1; } - -static int verify_last_error(git_filebuf *file) -{ - switch (file->last_error) { - case BUFERR_WRITE: - git_error_set(GIT_ERROR_OS, "failed to write out file"); - return -1; - - case BUFERR_MEM: - git_error_set_oom(); - return -1; - - case BUFERR_ZLIB: - git_error_set(GIT_ERROR_ZLIB, - "Buffer error when writing out ZLib data"); - return -1; - - default: - return 0; - } -} - -static int lock_file(git_filebuf *file, int flags, mode_t mode) -{ - if (git_fs_path_exists(file->path_lock) == true) { - git_error_clear(); /* actual OS error code just confuses */ - git_error_set(GIT_ERROR_OS, - "failed to lock file '%s' for writing", file->path_lock); - return GIT_ELOCKED; - } - - /* create path to the file buffer is required */ - if (flags & GIT_FILEBUF_CREATE_LEADING_DIRS) { - /* XXX: Should dirmode here be configurable? Or is 0777 always fine? */ - file->fd = git_futils_creat_locked_withpath(file->path_lock, 0777, mode); - } else { - file->fd = git_futils_creat_locked(file->path_lock, mode); - } - - if (file->fd < 0) - return file->fd; - - file->fd_is_open = true; - - if ((flags & GIT_FILEBUF_APPEND) && git_fs_path_exists(file->path_original) == true) { - git_file source; - char buffer[FILEIO_BUFSIZE]; - ssize_t read_bytes; - int error = 0; - - source = p_open(file->path_original, O_RDONLY); - if (source < 0) { - git_error_set(GIT_ERROR_OS, - "failed to open file '%s' for reading", - file->path_original); - return -1; - } - - while ((read_bytes = p_read(source, buffer, sizeof(buffer))) > 0) { - if ((error = p_write(file->fd, buffer, read_bytes)) < 0) - break; - if (file->compute_digest) - git_hash_update(&file->digest, buffer, read_bytes); - } - - p_close(source); - - if (read_bytes < 0) { - git_error_set(GIT_ERROR_OS, "failed to read file '%s'", file->path_original); - return -1; - } else if (error < 0) { - git_error_set(GIT_ERROR_OS, "failed to write file '%s'", file->path_lock); - return -1; - } - } - - return 0; -} - -void git_filebuf_cleanup(git_filebuf *file) -{ - if (file->fd_is_open && file->fd >= 0) - p_close(file->fd); - - if (file->created_lock && !file->did_rename && file->path_lock && git_fs_path_exists(file->path_lock)) - p_unlink(file->path_lock); - - if (file->compute_digest) { - git_hash_ctx_cleanup(&file->digest); - file->compute_digest = 0; - } - - if (file->buffer) - git__free(file->buffer); - - /* use the presence of z_buf to decide if we need to deflateEnd */ - if (file->z_buf) { - git__free(file->z_buf); - deflateEnd(&file->zs); - } - - if (file->path_original) - git__free(file->path_original); - if (file->path_lock) - git__free(file->path_lock); - - memset(file, 0x0, sizeof(git_filebuf)); - file->fd = -1; -} - -GIT_INLINE(int) flush_buffer(git_filebuf *file) -{ - int result = file->write(file, file->buffer, file->buf_pos); - file->buf_pos = 0; - return result; -} - -int git_filebuf_flush(git_filebuf *file) -{ - return flush_buffer(file); -} - -static int write_normal(git_filebuf *file, void *source, size_t len) -{ - if (len > 0) { - if (p_write(file->fd, (void *)source, len) < 0) { - file->last_error = BUFERR_WRITE; - return -1; - } - - if (file->compute_digest) - git_hash_update(&file->digest, source, len); - } - - return 0; -} - -static int write_deflate(git_filebuf *file, void *source, size_t len) -{ - z_stream *zs = &file->zs; - - if (len > 0 || file->flush_mode == Z_FINISH) { - zs->next_in = source; - zs->avail_in = (uInt)len; - - do { - size_t have; - - zs->next_out = file->z_buf; - zs->avail_out = (uInt)file->buf_size; - - if (deflate(zs, file->flush_mode) == Z_STREAM_ERROR) { - file->last_error = BUFERR_ZLIB; - return -1; - } - - have = file->buf_size - (size_t)zs->avail_out; - - if (p_write(file->fd, file->z_buf, have) < 0) { - file->last_error = BUFERR_WRITE; - return -1; - } - - } while (zs->avail_out == 0); - - GIT_ASSERT(zs->avail_in == 0); - - if (file->compute_digest) - git_hash_update(&file->digest, source, len); - } - - return 0; -} - -#define MAX_SYMLINK_DEPTH 5 - -static int resolve_symlink(git_str *out, const char *path) -{ - int i, error, root; - ssize_t ret; - struct stat st; - git_str curpath = GIT_STR_INIT, target = GIT_STR_INIT; - - if ((error = git_str_grow(&target, GIT_PATH_MAX + 1)) < 0 || - (error = git_str_puts(&curpath, path)) < 0) - return error; - - for (i = 0; i < MAX_SYMLINK_DEPTH; i++) { - error = p_lstat(curpath.ptr, &st); - if (error < 0 && errno == ENOENT) { - error = git_str_puts(out, curpath.ptr); - goto cleanup; - } - - if (error < 0) { - git_error_set(GIT_ERROR_OS, "failed to stat '%s'", curpath.ptr); - error = -1; - goto cleanup; - } - - if (!S_ISLNK(st.st_mode)) { - error = git_str_puts(out, curpath.ptr); - goto cleanup; - } - - ret = p_readlink(curpath.ptr, target.ptr, GIT_PATH_MAX); - if (ret < 0) { - git_error_set(GIT_ERROR_OS, "failed to read symlink '%s'", curpath.ptr); - error = -1; - goto cleanup; - } - - if (ret == GIT_PATH_MAX) { - git_error_set(GIT_ERROR_INVALID, "symlink target too long"); - error = -1; - goto cleanup; - } - - /* readlink(2) won't NUL-terminate for us */ - target.ptr[ret] = '\0'; - target.size = ret; - - root = git_fs_path_root(target.ptr); - if (root >= 0) { - if ((error = git_str_sets(&curpath, target.ptr)) < 0) - goto cleanup; - } else { - git_str dir = GIT_STR_INIT; - - if ((error = git_fs_path_dirname_r(&dir, curpath.ptr)) < 0) - goto cleanup; - - git_str_swap(&curpath, &dir); - git_str_dispose(&dir); - - if ((error = git_fs_path_apply_relative(&curpath, target.ptr)) < 0) - goto cleanup; - } - } - - git_error_set(GIT_ERROR_INVALID, "maximum symlink depth reached"); - error = -1; - -cleanup: - git_str_dispose(&curpath); - git_str_dispose(&target); - return error; -} - -int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode) -{ - return git_filebuf_open_withsize(file, path, flags, mode, WRITE_BUFFER_SIZE); -} - -int git_filebuf_open_withsize(git_filebuf *file, const char *path, int flags, mode_t mode, size_t size) -{ - int compression, error = -1; - size_t path_len, alloc_len; - - GIT_ASSERT_ARG(file); - GIT_ASSERT_ARG(path); - GIT_ASSERT(file->buffer == NULL); - - memset(file, 0x0, sizeof(git_filebuf)); - - if (flags & GIT_FILEBUF_DO_NOT_BUFFER) - file->do_not_buffer = true; - - if (flags & GIT_FILEBUF_FSYNC) - file->do_fsync = true; - - file->buf_size = size; - file->buf_pos = 0; - file->fd = -1; - file->last_error = BUFERR_OK; - - /* Allocate the main cache buffer */ - if (!file->do_not_buffer) { - file->buffer = git__malloc(file->buf_size); - GIT_ERROR_CHECK_ALLOC(file->buffer); - } - - /* If we are hashing on-write, allocate a new hash context */ - if (flags & GIT_FILEBUF_HASH_CONTENTS) { - file->compute_digest = 1; - - if (git_hash_ctx_init(&file->digest, GIT_HASH_ALGORITHM_SHA1) < 0) - goto cleanup; - } - - compression = flags >> GIT_FILEBUF_DEFLATE_SHIFT; - - /* If we are deflating on-write, */ - if (compression != 0) { - /* Initialize the ZLib stream */ - if (deflateInit(&file->zs, compression) != Z_OK) { - git_error_set(GIT_ERROR_ZLIB, "failed to initialize zlib"); - goto cleanup; - } - - /* Allocate the Zlib cache buffer */ - file->z_buf = git__malloc(file->buf_size); - GIT_ERROR_CHECK_ALLOC(file->z_buf); - - /* Never flush */ - file->flush_mode = Z_NO_FLUSH; - file->write = &write_deflate; - } else { - file->write = &write_normal; - } - - /* If we are writing to a temp file */ - if (flags & GIT_FILEBUF_TEMPORARY) { - git_str tmp_path = GIT_STR_INIT; - - /* Open the file as temporary for locking */ - file->fd = git_futils_mktmp(&tmp_path, path, mode); - - if (file->fd < 0) { - git_str_dispose(&tmp_path); - goto cleanup; - } - file->fd_is_open = true; - file->created_lock = true; - - /* No original path */ - file->path_original = NULL; - file->path_lock = git_str_detach(&tmp_path); - GIT_ERROR_CHECK_ALLOC(file->path_lock); - } else { - git_str resolved_path = GIT_STR_INIT; - - if ((error = resolve_symlink(&resolved_path, path)) < 0) - goto cleanup; - - /* Save the original path of the file */ - path_len = resolved_path.size; - file->path_original = git_str_detach(&resolved_path); - - /* create the locking path by appending ".lock" to the original */ - GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, path_len, GIT_FILELOCK_EXTLENGTH); - file->path_lock = git__malloc(alloc_len); - GIT_ERROR_CHECK_ALLOC(file->path_lock); - - memcpy(file->path_lock, file->path_original, path_len); - memcpy(file->path_lock + path_len, GIT_FILELOCK_EXTENSION, GIT_FILELOCK_EXTLENGTH); - - if (git_fs_path_isdir(file->path_original)) { - git_error_set(GIT_ERROR_FILESYSTEM, "path '%s' is a directory", file->path_original); - error = GIT_EDIRECTORY; - goto cleanup; - } - - /* open the file for locking */ - if ((error = lock_file(file, flags, mode)) < 0) - goto cleanup; - - file->created_lock = true; - } - - return 0; - -cleanup: - git_filebuf_cleanup(file); - return error; -} - -int git_filebuf_hash(unsigned char *out, git_filebuf *file) -{ - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(file); - GIT_ASSERT_ARG(file->compute_digest); - - flush_buffer(file); - - if (verify_last_error(file) < 0) - return -1; - - git_hash_final(out, &file->digest); - git_hash_ctx_cleanup(&file->digest); - file->compute_digest = 0; - - return 0; -} - -int git_filebuf_commit_at(git_filebuf *file, const char *path) -{ - git__free(file->path_original); - file->path_original = git__strdup(path); - GIT_ERROR_CHECK_ALLOC(file->path_original); - - return git_filebuf_commit(file); -} - -int git_filebuf_commit(git_filebuf *file) -{ - /* temporary files cannot be committed */ - GIT_ASSERT_ARG(file); - GIT_ASSERT(file->path_original); - - file->flush_mode = Z_FINISH; - flush_buffer(file); - - if (verify_last_error(file) < 0) - goto on_error; - - file->fd_is_open = false; - - if (file->do_fsync && p_fsync(file->fd) < 0) { - git_error_set(GIT_ERROR_OS, "failed to fsync '%s'", file->path_lock); - goto on_error; - } - - if (p_close(file->fd) < 0) { - git_error_set(GIT_ERROR_OS, "failed to close file at '%s'", file->path_lock); - goto on_error; - } - - file->fd = -1; - - if (p_rename(file->path_lock, file->path_original) < 0) { - git_error_set(GIT_ERROR_OS, "failed to rename lockfile to '%s'", file->path_original); - goto on_error; - } - - if (file->do_fsync && git_futils_fsync_parent(file->path_original) < 0) - goto on_error; - - file->did_rename = true; - - git_filebuf_cleanup(file); - return 0; - -on_error: - git_filebuf_cleanup(file); - return -1; -} - -GIT_INLINE(void) add_to_cache(git_filebuf *file, const void *buf, size_t len) -{ - memcpy(file->buffer + file->buf_pos, buf, len); - file->buf_pos += len; -} - -int git_filebuf_write(git_filebuf *file, const void *buff, size_t len) -{ - const unsigned char *buf = buff; - - ENSURE_BUF_OK(file); - - if (file->do_not_buffer) - return file->write(file, (void *)buff, len); - - for (;;) { - size_t space_left = file->buf_size - file->buf_pos; - - /* cache if it's small */ - if (space_left > len) { - add_to_cache(file, buf, len); - return 0; - } - - add_to_cache(file, buf, space_left); - if (flush_buffer(file) < 0) - return -1; - - len -= space_left; - buf += space_left; - } -} - -int git_filebuf_reserve(git_filebuf *file, void **buffer, size_t len) -{ - size_t space_left = file->buf_size - file->buf_pos; - - *buffer = NULL; - - ENSURE_BUF_OK(file); - - if (len > file->buf_size) { - file->last_error = BUFERR_MEM; - return -1; - } - - if (space_left <= len) { - if (flush_buffer(file) < 0) - return -1; - } - - *buffer = (file->buffer + file->buf_pos); - file->buf_pos += len; - - return 0; -} - -int git_filebuf_printf(git_filebuf *file, const char *format, ...) -{ - va_list arglist; - size_t space_left, len, alloclen; - int written, res; - char *tmp_buffer; - - ENSURE_BUF_OK(file); - - space_left = file->buf_size - file->buf_pos; - - do { - va_start(arglist, format); - written = p_vsnprintf((char *)file->buffer + file->buf_pos, space_left, format, arglist); - va_end(arglist); - - if (written < 0) { - file->last_error = BUFERR_MEM; - return -1; - } - - len = written; - if (len + 1 <= space_left) { - file->buf_pos += len; - return 0; - } - - if (flush_buffer(file) < 0) - return -1; - - space_left = file->buf_size - file->buf_pos; - - } while (len + 1 <= space_left); - - if (GIT_ADD_SIZET_OVERFLOW(&alloclen, len, 1) || - !(tmp_buffer = git__malloc(alloclen))) { - file->last_error = BUFERR_MEM; - return -1; - } - - va_start(arglist, format); - written = p_vsnprintf(tmp_buffer, len + 1, format, arglist); - va_end(arglist); - - if (written < 0) { - git__free(tmp_buffer); - file->last_error = BUFERR_MEM; - return -1; - } - - res = git_filebuf_write(file, tmp_buffer, len); - git__free(tmp_buffer); - - return res; -} - -int git_filebuf_stats(time_t *mtime, size_t *size, git_filebuf *file) -{ - int res; - struct stat st; - - if (file->fd_is_open) - res = p_fstat(file->fd, &st); - else - res = p_stat(file->path_original, &st); - - if (res < 0) { - git_error_set(GIT_ERROR_OS, "could not get stat info for '%s'", - file->path_original); - return res; - } - - if (mtime) - *mtime = st.st_mtime; - if (size) - *size = (size_t)st.st_size; - - return 0; -} diff --git a/vendor/libgit2/src/futils.c b/vendor/libgit2/src/futils.c deleted file mode 100644 index 42c35955..00000000 --- a/vendor/libgit2/src/futils.c +++ /dev/null @@ -1,1194 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "futils.h" - -#include "runtime.h" -#include "strmap.h" -#include "hash.h" -#include "rand.h" - -#include -#if GIT_WIN32 -#include "win32/findfile.h" -#endif - -#define GIT_FILEMODE_DEFAULT 0100666 - -int git_futils_mkpath2file(const char *file_path, const mode_t mode) -{ - return git_futils_mkdir( - file_path, mode, - GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST | GIT_MKDIR_VERIFY_DIR); -} - -int git_futils_mktmp(git_str *path_out, const char *filename, mode_t mode) -{ - const int open_flags = O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC; - unsigned int tries = 32; - int fd; - - while (tries--) { - uint64_t rand = git_rand_next(); - - git_str_sets(path_out, filename); - git_str_puts(path_out, "_git2_"); - git_str_encode_hexstr(path_out, (void *)&rand, sizeof(uint64_t)); - - if (git_str_oom(path_out)) - return -1; - - /* Note that we open with O_CREAT | O_EXCL */ - if ((fd = p_open(path_out->ptr, open_flags, mode)) >= 0) - return fd; - } - - git_error_set(GIT_ERROR_OS, - "failed to create temporary file '%s'", path_out->ptr); - git_str_dispose(path_out); - return -1; -} - -int git_futils_creat_withpath(const char *path, const mode_t dirmode, const mode_t mode) -{ - int fd; - - if (git_futils_mkpath2file(path, dirmode) < 0) - return -1; - - fd = p_creat(path, mode); - if (fd < 0) { - git_error_set(GIT_ERROR_OS, "failed to create file '%s'", path); - return -1; - } - - return fd; -} - -int git_futils_creat_locked(const char *path, const mode_t mode) -{ - int fd = p_open(path, O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, - mode); - - if (fd < 0) { - int error = errno; - git_error_set(GIT_ERROR_OS, "failed to create locked file '%s'", path); - switch (error) { - case EEXIST: - return GIT_ELOCKED; - case ENOENT: - return GIT_ENOTFOUND; - default: - return -1; - } - } - - return fd; -} - -int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, const mode_t mode) -{ - if (git_futils_mkpath2file(path, dirmode) < 0) - return -1; - - return git_futils_creat_locked(path, mode); -} - -int git_futils_open_ro(const char *path) -{ - int fd = p_open(path, O_RDONLY); - if (fd < 0) - return git_fs_path_set_error(errno, path, "open"); - return fd; -} - -int git_futils_truncate(const char *path, int mode) -{ - int fd = p_open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode); - if (fd < 0) - return git_fs_path_set_error(errno, path, "open"); - - close(fd); - return 0; -} - -int git_futils_filesize(uint64_t *out, git_file fd) -{ - struct stat sb; - - if (p_fstat(fd, &sb)) { - git_error_set(GIT_ERROR_OS, "failed to stat file descriptor"); - return -1; - } - - if (sb.st_size < 0) { - git_error_set(GIT_ERROR_INVALID, "invalid file size"); - return -1; - } - - *out = sb.st_size; - return 0; -} - -mode_t git_futils_canonical_mode(mode_t raw_mode) -{ - if (S_ISREG(raw_mode)) - return S_IFREG | GIT_PERMS_CANONICAL(raw_mode); - else if (S_ISLNK(raw_mode)) - return S_IFLNK; - else if (S_ISGITLINK(raw_mode)) - return S_IFGITLINK; - else if (S_ISDIR(raw_mode)) - return S_IFDIR; - else - return 0; -} - -int git_futils_readbuffer_fd(git_str *buf, git_file fd, size_t len) -{ - ssize_t read_size = 0; - size_t alloc_len; - - git_str_clear(buf); - - if (!git__is_ssizet(len)) { - git_error_set(GIT_ERROR_INVALID, "read too large"); - return -1; - } - - GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, len, 1); - if (git_str_grow(buf, alloc_len) < 0) - return -1; - - /* p_read loops internally to read len bytes */ - read_size = p_read(fd, buf->ptr, len); - - if (read_size != (ssize_t)len) { - git_error_set(GIT_ERROR_OS, "failed to read descriptor"); - git_str_dispose(buf); - return -1; - } - - buf->ptr[read_size] = '\0'; - buf->size = read_size; - - return 0; -} - -int git_futils_readbuffer_updated( - git_str *out, - const char *path, - unsigned char checksum[GIT_HASH_SHA1_SIZE], - int *updated) -{ - int error; - git_file fd; - struct stat st; - git_str buf = GIT_STR_INIT; - unsigned char checksum_new[GIT_HASH_SHA1_SIZE]; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(path && *path); - - if (updated != NULL) - *updated = 0; - - if (p_stat(path, &st) < 0) - return git_fs_path_set_error(errno, path, "stat"); - - - if (S_ISDIR(st.st_mode)) { - git_error_set(GIT_ERROR_INVALID, "requested file is a directory"); - return GIT_ENOTFOUND; - } - - if (!git__is_sizet(st.st_size+1)) { - git_error_set(GIT_ERROR_OS, "invalid regular file stat for '%s'", path); - return -1; - } - - if ((fd = git_futils_open_ro(path)) < 0) - return fd; - - if (git_futils_readbuffer_fd(&buf, fd, (size_t)st.st_size) < 0) { - p_close(fd); - return -1; - } - - p_close(fd); - - if (checksum) { - if ((error = git_hash_buf(checksum_new, buf.ptr, buf.size, GIT_HASH_ALGORITHM_SHA1)) < 0) { - git_str_dispose(&buf); - return error; - } - - /* - * If we were given a checksum, we only want to use it if it's different - */ - if (!memcmp(checksum, checksum_new, GIT_HASH_SHA1_SIZE)) { - git_str_dispose(&buf); - if (updated) - *updated = 0; - - return 0; - } - - memcpy(checksum, checksum_new, GIT_HASH_SHA1_SIZE); - } - - /* - * If we're here, the file did change, or the user didn't have an old version - */ - if (updated != NULL) - *updated = 1; - - git_str_swap(out, &buf); - git_str_dispose(&buf); - - return 0; -} - -int git_futils_readbuffer(git_str *buf, const char *path) -{ - return git_futils_readbuffer_updated(buf, path, NULL, NULL); -} - -int git_futils_writebuffer( - const git_str *buf, const char *path, int flags, mode_t mode) -{ - int fd, do_fsync = 0, error = 0; - - if (!flags) - flags = O_CREAT | O_TRUNC | O_WRONLY; - - if ((flags & O_FSYNC) != 0) - do_fsync = 1; - - flags &= ~O_FSYNC; - - if (!mode) - mode = GIT_FILEMODE_DEFAULT; - - if ((fd = p_open(path, flags, mode)) < 0) { - git_error_set(GIT_ERROR_OS, "could not open '%s' for writing", path); - return fd; - } - - if ((error = p_write(fd, git_str_cstr(buf), git_str_len(buf))) < 0) { - git_error_set(GIT_ERROR_OS, "could not write to '%s'", path); - (void)p_close(fd); - return error; - } - - if (do_fsync && (error = p_fsync(fd)) < 0) { - git_error_set(GIT_ERROR_OS, "could not fsync '%s'", path); - p_close(fd); - return error; - } - - if ((error = p_close(fd)) < 0) { - git_error_set(GIT_ERROR_OS, "error while closing '%s'", path); - return error; - } - - if (do_fsync && (flags & O_CREAT)) - error = git_futils_fsync_parent(path); - - return error; -} - -int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode) -{ - if (git_futils_mkpath2file(to, dirmode) < 0) - return -1; - - if (p_rename(from, to) < 0) { - git_error_set(GIT_ERROR_OS, "failed to rename '%s' to '%s'", from, to); - return -1; - } - - return 0; -} - -int git_futils_mmap_ro(git_map *out, git_file fd, off64_t begin, size_t len) -{ - return p_mmap(out, len, GIT_PROT_READ, GIT_MAP_SHARED, fd, begin); -} - -int git_futils_mmap_ro_file(git_map *out, const char *path) -{ - git_file fd = git_futils_open_ro(path); - uint64_t len; - int result; - - if (fd < 0) - return fd; - - if ((result = git_futils_filesize(&len, fd)) < 0) - goto out; - - if (!git__is_sizet(len)) { - git_error_set(GIT_ERROR_OS, "file `%s` too large to mmap", path); - result = -1; - goto out; - } - - result = git_futils_mmap_ro(out, fd, 0, (size_t)len); -out: - p_close(fd); - return result; -} - -void git_futils_mmap_free(git_map *out) -{ - p_munmap(out); -} - -GIT_INLINE(int) mkdir_validate_dir( - const char *path, - struct stat *st, - mode_t mode, - uint32_t flags, - struct git_futils_mkdir_options *opts) -{ - /* with exclusive create, existing dir is an error */ - if ((flags & GIT_MKDIR_EXCL) != 0) { - git_error_set(GIT_ERROR_FILESYSTEM, - "failed to make directory '%s': directory exists", path); - return GIT_EEXISTS; - } - - if ((S_ISREG(st->st_mode) && (flags & GIT_MKDIR_REMOVE_FILES)) || - (S_ISLNK(st->st_mode) && (flags & GIT_MKDIR_REMOVE_SYMLINKS))) { - if (p_unlink(path) < 0) { - git_error_set(GIT_ERROR_OS, "failed to remove %s '%s'", - S_ISLNK(st->st_mode) ? "symlink" : "file", path); - return GIT_EEXISTS; - } - - opts->perfdata.mkdir_calls++; - - if (p_mkdir(path, mode) < 0) { - git_error_set(GIT_ERROR_OS, "failed to make directory '%s'", path); - return GIT_EEXISTS; - } - } - - else if (S_ISLNK(st->st_mode)) { - /* Re-stat the target, make sure it's a directory */ - opts->perfdata.stat_calls++; - - if (p_stat(path, st) < 0) { - git_error_set(GIT_ERROR_OS, "failed to make directory '%s'", path); - return GIT_EEXISTS; - } - } - - else if (!S_ISDIR(st->st_mode)) { - git_error_set(GIT_ERROR_FILESYSTEM, - "failed to make directory '%s': directory exists", path); - return GIT_EEXISTS; - } - - return 0; -} - -GIT_INLINE(int) mkdir_validate_mode( - const char *path, - struct stat *st, - bool terminal_path, - mode_t mode, - uint32_t flags, - struct git_futils_mkdir_options *opts) -{ - if (((terminal_path && (flags & GIT_MKDIR_CHMOD) != 0) || - (flags & GIT_MKDIR_CHMOD_PATH) != 0) && st->st_mode != mode) { - - opts->perfdata.chmod_calls++; - - if (p_chmod(path, mode) < 0) { - git_error_set(GIT_ERROR_OS, "failed to set permissions on '%s'", path); - return -1; - } - } - - return 0; -} - -GIT_INLINE(int) mkdir_canonicalize( - git_str *path, - uint32_t flags) -{ - ssize_t root_len; - - if (path->size == 0) { - git_error_set(GIT_ERROR_OS, "attempt to create empty path"); - return -1; - } - - /* Trim trailing slashes (except the root) */ - if ((root_len = git_fs_path_root(path->ptr)) < 0) - root_len = 0; - else - root_len++; - - while (path->size > (size_t)root_len && path->ptr[path->size - 1] == '/') - path->ptr[--path->size] = '\0'; - - /* if we are not supposed to made the last element, truncate it */ - if ((flags & GIT_MKDIR_SKIP_LAST2) != 0) { - git_fs_path_dirname_r(path, path->ptr); - flags |= GIT_MKDIR_SKIP_LAST; - } - if ((flags & GIT_MKDIR_SKIP_LAST) != 0) { - git_fs_path_dirname_r(path, path->ptr); - } - - /* We were either given the root path (or trimmed it to - * the root), we don't have anything to do. - */ - if (path->size <= (size_t)root_len) - git_str_clear(path); - - return 0; -} - -int git_futils_mkdir( - const char *path, - mode_t mode, - uint32_t flags) -{ - git_str make_path = GIT_STR_INIT, parent_path = GIT_STR_INIT; - const char *relative; - struct git_futils_mkdir_options opts = { 0 }; - struct stat st; - size_t depth = 0; - int len = 0, root_len, error; - - if ((error = git_str_puts(&make_path, path)) < 0 || - (error = mkdir_canonicalize(&make_path, flags)) < 0 || - (error = git_str_puts(&parent_path, make_path.ptr)) < 0 || - make_path.size == 0) - goto done; - - root_len = git_fs_path_root(make_path.ptr); - - /* find the first parent directory that exists. this will be used - * as the base to dirname_relative. - */ - for (relative = make_path.ptr; parent_path.size; ) { - error = p_lstat(parent_path.ptr, &st); - - if (error == 0) { - break; - } else if (errno != ENOENT) { - git_error_set(GIT_ERROR_OS, "failed to stat '%s'", parent_path.ptr); - error = -1; - goto done; - } - - depth++; - - /* examine the parent of the current path */ - if ((len = git_fs_path_dirname_r(&parent_path, parent_path.ptr)) < 0) { - error = len; - goto done; - } - - GIT_ASSERT(len); - - /* - * We've walked all the given path's parents and it's either relative - * (the parent is simply '.') or rooted (the length is less than or - * equal to length of the root path). The path may be less than the - * root path length on Windows, where `C:` == `C:/`. - */ - if ((len == 1 && parent_path.ptr[0] == '.') || - (len == 1 && parent_path.ptr[0] == '/') || - len <= root_len) { - relative = make_path.ptr; - break; - } - - relative = make_path.ptr + len + 1; - - /* not recursive? just make this directory relative to its parent. */ - if ((flags & GIT_MKDIR_PATH) == 0) - break; - } - - /* we found an item at the location we're trying to create, - * validate it. - */ - if (depth == 0) { - error = mkdir_validate_dir(make_path.ptr, &st, mode, flags, &opts); - - if (!error) - error = mkdir_validate_mode( - make_path.ptr, &st, true, mode, flags, &opts); - - goto done; - } - - /* we already took `SKIP_LAST` and `SKIP_LAST2` into account when - * canonicalizing `make_path`. - */ - flags &= ~(GIT_MKDIR_SKIP_LAST2 | GIT_MKDIR_SKIP_LAST); - - error = git_futils_mkdir_relative(relative, - parent_path.size ? parent_path.ptr : NULL, mode, flags, &opts); - -done: - git_str_dispose(&make_path); - git_str_dispose(&parent_path); - return error; -} - -int git_futils_mkdir_r(const char *path, const mode_t mode) -{ - return git_futils_mkdir(path, mode, GIT_MKDIR_PATH); -} - -int git_futils_mkdir_relative( - const char *relative_path, - const char *base, - mode_t mode, - uint32_t flags, - struct git_futils_mkdir_options *opts) -{ - git_str make_path = GIT_STR_INIT; - ssize_t root = 0, min_root_len; - char lastch = '/', *tail; - struct stat st; - struct git_futils_mkdir_options empty_opts = {0}; - int error; - - if (!opts) - opts = &empty_opts; - - /* build path and find "root" where we should start calling mkdir */ - if (git_fs_path_join_unrooted(&make_path, relative_path, base, &root) < 0) - return -1; - - if ((error = mkdir_canonicalize(&make_path, flags)) < 0 || - make_path.size == 0) - goto done; - - /* if we are not supposed to make the whole path, reset root */ - if ((flags & GIT_MKDIR_PATH) == 0) - root = git_str_rfind(&make_path, '/'); - - /* advance root past drive name or network mount prefix */ - min_root_len = git_fs_path_root(make_path.ptr); - if (root < min_root_len) - root = min_root_len; - while (root >= 0 && make_path.ptr[root] == '/') - ++root; - - /* clip root to make_path length */ - if (root > (ssize_t)make_path.size) - root = (ssize_t)make_path.size; /* i.e. NUL byte of string */ - if (root < 0) - root = 0; - - /* walk down tail of path making each directory */ - for (tail = &make_path.ptr[root]; *tail; *tail = lastch) { - bool mkdir_attempted = false; - - /* advance tail to include next path component */ - while (*tail == '/') - tail++; - while (*tail && *tail != '/') - tail++; - - /* truncate path at next component */ - lastch = *tail; - *tail = '\0'; - st.st_mode = 0; - - if (opts->dir_map && git_strmap_exists(opts->dir_map, make_path.ptr)) - continue; - - /* See what's going on with this path component */ - opts->perfdata.stat_calls++; - -retry_lstat: - if (p_lstat(make_path.ptr, &st) < 0) { - if (mkdir_attempted || errno != ENOENT) { - git_error_set(GIT_ERROR_OS, "cannot access component in path '%s'", make_path.ptr); - error = -1; - goto done; - } - - git_error_clear(); - opts->perfdata.mkdir_calls++; - mkdir_attempted = true; - if (p_mkdir(make_path.ptr, mode) < 0) { - if (errno == EEXIST) - goto retry_lstat; - git_error_set(GIT_ERROR_OS, "failed to make directory '%s'", make_path.ptr); - error = -1; - goto done; - } - } else { - if ((error = mkdir_validate_dir( - make_path.ptr, &st, mode, flags, opts)) < 0) - goto done; - } - - /* chmod if requested and necessary */ - if ((error = mkdir_validate_mode( - make_path.ptr, &st, (lastch == '\0'), mode, flags, opts)) < 0) - goto done; - - if (opts->dir_map && opts->pool) { - char *cache_path; - size_t alloc_size; - - GIT_ERROR_CHECK_ALLOC_ADD(&alloc_size, make_path.size, 1); - cache_path = git_pool_malloc(opts->pool, alloc_size); - GIT_ERROR_CHECK_ALLOC(cache_path); - - memcpy(cache_path, make_path.ptr, make_path.size + 1); - - if ((error = git_strmap_set(opts->dir_map, cache_path, cache_path)) < 0) - goto done; - } - } - - error = 0; - - /* check that full path really is a directory if requested & needed */ - if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 && - lastch != '\0') { - opts->perfdata.stat_calls++; - - if (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode)) { - git_error_set(GIT_ERROR_OS, "path is not a directory '%s'", - make_path.ptr); - error = GIT_ENOTFOUND; - } - } - -done: - git_str_dispose(&make_path); - return error; -} - -typedef struct { - const char *base; - size_t baselen; - uint32_t flags; - int depth; -} futils__rmdir_data; - -#define FUTILS_MAX_DEPTH 100 - -static int futils__error_cannot_rmdir(const char *path, const char *filemsg) -{ - if (filemsg) - git_error_set(GIT_ERROR_OS, "could not remove directory '%s': %s", - path, filemsg); - else - git_error_set(GIT_ERROR_OS, "could not remove directory '%s'", path); - - return -1; -} - -static int futils__rm_first_parent(git_str *path, const char *ceiling) -{ - int error = GIT_ENOTFOUND; - struct stat st; - - while (error == GIT_ENOTFOUND) { - git_str_rtruncate_at_char(path, '/'); - - if (!path->size || git__prefixcmp(path->ptr, ceiling) != 0) - error = 0; - else if (p_lstat_posixly(path->ptr, &st) == 0) { - if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) - error = p_unlink(path->ptr); - else if (!S_ISDIR(st.st_mode)) - error = -1; /* fail to remove non-regular file */ - } else if (errno != ENOTDIR) - error = -1; - } - - if (error) - futils__error_cannot_rmdir(path->ptr, "cannot remove parent"); - - return error; -} - -static int futils__rmdir_recurs_foreach(void *opaque, git_str *path) -{ - int error = 0; - futils__rmdir_data *data = opaque; - struct stat st; - - if (data->depth > FUTILS_MAX_DEPTH) - error = futils__error_cannot_rmdir( - path->ptr, "directory nesting too deep"); - - else if ((error = p_lstat_posixly(path->ptr, &st)) < 0) { - if (errno == ENOENT) - error = 0; - else if (errno == ENOTDIR) { - /* asked to remove a/b/c/d/e and a/b is a normal file */ - if ((data->flags & GIT_RMDIR_REMOVE_BLOCKERS) != 0) - error = futils__rm_first_parent(path, data->base); - else - futils__error_cannot_rmdir( - path->ptr, "parent is not directory"); - } - else - error = git_fs_path_set_error(errno, path->ptr, "rmdir"); - } - - else if (S_ISDIR(st.st_mode)) { - data->depth++; - - error = git_fs_path_direach(path, 0, futils__rmdir_recurs_foreach, data); - - data->depth--; - - if (error < 0) - return error; - - if (data->depth == 0 && (data->flags & GIT_RMDIR_SKIP_ROOT) != 0) - return error; - - if ((error = p_rmdir(path->ptr)) < 0) { - if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) != 0 && - (errno == ENOTEMPTY || errno == EEXIST || errno == EBUSY)) - error = 0; - else - error = git_fs_path_set_error(errno, path->ptr, "rmdir"); - } - } - - else if ((data->flags & GIT_RMDIR_REMOVE_FILES) != 0) { - if (p_unlink(path->ptr) < 0) - error = git_fs_path_set_error(errno, path->ptr, "remove"); - } - - else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0) - error = futils__error_cannot_rmdir(path->ptr, "still present"); - - return error; -} - -static int futils__rmdir_empty_parent(void *opaque, const char *path) -{ - futils__rmdir_data *data = opaque; - int error = 0; - - if (strlen(path) <= data->baselen) - error = GIT_ITEROVER; - - else if (p_rmdir(path) < 0) { - int en = errno; - - if (en == ENOENT || en == ENOTDIR) { - /* do nothing */ - } else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0 && - en == EBUSY) { - error = git_fs_path_set_error(errno, path, "rmdir"); - } else if (en == ENOTEMPTY || en == EEXIST || en == EBUSY) { - error = GIT_ITEROVER; - } else { - error = git_fs_path_set_error(errno, path, "rmdir"); - } - } - - return error; -} - -int git_futils_rmdir_r( - const char *path, const char *base, uint32_t flags) -{ - int error; - git_str fullpath = GIT_STR_INIT; - futils__rmdir_data data; - - /* build path and find "root" where we should start calling mkdir */ - if (git_fs_path_join_unrooted(&fullpath, path, base, NULL) < 0) - return -1; - - memset(&data, 0, sizeof(data)); - data.base = base ? base : ""; - data.baselen = base ? strlen(base) : 0; - data.flags = flags; - - error = futils__rmdir_recurs_foreach(&data, &fullpath); - - /* remove now-empty parents if requested */ - if (!error && (flags & GIT_RMDIR_EMPTY_PARENTS) != 0) - error = git_fs_path_walk_up( - &fullpath, base, futils__rmdir_empty_parent, &data); - - if (error == GIT_ITEROVER) { - git_error_clear(); - error = 0; - } - - git_str_dispose(&fullpath); - - return error; -} - -int git_futils_fake_symlink(const char *target, const char *path) -{ - int retcode = GIT_ERROR; - int fd = git_futils_creat_withpath(path, 0755, 0644); - if (fd >= 0) { - retcode = p_write(fd, target, strlen(target)); - p_close(fd); - } - return retcode; -} - -static int cp_by_fd(int ifd, int ofd, bool close_fd_when_done) -{ - int error = 0; - char buffer[FILEIO_BUFSIZE]; - ssize_t len = 0; - - while (!error && (len = p_read(ifd, buffer, sizeof(buffer))) > 0) - /* p_write() does not have the same semantics as write(). It loops - * internally and will return 0 when it has completed writing. - */ - error = p_write(ofd, buffer, len); - - if (len < 0) { - git_error_set(GIT_ERROR_OS, "read error while copying file"); - error = (int)len; - } - - if (error < 0) - git_error_set(GIT_ERROR_OS, "write error while copying file"); - - if (close_fd_when_done) { - p_close(ifd); - p_close(ofd); - } - - return error; -} - -int git_futils_cp(const char *from, const char *to, mode_t filemode) -{ - int ifd, ofd; - - if ((ifd = git_futils_open_ro(from)) < 0) - return ifd; - - if ((ofd = p_open(to, O_WRONLY | O_CREAT | O_EXCL, filemode)) < 0) { - p_close(ifd); - return git_fs_path_set_error(errno, to, "open for writing"); - } - - return cp_by_fd(ifd, ofd, true); -} - -int git_futils_touch(const char *path, time_t *when) -{ - struct p_timeval times[2]; - int ret; - - times[0].tv_sec = times[1].tv_sec = when ? *when : time(NULL); - times[0].tv_usec = times[1].tv_usec = 0; - - ret = p_utimes(path, times); - - return (ret < 0) ? git_fs_path_set_error(errno, path, "touch") : 0; -} - -static int cp_link(const char *from, const char *to, size_t link_size) -{ - int error = 0; - ssize_t read_len; - char *link_data; - size_t alloc_size; - - GIT_ERROR_CHECK_ALLOC_ADD(&alloc_size, link_size, 1); - link_data = git__malloc(alloc_size); - GIT_ERROR_CHECK_ALLOC(link_data); - - read_len = p_readlink(from, link_data, link_size); - if (read_len != (ssize_t)link_size) { - git_error_set(GIT_ERROR_OS, "failed to read symlink data for '%s'", from); - error = -1; - } - else { - link_data[read_len] = '\0'; - - if (p_symlink(link_data, to) < 0) { - git_error_set(GIT_ERROR_OS, "could not symlink '%s' as '%s'", - link_data, to); - error = -1; - } - } - - git__free(link_data); - return error; -} - -typedef struct { - const char *to_root; - git_str to; - ssize_t from_prefix; - uint32_t flags; - uint32_t mkdir_flags; - mode_t dirmode; -} cp_r_info; - -#define GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT (1u << 10) - -static int _cp_r_mkdir(cp_r_info *info, git_str *from) -{ - int error = 0; - - /* create root directory the first time we need to create a directory */ - if ((info->flags & GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT) == 0) { - error = git_futils_mkdir( - info->to_root, info->dirmode, - (info->flags & GIT_CPDIR_CHMOD_DIRS) ? GIT_MKDIR_CHMOD : 0); - - info->flags |= GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT; - } - - /* create directory with root as base to prevent excess chmods */ - if (!error) - error = git_futils_mkdir_relative( - from->ptr + info->from_prefix, info->to_root, - info->dirmode, info->mkdir_flags, NULL); - - return error; -} - -static int _cp_r_callback(void *ref, git_str *from) -{ - int error = 0; - cp_r_info *info = ref; - struct stat from_st, to_st; - bool exists = false; - - if ((info->flags & GIT_CPDIR_COPY_DOTFILES) == 0 && - from->ptr[git_fs_path_basename_offset(from)] == '.') - return 0; - - if ((error = git_str_joinpath( - &info->to, info->to_root, from->ptr + info->from_prefix)) < 0) - return error; - - if (!(error = git_fs_path_lstat(info->to.ptr, &to_st))) - exists = true; - else if (error != GIT_ENOTFOUND) - return error; - else { - git_error_clear(); - error = 0; - } - - if ((error = git_fs_path_lstat(from->ptr, &from_st)) < 0) - return error; - - if (S_ISDIR(from_st.st_mode)) { - mode_t oldmode = info->dirmode; - - /* if we are not chmod'ing, then overwrite dirmode */ - if ((info->flags & GIT_CPDIR_CHMOD_DIRS) == 0) - info->dirmode = from_st.st_mode; - - /* make directory now if CREATE_EMPTY_DIRS is requested and needed */ - if (!exists && (info->flags & GIT_CPDIR_CREATE_EMPTY_DIRS) != 0) - error = _cp_r_mkdir(info, from); - - /* recurse onto target directory */ - if (!error && (!exists || S_ISDIR(to_st.st_mode))) - error = git_fs_path_direach(from, 0, _cp_r_callback, info); - - if (oldmode != 0) - info->dirmode = oldmode; - - return error; - } - - if (exists) { - if ((info->flags & GIT_CPDIR_OVERWRITE) == 0) - return 0; - - if (p_unlink(info->to.ptr) < 0) { - git_error_set(GIT_ERROR_OS, "cannot overwrite existing file '%s'", - info->to.ptr); - return GIT_EEXISTS; - } - } - - /* Done if this isn't a regular file or a symlink */ - if (!S_ISREG(from_st.st_mode) && - (!S_ISLNK(from_st.st_mode) || - (info->flags & GIT_CPDIR_COPY_SYMLINKS) == 0)) - return 0; - - /* Make container directory on demand if needed */ - if ((info->flags & GIT_CPDIR_CREATE_EMPTY_DIRS) == 0 && - (error = _cp_r_mkdir(info, from)) < 0) - return error; - - /* make symlink or regular file */ - if (info->flags & GIT_CPDIR_LINK_FILES) { - if ((error = p_link(from->ptr, info->to.ptr)) < 0) - git_error_set(GIT_ERROR_OS, "failed to link '%s'", from->ptr); - } else if (S_ISLNK(from_st.st_mode)) { - error = cp_link(from->ptr, info->to.ptr, (size_t)from_st.st_size); - } else { - mode_t usemode = from_st.st_mode; - - if ((info->flags & GIT_CPDIR_SIMPLE_TO_MODE) != 0) - usemode = GIT_PERMS_FOR_WRITE(usemode); - - error = git_futils_cp(from->ptr, info->to.ptr, usemode); - } - - return error; -} - -int git_futils_cp_r( - const char *from, - const char *to, - uint32_t flags, - mode_t dirmode) -{ - int error; - git_str path = GIT_STR_INIT; - cp_r_info info; - - if (git_str_joinpath(&path, from, "") < 0) /* ensure trailing slash */ - return -1; - - memset(&info, 0, sizeof(info)); - info.to_root = to; - info.flags = flags; - info.dirmode = dirmode; - info.from_prefix = path.size; - git_str_init(&info.to, 0); - - /* precalculate mkdir flags */ - if ((flags & GIT_CPDIR_CREATE_EMPTY_DIRS) == 0) { - /* if not creating empty dirs, then use mkdir to create the path on - * demand right before files are copied. - */ - info.mkdir_flags = GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST; - if ((flags & GIT_CPDIR_CHMOD_DIRS) != 0) - info.mkdir_flags |= GIT_MKDIR_CHMOD_PATH; - } else { - /* otherwise, we will do simple mkdir as directories are encountered */ - info.mkdir_flags = - ((flags & GIT_CPDIR_CHMOD_DIRS) != 0) ? GIT_MKDIR_CHMOD : 0; - } - - error = _cp_r_callback(&info, &path); - - git_str_dispose(&path); - git_str_dispose(&info.to); - - return error; -} - -int git_futils_filestamp_check( - git_futils_filestamp *stamp, const char *path) -{ - struct stat st; - - /* if the stamp is NULL, then always reload */ - if (stamp == NULL) - return 1; - - if (p_stat(path, &st) < 0) - return GIT_ENOTFOUND; - - if (stamp->mtime.tv_sec == st.st_mtime && -#if defined(GIT_USE_NSEC) - stamp->mtime.tv_nsec == st.st_mtime_nsec && -#endif - stamp->size == (uint64_t)st.st_size && - stamp->ino == (unsigned int)st.st_ino) - return 0; - - stamp->mtime.tv_sec = st.st_mtime; -#if defined(GIT_USE_NSEC) - stamp->mtime.tv_nsec = st.st_mtime_nsec; -#endif - stamp->size = (uint64_t)st.st_size; - stamp->ino = (unsigned int)st.st_ino; - - return 1; -} - -void git_futils_filestamp_set( - git_futils_filestamp *target, const git_futils_filestamp *source) -{ - if (source) - memcpy(target, source, sizeof(*target)); - else - memset(target, 0, sizeof(*target)); -} - - -void git_futils_filestamp_set_from_stat( - git_futils_filestamp *stamp, struct stat *st) -{ - if (st) { - stamp->mtime.tv_sec = st->st_mtime; -#if defined(GIT_USE_NSEC) - stamp->mtime.tv_nsec = st->st_mtime_nsec; -#else - stamp->mtime.tv_nsec = 0; -#endif - stamp->size = (uint64_t)st->st_size; - stamp->ino = (unsigned int)st->st_ino; - } else { - memset(stamp, 0, sizeof(*stamp)); - } -} - -int git_futils_fsync_dir(const char *path) -{ -#ifdef GIT_WIN32 - GIT_UNUSED(path); - return 0; -#else - int fd, error = -1; - - if ((fd = p_open(path, O_RDONLY)) < 0) { - git_error_set(GIT_ERROR_OS, "failed to open directory '%s' for fsync", path); - return -1; - } - - if ((error = p_fsync(fd)) < 0) - git_error_set(GIT_ERROR_OS, "failed to fsync directory '%s'", path); - - p_close(fd); - return error; -#endif -} - -int git_futils_fsync_parent(const char *path) -{ - char *parent; - int error; - - if ((parent = git_fs_path_dirname(path)) == NULL) - return -1; - - error = git_futils_fsync_dir(parent); - git__free(parent); - return error; -} diff --git a/vendor/libgit2/src/hash.c b/vendor/libgit2/src/hash.c deleted file mode 100644 index 98ceb05d..00000000 --- a/vendor/libgit2/src/hash.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "hash.h" - -int git_hash_global_init(void) -{ - return git_hash_sha1_global_init(); -} - -int git_hash_ctx_init(git_hash_ctx *ctx, git_hash_algorithm_t algorithm) -{ - int error; - - switch (algorithm) { - case GIT_HASH_ALGORITHM_SHA1: - error = git_hash_sha1_ctx_init(&ctx->ctx.sha1); - break; - default: - git_error_set(GIT_ERROR_INTERNAL, "unknown hash algorithm"); - error = -1; - } - - ctx->algorithm = algorithm; - return error; -} - -void git_hash_ctx_cleanup(git_hash_ctx *ctx) -{ - switch (ctx->algorithm) { - case GIT_HASH_ALGORITHM_SHA1: - git_hash_sha1_ctx_cleanup(&ctx->ctx.sha1); - return; - default: - /* unreachable */ ; - } -} - -int git_hash_init(git_hash_ctx *ctx) -{ - switch (ctx->algorithm) { - case GIT_HASH_ALGORITHM_SHA1: - return git_hash_sha1_init(&ctx->ctx.sha1); - default: - /* unreachable */ ; - } - - git_error_set(GIT_ERROR_INTERNAL, "unknown hash algorithm"); - return -1; -} - -int git_hash_update(git_hash_ctx *ctx, const void *data, size_t len) -{ - switch (ctx->algorithm) { - case GIT_HASH_ALGORITHM_SHA1: - return git_hash_sha1_update(&ctx->ctx.sha1, data, len); - default: - /* unreachable */ ; - } - - git_error_set(GIT_ERROR_INTERNAL, "unknown hash algorithm"); - return -1; -} - -int git_hash_final(unsigned char *out, git_hash_ctx *ctx) -{ - switch (ctx->algorithm) { - case GIT_HASH_ALGORITHM_SHA1: - return git_hash_sha1_final(out, &ctx->ctx.sha1); - default: - /* unreachable */ ; - } - - git_error_set(GIT_ERROR_INTERNAL, "unknown hash algorithm"); - return -1; -} - -int git_hash_buf( - unsigned char *out, - const void *data, - size_t len, - git_hash_algorithm_t algorithm) -{ - git_hash_ctx ctx; - int error = 0; - - if (git_hash_ctx_init(&ctx, algorithm) < 0) - return -1; - - if ((error = git_hash_update(&ctx, data, len)) >= 0) - error = git_hash_final(out, &ctx); - - git_hash_ctx_cleanup(&ctx); - - return error; -} - -int git_hash_vec( - unsigned char *out, - git_str_vec *vec, - size_t n, - git_hash_algorithm_t algorithm) -{ - git_hash_ctx ctx; - size_t i; - int error = 0; - - if (git_hash_ctx_init(&ctx, algorithm) < 0) - return -1; - - for (i = 0; i < n; i++) { - if ((error = git_hash_update(&ctx, vec[i].data, vec[i].len)) < 0) - goto done; - } - - error = git_hash_final(out, &ctx); - -done: - git_hash_ctx_cleanup(&ctx); - - return error; -} - -int git_hash_fmt(char *out, unsigned char *hash, size_t hash_len) -{ - static char hex[] = "0123456789abcdef"; - char *str = out; - size_t i; - - for (i = 0; i < hash_len; i++) { - *str++ = hex[hash[i] >> 4]; - *str++ = hex[hash[i] & 0x0f]; - } - - *str++ = '\0'; - - return 0; -} diff --git a/vendor/libgit2/src/hash.h b/vendor/libgit2/src/hash.h deleted file mode 100644 index 507c1cb2..00000000 --- a/vendor/libgit2/src/hash.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#ifndef INCLUDE_hash_h__ -#define INCLUDE_hash_h__ - -#include "common.h" - -#include "hash/sha1.h" - -typedef struct { - void *data; - size_t len; -} git_str_vec; - -typedef enum { - GIT_HASH_ALGORITHM_NONE = 0, - GIT_HASH_ALGORITHM_SHA1 -} git_hash_algorithm_t; - -typedef struct git_hash_ctx { - union { - git_hash_sha1_ctx sha1; - } ctx; - git_hash_algorithm_t algorithm; -} git_hash_ctx; - -int git_hash_global_init(void); - -int git_hash_ctx_init(git_hash_ctx *ctx, git_hash_algorithm_t algorithm); -void git_hash_ctx_cleanup(git_hash_ctx *ctx); - -int git_hash_init(git_hash_ctx *c); -int git_hash_update(git_hash_ctx *c, const void *data, size_t len); -int git_hash_final(unsigned char *out, git_hash_ctx *c); - -int git_hash_buf(unsigned char *out, const void *data, size_t len, git_hash_algorithm_t algorithm); -int git_hash_vec(unsigned char *out, git_str_vec *vec, size_t n, git_hash_algorithm_t algorithm); - -int git_hash_fmt(char *out, unsigned char *hash, size_t hash_len); - -#endif diff --git a/vendor/libgit2/src/hash/sha1.h b/vendor/libgit2/src/hash/sha1.h deleted file mode 100644 index 4b4dae3f..00000000 --- a/vendor/libgit2/src/hash/sha1.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#ifndef INCLUDE_hash_sha1_h__ -#define INCLUDE_hash_sha1_h__ - -#include "common.h" - -typedef struct git_hash_sha1_ctx git_hash_sha1_ctx; - -#if defined(GIT_SHA1_COLLISIONDETECT) -# include "sha1/collisiondetect.h" -#elif defined(GIT_SHA1_COMMON_CRYPTO) -# include "sha1/common_crypto.h" -#elif defined(GIT_SHA1_OPENSSL) -# include "sha1/openssl.h" -#elif defined(GIT_SHA1_WIN32) -# include "sha1/win32.h" -#elif defined(GIT_SHA1_MBEDTLS) -# include "sha1/mbedtls.h" -#else -# include "sha1/generic.h" -#endif - -#define GIT_HASH_SHA1_SIZE 20 - -int git_hash_sha1_global_init(void); - -int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx); -void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx); - -int git_hash_sha1_init(git_hash_sha1_ctx *c); -int git_hash_sha1_update(git_hash_sha1_ctx *c, const void *data, size_t len); -int git_hash_sha1_final(unsigned char *out, git_hash_sha1_ctx *c); - -#endif diff --git a/vendor/libgit2/src/hash/sha1/collisiondetect.h b/vendor/libgit2/src/hash/sha1/collisiondetect.h deleted file mode 100644 index eb88e86c..00000000 --- a/vendor/libgit2/src/hash/sha1/collisiondetect.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#ifndef INCLUDE_hash_sha1_collisiondetect_h__ -#define INCLUDE_hash_sha1_collisiondetect_h__ - -#include "hash/sha1.h" - -#include "sha1dc/sha1.h" - -struct git_hash_sha1_ctx { - SHA1_CTX c; -}; - -#endif diff --git a/vendor/libgit2/src/hash/sha1/common_crypto.c b/vendor/libgit2/src/hash/sha1/common_crypto.c deleted file mode 100644 index 9d608f44..00000000 --- a/vendor/libgit2/src/hash/sha1/common_crypto.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "common_crypto.h" - -#define CC_LONG_MAX ((CC_LONG)-1) - -int git_hash_sha1_global_init(void) -{ - return 0; -} - -int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx) -{ - return git_hash_sha1_init(ctx); -} - -void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx) -{ - GIT_UNUSED(ctx); -} - -int git_hash_sha1_init(git_hash_sha1_ctx *ctx) -{ - GIT_ASSERT_ARG(ctx); - CC_SHA1_Init(&ctx->c); - return 0; -} - -int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *_data, size_t len) -{ - const unsigned char *data = _data; - - GIT_ASSERT_ARG(ctx); - - while (len > 0) { - CC_LONG chunk = (len > CC_LONG_MAX) ? CC_LONG_MAX : (CC_LONG)len; - - CC_SHA1_Update(&ctx->c, data, chunk); - - data += chunk; - len -= chunk; - } - - return 0; -} - -int git_hash_sha1_final(unsigned char *out, git_hash_sha1_ctx *ctx) -{ - GIT_ASSERT_ARG(ctx); - CC_SHA1_Final(out, &ctx->c); - return 0; -} diff --git a/vendor/libgit2/src/hash/sha1/common_crypto.h b/vendor/libgit2/src/hash/sha1/common_crypto.h deleted file mode 100644 index a5fcfb33..00000000 --- a/vendor/libgit2/src/hash/sha1/common_crypto.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#ifndef INCLUDE_hash_sha1_common_crypto_h__ -#define INCLUDE_hash_sha1_common_crypto_h__ - -#include "hash/sha1.h" - -#include - -struct git_hash_sha1_ctx { - CC_SHA1_CTX c; -}; - -#endif diff --git a/vendor/libgit2/src/hash/sha1/generic.c b/vendor/libgit2/src/hash/sha1/generic.c deleted file mode 100644 index 85b34c57..00000000 --- a/vendor/libgit2/src/hash/sha1/generic.c +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "generic.h" - -#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - -/* - * Force usage of rol or ror by selecting the one with the smaller constant. - * It _can_ generate slightly smaller code (a constant of 1 is special), but - * perhaps more importantly it's possibly faster on any uarch that does a - * rotate with a loop. - */ - -#define SHA_ASM(op, x, n) (__extension__ ({ unsigned int __res; __asm__(op " %1,%0":"=r" (__res):"i" (n), "0" (x)); __res; })) -#define SHA_ROL(x,n) SHA_ASM("rol", x, n) -#define SHA_ROR(x,n) SHA_ASM("ror", x, n) - -#else - -#define SHA_ROT(X,l,r) (((X) << (l)) | ((X) >> (r))) -#define SHA_ROL(X,n) SHA_ROT(X,n,32-(n)) -#define SHA_ROR(X,n) SHA_ROT(X,32-(n),n) - -#endif - -/* - * If you have 32 registers or more, the compiler can (and should) - * try to change the array[] accesses into registers. However, on - * machines with less than ~25 registers, that won't really work, - * and at least gcc will make an unholy mess of it. - * - * So to avoid that mess which just slows things down, we force - * the stores to memory to actually happen (we might be better off - * with a 'W(t)=(val);asm("":"+m" (W(t))' there instead, as - * suggested by Artur Skawina - that will also make gcc unable to - * try to do the silly "optimize away loads" part because it won't - * see what the value will be). - * - * Ben Herrenschmidt reports that on PPC, the C version comes close - * to the optimized asm with this (ie on PPC you don't want that - * 'volatile', since there are lots of registers). - * - * On ARM we get the best code generation by forcing a full memory barrier - * between each SHA_ROUND, otherwise gcc happily get wild with spilling and - * the stack frame size simply explode and performance goes down the drain. - */ - -#if defined(__i386__) || defined(__x86_64__) - #define setW(x, val) (*(volatile unsigned int *)&W(x) = (val)) -#elif defined(__GNUC__) && defined(__arm__) - #define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while (0) -#else - #define setW(x, val) (W(x) = (val)) -#endif - -/* - * Performance might be improved if the CPU architecture is OK with - * unaligned 32-bit loads and a fast ntohl() is available. - * Otherwise fall back to byte loads and shifts which is portable, - * and is faster on architectures with memory alignment issues. - */ - -#if defined(__i386__) || defined(__x86_64__) || \ - defined(_M_IX86) || defined(_M_X64) || \ - defined(__ppc__) || defined(__ppc64__) || \ - defined(__powerpc__) || defined(__powerpc64__) || \ - defined(__s390__) || defined(__s390x__) - -#define get_be32(p) ntohl(*(const unsigned int *)(p)) -#define put_be32(p, v) do { *(unsigned int *)(p) = htonl(v); } while (0) - -#else - -#define get_be32(p) ( \ - (*((const unsigned char *)(p) + 0) << 24) | \ - (*((const unsigned char *)(p) + 1) << 16) | \ - (*((const unsigned char *)(p) + 2) << 8) | \ - (*((const unsigned char *)(p) + 3) << 0) ) -#define put_be32(p, v) do { \ - unsigned int __v = (v); \ - *((unsigned char *)(p) + 0) = __v >> 24; \ - *((unsigned char *)(p) + 1) = __v >> 16; \ - *((unsigned char *)(p) + 2) = __v >> 8; \ - *((unsigned char *)(p) + 3) = __v >> 0; } while (0) - -#endif - -/* This "rolls" over the 512-bit array */ -#define W(x) (array[(x)&15]) - -/* - * Where do we get the source from? The first 16 iterations get it from - * the input data, the next mix it from the 512-bit array. - */ -#define SHA_SRC(t) get_be32(data + t) -#define SHA_MIX(t) SHA_ROL(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1) - -#define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \ - unsigned int TEMP = input(t); setW(t, TEMP); \ - E += TEMP + SHA_ROL(A,5) + (fn) + (constant); \ - B = SHA_ROR(B, 2); } while (0) - -#define T_0_15(t, A, B, C, D, E) SHA_ROUND(t, SHA_SRC, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E ) -#define T_16_19(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E ) -#define T_20_39(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0x6ed9eba1, A, B, C, D, E ) -#define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E ) -#define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0xca62c1d6, A, B, C, D, E ) - -static void hash__block(git_hash_sha1_ctx *ctx, const unsigned int *data) -{ - unsigned int A,B,C,D,E; - unsigned int array[16]; - - A = ctx->H[0]; - B = ctx->H[1]; - C = ctx->H[2]; - D = ctx->H[3]; - E = ctx->H[4]; - - /* Round 1 - iterations 0-16 take their input from 'data' */ - T_0_15( 0, A, B, C, D, E); - T_0_15( 1, E, A, B, C, D); - T_0_15( 2, D, E, A, B, C); - T_0_15( 3, C, D, E, A, B); - T_0_15( 4, B, C, D, E, A); - T_0_15( 5, A, B, C, D, E); - T_0_15( 6, E, A, B, C, D); - T_0_15( 7, D, E, A, B, C); - T_0_15( 8, C, D, E, A, B); - T_0_15( 9, B, C, D, E, A); - T_0_15(10, A, B, C, D, E); - T_0_15(11, E, A, B, C, D); - T_0_15(12, D, E, A, B, C); - T_0_15(13, C, D, E, A, B); - T_0_15(14, B, C, D, E, A); - T_0_15(15, A, B, C, D, E); - - /* Round 1 - tail. Input from 512-bit mixing array */ - T_16_19(16, E, A, B, C, D); - T_16_19(17, D, E, A, B, C); - T_16_19(18, C, D, E, A, B); - T_16_19(19, B, C, D, E, A); - - /* Round 2 */ - T_20_39(20, A, B, C, D, E); - T_20_39(21, E, A, B, C, D); - T_20_39(22, D, E, A, B, C); - T_20_39(23, C, D, E, A, B); - T_20_39(24, B, C, D, E, A); - T_20_39(25, A, B, C, D, E); - T_20_39(26, E, A, B, C, D); - T_20_39(27, D, E, A, B, C); - T_20_39(28, C, D, E, A, B); - T_20_39(29, B, C, D, E, A); - T_20_39(30, A, B, C, D, E); - T_20_39(31, E, A, B, C, D); - T_20_39(32, D, E, A, B, C); - T_20_39(33, C, D, E, A, B); - T_20_39(34, B, C, D, E, A); - T_20_39(35, A, B, C, D, E); - T_20_39(36, E, A, B, C, D); - T_20_39(37, D, E, A, B, C); - T_20_39(38, C, D, E, A, B); - T_20_39(39, B, C, D, E, A); - - /* Round 3 */ - T_40_59(40, A, B, C, D, E); - T_40_59(41, E, A, B, C, D); - T_40_59(42, D, E, A, B, C); - T_40_59(43, C, D, E, A, B); - T_40_59(44, B, C, D, E, A); - T_40_59(45, A, B, C, D, E); - T_40_59(46, E, A, B, C, D); - T_40_59(47, D, E, A, B, C); - T_40_59(48, C, D, E, A, B); - T_40_59(49, B, C, D, E, A); - T_40_59(50, A, B, C, D, E); - T_40_59(51, E, A, B, C, D); - T_40_59(52, D, E, A, B, C); - T_40_59(53, C, D, E, A, B); - T_40_59(54, B, C, D, E, A); - T_40_59(55, A, B, C, D, E); - T_40_59(56, E, A, B, C, D); - T_40_59(57, D, E, A, B, C); - T_40_59(58, C, D, E, A, B); - T_40_59(59, B, C, D, E, A); - - /* Round 4 */ - T_60_79(60, A, B, C, D, E); - T_60_79(61, E, A, B, C, D); - T_60_79(62, D, E, A, B, C); - T_60_79(63, C, D, E, A, B); - T_60_79(64, B, C, D, E, A); - T_60_79(65, A, B, C, D, E); - T_60_79(66, E, A, B, C, D); - T_60_79(67, D, E, A, B, C); - T_60_79(68, C, D, E, A, B); - T_60_79(69, B, C, D, E, A); - T_60_79(70, A, B, C, D, E); - T_60_79(71, E, A, B, C, D); - T_60_79(72, D, E, A, B, C); - T_60_79(73, C, D, E, A, B); - T_60_79(74, B, C, D, E, A); - T_60_79(75, A, B, C, D, E); - T_60_79(76, E, A, B, C, D); - T_60_79(77, D, E, A, B, C); - T_60_79(78, C, D, E, A, B); - T_60_79(79, B, C, D, E, A); - - ctx->H[0] += A; - ctx->H[1] += B; - ctx->H[2] += C; - ctx->H[3] += D; - ctx->H[4] += E; -} - -int git_hash_sha1_global_init(void) -{ - return 0; -} - -int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx) -{ - return git_hash_sha1_init(ctx); -} - -void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx) -{ - GIT_UNUSED(ctx); -} - -int git_hash_sha1_init(git_hash_sha1_ctx *ctx) -{ - ctx->size = 0; - - /* Initialize H with the magic constants (see FIPS180 for constants) */ - ctx->H[0] = 0x67452301; - ctx->H[1] = 0xefcdab89; - ctx->H[2] = 0x98badcfe; - ctx->H[3] = 0x10325476; - ctx->H[4] = 0xc3d2e1f0; - - return 0; -} - -int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len) -{ - unsigned int lenW = ctx->size & 63; - - ctx->size += len; - - /* Read the data into W and process blocks as they get full */ - if (lenW) { - unsigned int left = 64 - lenW; - if (len < left) - left = (unsigned int)len; - memcpy(lenW + (char *)ctx->W, data, left); - lenW = (lenW + left) & 63; - len -= left; - data = ((const char *)data + left); - if (lenW) - return 0; - hash__block(ctx, ctx->W); - } - while (len >= 64) { - hash__block(ctx, data); - data = ((const char *)data + 64); - len -= 64; - } - if (len) - memcpy(ctx->W, data, len); - - return 0; -} - -int git_hash_sha1_final(unsigned char *out, git_hash_sha1_ctx *ctx) -{ - static const unsigned char pad[64] = { 0x80 }; - unsigned int padlen[2]; - int i; - - /* Pad with a binary 1 (ie 0x80), then zeroes, then length */ - padlen[0] = htonl((uint32_t)(ctx->size >> 29)); - padlen[1] = htonl((uint32_t)(ctx->size << 3)); - - i = ctx->size & 63; - git_hash_sha1_update(ctx, pad, 1+ (63 & (55 - i))); - git_hash_sha1_update(ctx, padlen, 8); - - /* Output hash */ - for (i = 0; i < 5; i++) - put_be32(out + i*4, ctx->H[i]); - - return 0; -} diff --git a/vendor/libgit2/src/hash/sha1/generic.h b/vendor/libgit2/src/hash/sha1/generic.h deleted file mode 100644 index 53fc0823..00000000 --- a/vendor/libgit2/src/hash/sha1/generic.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#ifndef INCLUDE_hash_sha1_generic_h__ -#define INCLUDE_hash_sha1_generic_h__ - -#include "hash/sha1.h" - -struct git_hash_sha1_ctx { - uint64_t size; - unsigned int H[5]; - unsigned int W[16]; -}; - -#endif diff --git a/vendor/libgit2/src/hash/sha1/mbedtls.c b/vendor/libgit2/src/hash/sha1/mbedtls.c deleted file mode 100644 index 56016bec..00000000 --- a/vendor/libgit2/src/hash/sha1/mbedtls.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "mbedtls.h" - -int git_hash_sha1_global_init(void) -{ - return 0; -} - -int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx) -{ - return git_hash_sha1_init(ctx); -} - -void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx) -{ - if (ctx) - mbedtls_sha1_free(&ctx->c); -} - -int git_hash_sha1_init(git_hash_sha1_ctx *ctx) -{ - GIT_ASSERT_ARG(ctx); - mbedtls_sha1_init(&ctx->c); - mbedtls_sha1_starts(&ctx->c); - return 0; -} - -int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len) -{ - GIT_ASSERT_ARG(ctx); - mbedtls_sha1_update(&ctx->c, data, len); - return 0; -} - -int git_hash_sha1_final(unsigned char *out, git_hash_sha1_ctx *ctx) -{ - GIT_ASSERT_ARG(ctx); - mbedtls_sha1_finish(&ctx->c, out); - return 0; -} diff --git a/vendor/libgit2/src/hash/sha1/mbedtls.h b/vendor/libgit2/src/hash/sha1/mbedtls.h deleted file mode 100644 index 15f7462a..00000000 --- a/vendor/libgit2/src/hash/sha1/mbedtls.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#ifndef INCLUDE_hash_sha1_mbedtls_h__ -#define INCLUDE_hash_sha1_mbedtls_h__ - -#include "hash/sha1.h" - -#include - -struct git_hash_sha1_ctx { - mbedtls_sha1_context c; -}; - -#endif /* INCLUDE_hash_sha1_mbedtls_h__ */ diff --git a/vendor/libgit2/src/hash/sha1/openssl.c b/vendor/libgit2/src/hash/sha1/openssl.c deleted file mode 100644 index 64bf99b3..00000000 --- a/vendor/libgit2/src/hash/sha1/openssl.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "openssl.h" - -int git_hash_sha1_global_init(void) -{ - return 0; -} - -int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx) -{ - return git_hash_sha1_init(ctx); -} - -void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx) -{ - GIT_UNUSED(ctx); -} - -int git_hash_sha1_init(git_hash_sha1_ctx *ctx) -{ - GIT_ASSERT_ARG(ctx); - - if (SHA1_Init(&ctx->c) != 1) { - git_error_set(GIT_ERROR_SHA1, "hash_openssl: failed to initialize hash context"); - return -1; - } - - return 0; -} - -int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len) -{ - GIT_ASSERT_ARG(ctx); - - if (SHA1_Update(&ctx->c, data, len) != 1) { - git_error_set(GIT_ERROR_SHA1, "hash_openssl: failed to update hash"); - return -1; - } - - return 0; -} - -int git_hash_sha1_final(unsigned char *out, git_hash_sha1_ctx *ctx) -{ - GIT_ASSERT_ARG(ctx); - - if (SHA1_Final(out, &ctx->c) != 1) { - git_error_set(GIT_ERROR_SHA1, "hash_openssl: failed to finalize hash"); - return -1; - } - - return 0; -} diff --git a/vendor/libgit2/src/hash/sha1/openssl.h b/vendor/libgit2/src/hash/sha1/openssl.h deleted file mode 100644 index a223ca03..00000000 --- a/vendor/libgit2/src/hash/sha1/openssl.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#ifndef INCLUDE_hash_sha1_openssl_h__ -#define INCLUDE_hash_sha1_openssl_h__ - -#include "hash/sha1.h" - -#include - -struct git_hash_sha1_ctx { - SHA_CTX c; -}; - -#endif diff --git a/vendor/libgit2/src/hash/sha1/win32.c b/vendor/libgit2/src/hash/sha1/win32.c deleted file mode 100644 index b89dfbad..00000000 --- a/vendor/libgit2/src/hash/sha1/win32.c +++ /dev/null @@ -1,333 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "win32.h" - -#include "runtime.h" - -#include -#include - -#define GIT_HASH_CNG_DLL_NAME "bcrypt.dll" - -/* BCRYPT_SHA1_ALGORITHM */ -#define GIT_HASH_CNG_HASH_TYPE L"SHA1" - -/* BCRYPT_OBJECT_LENGTH */ -#define GIT_HASH_CNG_HASH_OBJECT_LEN L"ObjectLength" - -/* BCRYPT_HASH_REUSEABLE_FLAGS */ -#define GIT_HASH_CNG_HASH_REUSABLE 0x00000020 - -static git_hash_prov hash_prov = {0}; - -/* Hash initialization */ - -/* Initialize CNG, if available */ -GIT_INLINE(int) hash_cng_prov_init(void) -{ - char dll_path[MAX_PATH]; - DWORD dll_path_len, size_len; - - /* Only use CNG on Windows 2008 / Vista SP1 or better (Windows 6.0 SP1) */ - if (!git_has_win32_version(6, 0, 1)) { - git_error_set(GIT_ERROR_SHA1, "CryptoNG is not supported on this platform"); - return -1; - } - - /* Load bcrypt.dll explicitly from the system directory */ - if ((dll_path_len = GetSystemDirectory(dll_path, MAX_PATH)) == 0 || - dll_path_len > MAX_PATH || - StringCchCat(dll_path, MAX_PATH, "\\") < 0 || - StringCchCat(dll_path, MAX_PATH, GIT_HASH_CNG_DLL_NAME) < 0 || - (hash_prov.prov.cng.dll = LoadLibrary(dll_path)) == NULL) { - git_error_set(GIT_ERROR_SHA1, "CryptoNG library could not be loaded"); - return -1; - } - - /* Load the function addresses */ - if ((hash_prov.prov.cng.open_algorithm_provider = (hash_win32_cng_open_algorithm_provider_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptOpenAlgorithmProvider")) == NULL || - (hash_prov.prov.cng.get_property = (hash_win32_cng_get_property_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptGetProperty")) == NULL || - (hash_prov.prov.cng.create_hash = (hash_win32_cng_create_hash_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptCreateHash")) == NULL || - (hash_prov.prov.cng.finish_hash = (hash_win32_cng_finish_hash_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptFinishHash")) == NULL || - (hash_prov.prov.cng.hash_data = (hash_win32_cng_hash_data_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptHashData")) == NULL || - (hash_prov.prov.cng.destroy_hash = (hash_win32_cng_destroy_hash_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptDestroyHash")) == NULL || - (hash_prov.prov.cng.close_algorithm_provider = (hash_win32_cng_close_algorithm_provider_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptCloseAlgorithmProvider")) == NULL) { - FreeLibrary(hash_prov.prov.cng.dll); - - git_error_set(GIT_ERROR_OS, "CryptoNG functions could not be loaded"); - return -1; - } - - /* Load the SHA1 algorithm */ - if (hash_prov.prov.cng.open_algorithm_provider(&hash_prov.prov.cng.handle, GIT_HASH_CNG_HASH_TYPE, NULL, GIT_HASH_CNG_HASH_REUSABLE) < 0) { - FreeLibrary(hash_prov.prov.cng.dll); - - git_error_set(GIT_ERROR_OS, "algorithm provider could not be initialized"); - return -1; - } - - /* Get storage space for the hash object */ - if (hash_prov.prov.cng.get_property(hash_prov.prov.cng.handle, GIT_HASH_CNG_HASH_OBJECT_LEN, (PBYTE)&hash_prov.prov.cng.hash_object_size, sizeof(DWORD), &size_len, 0) < 0) { - hash_prov.prov.cng.close_algorithm_provider(hash_prov.prov.cng.handle, 0); - FreeLibrary(hash_prov.prov.cng.dll); - - git_error_set(GIT_ERROR_OS, "algorithm handle could not be found"); - return -1; - } - - hash_prov.type = CNG; - return 0; -} - -GIT_INLINE(void) hash_cng_prov_shutdown(void) -{ - hash_prov.prov.cng.close_algorithm_provider(hash_prov.prov.cng.handle, 0); - FreeLibrary(hash_prov.prov.cng.dll); - - hash_prov.type = INVALID; -} - -/* Initialize CryptoAPI */ -GIT_INLINE(int) hash_cryptoapi_prov_init() -{ - if (!CryptAcquireContext(&hash_prov.prov.cryptoapi.handle, NULL, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { - git_error_set(GIT_ERROR_OS, "legacy hash context could not be started"); - return -1; - } - - hash_prov.type = CRYPTOAPI; - return 0; -} - -GIT_INLINE(void) hash_cryptoapi_prov_shutdown(void) -{ - CryptReleaseContext(hash_prov.prov.cryptoapi.handle, 0); - - hash_prov.type = INVALID; -} - -static void sha1_shutdown(void) -{ - if (hash_prov.type == CNG) - hash_cng_prov_shutdown(); - else if(hash_prov.type == CRYPTOAPI) - hash_cryptoapi_prov_shutdown(); -} - -int git_hash_sha1_global_init(void) -{ - int error = 0; - - if (hash_prov.type != INVALID) - return 0; - - if ((error = hash_cng_prov_init()) < 0) - error = hash_cryptoapi_prov_init(); - - if (!error) - error = git_runtime_shutdown_register(sha1_shutdown); - - return error; -} - -/* CryptoAPI: available in Windows XP and newer */ - -GIT_INLINE(int) hash_ctx_cryptoapi_init(git_hash_sha1_ctx *ctx) -{ - ctx->type = CRYPTOAPI; - ctx->prov = &hash_prov; - - return git_hash_sha1_init(ctx); -} - -GIT_INLINE(int) hash_cryptoapi_init(git_hash_sha1_ctx *ctx) -{ - if (ctx->ctx.cryptoapi.valid) - CryptDestroyHash(ctx->ctx.cryptoapi.hash_handle); - - if (!CryptCreateHash(ctx->prov->prov.cryptoapi.handle, CALG_SHA1, 0, 0, &ctx->ctx.cryptoapi.hash_handle)) { - ctx->ctx.cryptoapi.valid = 0; - git_error_set(GIT_ERROR_OS, "legacy hash implementation could not be created"); - return -1; - } - - ctx->ctx.cryptoapi.valid = 1; - return 0; -} - -GIT_INLINE(int) hash_cryptoapi_update(git_hash_sha1_ctx *ctx, const void *_data, size_t len) -{ - const BYTE *data = (BYTE *)_data; - - GIT_ASSERT(ctx->ctx.cryptoapi.valid); - - while (len > 0) { - DWORD chunk = (len > MAXDWORD) ? MAXDWORD : (DWORD)len; - - if (!CryptHashData(ctx->ctx.cryptoapi.hash_handle, data, chunk, 0)) { - git_error_set(GIT_ERROR_OS, "legacy hash data could not be updated"); - return -1; - } - - data += chunk; - len -= chunk; - } - - return 0; -} - -GIT_INLINE(int) hash_cryptoapi_final(unsigned char *out, git_hash_sha1_ctx *ctx) -{ - DWORD len = GIT_HASH_SHA1_SIZE; - int error = 0; - - GIT_ASSERT(ctx->ctx.cryptoapi.valid); - - if (!CryptGetHashParam(ctx->ctx.cryptoapi.hash_handle, HP_HASHVAL, out, &len, 0)) { - git_error_set(GIT_ERROR_OS, "legacy hash data could not be finished"); - error = -1; - } - - CryptDestroyHash(ctx->ctx.cryptoapi.hash_handle); - ctx->ctx.cryptoapi.valid = 0; - - return error; -} - -GIT_INLINE(void) hash_ctx_cryptoapi_cleanup(git_hash_sha1_ctx *ctx) -{ - if (ctx->ctx.cryptoapi.valid) - CryptDestroyHash(ctx->ctx.cryptoapi.hash_handle); -} - -/* CNG: Available in Windows Server 2008 and newer */ - -GIT_INLINE(int) hash_ctx_cng_init(git_hash_sha1_ctx *ctx) -{ - if ((ctx->ctx.cng.hash_object = git__malloc(hash_prov.prov.cng.hash_object_size)) == NULL) - return -1; - - if (hash_prov.prov.cng.create_hash(hash_prov.prov.cng.handle, &ctx->ctx.cng.hash_handle, ctx->ctx.cng.hash_object, hash_prov.prov.cng.hash_object_size, NULL, 0, 0) < 0) { - git__free(ctx->ctx.cng.hash_object); - - git_error_set(GIT_ERROR_OS, "hash implementation could not be created"); - return -1; - } - - ctx->type = CNG; - ctx->prov = &hash_prov; - - return 0; -} - -GIT_INLINE(int) hash_cng_init(git_hash_sha1_ctx *ctx) -{ - BYTE hash[GIT_OID_RAWSZ]; - - if (!ctx->ctx.cng.updated) - return 0; - - /* CNG needs to be finished to restart */ - if (ctx->prov->prov.cng.finish_hash(ctx->ctx.cng.hash_handle, hash, GIT_OID_RAWSZ, 0) < 0) { - git_error_set(GIT_ERROR_OS, "hash implementation could not be finished"); - return -1; - } - - ctx->ctx.cng.updated = 0; - - return 0; -} - -GIT_INLINE(int) hash_cng_update(git_hash_sha1_ctx *ctx, const void *_data, size_t len) -{ - PBYTE data = (PBYTE)_data; - - while (len > 0) { - ULONG chunk = (len > ULONG_MAX) ? ULONG_MAX : (ULONG)len; - - if (ctx->prov->prov.cng.hash_data(ctx->ctx.cng.hash_handle, data, chunk, 0) < 0) { - git_error_set(GIT_ERROR_OS, "hash could not be updated"); - return -1; - } - - data += chunk; - len -= chunk; - } - - return 0; -} - -GIT_INLINE(int) hash_cng_final(unsigned char *out, git_hash_sha1_ctx *ctx) -{ - if (ctx->prov->prov.cng.finish_hash(ctx->ctx.cng.hash_handle, out, GIT_HASH_SHA1_SIZE, 0) < 0) { - git_error_set(GIT_ERROR_OS, "hash could not be finished"); - return -1; - } - - ctx->ctx.cng.updated = 0; - - return 0; -} - -GIT_INLINE(void) hash_ctx_cng_cleanup(git_hash_sha1_ctx *ctx) -{ - ctx->prov->prov.cng.destroy_hash(ctx->ctx.cng.hash_handle); - git__free(ctx->ctx.cng.hash_object); -} - -/* Indirection between CryptoAPI and CNG */ - -int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx) -{ - int error = 0; - - GIT_ASSERT_ARG(ctx); - - /* - * When compiled with GIT_THREADS, the global hash_prov data is - * initialized with git_libgit2_init. Otherwise, it must be initialized - * at first use. - */ - if (hash_prov.type == INVALID && (error = git_hash_sha1_global_init()) < 0) - return error; - - memset(ctx, 0x0, sizeof(git_hash_sha1_ctx)); - - return (hash_prov.type == CNG) ? hash_ctx_cng_init(ctx) : hash_ctx_cryptoapi_init(ctx); -} - -int git_hash_sha1_init(git_hash_sha1_ctx *ctx) -{ - GIT_ASSERT_ARG(ctx); - GIT_ASSERT_ARG(ctx->type); - return (ctx->type == CNG) ? hash_cng_init(ctx) : hash_cryptoapi_init(ctx); -} - -int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len) -{ - GIT_ASSERT_ARG(ctx); - GIT_ASSERT_ARG(ctx->type); - return (ctx->type == CNG) ? hash_cng_update(ctx, data, len) : hash_cryptoapi_update(ctx, data, len); -} - -int git_hash_sha1_final(unsigned char *out, git_hash_sha1_ctx *ctx) -{ - GIT_ASSERT_ARG(ctx); - GIT_ASSERT_ARG(ctx->type); - return (ctx->type == CNG) ? hash_cng_final(out, ctx) : hash_cryptoapi_final(out, ctx); -} - -void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx) -{ - if (!ctx) - return; - else if (ctx->type == CNG) - hash_ctx_cng_cleanup(ctx); - else if(ctx->type == CRYPTOAPI) - hash_ctx_cryptoapi_cleanup(ctx); -} diff --git a/vendor/libgit2/src/hash/sha1/win32.h b/vendor/libgit2/src/hash/sha1/win32.h deleted file mode 100644 index 791d20a4..00000000 --- a/vendor/libgit2/src/hash/sha1/win32.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#ifndef INCLUDE_hash_sha1_win32_h__ -#define INCLUDE_hash_sha1_win32_h__ - -#include "hash/sha1.h" - -#include -#include - -enum hash_win32_prov_type { - INVALID = 0, - CRYPTOAPI, - CNG -}; - -/* - * CryptoAPI is available for hashing on Windows XP and newer. - */ - -struct hash_cryptoapi_prov { - HCRYPTPROV handle; -}; - -/* - * CNG (bcrypt.dll) is significantly more performant than CryptoAPI and is - * preferred, however it is only available on Windows 2008 and newer and - * must therefore be dynamically loaded, and we must inline constants that - * would not exist when building in pre-Windows 2008 environments. - */ - -/* Function declarations for CNG */ -typedef NTSTATUS (WINAPI *hash_win32_cng_open_algorithm_provider_fn)( - HANDLE /* BCRYPT_ALG_HANDLE */ *phAlgorithm, - LPCWSTR pszAlgId, - LPCWSTR pszImplementation, - DWORD dwFlags); - -typedef NTSTATUS (WINAPI *hash_win32_cng_get_property_fn)( - HANDLE /* BCRYPT_HANDLE */ hObject, - LPCWSTR pszProperty, - PUCHAR pbOutput, - ULONG cbOutput, - ULONG *pcbResult, - ULONG dwFlags); - -typedef NTSTATUS (WINAPI *hash_win32_cng_create_hash_fn)( - HANDLE /* BCRYPT_ALG_HANDLE */ hAlgorithm, - HANDLE /* BCRYPT_HASH_HANDLE */ *phHash, - PUCHAR pbHashObject, ULONG cbHashObject, - PUCHAR pbSecret, - ULONG cbSecret, - ULONG dwFlags); - -typedef NTSTATUS (WINAPI *hash_win32_cng_finish_hash_fn)( - HANDLE /* BCRYPT_HASH_HANDLE */ hHash, - PUCHAR pbOutput, - ULONG cbOutput, - ULONG dwFlags); - -typedef NTSTATUS (WINAPI *hash_win32_cng_hash_data_fn)( - HANDLE /* BCRYPT_HASH_HANDLE */ hHash, - PUCHAR pbInput, - ULONG cbInput, - ULONG dwFlags); - -typedef NTSTATUS (WINAPI *hash_win32_cng_destroy_hash_fn)( - HANDLE /* BCRYPT_HASH_HANDLE */ hHash); - -typedef NTSTATUS (WINAPI *hash_win32_cng_close_algorithm_provider_fn)( - HANDLE /* BCRYPT_ALG_HANDLE */ hAlgorithm, - ULONG dwFlags); - -struct hash_cng_prov { - /* DLL for CNG */ - HINSTANCE dll; - - /* Function pointers for CNG */ - hash_win32_cng_open_algorithm_provider_fn open_algorithm_provider; - hash_win32_cng_get_property_fn get_property; - hash_win32_cng_create_hash_fn create_hash; - hash_win32_cng_finish_hash_fn finish_hash; - hash_win32_cng_hash_data_fn hash_data; - hash_win32_cng_destroy_hash_fn destroy_hash; - hash_win32_cng_close_algorithm_provider_fn close_algorithm_provider; - - HANDLE /* BCRYPT_ALG_HANDLE */ handle; - DWORD hash_object_size; -}; - -typedef struct { - enum hash_win32_prov_type type; - - union { - struct hash_cryptoapi_prov cryptoapi; - struct hash_cng_prov cng; - } prov; -} git_hash_prov; - -/* Hash contexts */ - -struct hash_cryptoapi_ctx { - bool valid; - HCRYPTHASH hash_handle; -}; - -struct hash_cng_ctx { - bool updated; - HANDLE /* BCRYPT_HASH_HANDLE */ hash_handle; - PBYTE hash_object; -}; - -struct git_hash_sha1_ctx { - enum hash_win32_prov_type type; - git_hash_prov *prov; - - union { - struct hash_cryptoapi_ctx cryptoapi; - struct hash_cng_ctx cng; - } ctx; -}; - -#endif diff --git a/vendor/libgit2/src/index.c b/vendor/libgit2/src/index.c deleted file mode 100644 index aa97c642..00000000 --- a/vendor/libgit2/src/index.c +++ /dev/null @@ -1,3765 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "index.h" - -#include - -#include "repository.h" -#include "tree.h" -#include "tree-cache.h" -#include "hash.h" -#include "iterator.h" -#include "pathspec.h" -#include "ignore.h" -#include "blob.h" -#include "idxmap.h" -#include "diff.h" -#include "varint.h" -#include "path.h" - -#include "git2/odb.h" -#include "git2/oid.h" -#include "git2/blob.h" -#include "git2/config.h" -#include "git2/sys/index.h" - -static int index_apply_to_wd_diff(git_index *index, int action, const git_strarray *paths, - unsigned int flags, - git_index_matched_path_cb cb, void *payload); - -#define minimal_entry_size (offsetof(struct entry_short, path)) - -static const size_t INDEX_HEADER_SIZE = 12; - -static const unsigned int INDEX_VERSION_NUMBER_DEFAULT = 2; -static const unsigned int INDEX_VERSION_NUMBER_LB = 2; -static const unsigned int INDEX_VERSION_NUMBER_EXT = 3; -static const unsigned int INDEX_VERSION_NUMBER_COMP = 4; -static const unsigned int INDEX_VERSION_NUMBER_UB = 4; - -static const unsigned int INDEX_HEADER_SIG = 0x44495243; -static const char INDEX_EXT_TREECACHE_SIG[] = {'T', 'R', 'E', 'E'}; -static const char INDEX_EXT_UNMERGED_SIG[] = {'R', 'E', 'U', 'C'}; -static const char INDEX_EXT_CONFLICT_NAME_SIG[] = {'N', 'A', 'M', 'E'}; - -#define INDEX_OWNER(idx) ((git_repository *)(GIT_REFCOUNT_OWNER(idx))) - -struct index_header { - uint32_t signature; - uint32_t version; - uint32_t entry_count; -}; - -struct index_extension { - char signature[4]; - uint32_t extension_size; -}; - -struct entry_time { - uint32_t seconds; - uint32_t nanoseconds; -}; - -struct entry_short { - struct entry_time ctime; - struct entry_time mtime; - uint32_t dev; - uint32_t ino; - uint32_t mode; - uint32_t uid; - uint32_t gid; - uint32_t file_size; - git_oid oid; - uint16_t flags; - char path[1]; /* arbitrary length */ -}; - -struct entry_long { - struct entry_time ctime; - struct entry_time mtime; - uint32_t dev; - uint32_t ino; - uint32_t mode; - uint32_t uid; - uint32_t gid; - uint32_t file_size; - git_oid oid; - uint16_t flags; - uint16_t flags_extended; - char path[1]; /* arbitrary length */ -}; - -struct entry_srch_key { - const char *path; - size_t pathlen; - int stage; -}; - -struct entry_internal { - git_index_entry entry; - size_t pathlen; - char path[GIT_FLEX_ARRAY]; -}; - -struct reuc_entry_internal { - git_index_reuc_entry entry; - size_t pathlen; - char path[GIT_FLEX_ARRAY]; -}; - -bool git_index__enforce_unsaved_safety = false; - -/* local declarations */ -static int read_extension(size_t *read_len, git_index *index, const char *buffer, size_t buffer_size); -static int read_header(struct index_header *dest, const void *buffer); - -static int parse_index(git_index *index, const char *buffer, size_t buffer_size); -static bool is_index_extended(git_index *index); -static int write_index(unsigned char checksum[GIT_HASH_SHA1_SIZE], size_t *checksum_size, git_index *index, git_filebuf *file); - -static void index_entry_free(git_index_entry *entry); -static void index_entry_reuc_free(git_index_reuc_entry *reuc); - -GIT_INLINE(int) index_map_set(git_idxmap *map, git_index_entry *e, bool ignore_case) -{ - if (ignore_case) - return git_idxmap_icase_set((git_idxmap_icase *) map, e, e); - else - return git_idxmap_set(map, e, e); -} - -GIT_INLINE(int) index_map_delete(git_idxmap *map, git_index_entry *e, bool ignore_case) -{ - if (ignore_case) - return git_idxmap_icase_delete((git_idxmap_icase *) map, e); - else - return git_idxmap_delete(map, e); -} - -GIT_INLINE(int) index_map_resize(git_idxmap *map, size_t count, bool ignore_case) -{ - if (ignore_case) - return git_idxmap_icase_resize((git_idxmap_icase *) map, count); - else - return git_idxmap_resize(map, count); -} - -int git_index_entry_srch(const void *key, const void *array_member) -{ - const struct entry_srch_key *srch_key = key; - const struct entry_internal *entry = array_member; - int cmp; - size_t len1, len2, len; - - len1 = srch_key->pathlen; - len2 = entry->pathlen; - len = len1 < len2 ? len1 : len2; - - cmp = memcmp(srch_key->path, entry->path, len); - if (cmp) - return cmp; - if (len1 < len2) - return -1; - if (len1 > len2) - return 1; - - if (srch_key->stage != GIT_INDEX_STAGE_ANY) - return srch_key->stage - GIT_INDEX_ENTRY_STAGE(&entry->entry); - - return 0; -} - -int git_index_entry_isrch(const void *key, const void *array_member) -{ - const struct entry_srch_key *srch_key = key; - const struct entry_internal *entry = array_member; - int cmp; - size_t len1, len2, len; - - len1 = srch_key->pathlen; - len2 = entry->pathlen; - len = len1 < len2 ? len1 : len2; - - cmp = strncasecmp(srch_key->path, entry->path, len); - - if (cmp) - return cmp; - if (len1 < len2) - return -1; - if (len1 > len2) - return 1; - - if (srch_key->stage != GIT_INDEX_STAGE_ANY) - return srch_key->stage - GIT_INDEX_ENTRY_STAGE(&entry->entry); - - return 0; -} - -static int index_entry_srch_path(const void *path, const void *array_member) -{ - const git_index_entry *entry = array_member; - - return strcmp((const char *)path, entry->path); -} - -static int index_entry_isrch_path(const void *path, const void *array_member) -{ - const git_index_entry *entry = array_member; - - return strcasecmp((const char *)path, entry->path); -} - -int git_index_entry_cmp(const void *a, const void *b) -{ - int diff; - const git_index_entry *entry_a = a; - const git_index_entry *entry_b = b; - - diff = strcmp(entry_a->path, entry_b->path); - - if (diff == 0) - diff = (GIT_INDEX_ENTRY_STAGE(entry_a) - GIT_INDEX_ENTRY_STAGE(entry_b)); - - return diff; -} - -int git_index_entry_icmp(const void *a, const void *b) -{ - int diff; - const git_index_entry *entry_a = a; - const git_index_entry *entry_b = b; - - diff = strcasecmp(entry_a->path, entry_b->path); - - if (diff == 0) - diff = (GIT_INDEX_ENTRY_STAGE(entry_a) - GIT_INDEX_ENTRY_STAGE(entry_b)); - - return diff; -} - -static int conflict_name_cmp(const void *a, const void *b) -{ - const git_index_name_entry *name_a = a; - const git_index_name_entry *name_b = b; - - if (name_a->ancestor && !name_b->ancestor) - return 1; - - if (!name_a->ancestor && name_b->ancestor) - return -1; - - if (name_a->ancestor) - return strcmp(name_a->ancestor, name_b->ancestor); - - if (!name_a->ours || !name_b->ours) - return 0; - - return strcmp(name_a->ours, name_b->ours); -} - -/** - * TODO: enable this when resolving case insensitive conflicts - */ -#if 0 -static int conflict_name_icmp(const void *a, const void *b) -{ - const git_index_name_entry *name_a = a; - const git_index_name_entry *name_b = b; - - if (name_a->ancestor && !name_b->ancestor) - return 1; - - if (!name_a->ancestor && name_b->ancestor) - return -1; - - if (name_a->ancestor) - return strcasecmp(name_a->ancestor, name_b->ancestor); - - if (!name_a->ours || !name_b->ours) - return 0; - - return strcasecmp(name_a->ours, name_b->ours); -} -#endif - -static int reuc_srch(const void *key, const void *array_member) -{ - const git_index_reuc_entry *reuc = array_member; - - return strcmp(key, reuc->path); -} - -static int reuc_isrch(const void *key, const void *array_member) -{ - const git_index_reuc_entry *reuc = array_member; - - return strcasecmp(key, reuc->path); -} - -static int reuc_cmp(const void *a, const void *b) -{ - const git_index_reuc_entry *info_a = a; - const git_index_reuc_entry *info_b = b; - - return strcmp(info_a->path, info_b->path); -} - -static int reuc_icmp(const void *a, const void *b) -{ - const git_index_reuc_entry *info_a = a; - const git_index_reuc_entry *info_b = b; - - return strcasecmp(info_a->path, info_b->path); -} - -static void index_entry_reuc_free(git_index_reuc_entry *reuc) -{ - git__free(reuc); -} - -static void index_entry_free(git_index_entry *entry) -{ - if (!entry) - return; - - memset(&entry->id, 0, sizeof(entry->id)); - git__free(entry); -} - -unsigned int git_index__create_mode(unsigned int mode) -{ - if (S_ISLNK(mode)) - return S_IFLNK; - - if (S_ISDIR(mode) || (mode & S_IFMT) == (S_IFLNK | S_IFDIR)) - return (S_IFLNK | S_IFDIR); - - return S_IFREG | GIT_PERMS_CANONICAL(mode); -} - -static unsigned int index_merge_mode( - git_index *index, git_index_entry *existing, unsigned int mode) -{ - if (index->no_symlinks && S_ISREG(mode) && - existing && S_ISLNK(existing->mode)) - return existing->mode; - - if (index->distrust_filemode && S_ISREG(mode)) - return (existing && S_ISREG(existing->mode)) ? - existing->mode : git_index__create_mode(0666); - - return git_index__create_mode(mode); -} - -GIT_INLINE(int) index_find_in_entries( - size_t *out, git_vector *entries, git_vector_cmp entry_srch, - const char *path, size_t path_len, int stage) -{ - struct entry_srch_key srch_key; - srch_key.path = path; - srch_key.pathlen = !path_len ? strlen(path) : path_len; - srch_key.stage = stage; - return git_vector_bsearch2(out, entries, entry_srch, &srch_key); -} - -GIT_INLINE(int) index_find( - size_t *out, git_index *index, - const char *path, size_t path_len, int stage) -{ - git_vector_sort(&index->entries); - - return index_find_in_entries( - out, &index->entries, index->entries_search, path, path_len, stage); -} - -void git_index__set_ignore_case(git_index *index, bool ignore_case) -{ - index->ignore_case = ignore_case; - - if (ignore_case) { - index->entries_cmp_path = git__strcasecmp_cb; - index->entries_search = git_index_entry_isrch; - index->entries_search_path = index_entry_isrch_path; - index->reuc_search = reuc_isrch; - } else { - index->entries_cmp_path = git__strcmp_cb; - index->entries_search = git_index_entry_srch; - index->entries_search_path = index_entry_srch_path; - index->reuc_search = reuc_srch; - } - - git_vector_set_cmp(&index->entries, - ignore_case ? git_index_entry_icmp : git_index_entry_cmp); - git_vector_sort(&index->entries); - - git_vector_set_cmp(&index->reuc, ignore_case ? reuc_icmp : reuc_cmp); - git_vector_sort(&index->reuc); -} - -int git_index_open(git_index **index_out, const char *index_path) -{ - git_index *index; - int error = -1; - - GIT_ASSERT_ARG(index_out); - - index = git__calloc(1, sizeof(git_index)); - GIT_ERROR_CHECK_ALLOC(index); - - if (git_pool_init(&index->tree_pool, 1) < 0) - goto fail; - - if (index_path != NULL) { - index->index_file_path = git__strdup(index_path); - if (!index->index_file_path) - goto fail; - - /* Check if index file is stored on disk already */ - if (git_fs_path_exists(index->index_file_path) == true) - index->on_disk = 1; - } - - if (git_vector_init(&index->entries, 32, git_index_entry_cmp) < 0 || - git_idxmap_new(&index->entries_map) < 0 || - git_vector_init(&index->names, 8, conflict_name_cmp) < 0 || - git_vector_init(&index->reuc, 8, reuc_cmp) < 0 || - git_vector_init(&index->deleted, 8, git_index_entry_cmp) < 0) - goto fail; - - index->entries_cmp_path = git__strcmp_cb; - index->entries_search = git_index_entry_srch; - index->entries_search_path = index_entry_srch_path; - index->reuc_search = reuc_srch; - index->version = INDEX_VERSION_NUMBER_DEFAULT; - - if (index_path != NULL && (error = git_index_read(index, true)) < 0) - goto fail; - - *index_out = index; - GIT_REFCOUNT_INC(index); - - return 0; - -fail: - git_pool_clear(&index->tree_pool); - git_index_free(index); - return error; -} - -int git_index_new(git_index **out) -{ - return git_index_open(out, NULL); -} - -static void index_free(git_index *index) -{ - /* index iterators increment the refcount of the index, so if we - * get here then there should be no outstanding iterators. - */ - if (git_atomic32_get(&index->readers)) - return; - - git_index_clear(index); - git_idxmap_free(index->entries_map); - git_vector_free(&index->entries); - git_vector_free(&index->names); - git_vector_free(&index->reuc); - git_vector_free(&index->deleted); - - git__free(index->index_file_path); - - git__memzero(index, sizeof(*index)); - git__free(index); -} - -void git_index_free(git_index *index) -{ - if (index == NULL) - return; - - GIT_REFCOUNT_DEC(index, index_free); -} - -/* call with locked index */ -static void index_free_deleted(git_index *index) -{ - int readers = (int)git_atomic32_get(&index->readers); - size_t i; - - if (readers > 0 || !index->deleted.length) - return; - - for (i = 0; i < index->deleted.length; ++i) { - git_index_entry *ie = git_atomic_swap(index->deleted.contents[i], NULL); - index_entry_free(ie); - } - - git_vector_clear(&index->deleted); -} - -/* call with locked index */ -static int index_remove_entry(git_index *index, size_t pos) -{ - int error = 0; - git_index_entry *entry = git_vector_get(&index->entries, pos); - - if (entry != NULL) { - git_tree_cache_invalidate_path(index->tree, entry->path); - index_map_delete(index->entries_map, entry, index->ignore_case); - } - - error = git_vector_remove(&index->entries, pos); - - if (!error) { - if (git_atomic32_get(&index->readers) > 0) { - error = git_vector_insert(&index->deleted, entry); - } else { - index_entry_free(entry); - } - - index->dirty = 1; - } - - return error; -} - -int git_index_clear(git_index *index) -{ - int error = 0; - - GIT_ASSERT_ARG(index); - - index->dirty = 1; - index->tree = NULL; - git_pool_clear(&index->tree_pool); - - git_idxmap_clear(index->entries_map); - while (!error && index->entries.length > 0) - error = index_remove_entry(index, index->entries.length - 1); - - if (error) - goto done; - - index_free_deleted(index); - - if ((error = git_index_name_clear(index)) < 0 || - (error = git_index_reuc_clear(index)) < 0) - goto done; - - git_futils_filestamp_set(&index->stamp, NULL); - -done: - return error; -} - -static int create_index_error(int error, const char *msg) -{ - git_error_set_str(GIT_ERROR_INDEX, msg); - return error; -} - -int git_index_set_caps(git_index *index, int caps) -{ - unsigned int old_ignore_case; - - GIT_ASSERT_ARG(index); - - old_ignore_case = index->ignore_case; - - if (caps == GIT_INDEX_CAPABILITY_FROM_OWNER) { - git_repository *repo = INDEX_OWNER(index); - int val; - - if (!repo) - return create_index_error( - -1, "cannot access repository to set index caps"); - - if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_IGNORECASE)) - index->ignore_case = (val != 0); - if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_FILEMODE)) - index->distrust_filemode = (val == 0); - if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_SYMLINKS)) - index->no_symlinks = (val == 0); - } - else { - index->ignore_case = ((caps & GIT_INDEX_CAPABILITY_IGNORE_CASE) != 0); - index->distrust_filemode = ((caps & GIT_INDEX_CAPABILITY_NO_FILEMODE) != 0); - index->no_symlinks = ((caps & GIT_INDEX_CAPABILITY_NO_SYMLINKS) != 0); - } - - if (old_ignore_case != index->ignore_case) { - git_index__set_ignore_case(index, (bool)index->ignore_case); - } - - return 0; -} - -int git_index_caps(const git_index *index) -{ - return ((index->ignore_case ? GIT_INDEX_CAPABILITY_IGNORE_CASE : 0) | - (index->distrust_filemode ? GIT_INDEX_CAPABILITY_NO_FILEMODE : 0) | - (index->no_symlinks ? GIT_INDEX_CAPABILITY_NO_SYMLINKS : 0)); -} - -#ifndef GIT_DEPRECATE_HARD -const git_oid *git_index_checksum(git_index *index) -{ - return (git_oid *)index->checksum; -} -#endif - -/** - * Returns 1 for changed, 0 for not changed and <0 for errors - */ -static int compare_checksum(git_index *index) -{ - int fd; - ssize_t bytes_read; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; - size_t checksum_size = GIT_HASH_SHA1_SIZE; - - if ((fd = p_open(index->index_file_path, O_RDONLY)) < 0) - return fd; - - if (p_lseek(fd, (0 - (ssize_t)checksum_size), SEEK_END) < 0) { - p_close(fd); - git_error_set(GIT_ERROR_OS, "failed to seek to end of file"); - return -1; - } - - bytes_read = p_read(fd, checksum, checksum_size); - p_close(fd); - - if (bytes_read < (ssize_t)checksum_size) - return -1; - - return !!memcmp(checksum, index->checksum, checksum_size); -} - -int git_index_read(git_index *index, int force) -{ - int error = 0, updated; - git_str buffer = GIT_STR_INIT; - git_futils_filestamp stamp = index->stamp; - - if (!index->index_file_path) - return create_index_error(-1, - "failed to read index: The index is in-memory only"); - - index->on_disk = git_fs_path_exists(index->index_file_path); - - if (!index->on_disk) { - if (force && (error = git_index_clear(index)) < 0) - return error; - - index->dirty = 0; - return 0; - } - - if ((updated = git_futils_filestamp_check(&stamp, index->index_file_path) < 0) || - ((updated = compare_checksum(index)) < 0)) { - git_error_set( - GIT_ERROR_INDEX, - "failed to read index: '%s' no longer exists", - index->index_file_path); - return updated; - } - - if (!updated && !force) - return 0; - - error = git_futils_readbuffer(&buffer, index->index_file_path); - if (error < 0) - return error; - - index->tree = NULL; - git_pool_clear(&index->tree_pool); - - error = git_index_clear(index); - - if (!error) - error = parse_index(index, buffer.ptr, buffer.size); - - if (!error) { - git_futils_filestamp_set(&index->stamp, &stamp); - index->dirty = 0; - } - - git_str_dispose(&buffer); - return error; -} - -int git_index_read_safely(git_index *index) -{ - if (git_index__enforce_unsaved_safety && index->dirty) { - git_error_set(GIT_ERROR_INDEX, - "the index has unsaved changes that would be overwritten by this operation"); - return GIT_EINDEXDIRTY; - } - - return git_index_read(index, false); -} - -static bool is_racy_entry(git_index *index, const git_index_entry *entry) -{ - /* Git special-cases submodules in the check */ - if (S_ISGITLINK(entry->mode)) - return false; - - return git_index_entry_newer_than_index(entry, index); -} - -/* - * Force the next diff to take a look at those entries which have the - * same timestamp as the current index. - */ -static int truncate_racily_clean(git_index *index) -{ - size_t i; - int error; - git_index_entry *entry; - git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; - git_diff *diff = NULL; - git_vector paths = GIT_VECTOR_INIT; - git_diff_delta *delta; - - /* Nothing to do if there's no repo to talk about */ - if (!INDEX_OWNER(index)) - return 0; - - /* If there's no workdir, we can't know where to even check */ - if (!git_repository_workdir(INDEX_OWNER(index))) - return 0; - - diff_opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE | GIT_DIFF_IGNORE_SUBMODULES | GIT_DIFF_DISABLE_PATHSPEC_MATCH; - git_vector_foreach(&index->entries, i, entry) { - if ((entry->flags_extended & GIT_INDEX_ENTRY_UPTODATE) == 0 && - is_racy_entry(index, entry)) - git_vector_insert(&paths, (char *)entry->path); - } - - if (paths.length == 0) - goto done; - - diff_opts.pathspec.count = paths.length; - diff_opts.pathspec.strings = (char **)paths.contents; - - if ((error = git_diff_index_to_workdir(&diff, INDEX_OWNER(index), index, &diff_opts)) < 0) - return error; - - git_vector_foreach(&diff->deltas, i, delta) { - entry = (git_index_entry *)git_index_get_bypath(index, delta->old_file.path, 0); - - /* Ensure that we have a stage 0 for this file (ie, it's not a - * conflict), otherwise smudging it is quite pointless. - */ - if (entry) { - entry->file_size = 0; - index->dirty = 1; - } - } - -done: - git_diff_free(diff); - git_vector_free(&paths); - return 0; -} - -unsigned git_index_version(git_index *index) -{ - GIT_ASSERT_ARG(index); - - return index->version; -} - -int git_index_set_version(git_index *index, unsigned int version) -{ - GIT_ASSERT_ARG(index); - - if (version < INDEX_VERSION_NUMBER_LB || - version > INDEX_VERSION_NUMBER_UB) { - git_error_set(GIT_ERROR_INDEX, "invalid version number"); - return -1; - } - - index->version = version; - - return 0; -} - -int git_index_write(git_index *index) -{ - git_indexwriter writer = GIT_INDEXWRITER_INIT; - int error; - - truncate_racily_clean(index); - - if ((error = git_indexwriter_init(&writer, index)) == 0 && - (error = git_indexwriter_commit(&writer)) == 0) - index->dirty = 0; - - git_indexwriter_cleanup(&writer); - - return error; -} - -const char *git_index_path(const git_index *index) -{ - GIT_ASSERT_ARG_WITH_RETVAL(index, NULL); - return index->index_file_path; -} - -int git_index_write_tree(git_oid *oid, git_index *index) -{ - git_repository *repo; - - GIT_ASSERT_ARG(oid); - GIT_ASSERT_ARG(index); - - repo = INDEX_OWNER(index); - - if (repo == NULL) - return create_index_error(-1, "Failed to write tree. " - "the index file is not backed up by an existing repository"); - - return git_tree__write_index(oid, index, repo); -} - -int git_index_write_tree_to( - git_oid *oid, git_index *index, git_repository *repo) -{ - GIT_ASSERT_ARG(oid); - GIT_ASSERT_ARG(index); - GIT_ASSERT_ARG(repo); - - return git_tree__write_index(oid, index, repo); -} - -size_t git_index_entrycount(const git_index *index) -{ - GIT_ASSERT_ARG(index); - - return index->entries.length; -} - -const git_index_entry *git_index_get_byindex( - git_index *index, size_t n) -{ - GIT_ASSERT_ARG_WITH_RETVAL(index, NULL); - - git_vector_sort(&index->entries); - return git_vector_get(&index->entries, n); -} - -const git_index_entry *git_index_get_bypath( - git_index *index, const char *path, int stage) -{ - git_index_entry key = {{ 0 }}; - git_index_entry *value; - - GIT_ASSERT_ARG_WITH_RETVAL(index, NULL); - - key.path = path; - GIT_INDEX_ENTRY_STAGE_SET(&key, stage); - - if (index->ignore_case) - value = git_idxmap_icase_get((git_idxmap_icase *) index->entries_map, &key); - else - value = git_idxmap_get(index->entries_map, &key); - - if (!value) { - git_error_set(GIT_ERROR_INDEX, "index does not contain '%s'", path); - return NULL; - } - - return value; -} - -void git_index_entry__init_from_stat( - git_index_entry *entry, struct stat *st, bool trust_mode) -{ - entry->ctime.seconds = (int32_t)st->st_ctime; - entry->mtime.seconds = (int32_t)st->st_mtime; -#if defined(GIT_USE_NSEC) - entry->mtime.nanoseconds = st->st_mtime_nsec; - entry->ctime.nanoseconds = st->st_ctime_nsec; -#endif - entry->dev = st->st_rdev; - entry->ino = st->st_ino; - entry->mode = (!trust_mode && S_ISREG(st->st_mode)) ? - git_index__create_mode(0666) : git_index__create_mode(st->st_mode); - entry->uid = st->st_uid; - entry->gid = st->st_gid; - entry->file_size = (uint32_t)st->st_size; -} - -static void index_entry_adjust_namemask( - git_index_entry *entry, - size_t path_length) -{ - entry->flags &= ~GIT_INDEX_ENTRY_NAMEMASK; - - if (path_length < GIT_INDEX_ENTRY_NAMEMASK) - entry->flags |= path_length & GIT_INDEX_ENTRY_NAMEMASK; - else - entry->flags |= GIT_INDEX_ENTRY_NAMEMASK; -} - -/* When `from_workdir` is true, we will validate the paths to avoid placing - * paths that are invalid for the working directory on the current filesystem - * (eg, on Windows, we will disallow `GIT~1`, `AUX`, `COM1`, etc). This - * function will *always* prevent `.git` and directory traversal `../` from - * being added to the index. - */ -static int index_entry_create( - git_index_entry **out, - git_repository *repo, - const char *path, - struct stat *st, - bool from_workdir) -{ - size_t pathlen = strlen(path), alloclen; - struct entry_internal *entry; - unsigned int path_valid_flags = GIT_PATH_REJECT_INDEX_DEFAULTS; - uint16_t mode = 0; - - /* always reject placing `.git` in the index and directory traversal. - * when requested, disallow platform-specific filenames and upgrade to - * the platform-specific `.git` tests (eg, `git~1`, etc). - */ - if (from_workdir) - path_valid_flags |= GIT_PATH_REJECT_WORKDIR_DEFAULTS; - if (st) - mode = st->st_mode; - - if (!git_path_is_valid(repo, path, mode, path_valid_flags)) { - git_error_set(GIT_ERROR_INDEX, "invalid path: '%s'", path); - return -1; - } - - GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, sizeof(struct entry_internal), pathlen); - GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1); - entry = git__calloc(1, alloclen); - GIT_ERROR_CHECK_ALLOC(entry); - - entry->pathlen = pathlen; - memcpy(entry->path, path, pathlen); - entry->entry.path = entry->path; - - *out = (git_index_entry *)entry; - return 0; -} - -static int index_entry_init( - git_index_entry **entry_out, - git_index *index, - const char *rel_path) -{ - int error = 0; - git_index_entry *entry = NULL; - git_str path = GIT_STR_INIT; - struct stat st; - git_oid oid; - git_repository *repo; - - if (INDEX_OWNER(index) == NULL) - return create_index_error(-1, - "could not initialize index entry. " - "Index is not backed up by an existing repository."); - - /* - * FIXME: this is duplicated with the work in - * git_blob__create_from_paths. It should accept an optional stat - * structure so we can pass in the one we have to do here. - */ - repo = INDEX_OWNER(index); - if (git_repository__ensure_not_bare(repo, "create blob from file") < 0) - return GIT_EBAREREPO; - - if (git_repository_workdir_path(&path, repo, rel_path) < 0) - return -1; - - error = git_fs_path_lstat(path.ptr, &st); - git_str_dispose(&path); - - if (error < 0) - return error; - - if (index_entry_create(&entry, INDEX_OWNER(index), rel_path, &st, true) < 0) - return -1; - - /* write the blob to disk and get the oid and stat info */ - error = git_blob__create_from_paths( - &oid, &st, INDEX_OWNER(index), NULL, rel_path, 0, true); - - if (error < 0) { - index_entry_free(entry); - return error; - } - - entry->id = oid; - git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode); - - *entry_out = (git_index_entry *)entry; - return 0; -} - -static git_index_reuc_entry *reuc_entry_alloc(const char *path) -{ - size_t pathlen = strlen(path), - structlen = sizeof(struct reuc_entry_internal), - alloclen; - struct reuc_entry_internal *entry; - - if (GIT_ADD_SIZET_OVERFLOW(&alloclen, structlen, pathlen) || - GIT_ADD_SIZET_OVERFLOW(&alloclen, alloclen, 1)) - return NULL; - - entry = git__calloc(1, alloclen); - if (!entry) - return NULL; - - entry->pathlen = pathlen; - memcpy(entry->path, path, pathlen); - entry->entry.path = entry->path; - - return (git_index_reuc_entry *)entry; -} - -static int index_entry_reuc_init(git_index_reuc_entry **reuc_out, - const char *path, - int ancestor_mode, const git_oid *ancestor_oid, - int our_mode, const git_oid *our_oid, - int their_mode, const git_oid *their_oid) -{ - git_index_reuc_entry *reuc = NULL; - - GIT_ASSERT_ARG(reuc_out); - GIT_ASSERT_ARG(path); - - *reuc_out = reuc = reuc_entry_alloc(path); - GIT_ERROR_CHECK_ALLOC(reuc); - - if ((reuc->mode[0] = ancestor_mode) > 0) { - GIT_ASSERT(ancestor_oid); - git_oid_cpy(&reuc->oid[0], ancestor_oid); - } - - if ((reuc->mode[1] = our_mode) > 0) { - GIT_ASSERT(our_oid); - git_oid_cpy(&reuc->oid[1], our_oid); - } - - if ((reuc->mode[2] = their_mode) > 0) { - GIT_ASSERT(their_oid); - git_oid_cpy(&reuc->oid[2], their_oid); - } - - return 0; -} - -static void index_entry_cpy( - git_index_entry *tgt, - const git_index_entry *src) -{ - const char *tgt_path = tgt->path; - memcpy(tgt, src, sizeof(*tgt)); - tgt->path = tgt_path; -} - -static int index_entry_dup( - git_index_entry **out, - git_index *index, - const git_index_entry *src) -{ - if (index_entry_create(out, INDEX_OWNER(index), src->path, NULL, false) < 0) - return -1; - - index_entry_cpy(*out, src); - return 0; -} - -static void index_entry_cpy_nocache( - git_index_entry *tgt, - const git_index_entry *src) -{ - git_oid_cpy(&tgt->id, &src->id); - tgt->mode = src->mode; - tgt->flags = src->flags; - tgt->flags_extended = (src->flags_extended & GIT_INDEX_ENTRY_EXTENDED_FLAGS); -} - -static int index_entry_dup_nocache( - git_index_entry **out, - git_index *index, - const git_index_entry *src) -{ - if (index_entry_create(out, INDEX_OWNER(index), src->path, NULL, false) < 0) - return -1; - - index_entry_cpy_nocache(*out, src); - return 0; -} - -static int has_file_name(git_index *index, - const git_index_entry *entry, size_t pos, int ok_to_replace) -{ - size_t len = strlen(entry->path); - int stage = GIT_INDEX_ENTRY_STAGE(entry); - const char *name = entry->path; - - while (pos < index->entries.length) { - struct entry_internal *p = index->entries.contents[pos++]; - - if (len >= p->pathlen) - break; - if (memcmp(name, p->path, len)) - break; - if (GIT_INDEX_ENTRY_STAGE(&p->entry) != stage) - continue; - if (p->path[len] != '/') - continue; - if (!ok_to_replace) - return -1; - - if (index_remove_entry(index, --pos) < 0) - break; - } - return 0; -} - -/* - * Do we have another file with a pathname that is a proper - * subset of the name we're trying to add? - */ -static int has_dir_name(git_index *index, - const git_index_entry *entry, int ok_to_replace) -{ - int stage = GIT_INDEX_ENTRY_STAGE(entry); - const char *name = entry->path; - const char *slash = name + strlen(name); - - for (;;) { - size_t len, pos; - - for (;;) { - if (*--slash == '/') - break; - if (slash <= entry->path) - return 0; - } - len = slash - name; - - if (!index_find(&pos, index, name, len, stage)) { - if (!ok_to_replace) - return -1; - - if (index_remove_entry(index, pos) < 0) - break; - continue; - } - - /* - * Trivial optimization: if we find an entry that - * already matches the sub-directory, then we know - * we're ok, and we can exit. - */ - for (; pos < index->entries.length; ++pos) { - struct entry_internal *p = index->entries.contents[pos]; - - if (p->pathlen <= len || - p->path[len] != '/' || - memcmp(p->path, name, len)) - break; /* not our subdirectory */ - - if (GIT_INDEX_ENTRY_STAGE(&p->entry) == stage) - return 0; - } - } - - return 0; -} - -static int check_file_directory_collision(git_index *index, - git_index_entry *entry, size_t pos, int ok_to_replace) -{ - if (has_file_name(index, entry, pos, ok_to_replace) < 0 || - has_dir_name(index, entry, ok_to_replace) < 0) { - git_error_set(GIT_ERROR_INDEX, - "'%s' appears as both a file and a directory", entry->path); - return -1; - } - - return 0; -} - -static int canonicalize_directory_path( - git_index *index, - git_index_entry *entry, - git_index_entry *existing) -{ - const git_index_entry *match, *best = NULL; - char *search, *sep; - size_t pos, search_len, best_len; - - if (!index->ignore_case) - return 0; - - /* item already exists in the index, simply re-use the existing case */ - if (existing) { - memcpy((char *)entry->path, existing->path, strlen(existing->path)); - return 0; - } - - /* nothing to do */ - if (strchr(entry->path, '/') == NULL) - return 0; - - if ((search = git__strdup(entry->path)) == NULL) - return -1; - - /* starting at the parent directory and descending to the root, find the - * common parent directory. - */ - while (!best && (sep = strrchr(search, '/'))) { - sep[1] = '\0'; - - search_len = strlen(search); - - git_vector_bsearch2( - &pos, &index->entries, index->entries_search_path, search); - - while ((match = git_vector_get(&index->entries, pos))) { - if (GIT_INDEX_ENTRY_STAGE(match) != 0) { - /* conflicts do not contribute to canonical paths */ - } else if (strncmp(search, match->path, search_len) == 0) { - /* prefer an exact match to the input filename */ - best = match; - best_len = search_len; - break; - } else if (strncasecmp(search, match->path, search_len) == 0) { - /* continue walking, there may be a path with an exact - * (case sensitive) match later in the index, but use this - * as the best match until that happens. - */ - if (!best) { - best = match; - best_len = search_len; - } - } else { - break; - } - - pos++; - } - - sep[0] = '\0'; - } - - if (best) - memcpy((char *)entry->path, best->path, best_len); - - git__free(search); - return 0; -} - -static int index_no_dups(void **old, void *new) -{ - const git_index_entry *entry = new; - GIT_UNUSED(old); - git_error_set(GIT_ERROR_INDEX, "'%s' appears multiple times at stage %d", - entry->path, GIT_INDEX_ENTRY_STAGE(entry)); - return GIT_EEXISTS; -} - -static void index_existing_and_best( - git_index_entry **existing, - size_t *existing_position, - git_index_entry **best, - git_index *index, - const git_index_entry *entry) -{ - git_index_entry *e; - size_t pos; - int error; - - error = index_find(&pos, - index, entry->path, 0, GIT_INDEX_ENTRY_STAGE(entry)); - - if (error == 0) { - *existing = index->entries.contents[pos]; - *existing_position = pos; - *best = index->entries.contents[pos]; - return; - } - - *existing = NULL; - *existing_position = 0; - *best = NULL; - - if (GIT_INDEX_ENTRY_STAGE(entry) == 0) { - for (; pos < index->entries.length; pos++) { - int (*strcomp)(const char *a, const char *b) = - index->ignore_case ? git__strcasecmp : git__strcmp; - - e = index->entries.contents[pos]; - - if (strcomp(entry->path, e->path) != 0) - break; - - if (GIT_INDEX_ENTRY_STAGE(e) == GIT_INDEX_STAGE_ANCESTOR) { - *best = e; - continue; - } else { - *best = e; - break; - } - } - } -} - -/* index_insert takes ownership of the new entry - if it can't insert - * it, then it will return an error **and also free the entry**. When - * it replaces an existing entry, it will update the entry_ptr with the - * actual entry in the index (and free the passed in one). - * - * trust_path is whether we use the given path, or whether (on case - * insensitive systems only) we try to canonicalize the given path to - * be within an existing directory. - * - * trust_mode is whether we trust the mode in entry_ptr. - * - * trust_id is whether we trust the id or it should be validated. - */ -static int index_insert( - git_index *index, - git_index_entry **entry_ptr, - int replace, - bool trust_path, - bool trust_mode, - bool trust_id) -{ - git_index_entry *existing, *best, *entry; - size_t path_length, position; - int error; - - GIT_ASSERT_ARG(index); - GIT_ASSERT_ARG(entry_ptr); - - entry = *entry_ptr; - - /* Make sure that the path length flag is correct */ - path_length = ((struct entry_internal *)entry)->pathlen; - index_entry_adjust_namemask(entry, path_length); - - /* This entry is now up-to-date and should not be checked for raciness */ - entry->flags_extended |= GIT_INDEX_ENTRY_UPTODATE; - - git_vector_sort(&index->entries); - - /* - * Look if an entry with this path already exists, either staged, or (if - * this entry is a regular staged item) as the "ours" side of a conflict. - */ - index_existing_and_best(&existing, &position, &best, index, entry); - - /* Update the file mode */ - entry->mode = trust_mode ? - git_index__create_mode(entry->mode) : - index_merge_mode(index, best, entry->mode); - - /* Canonicalize the directory name */ - if (!trust_path && (error = canonicalize_directory_path(index, entry, best)) < 0) - goto out; - - /* Ensure that the given id exists (unless it's a submodule) */ - if (!trust_id && INDEX_OWNER(index) && - (entry->mode & GIT_FILEMODE_COMMIT) != GIT_FILEMODE_COMMIT) { - - if (!git_object__is_valid(INDEX_OWNER(index), &entry->id, - git_object__type_from_filemode(entry->mode))) { - error = -1; - goto out; - } - } - - /* Look for tree / blob name collisions, removing conflicts if requested */ - if ((error = check_file_directory_collision(index, entry, position, replace)) < 0) - goto out; - - /* - * If we are replacing an existing item, overwrite the existing entry - * and return it in place of the passed in one. - */ - if (existing) { - if (replace) { - index_entry_cpy(existing, entry); - - if (trust_path) - memcpy((char *)existing->path, entry->path, strlen(entry->path)); - } - - index_entry_free(entry); - *entry_ptr = existing; - } else { - /* - * If replace is not requested or no existing entry exists, insert - * at the sorted position. (Since we re-sort after each insert to - * check for dups, this is actually cheaper in the long run.) - */ - if ((error = git_vector_insert_sorted(&index->entries, entry, index_no_dups)) < 0 || - (error = index_map_set(index->entries_map, entry, index->ignore_case)) < 0) - goto out; - } - - index->dirty = 1; - -out: - if (error < 0) { - index_entry_free(*entry_ptr); - *entry_ptr = NULL; - } - - return error; -} - -static int index_conflict_to_reuc(git_index *index, const char *path) -{ - const git_index_entry *conflict_entries[3]; - int ancestor_mode, our_mode, their_mode; - git_oid const *ancestor_oid, *our_oid, *their_oid; - int ret; - - if ((ret = git_index_conflict_get(&conflict_entries[0], - &conflict_entries[1], &conflict_entries[2], index, path)) < 0) - return ret; - - ancestor_mode = conflict_entries[0] == NULL ? 0 : conflict_entries[0]->mode; - our_mode = conflict_entries[1] == NULL ? 0 : conflict_entries[1]->mode; - their_mode = conflict_entries[2] == NULL ? 0 : conflict_entries[2]->mode; - - ancestor_oid = conflict_entries[0] == NULL ? NULL : &conflict_entries[0]->id; - our_oid = conflict_entries[1] == NULL ? NULL : &conflict_entries[1]->id; - their_oid = conflict_entries[2] == NULL ? NULL : &conflict_entries[2]->id; - - if ((ret = git_index_reuc_add(index, path, ancestor_mode, ancestor_oid, - our_mode, our_oid, their_mode, their_oid)) >= 0) - ret = git_index_conflict_remove(index, path); - - return ret; -} - -GIT_INLINE(bool) is_file_or_link(const int filemode) -{ - return (filemode == GIT_FILEMODE_BLOB || - filemode == GIT_FILEMODE_BLOB_EXECUTABLE || - filemode == GIT_FILEMODE_LINK); -} - -GIT_INLINE(bool) valid_filemode(const int filemode) -{ - return (is_file_or_link(filemode) || filemode == GIT_FILEMODE_COMMIT); -} - -int git_index_add_from_buffer( - git_index *index, const git_index_entry *source_entry, - const void *buffer, size_t len) -{ - git_index_entry *entry = NULL; - int error = 0; - git_oid id; - - GIT_ASSERT_ARG(index); - GIT_ASSERT_ARG(source_entry && source_entry->path); - - if (INDEX_OWNER(index) == NULL) - return create_index_error(-1, - "could not initialize index entry. " - "Index is not backed up by an existing repository."); - - if (!is_file_or_link(source_entry->mode)) { - git_error_set(GIT_ERROR_INDEX, "invalid filemode"); - return -1; - } - - if (len > UINT32_MAX) { - git_error_set(GIT_ERROR_INDEX, "buffer is too large"); - return -1; - } - - if (index_entry_dup(&entry, index, source_entry) < 0) - return -1; - - error = git_blob_create_from_buffer(&id, INDEX_OWNER(index), buffer, len); - if (error < 0) { - index_entry_free(entry); - return error; - } - - git_oid_cpy(&entry->id, &id); - entry->file_size = (uint32_t)len; - - if ((error = index_insert(index, &entry, 1, true, true, true)) < 0) - return error; - - /* Adding implies conflict was resolved, move conflict entries to REUC */ - if ((error = index_conflict_to_reuc(index, entry->path)) < 0 && error != GIT_ENOTFOUND) - return error; - - git_tree_cache_invalidate_path(index->tree, entry->path); - return 0; -} - -static int add_repo_as_submodule(git_index_entry **out, git_index *index, const char *path) -{ - git_repository *sub; - git_str abspath = GIT_STR_INIT; - git_repository *repo = INDEX_OWNER(index); - git_reference *head; - git_index_entry *entry; - struct stat st; - int error; - - if ((error = git_repository_workdir_path(&abspath, repo, path)) < 0) - return error; - - if ((error = p_stat(abspath.ptr, &st)) < 0) { - git_error_set(GIT_ERROR_OS, "failed to stat repository dir"); - return -1; - } - - if (index_entry_create(&entry, INDEX_OWNER(index), path, &st, true) < 0) - return -1; - - git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode); - - if ((error = git_repository_open(&sub, abspath.ptr)) < 0) - return error; - - if ((error = git_repository_head(&head, sub)) < 0) - return error; - - git_oid_cpy(&entry->id, git_reference_target(head)); - entry->mode = GIT_FILEMODE_COMMIT; - - git_reference_free(head); - git_repository_free(sub); - git_str_dispose(&abspath); - - *out = entry; - return 0; -} - -int git_index_add_bypath(git_index *index, const char *path) -{ - git_index_entry *entry = NULL; - int ret; - - GIT_ASSERT_ARG(index); - GIT_ASSERT_ARG(path); - - if ((ret = index_entry_init(&entry, index, path)) == 0) - ret = index_insert(index, &entry, 1, false, false, true); - - /* If we were given a directory, let's see if it's a submodule */ - if (ret < 0 && ret != GIT_EDIRECTORY) - return ret; - - if (ret == GIT_EDIRECTORY) { - git_submodule *sm; - git_error_state err; - - git_error_state_capture(&err, ret); - - ret = git_submodule_lookup(&sm, INDEX_OWNER(index), path); - if (ret == GIT_ENOTFOUND) - return git_error_state_restore(&err); - - git_error_state_free(&err); - - /* - * EEXISTS means that there is a repository at that path, but it's not known - * as a submodule. We add its HEAD as an entry and don't register it. - */ - if (ret == GIT_EEXISTS) { - if ((ret = add_repo_as_submodule(&entry, index, path)) < 0) - return ret; - - if ((ret = index_insert(index, &entry, 1, false, false, true)) < 0) - return ret; - } else if (ret < 0) { - return ret; - } else { - ret = git_submodule_add_to_index(sm, false); - git_submodule_free(sm); - return ret; - } - } - - /* Adding implies conflict was resolved, move conflict entries to REUC */ - if ((ret = index_conflict_to_reuc(index, path)) < 0 && ret != GIT_ENOTFOUND) - return ret; - - git_tree_cache_invalidate_path(index->tree, entry->path); - return 0; -} - -int git_index_remove_bypath(git_index *index, const char *path) -{ - int ret; - - GIT_ASSERT_ARG(index); - GIT_ASSERT_ARG(path); - - if (((ret = git_index_remove(index, path, 0)) < 0 && - ret != GIT_ENOTFOUND) || - ((ret = index_conflict_to_reuc(index, path)) < 0 && - ret != GIT_ENOTFOUND)) - return ret; - - if (ret == GIT_ENOTFOUND) - git_error_clear(); - - return 0; -} - -int git_index__fill(git_index *index, const git_vector *source_entries) -{ - const git_index_entry *source_entry = NULL; - int error = 0; - size_t i; - - GIT_ASSERT_ARG(index); - - if (!source_entries->length) - return 0; - - if (git_vector_size_hint(&index->entries, source_entries->length) < 0 || - index_map_resize(index->entries_map, (size_t)(source_entries->length * 1.3), - index->ignore_case) < 0) - return -1; - - git_vector_foreach(source_entries, i, source_entry) { - git_index_entry *entry = NULL; - - if ((error = index_entry_dup(&entry, index, source_entry)) < 0) - break; - - index_entry_adjust_namemask(entry, ((struct entry_internal *)entry)->pathlen); - entry->flags_extended |= GIT_INDEX_ENTRY_UPTODATE; - entry->mode = git_index__create_mode(entry->mode); - - if ((error = git_vector_insert(&index->entries, entry)) < 0) - break; - - if ((error = index_map_set(index->entries_map, entry, index->ignore_case)) < 0) - break; - - index->dirty = 1; - } - - if (!error) - git_vector_sort(&index->entries); - - return error; -} - - -int git_index_add(git_index *index, const git_index_entry *source_entry) -{ - git_index_entry *entry = NULL; - int ret; - - GIT_ASSERT_ARG(index); - GIT_ASSERT_ARG(source_entry && source_entry->path); - - if (!valid_filemode(source_entry->mode)) { - git_error_set(GIT_ERROR_INDEX, "invalid entry mode"); - return -1; - } - - if ((ret = index_entry_dup(&entry, index, source_entry)) < 0 || - (ret = index_insert(index, &entry, 1, true, true, false)) < 0) - return ret; - - git_tree_cache_invalidate_path(index->tree, entry->path); - return 0; -} - -int git_index_remove(git_index *index, const char *path, int stage) -{ - int error; - size_t position; - git_index_entry remove_key = {{ 0 }}; - - remove_key.path = path; - GIT_INDEX_ENTRY_STAGE_SET(&remove_key, stage); - - index_map_delete(index->entries_map, &remove_key, index->ignore_case); - - if (index_find(&position, index, path, 0, stage) < 0) { - git_error_set( - GIT_ERROR_INDEX, "index does not contain %s at stage %d", path, stage); - error = GIT_ENOTFOUND; - } else { - error = index_remove_entry(index, position); - } - - return error; -} - -int git_index_remove_directory(git_index *index, const char *dir, int stage) -{ - git_str pfx = GIT_STR_INIT; - int error = 0; - size_t pos; - git_index_entry *entry; - - if (!(error = git_str_sets(&pfx, dir)) && - !(error = git_fs_path_to_dir(&pfx))) - index_find(&pos, index, pfx.ptr, pfx.size, GIT_INDEX_STAGE_ANY); - - while (!error) { - entry = git_vector_get(&index->entries, pos); - if (!entry || git__prefixcmp(entry->path, pfx.ptr) != 0) - break; - - if (GIT_INDEX_ENTRY_STAGE(entry) != stage) { - ++pos; - continue; - } - - error = index_remove_entry(index, pos); - - /* removed entry at 'pos' so we don't need to increment */ - } - - git_str_dispose(&pfx); - - return error; -} - -int git_index_find_prefix(size_t *at_pos, git_index *index, const char *prefix) -{ - int error = 0; - size_t pos; - const git_index_entry *entry; - - index_find(&pos, index, prefix, strlen(prefix), GIT_INDEX_STAGE_ANY); - entry = git_vector_get(&index->entries, pos); - if (!entry || git__prefixcmp(entry->path, prefix) != 0) - error = GIT_ENOTFOUND; - - if (!error && at_pos) - *at_pos = pos; - - return error; -} - -int git_index__find_pos( - size_t *out, git_index *index, const char *path, size_t path_len, int stage) -{ - GIT_ASSERT_ARG(index); - GIT_ASSERT_ARG(path); - return index_find(out, index, path, path_len, stage); -} - -int git_index_find(size_t *at_pos, git_index *index, const char *path) -{ - size_t pos; - - GIT_ASSERT_ARG(index); - GIT_ASSERT_ARG(path); - - if (git_vector_bsearch2( - &pos, &index->entries, index->entries_search_path, path) < 0) { - git_error_set(GIT_ERROR_INDEX, "index does not contain %s", path); - return GIT_ENOTFOUND; - } - - /* Since our binary search only looked at path, we may be in the - * middle of a list of stages. - */ - for (; pos > 0; --pos) { - const git_index_entry *prev = git_vector_get(&index->entries, pos - 1); - - if (index->entries_cmp_path(prev->path, path) != 0) - break; - } - - if (at_pos) - *at_pos = pos; - - return 0; -} - -int git_index_conflict_add(git_index *index, - const git_index_entry *ancestor_entry, - const git_index_entry *our_entry, - const git_index_entry *their_entry) -{ - git_index_entry *entries[3] = { 0 }; - unsigned short i; - int ret = 0; - - GIT_ASSERT_ARG(index); - - if ((ancestor_entry && - (ret = index_entry_dup(&entries[0], index, ancestor_entry)) < 0) || - (our_entry && - (ret = index_entry_dup(&entries[1], index, our_entry)) < 0) || - (their_entry && - (ret = index_entry_dup(&entries[2], index, their_entry)) < 0)) - goto on_error; - - /* Validate entries */ - for (i = 0; i < 3; i++) { - if (entries[i] && !valid_filemode(entries[i]->mode)) { - git_error_set(GIT_ERROR_INDEX, "invalid filemode for stage %d entry", - i + 1); - ret = -1; - goto on_error; - } - } - - /* Remove existing index entries for each path */ - for (i = 0; i < 3; i++) { - if (entries[i] == NULL) - continue; - - if ((ret = git_index_remove(index, entries[i]->path, 0)) != 0) { - if (ret != GIT_ENOTFOUND) - goto on_error; - - git_error_clear(); - ret = 0; - } - } - - /* Add the conflict entries */ - for (i = 0; i < 3; i++) { - if (entries[i] == NULL) - continue; - - /* Make sure stage is correct */ - GIT_INDEX_ENTRY_STAGE_SET(entries[i], i + 1); - - if ((ret = index_insert(index, &entries[i], 1, true, true, false)) < 0) - goto on_error; - - entries[i] = NULL; /* don't free if later entry fails */ - } - - return 0; - -on_error: - for (i = 0; i < 3; i++) { - if (entries[i] != NULL) - index_entry_free(entries[i]); - } - - return ret; -} - -static int index_conflict__get_byindex( - const git_index_entry **ancestor_out, - const git_index_entry **our_out, - const git_index_entry **their_out, - git_index *index, - size_t n) -{ - const git_index_entry *conflict_entry; - const char *path = NULL; - size_t count; - int stage, len = 0; - - GIT_ASSERT_ARG(ancestor_out); - GIT_ASSERT_ARG(our_out); - GIT_ASSERT_ARG(their_out); - GIT_ASSERT_ARG(index); - - *ancestor_out = NULL; - *our_out = NULL; - *their_out = NULL; - - for (count = git_index_entrycount(index); n < count; ++n) { - conflict_entry = git_vector_get(&index->entries, n); - - if (path && index->entries_cmp_path(conflict_entry->path, path) != 0) - break; - - stage = GIT_INDEX_ENTRY_STAGE(conflict_entry); - path = conflict_entry->path; - - switch (stage) { - case 3: - *their_out = conflict_entry; - len++; - break; - case 2: - *our_out = conflict_entry; - len++; - break; - case 1: - *ancestor_out = conflict_entry; - len++; - break; - default: - break; - }; - } - - return len; -} - -int git_index_conflict_get( - const git_index_entry **ancestor_out, - const git_index_entry **our_out, - const git_index_entry **their_out, - git_index *index, - const char *path) -{ - size_t pos; - int len = 0; - - GIT_ASSERT_ARG(ancestor_out); - GIT_ASSERT_ARG(our_out); - GIT_ASSERT_ARG(their_out); - GIT_ASSERT_ARG(index); - GIT_ASSERT_ARG(path); - - *ancestor_out = NULL; - *our_out = NULL; - *their_out = NULL; - - if (git_index_find(&pos, index, path) < 0) - return GIT_ENOTFOUND; - - if ((len = index_conflict__get_byindex( - ancestor_out, our_out, their_out, index, pos)) < 0) - return len; - else if (len == 0) - return GIT_ENOTFOUND; - - return 0; -} - -static int index_conflict_remove(git_index *index, const char *path) -{ - size_t pos = 0; - git_index_entry *conflict_entry; - int error = 0; - - if (path != NULL && git_index_find(&pos, index, path) < 0) - return GIT_ENOTFOUND; - - while ((conflict_entry = git_vector_get(&index->entries, pos)) != NULL) { - - if (path != NULL && - index->entries_cmp_path(conflict_entry->path, path) != 0) - break; - - if (GIT_INDEX_ENTRY_STAGE(conflict_entry) == 0) { - pos++; - continue; - } - - if ((error = index_remove_entry(index, pos)) < 0) - break; - } - - return error; -} - -int git_index_conflict_remove(git_index *index, const char *path) -{ - GIT_ASSERT_ARG(index); - GIT_ASSERT_ARG(path); - return index_conflict_remove(index, path); -} - -int git_index_conflict_cleanup(git_index *index) -{ - GIT_ASSERT_ARG(index); - return index_conflict_remove(index, NULL); -} - -int git_index_has_conflicts(const git_index *index) -{ - size_t i; - git_index_entry *entry; - - GIT_ASSERT_ARG(index); - - git_vector_foreach(&index->entries, i, entry) { - if (GIT_INDEX_ENTRY_STAGE(entry) > 0) - return 1; - } - - return 0; -} - -int git_index_iterator_new( - git_index_iterator **iterator_out, - git_index *index) -{ - git_index_iterator *it; - int error; - - GIT_ASSERT_ARG(iterator_out); - GIT_ASSERT_ARG(index); - - it = git__calloc(1, sizeof(git_index_iterator)); - GIT_ERROR_CHECK_ALLOC(it); - - if ((error = git_index_snapshot_new(&it->snap, index)) < 0) { - git__free(it); - return error; - } - - it->index = index; - - *iterator_out = it; - return 0; -} - -int git_index_iterator_next( - const git_index_entry **out, - git_index_iterator *it) -{ - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(it); - - if (it->cur >= git_vector_length(&it->snap)) - return GIT_ITEROVER; - - *out = (git_index_entry *)git_vector_get(&it->snap, it->cur++); - return 0; -} - -void git_index_iterator_free(git_index_iterator *it) -{ - if (it == NULL) - return; - - git_index_snapshot_release(&it->snap, it->index); - git__free(it); -} - -int git_index_conflict_iterator_new( - git_index_conflict_iterator **iterator_out, - git_index *index) -{ - git_index_conflict_iterator *it = NULL; - - GIT_ASSERT_ARG(iterator_out); - GIT_ASSERT_ARG(index); - - it = git__calloc(1, sizeof(git_index_conflict_iterator)); - GIT_ERROR_CHECK_ALLOC(it); - - it->index = index; - - *iterator_out = it; - return 0; -} - -int git_index_conflict_next( - const git_index_entry **ancestor_out, - const git_index_entry **our_out, - const git_index_entry **their_out, - git_index_conflict_iterator *iterator) -{ - const git_index_entry *entry; - int len; - - GIT_ASSERT_ARG(ancestor_out); - GIT_ASSERT_ARG(our_out); - GIT_ASSERT_ARG(their_out); - GIT_ASSERT_ARG(iterator); - - *ancestor_out = NULL; - *our_out = NULL; - *their_out = NULL; - - while (iterator->cur < iterator->index->entries.length) { - entry = git_index_get_byindex(iterator->index, iterator->cur); - - if (git_index_entry_is_conflict(entry)) { - if ((len = index_conflict__get_byindex( - ancestor_out, - our_out, - their_out, - iterator->index, - iterator->cur)) < 0) - return len; - - iterator->cur += len; - return 0; - } - - iterator->cur++; - } - - return GIT_ITEROVER; -} - -void git_index_conflict_iterator_free(git_index_conflict_iterator *iterator) -{ - if (iterator == NULL) - return; - - git__free(iterator); -} - -size_t git_index_name_entrycount(git_index *index) -{ - GIT_ASSERT_ARG(index); - return index->names.length; -} - -const git_index_name_entry *git_index_name_get_byindex( - git_index *index, size_t n) -{ - GIT_ASSERT_ARG_WITH_RETVAL(index, NULL); - - git_vector_sort(&index->names); - return git_vector_get(&index->names, n); -} - -static void index_name_entry_free(git_index_name_entry *ne) -{ - if (!ne) - return; - git__free(ne->ancestor); - git__free(ne->ours); - git__free(ne->theirs); - git__free(ne); -} - -int git_index_name_add(git_index *index, - const char *ancestor, const char *ours, const char *theirs) -{ - git_index_name_entry *conflict_name; - - GIT_ASSERT_ARG((ancestor && ours) || (ancestor && theirs) || (ours && theirs)); - - conflict_name = git__calloc(1, sizeof(git_index_name_entry)); - GIT_ERROR_CHECK_ALLOC(conflict_name); - - if ((ancestor && !(conflict_name->ancestor = git__strdup(ancestor))) || - (ours && !(conflict_name->ours = git__strdup(ours))) || - (theirs && !(conflict_name->theirs = git__strdup(theirs))) || - git_vector_insert(&index->names, conflict_name) < 0) - { - index_name_entry_free(conflict_name); - return -1; - } - - index->dirty = 1; - return 0; -} - -int git_index_name_clear(git_index *index) -{ - size_t i; - git_index_name_entry *conflict_name; - - GIT_ASSERT_ARG(index); - - git_vector_foreach(&index->names, i, conflict_name) - index_name_entry_free(conflict_name); - - git_vector_clear(&index->names); - - index->dirty = 1; - - return 0; -} - -size_t git_index_reuc_entrycount(git_index *index) -{ - GIT_ASSERT_ARG(index); - return index->reuc.length; -} - -static int index_reuc_on_dup(void **old, void *new) -{ - index_entry_reuc_free(*old); - *old = new; - return GIT_EEXISTS; -} - -static int index_reuc_insert( - git_index *index, - git_index_reuc_entry *reuc) -{ - int res; - - GIT_ASSERT_ARG(index); - GIT_ASSERT_ARG(reuc && reuc->path != NULL); - GIT_ASSERT(git_vector_is_sorted(&index->reuc)); - - res = git_vector_insert_sorted(&index->reuc, reuc, &index_reuc_on_dup); - index->dirty = 1; - - return res == GIT_EEXISTS ? 0 : res; -} - -int git_index_reuc_add(git_index *index, const char *path, - int ancestor_mode, const git_oid *ancestor_oid, - int our_mode, const git_oid *our_oid, - int their_mode, const git_oid *their_oid) -{ - git_index_reuc_entry *reuc = NULL; - int error = 0; - - GIT_ASSERT_ARG(index); - GIT_ASSERT_ARG(path); - - if ((error = index_entry_reuc_init(&reuc, path, ancestor_mode, - ancestor_oid, our_mode, our_oid, their_mode, their_oid)) < 0 || - (error = index_reuc_insert(index, reuc)) < 0) - index_entry_reuc_free(reuc); - - return error; -} - -int git_index_reuc_find(size_t *at_pos, git_index *index, const char *path) -{ - return git_vector_bsearch2(at_pos, &index->reuc, index->reuc_search, path); -} - -const git_index_reuc_entry *git_index_reuc_get_bypath( - git_index *index, const char *path) -{ - size_t pos; - - GIT_ASSERT_ARG_WITH_RETVAL(index, NULL); - GIT_ASSERT_ARG_WITH_RETVAL(path, NULL); - - if (!index->reuc.length) - return NULL; - - GIT_ASSERT_WITH_RETVAL(git_vector_is_sorted(&index->reuc), NULL); - - if (git_index_reuc_find(&pos, index, path) < 0) - return NULL; - - return git_vector_get(&index->reuc, pos); -} - -const git_index_reuc_entry *git_index_reuc_get_byindex( - git_index *index, size_t n) -{ - GIT_ASSERT_ARG_WITH_RETVAL(index, NULL); - GIT_ASSERT_WITH_RETVAL(git_vector_is_sorted(&index->reuc), NULL); - - return git_vector_get(&index->reuc, n); -} - -int git_index_reuc_remove(git_index *index, size_t position) -{ - int error; - git_index_reuc_entry *reuc; - - GIT_ASSERT_ARG(index); - GIT_ASSERT(git_vector_is_sorted(&index->reuc)); - - reuc = git_vector_get(&index->reuc, position); - error = git_vector_remove(&index->reuc, position); - - if (!error) - index_entry_reuc_free(reuc); - - index->dirty = 1; - return error; -} - -int git_index_reuc_clear(git_index *index) -{ - size_t i; - - GIT_ASSERT_ARG(index); - - for (i = 0; i < index->reuc.length; ++i) - index_entry_reuc_free(git_atomic_swap(index->reuc.contents[i], NULL)); - - git_vector_clear(&index->reuc); - - index->dirty = 1; - - return 0; -} - -static int index_error_invalid(const char *message) -{ - git_error_set(GIT_ERROR_INDEX, "invalid data in index - %s", message); - return -1; -} - -static int read_reuc(git_index *index, const char *buffer, size_t size) -{ - const char *endptr; - size_t len; - int i; - - /* If called multiple times, the vector might already be initialized */ - if (index->reuc._alloc_size == 0 && - git_vector_init(&index->reuc, 16, reuc_cmp) < 0) - return -1; - - while (size) { - git_index_reuc_entry *lost; - - len = p_strnlen(buffer, size) + 1; - if (size <= len) - return index_error_invalid("reading reuc entries"); - - lost = reuc_entry_alloc(buffer); - GIT_ERROR_CHECK_ALLOC(lost); - - size -= len; - buffer += len; - - /* read 3 ASCII octal numbers for stage entries */ - for (i = 0; i < 3; i++) { - int64_t tmp; - - if (git__strntol64(&tmp, buffer, size, &endptr, 8) < 0 || - !endptr || endptr == buffer || *endptr || - tmp < 0 || tmp > UINT32_MAX) { - index_entry_reuc_free(lost); - return index_error_invalid("reading reuc entry stage"); - } - - lost->mode[i] = (uint32_t)tmp; - - len = (endptr + 1) - buffer; - if (size <= len) { - index_entry_reuc_free(lost); - return index_error_invalid("reading reuc entry stage"); - } - - size -= len; - buffer += len; - } - - /* read up to 3 OIDs for stage entries */ - for (i = 0; i < 3; i++) { - if (!lost->mode[i]) - continue; - if (size < 20) { - index_entry_reuc_free(lost); - return index_error_invalid("reading reuc entry oid"); - } - - git_oid_fromraw(&lost->oid[i], (const unsigned char *) buffer); - size -= 20; - buffer += 20; - } - - /* entry was read successfully - insert into reuc vector */ - if (git_vector_insert(&index->reuc, lost) < 0) - return -1; - } - - /* entries are guaranteed to be sorted on-disk */ - git_vector_set_sorted(&index->reuc, true); - - return 0; -} - - -static int read_conflict_names(git_index *index, const char *buffer, size_t size) -{ - size_t len; - - /* This gets called multiple times, the vector might already be initialized */ - if (index->names._alloc_size == 0 && - git_vector_init(&index->names, 16, conflict_name_cmp) < 0) - return -1; - -#define read_conflict_name(ptr) \ - len = p_strnlen(buffer, size) + 1; \ - if (size < len) { \ - index_error_invalid("reading conflict name entries"); \ - goto out_err; \ - } \ - if (len == 1) \ - ptr = NULL; \ - else { \ - ptr = git__malloc(len); \ - GIT_ERROR_CHECK_ALLOC(ptr); \ - memcpy(ptr, buffer, len); \ - } \ - \ - buffer += len; \ - size -= len; - - while (size) { - git_index_name_entry *conflict_name = git__calloc(1, sizeof(git_index_name_entry)); - GIT_ERROR_CHECK_ALLOC(conflict_name); - - read_conflict_name(conflict_name->ancestor); - read_conflict_name(conflict_name->ours); - read_conflict_name(conflict_name->theirs); - - if (git_vector_insert(&index->names, conflict_name) < 0) - goto out_err; - - continue; - -out_err: - git__free(conflict_name->ancestor); - git__free(conflict_name->ours); - git__free(conflict_name->theirs); - git__free(conflict_name); - return -1; - } - -#undef read_conflict_name - - /* entries are guaranteed to be sorted on-disk */ - git_vector_set_sorted(&index->names, true); - - return 0; -} - -static size_t index_entry_size(size_t path_len, size_t varint_len, uint32_t flags) -{ - if (varint_len) { - if (flags & GIT_INDEX_ENTRY_EXTENDED) - return offsetof(struct entry_long, path) + path_len + 1 + varint_len; - else - return offsetof(struct entry_short, path) + path_len + 1 + varint_len; - } else { -#define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7) - if (flags & GIT_INDEX_ENTRY_EXTENDED) - return entry_size(struct entry_long, path_len); - else - return entry_size(struct entry_short, path_len); -#undef entry_size - } -} - -static int read_entry( - git_index_entry **out, - size_t *out_size, - git_index *index, - const void *buffer, - size_t buffer_size, - const char *last) -{ - size_t path_length, entry_size; - const char *path_ptr; - struct entry_short source; - git_index_entry entry = {{0}}; - bool compressed = index->version >= INDEX_VERSION_NUMBER_COMP; - char *tmp_path = NULL; - size_t checksum_size = GIT_HASH_SHA1_SIZE; - - if (checksum_size + minimal_entry_size > buffer_size) - return -1; - - /* buffer is not guaranteed to be aligned */ - memcpy(&source, buffer, sizeof(struct entry_short)); - - entry.ctime.seconds = (git_time_t)ntohl(source.ctime.seconds); - entry.ctime.nanoseconds = ntohl(source.ctime.nanoseconds); - entry.mtime.seconds = (git_time_t)ntohl(source.mtime.seconds); - entry.mtime.nanoseconds = ntohl(source.mtime.nanoseconds); - entry.dev = ntohl(source.dev); - entry.ino = ntohl(source.ino); - entry.mode = ntohl(source.mode); - entry.uid = ntohl(source.uid); - entry.gid = ntohl(source.gid); - entry.file_size = ntohl(source.file_size); - git_oid_cpy(&entry.id, &source.oid); - entry.flags = ntohs(source.flags); - - if (entry.flags & GIT_INDEX_ENTRY_EXTENDED) { - uint16_t flags_raw; - size_t flags_offset; - - flags_offset = offsetof(struct entry_long, flags_extended); - memcpy(&flags_raw, (const char *) buffer + flags_offset, - sizeof(flags_raw)); - flags_raw = ntohs(flags_raw); - - memcpy(&entry.flags_extended, &flags_raw, sizeof(flags_raw)); - path_ptr = (const char *) buffer + offsetof(struct entry_long, path); - } else - path_ptr = (const char *) buffer + offsetof(struct entry_short, path); - - if (!compressed) { - path_length = entry.flags & GIT_INDEX_ENTRY_NAMEMASK; - - /* if this is a very long string, we must find its - * real length without overflowing */ - if (path_length == 0xFFF) { - const char *path_end; - - path_end = memchr(path_ptr, '\0', buffer_size); - if (path_end == NULL) - return -1; - - path_length = path_end - path_ptr; - } - - entry_size = index_entry_size(path_length, 0, entry.flags); - entry.path = (char *)path_ptr; - } else { - size_t varint_len, last_len, prefix_len, suffix_len, path_len; - uintmax_t strip_len; - - strip_len = git_decode_varint((const unsigned char *)path_ptr, &varint_len); - last_len = strlen(last); - - if (varint_len == 0 || last_len < strip_len) - return index_error_invalid("incorrect prefix length"); - - prefix_len = last_len - (size_t)strip_len; - suffix_len = strlen(path_ptr + varint_len); - - GIT_ERROR_CHECK_ALLOC_ADD(&path_len, prefix_len, suffix_len); - GIT_ERROR_CHECK_ALLOC_ADD(&path_len, path_len, 1); - - if (path_len > GIT_PATH_MAX) - return index_error_invalid("unreasonable path length"); - - tmp_path = git__malloc(path_len); - GIT_ERROR_CHECK_ALLOC(tmp_path); - - memcpy(tmp_path, last, prefix_len); - memcpy(tmp_path + prefix_len, path_ptr + varint_len, suffix_len + 1); - entry_size = index_entry_size(suffix_len, varint_len, entry.flags); - entry.path = tmp_path; - } - - if (entry_size == 0) - return -1; - - if (checksum_size + entry_size > buffer_size) - return -1; - - if (index_entry_dup(out, index, &entry) < 0) { - git__free(tmp_path); - return -1; - } - - git__free(tmp_path); - *out_size = entry_size; - return 0; -} - -static int read_header(struct index_header *dest, const void *buffer) -{ - const struct index_header *source = buffer; - - dest->signature = ntohl(source->signature); - if (dest->signature != INDEX_HEADER_SIG) - return index_error_invalid("incorrect header signature"); - - dest->version = ntohl(source->version); - if (dest->version < INDEX_VERSION_NUMBER_LB || - dest->version > INDEX_VERSION_NUMBER_UB) - return index_error_invalid("incorrect header version"); - - dest->entry_count = ntohl(source->entry_count); - return 0; -} - -static int read_extension(size_t *read_len, git_index *index, const char *buffer, size_t buffer_size) -{ - struct index_extension dest; - size_t total_size; - size_t checksum_size = GIT_HASH_SHA1_SIZE; - - /* buffer is not guaranteed to be aligned */ - memcpy(&dest, buffer, sizeof(struct index_extension)); - dest.extension_size = ntohl(dest.extension_size); - - total_size = dest.extension_size + sizeof(struct index_extension); - - if (dest.extension_size > total_size || - buffer_size < total_size || - buffer_size - total_size < checksum_size) { - index_error_invalid("extension is truncated"); - return -1; - } - - /* optional extension */ - if (dest.signature[0] >= 'A' && dest.signature[0] <= 'Z') { - /* tree cache */ - if (memcmp(dest.signature, INDEX_EXT_TREECACHE_SIG, 4) == 0) { - if (git_tree_cache_read(&index->tree, buffer + 8, dest.extension_size, &index->tree_pool) < 0) - return -1; - } else if (memcmp(dest.signature, INDEX_EXT_UNMERGED_SIG, 4) == 0) { - if (read_reuc(index, buffer + 8, dest.extension_size) < 0) - return -1; - } else if (memcmp(dest.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4) == 0) { - if (read_conflict_names(index, buffer + 8, dest.extension_size) < 0) - return -1; - } - /* else, unsupported extension. We cannot parse this, but we can skip - * it by returning `total_size */ - } else { - /* we cannot handle non-ignorable extensions; - * in fact they aren't even defined in the standard */ - git_error_set(GIT_ERROR_INDEX, "unsupported mandatory extension: '%.4s'", dest.signature); - return -1; - } - - *read_len = total_size; - - return 0; -} - -static int parse_index(git_index *index, const char *buffer, size_t buffer_size) -{ - int error = 0; - unsigned int i; - struct index_header header = { 0 }; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; - size_t checksum_size = GIT_HASH_SHA1_SIZE; - const char *last = NULL; - const char *empty = ""; - -#define seek_forward(_increase) { \ - if (_increase >= buffer_size) { \ - error = index_error_invalid("ran out of data while parsing"); \ - goto done; } \ - buffer += _increase; \ - buffer_size -= _increase;\ -} - - if (buffer_size < INDEX_HEADER_SIZE + checksum_size) - return index_error_invalid("insufficient buffer space"); - - /* Precalculate the SHA1 of the files's contents -- we'll match it to - * the provided SHA1 in the footer */ - git_hash_buf(checksum, buffer, buffer_size - checksum_size, GIT_HASH_ALGORITHM_SHA1); - - /* Parse header */ - if ((error = read_header(&header, buffer)) < 0) - return error; - - index->version = header.version; - if (index->version >= INDEX_VERSION_NUMBER_COMP) - last = empty; - - seek_forward(INDEX_HEADER_SIZE); - - GIT_ASSERT(!index->entries.length); - - if ((error = index_map_resize(index->entries_map, header.entry_count, index->ignore_case)) < 0) - return error; - - /* Parse all the entries */ - for (i = 0; i < header.entry_count && buffer_size > checksum_size; ++i) { - git_index_entry *entry = NULL; - size_t entry_size; - - if ((error = read_entry(&entry, &entry_size, index, buffer, buffer_size, last)) < 0) { - error = index_error_invalid("invalid entry"); - goto done; - } - - if ((error = git_vector_insert(&index->entries, entry)) < 0) { - index_entry_free(entry); - goto done; - } - - if ((error = index_map_set(index->entries_map, entry, index->ignore_case)) < 0) { - index_entry_free(entry); - goto done; - } - error = 0; - - if (index->version >= INDEX_VERSION_NUMBER_COMP) - last = entry->path; - - seek_forward(entry_size); - } - - if (i != header.entry_count) { - error = index_error_invalid("header entries changed while parsing"); - goto done; - } - - /* There's still space for some extensions! */ - while (buffer_size > checksum_size) { - size_t extension_size; - - if ((error = read_extension(&extension_size, index, buffer, buffer_size)) < 0) { - goto done; - } - - seek_forward(extension_size); - } - - if (buffer_size != checksum_size) { - error = index_error_invalid( - "buffer size does not match index footer size"); - goto done; - } - - /* 160-bit SHA-1 over the content of the index file before this checksum. */ - if (memcmp(checksum, buffer, checksum_size) != 0) { - error = index_error_invalid( - "calculated checksum does not match expected"); - goto done; - } - - memcpy(index->checksum, checksum, checksum_size); - -#undef seek_forward - - /* Entries are stored case-sensitively on disk, so re-sort now if - * in-memory index is supposed to be case-insensitive - */ - git_vector_set_sorted(&index->entries, !index->ignore_case); - git_vector_sort(&index->entries); - - index->dirty = 0; -done: - return error; -} - -static bool is_index_extended(git_index *index) -{ - size_t i, extended; - git_index_entry *entry; - - extended = 0; - - git_vector_foreach(&index->entries, i, entry) { - entry->flags &= ~GIT_INDEX_ENTRY_EXTENDED; - if (entry->flags_extended & GIT_INDEX_ENTRY_EXTENDED_FLAGS) { - extended++; - entry->flags |= GIT_INDEX_ENTRY_EXTENDED; - } - } - - return (extended > 0); -} - -static int write_disk_entry(git_filebuf *file, git_index_entry *entry, const char *last) -{ - void *mem = NULL; - struct entry_short ondisk; - size_t path_len, disk_size; - int varint_len = 0; - char *path; - const char *path_start = entry->path; - size_t same_len = 0; - - path_len = ((struct entry_internal *)entry)->pathlen; - - if (last) { - const char *last_c = last; - - while (*path_start == *last_c) { - if (!*path_start || !*last_c) - break; - ++path_start; - ++last_c; - ++same_len; - } - path_len -= same_len; - varint_len = git_encode_varint(NULL, 0, strlen(last) - same_len); - } - - disk_size = index_entry_size(path_len, varint_len, entry->flags); - - if (git_filebuf_reserve(file, &mem, disk_size) < 0) - return -1; - - memset(mem, 0x0, disk_size); - - /** - * Yes, we have to truncate. - * - * The on-disk format for Index entries clearly defines - * the time and size fields to be 4 bytes each -- so even if - * we store these values with 8 bytes on-memory, they must - * be truncated to 4 bytes before writing to disk. - * - * In 2038 I will be either too dead or too rich to care about this - */ - ondisk.ctime.seconds = htonl((uint32_t)entry->ctime.seconds); - ondisk.mtime.seconds = htonl((uint32_t)entry->mtime.seconds); - ondisk.ctime.nanoseconds = htonl(entry->ctime.nanoseconds); - ondisk.mtime.nanoseconds = htonl(entry->mtime.nanoseconds); - ondisk.dev = htonl(entry->dev); - ondisk.ino = htonl(entry->ino); - ondisk.mode = htonl(entry->mode); - ondisk.uid = htonl(entry->uid); - ondisk.gid = htonl(entry->gid); - ondisk.file_size = htonl((uint32_t)entry->file_size); - - git_oid_cpy(&ondisk.oid, &entry->id); - - ondisk.flags = htons(entry->flags); - - if (entry->flags & GIT_INDEX_ENTRY_EXTENDED) { - const size_t path_offset = offsetof(struct entry_long, path); - struct entry_long ondisk_ext; - memcpy(&ondisk_ext, &ondisk, sizeof(struct entry_short)); - ondisk_ext.flags_extended = htons(entry->flags_extended & - GIT_INDEX_ENTRY_EXTENDED_FLAGS); - memcpy(mem, &ondisk_ext, path_offset); - path = (char *)mem + path_offset; - disk_size -= path_offset; - } else { - const size_t path_offset = offsetof(struct entry_short, path); - memcpy(mem, &ondisk, path_offset); - path = (char *)mem + path_offset; - disk_size -= path_offset; - } - - if (last) { - varint_len = git_encode_varint((unsigned char *) path, - disk_size, strlen(last) - same_len); - GIT_ASSERT(varint_len > 0); - - path += varint_len; - disk_size -= varint_len; - - /* - * If using path compression, we are not allowed - * to have additional trailing NULs. - */ - GIT_ASSERT(disk_size == path_len + 1); - } else { - /* - * If no path compression is used, we do have - * NULs as padding. As such, simply assert that - * we have enough space left to write the path. - */ - GIT_ASSERT(disk_size > path_len); - } - - memcpy(path, path_start, path_len + 1); - - return 0; -} - -static int write_entries(git_index *index, git_filebuf *file) -{ - int error = 0; - size_t i; - git_vector case_sorted = GIT_VECTOR_INIT, *entries = NULL; - git_index_entry *entry; - const char *last = NULL; - - /* If index->entries is sorted case-insensitively, then we need - * to re-sort it case-sensitively before writing */ - if (index->ignore_case) { - if ((error = git_vector_dup(&case_sorted, &index->entries, git_index_entry_cmp)) < 0) - goto done; - - git_vector_sort(&case_sorted); - entries = &case_sorted; - } else { - entries = &index->entries; - } - - if (index->version >= INDEX_VERSION_NUMBER_COMP) - last = ""; - - git_vector_foreach(entries, i, entry) { - if ((error = write_disk_entry(file, entry, last)) < 0) - break; - if (index->version >= INDEX_VERSION_NUMBER_COMP) - last = entry->path; - } - -done: - git_vector_free(&case_sorted); - return error; -} - -static int write_extension(git_filebuf *file, struct index_extension *header, git_str *data) -{ - struct index_extension ondisk; - - memset(&ondisk, 0x0, sizeof(struct index_extension)); - memcpy(&ondisk, header, 4); - ondisk.extension_size = htonl(header->extension_size); - - git_filebuf_write(file, &ondisk, sizeof(struct index_extension)); - return git_filebuf_write(file, data->ptr, data->size); -} - -static int create_name_extension_data(git_str *name_buf, git_index_name_entry *conflict_name) -{ - int error = 0; - - if (conflict_name->ancestor == NULL) - error = git_str_put(name_buf, "\0", 1); - else - error = git_str_put(name_buf, conflict_name->ancestor, strlen(conflict_name->ancestor) + 1); - - if (error != 0) - goto on_error; - - if (conflict_name->ours == NULL) - error = git_str_put(name_buf, "\0", 1); - else - error = git_str_put(name_buf, conflict_name->ours, strlen(conflict_name->ours) + 1); - - if (error != 0) - goto on_error; - - if (conflict_name->theirs == NULL) - error = git_str_put(name_buf, "\0", 1); - else - error = git_str_put(name_buf, conflict_name->theirs, strlen(conflict_name->theirs) + 1); - -on_error: - return error; -} - -static int write_name_extension(git_index *index, git_filebuf *file) -{ - git_str name_buf = GIT_STR_INIT; - git_vector *out = &index->names; - git_index_name_entry *conflict_name; - struct index_extension extension; - size_t i; - int error = 0; - - git_vector_foreach(out, i, conflict_name) { - if ((error = create_name_extension_data(&name_buf, conflict_name)) < 0) - goto done; - } - - memset(&extension, 0x0, sizeof(struct index_extension)); - memcpy(&extension.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4); - extension.extension_size = (uint32_t)name_buf.size; - - error = write_extension(file, &extension, &name_buf); - - git_str_dispose(&name_buf); - -done: - return error; -} - -static int create_reuc_extension_data(git_str *reuc_buf, git_index_reuc_entry *reuc) -{ - int i; - int error = 0; - - if ((error = git_str_put(reuc_buf, reuc->path, strlen(reuc->path) + 1)) < 0) - return error; - - for (i = 0; i < 3; i++) { - if ((error = git_str_printf(reuc_buf, "%o", reuc->mode[i])) < 0 || - (error = git_str_put(reuc_buf, "\0", 1)) < 0) - return error; - } - - for (i = 0; i < 3; i++) { - if (reuc->mode[i] && (error = git_str_put(reuc_buf, (char *)&reuc->oid[i].id, GIT_OID_RAWSZ)) < 0) - return error; - } - - return 0; -} - -static int write_reuc_extension(git_index *index, git_filebuf *file) -{ - git_str reuc_buf = GIT_STR_INIT; - git_vector *out = &index->reuc; - git_index_reuc_entry *reuc; - struct index_extension extension; - size_t i; - int error = 0; - - git_vector_foreach(out, i, reuc) { - if ((error = create_reuc_extension_data(&reuc_buf, reuc)) < 0) - goto done; - } - - memset(&extension, 0x0, sizeof(struct index_extension)); - memcpy(&extension.signature, INDEX_EXT_UNMERGED_SIG, 4); - extension.extension_size = (uint32_t)reuc_buf.size; - - error = write_extension(file, &extension, &reuc_buf); - - git_str_dispose(&reuc_buf); - -done: - return error; -} - -static int write_tree_extension(git_index *index, git_filebuf *file) -{ - struct index_extension extension; - git_str buf = GIT_STR_INIT; - int error; - - if (index->tree == NULL) - return 0; - - if ((error = git_tree_cache_write(&buf, index->tree)) < 0) - return error; - - memset(&extension, 0x0, sizeof(struct index_extension)); - memcpy(&extension.signature, INDEX_EXT_TREECACHE_SIG, 4); - extension.extension_size = (uint32_t)buf.size; - - error = write_extension(file, &extension, &buf); - - git_str_dispose(&buf); - - return error; -} - -static void clear_uptodate(git_index *index) -{ - git_index_entry *entry; - size_t i; - - git_vector_foreach(&index->entries, i, entry) - entry->flags_extended &= ~GIT_INDEX_ENTRY_UPTODATE; -} - -static int write_index( - unsigned char checksum[GIT_HASH_SHA1_SIZE], - size_t *checksum_size, - git_index *index, - git_filebuf *file) -{ - struct index_header header; - bool is_extended; - uint32_t index_version_number; - - GIT_ASSERT_ARG(index); - GIT_ASSERT_ARG(file); - - *checksum_size = GIT_HASH_SHA1_SIZE; - - if (index->version <= INDEX_VERSION_NUMBER_EXT) { - is_extended = is_index_extended(index); - index_version_number = is_extended ? INDEX_VERSION_NUMBER_EXT : INDEX_VERSION_NUMBER_LB; - } else { - index_version_number = index->version; - } - - header.signature = htonl(INDEX_HEADER_SIG); - header.version = htonl(index_version_number); - header.entry_count = htonl((uint32_t)index->entries.length); - - if (git_filebuf_write(file, &header, sizeof(struct index_header)) < 0) - return -1; - - if (write_entries(index, file) < 0) - return -1; - - /* write the tree cache extension */ - if (index->tree != NULL && write_tree_extension(index, file) < 0) - return -1; - - /* write the rename conflict extension */ - if (index->names.length > 0 && write_name_extension(index, file) < 0) - return -1; - - /* write the reuc extension */ - if (index->reuc.length > 0 && write_reuc_extension(index, file) < 0) - return -1; - - /* get out the hash for all the contents we've appended to the file */ - git_filebuf_hash(checksum, file); - - /* write it at the end of the file */ - if (git_filebuf_write(file, checksum, *checksum_size) < 0) - return -1; - - /* file entries are no longer up to date */ - clear_uptodate(index); - - return 0; -} - -int git_index_entry_stage(const git_index_entry *entry) -{ - return GIT_INDEX_ENTRY_STAGE(entry); -} - -int git_index_entry_is_conflict(const git_index_entry *entry) -{ - return (GIT_INDEX_ENTRY_STAGE(entry) > 0); -} - -typedef struct read_tree_data { - git_index *index; - git_vector *old_entries; - git_vector *new_entries; - git_vector_cmp entry_cmp; - git_tree_cache *tree; -} read_tree_data; - -static int read_tree_cb( - const char *root, const git_tree_entry *tentry, void *payload) -{ - read_tree_data *data = payload; - git_index_entry *entry = NULL, *old_entry; - git_str path = GIT_STR_INIT; - size_t pos; - - if (git_tree_entry__is_tree(tentry)) - return 0; - - if (git_str_joinpath(&path, root, tentry->filename) < 0) - return -1; - - if (index_entry_create(&entry, INDEX_OWNER(data->index), path.ptr, NULL, false) < 0) - return -1; - - entry->mode = tentry->attr; - git_oid_cpy(&entry->id, git_tree_entry_id(tentry)); - - /* look for corresponding old entry and copy data to new entry */ - if (data->old_entries != NULL && - !index_find_in_entries( - &pos, data->old_entries, data->entry_cmp, path.ptr, 0, 0) && - (old_entry = git_vector_get(data->old_entries, pos)) != NULL && - entry->mode == old_entry->mode && - git_oid_equal(&entry->id, &old_entry->id)) - { - index_entry_cpy(entry, old_entry); - entry->flags_extended = 0; - } - - index_entry_adjust_namemask(entry, path.size); - git_str_dispose(&path); - - if (git_vector_insert(data->new_entries, entry) < 0) { - index_entry_free(entry); - return -1; - } - - return 0; -} - -int git_index_read_tree(git_index *index, const git_tree *tree) -{ - int error = 0; - git_vector entries = GIT_VECTOR_INIT; - git_idxmap *entries_map; - read_tree_data data; - size_t i; - git_index_entry *e; - - if (git_idxmap_new(&entries_map) < 0) - return -1; - - git_vector_set_cmp(&entries, index->entries._cmp); /* match sort */ - - data.index = index; - data.old_entries = &index->entries; - data.new_entries = &entries; - data.entry_cmp = index->entries_search; - - index->tree = NULL; - git_pool_clear(&index->tree_pool); - - git_vector_sort(&index->entries); - - if ((error = git_tree_walk(tree, GIT_TREEWALK_POST, read_tree_cb, &data)) < 0) - goto cleanup; - - if ((error = index_map_resize(entries_map, entries.length, index->ignore_case)) < 0) - goto cleanup; - - git_vector_foreach(&entries, i, e) { - if ((error = index_map_set(entries_map, e, index->ignore_case)) < 0) { - git_error_set(GIT_ERROR_INDEX, "failed to insert entry into map"); - return error; - } - } - - error = 0; - - git_vector_sort(&entries); - - if ((error = git_index_clear(index)) < 0) { - /* well, this isn't good */; - } else { - git_vector_swap(&entries, &index->entries); - entries_map = git_atomic_swap(index->entries_map, entries_map); - } - - index->dirty = 1; - -cleanup: - git_vector_free(&entries); - git_idxmap_free(entries_map); - if (error < 0) - return error; - - error = git_tree_cache_read_tree(&index->tree, tree, &index->tree_pool); - - return error; -} - -static int git_index_read_iterator( - git_index *index, - git_iterator *new_iterator, - size_t new_length_hint) -{ - git_vector new_entries = GIT_VECTOR_INIT, - remove_entries = GIT_VECTOR_INIT; - git_idxmap *new_entries_map = NULL; - git_iterator *index_iterator = NULL; - git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT; - const git_index_entry *old_entry, *new_entry; - git_index_entry *entry; - size_t i; - int error; - - GIT_ASSERT((new_iterator->flags & GIT_ITERATOR_DONT_IGNORE_CASE)); - - if ((error = git_vector_init(&new_entries, new_length_hint, index->entries._cmp)) < 0 || - (error = git_vector_init(&remove_entries, index->entries.length, NULL)) < 0 || - (error = git_idxmap_new(&new_entries_map)) < 0) - goto done; - - if (new_length_hint && (error = index_map_resize(new_entries_map, new_length_hint, - index->ignore_case)) < 0) - goto done; - - opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE | - GIT_ITERATOR_INCLUDE_CONFLICTS; - - if ((error = git_iterator_for_index(&index_iterator, - git_index_owner(index), index, &opts)) < 0 || - ((error = git_iterator_current(&old_entry, index_iterator)) < 0 && - error != GIT_ITEROVER) || - ((error = git_iterator_current(&new_entry, new_iterator)) < 0 && - error != GIT_ITEROVER)) - goto done; - - while (true) { - git_index_entry - *dup_entry = NULL, - *add_entry = NULL, - *remove_entry = NULL; - int diff; - - error = 0; - - if (old_entry && new_entry) - diff = git_index_entry_cmp(old_entry, new_entry); - else if (!old_entry && new_entry) - diff = 1; - else if (old_entry && !new_entry) - diff = -1; - else - break; - - if (diff < 0) { - remove_entry = (git_index_entry *)old_entry; - } else if (diff > 0) { - dup_entry = (git_index_entry *)new_entry; - } else { - /* Path and stage are equal, if the OID is equal, keep it to - * keep the stat cache data. - */ - if (git_oid_equal(&old_entry->id, &new_entry->id) && - old_entry->mode == new_entry->mode) { - add_entry = (git_index_entry *)old_entry; - } else { - dup_entry = (git_index_entry *)new_entry; - remove_entry = (git_index_entry *)old_entry; - } - } - - if (dup_entry) { - if ((error = index_entry_dup_nocache(&add_entry, index, dup_entry)) < 0) - goto done; - - index_entry_adjust_namemask(add_entry, - ((struct entry_internal *)add_entry)->pathlen); - } - - /* invalidate this path in the tree cache if this is new (to - * invalidate the parent trees) - */ - if (dup_entry && !remove_entry && index->tree) - git_tree_cache_invalidate_path(index->tree, dup_entry->path); - - if (add_entry) { - if ((error = git_vector_insert(&new_entries, add_entry)) == 0) - error = index_map_set(new_entries_map, add_entry, - index->ignore_case); - } - - if (remove_entry && error >= 0) - error = git_vector_insert(&remove_entries, remove_entry); - - if (error < 0) { - git_error_set(GIT_ERROR_INDEX, "failed to insert entry"); - goto done; - } - - if (diff <= 0) { - if ((error = git_iterator_advance(&old_entry, index_iterator)) < 0 && - error != GIT_ITEROVER) - goto done; - } - - if (diff >= 0) { - if ((error = git_iterator_advance(&new_entry, new_iterator)) < 0 && - error != GIT_ITEROVER) - goto done; - } - } - - if ((error = git_index_name_clear(index)) < 0 || - (error = git_index_reuc_clear(index)) < 0) - goto done; - - git_vector_swap(&new_entries, &index->entries); - new_entries_map = git_atomic_swap(index->entries_map, new_entries_map); - - git_vector_foreach(&remove_entries, i, entry) { - if (index->tree) - git_tree_cache_invalidate_path(index->tree, entry->path); - - index_entry_free(entry); - } - - clear_uptodate(index); - - index->dirty = 1; - error = 0; - -done: - git_idxmap_free(new_entries_map); - git_vector_free(&new_entries); - git_vector_free(&remove_entries); - git_iterator_free(index_iterator); - return error; -} - -int git_index_read_index( - git_index *index, - const git_index *new_index) -{ - git_iterator *new_iterator = NULL; - git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT; - int error; - - opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE | - GIT_ITERATOR_INCLUDE_CONFLICTS; - - if ((error = git_iterator_for_index(&new_iterator, - git_index_owner(new_index), (git_index *)new_index, &opts)) < 0 || - (error = git_index_read_iterator(index, new_iterator, - new_index->entries.length)) < 0) - goto done; - -done: - git_iterator_free(new_iterator); - return error; -} - -git_repository *git_index_owner(const git_index *index) -{ - return INDEX_OWNER(index); -} - -enum { - INDEX_ACTION_NONE = 0, - INDEX_ACTION_UPDATE = 1, - INDEX_ACTION_REMOVE = 2, - INDEX_ACTION_ADDALL = 3 -}; - -int git_index_add_all( - git_index *index, - const git_strarray *paths, - unsigned int flags, - git_index_matched_path_cb cb, - void *payload) -{ - int error; - git_repository *repo; - git_iterator *wditer = NULL; - git_pathspec ps; - bool no_fnmatch = (flags & GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH) != 0; - - GIT_ASSERT_ARG(index); - - repo = INDEX_OWNER(index); - if ((error = git_repository__ensure_not_bare(repo, "index add all")) < 0) - return error; - - if ((error = git_pathspec__init(&ps, paths)) < 0) - return error; - - /* optionally check that pathspec doesn't mention any ignored files */ - if ((flags & GIT_INDEX_ADD_CHECK_PATHSPEC) != 0 && - (flags & GIT_INDEX_ADD_FORCE) == 0 && - (error = git_ignore__check_pathspec_for_exact_ignores( - repo, &ps.pathspec, no_fnmatch)) < 0) - goto cleanup; - - error = index_apply_to_wd_diff(index, INDEX_ACTION_ADDALL, paths, flags, cb, payload); - - if (error) - git_error_set_after_callback(error); - -cleanup: - git_iterator_free(wditer); - git_pathspec__clear(&ps); - - return error; -} - -struct foreach_diff_data { - git_index *index; - const git_pathspec *pathspec; - unsigned int flags; - git_index_matched_path_cb cb; - void *payload; -}; - -static int apply_each_file(const git_diff_delta *delta, float progress, void *payload) -{ - struct foreach_diff_data *data = payload; - const char *match, *path; - int error = 0; - - GIT_UNUSED(progress); - - path = delta->old_file.path; - - /* We only want those which match the pathspecs */ - if (!git_pathspec__match( - &data->pathspec->pathspec, path, false, (bool)data->index->ignore_case, - &match, NULL)) - return 0; - - if (data->cb) - error = data->cb(path, match, data->payload); - - if (error > 0) /* skip this entry */ - return 0; - if (error < 0) /* actual error */ - return error; - - /* If the workdir item does not exist, remove it from the index. */ - if ((delta->new_file.flags & GIT_DIFF_FLAG_EXISTS) == 0) - error = git_index_remove_bypath(data->index, path); - else - error = git_index_add_bypath(data->index, delta->new_file.path); - - return error; -} - -static int index_apply_to_wd_diff(git_index *index, int action, const git_strarray *paths, - unsigned int flags, - git_index_matched_path_cb cb, void *payload) -{ - int error; - git_diff *diff; - git_pathspec ps; - git_repository *repo; - git_diff_options opts = GIT_DIFF_OPTIONS_INIT; - struct foreach_diff_data data = { - index, - NULL, - flags, - cb, - payload, - }; - - GIT_ASSERT_ARG(index); - GIT_ASSERT_ARG(action == INDEX_ACTION_UPDATE || action == INDEX_ACTION_ADDALL); - - repo = INDEX_OWNER(index); - - if (!repo) { - return create_index_error(-1, - "cannot run update; the index is not backed up by a repository."); - } - - /* - * We do the matching ourselves instead of passing the list to - * diff because we want to tell the callback which one - * matched, which we do not know if we ask diff to filter for us. - */ - if ((error = git_pathspec__init(&ps, paths)) < 0) - return error; - - opts.flags = GIT_DIFF_INCLUDE_TYPECHANGE; - if (action == INDEX_ACTION_ADDALL) { - opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED | - GIT_DIFF_RECURSE_UNTRACKED_DIRS; - - if (flags == GIT_INDEX_ADD_FORCE) - opts.flags |= GIT_DIFF_INCLUDE_IGNORED; - } - - if ((error = git_diff_index_to_workdir(&diff, repo, index, &opts)) < 0) - goto cleanup; - - data.pathspec = &ps; - error = git_diff_foreach(diff, apply_each_file, NULL, NULL, NULL, &data); - git_diff_free(diff); - - if (error) /* make sure error is set if callback stopped iteration */ - git_error_set_after_callback(error); - -cleanup: - git_pathspec__clear(&ps); - return error; -} - -static int index_apply_to_all( - git_index *index, - int action, - const git_strarray *paths, - git_index_matched_path_cb cb, - void *payload) -{ - int error = 0; - size_t i; - git_pathspec ps; - const char *match; - git_str path = GIT_STR_INIT; - - GIT_ASSERT_ARG(index); - - if ((error = git_pathspec__init(&ps, paths)) < 0) - return error; - - git_vector_sort(&index->entries); - - for (i = 0; !error && i < index->entries.length; ++i) { - git_index_entry *entry = git_vector_get(&index->entries, i); - - /* check if path actually matches */ - if (!git_pathspec__match( - &ps.pathspec, entry->path, false, (bool)index->ignore_case, - &match, NULL)) - continue; - - /* issue notification callback if requested */ - if (cb && (error = cb(entry->path, match, payload)) != 0) { - if (error > 0) { /* return > 0 means skip this one */ - error = 0; - continue; - } - if (error < 0) /* return < 0 means abort */ - break; - } - - /* index manipulation may alter entry, so don't depend on it */ - if ((error = git_str_sets(&path, entry->path)) < 0) - break; - - switch (action) { - case INDEX_ACTION_NONE: - break; - case INDEX_ACTION_UPDATE: - error = git_index_add_bypath(index, path.ptr); - - if (error == GIT_ENOTFOUND) { - git_error_clear(); - - error = git_index_remove_bypath(index, path.ptr); - - if (!error) /* back up foreach if we removed this */ - i--; - } - break; - case INDEX_ACTION_REMOVE: - if (!(error = git_index_remove_bypath(index, path.ptr))) - i--; /* back up foreach if we removed this */ - break; - default: - git_error_set(GIT_ERROR_INVALID, "unknown index action %d", action); - error = -1; - break; - } - } - - git_str_dispose(&path); - git_pathspec__clear(&ps); - - return error; -} - -int git_index_remove_all( - git_index *index, - const git_strarray *pathspec, - git_index_matched_path_cb cb, - void *payload) -{ - int error = index_apply_to_all( - index, INDEX_ACTION_REMOVE, pathspec, cb, payload); - - if (error) /* make sure error is set if callback stopped iteration */ - git_error_set_after_callback(error); - - return error; -} - -int git_index_update_all( - git_index *index, - const git_strarray *pathspec, - git_index_matched_path_cb cb, - void *payload) -{ - int error = index_apply_to_wd_diff(index, INDEX_ACTION_UPDATE, pathspec, 0, cb, payload); - if (error) /* make sure error is set if callback stopped iteration */ - git_error_set_after_callback(error); - - return error; -} - -int git_index_snapshot_new(git_vector *snap, git_index *index) -{ - int error; - - GIT_REFCOUNT_INC(index); - - git_atomic32_inc(&index->readers); - git_vector_sort(&index->entries); - - error = git_vector_dup(snap, &index->entries, index->entries._cmp); - - if (error < 0) - git_index_snapshot_release(snap, index); - - return error; -} - -void git_index_snapshot_release(git_vector *snap, git_index *index) -{ - git_vector_free(snap); - - git_atomic32_dec(&index->readers); - - git_index_free(index); -} - -int git_index_snapshot_find( - size_t *out, git_vector *entries, git_vector_cmp entry_srch, - const char *path, size_t path_len, int stage) -{ - return index_find_in_entries(out, entries, entry_srch, path, path_len, stage); -} - -int git_indexwriter_init( - git_indexwriter *writer, - git_index *index) -{ - int error; - - GIT_REFCOUNT_INC(index); - - writer->index = index; - - if (!index->index_file_path) - return create_index_error(-1, - "failed to write index: The index is in-memory only"); - - if ((error = git_filebuf_open( - &writer->file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS, GIT_INDEX_FILE_MODE)) < 0) { - - if (error == GIT_ELOCKED) - git_error_set(GIT_ERROR_INDEX, "the index is locked; this might be due to a concurrent or crashed process"); - - return error; - } - - writer->should_write = 1; - - return 0; -} - -int git_indexwriter_init_for_operation( - git_indexwriter *writer, - git_repository *repo, - unsigned int *checkout_strategy) -{ - git_index *index; - int error; - - if ((error = git_repository_index__weakptr(&index, repo)) < 0 || - (error = git_indexwriter_init(writer, index)) < 0) - return error; - - writer->should_write = (*checkout_strategy & GIT_CHECKOUT_DONT_WRITE_INDEX) == 0; - *checkout_strategy |= GIT_CHECKOUT_DONT_WRITE_INDEX; - - return 0; -} - -int git_indexwriter_commit(git_indexwriter *writer) -{ - unsigned char checksum[GIT_HASH_SHA1_SIZE]; - size_t checksum_size; - int error; - - if (!writer->should_write) - return 0; - - git_vector_sort(&writer->index->entries); - git_vector_sort(&writer->index->reuc); - - if ((error = write_index(checksum, &checksum_size, writer->index, &writer->file)) < 0) { - git_indexwriter_cleanup(writer); - return error; - } - - if ((error = git_filebuf_commit(&writer->file)) < 0) - return error; - - if ((error = git_futils_filestamp_check( - &writer->index->stamp, writer->index->index_file_path)) < 0) { - git_error_set(GIT_ERROR_OS, "could not read index timestamp"); - return -1; - } - - writer->index->dirty = 0; - writer->index->on_disk = 1; - memcpy(writer->index->checksum, checksum, checksum_size); - - git_index_free(writer->index); - writer->index = NULL; - - return 0; -} - -void git_indexwriter_cleanup(git_indexwriter *writer) -{ - git_filebuf_cleanup(&writer->file); - - git_index_free(writer->index); - writer->index = NULL; -} - -/* Deprecated functions */ - -#ifndef GIT_DEPRECATE_HARD -int git_index_add_frombuffer( - git_index *index, const git_index_entry *source_entry, - const void *buffer, size_t len) -{ - return git_index_add_from_buffer(index, source_entry, buffer, len); -} -#endif diff --git a/vendor/libgit2/src/indexer.c b/vendor/libgit2/src/indexer.c deleted file mode 100644 index f9a32e7a..00000000 --- a/vendor/libgit2/src/indexer.c +++ /dev/null @@ -1,1413 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "indexer.h" - -#include "git2/indexer.h" -#include "git2/object.h" - -#include "commit.h" -#include "tree.h" -#include "tag.h" -#include "pack.h" -#include "mwindow.h" -#include "posix.h" -#include "pack.h" -#include "filebuf.h" -#include "oid.h" -#include "oidarray.h" -#include "oidmap.h" -#include "zstream.h" -#include "object.h" - -size_t git_indexer__max_objects = UINT32_MAX; - -#define UINT31_MAX (0x7FFFFFFF) - -struct entry { - git_oid oid; - uint32_t crc; - uint32_t offset; - uint64_t offset_long; -}; - -struct git_indexer { - unsigned int parsed_header :1, - pack_committed :1, - have_stream :1, - have_delta :1, - do_fsync :1, - do_verify :1; - struct git_pack_header hdr; - struct git_pack_file *pack; - unsigned int mode; - off64_t off; - off64_t entry_start; - git_object_t entry_type; - git_str entry_data; - git_packfile_stream stream; - size_t nr_objects; - git_vector objects; - git_vector deltas; - unsigned int fanout[256]; - git_hash_ctx hash_ctx; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; - char name[(GIT_HASH_SHA1_SIZE * 2) + 1]; - git_indexer_progress_cb progress_cb; - void *progress_payload; - char objbuf[8*1024]; - - /* OIDs referenced from pack objects. Used for verification. */ - git_oidmap *expected_oids; - - /* Needed to look up objects which we want to inject to fix a thin pack */ - git_odb *odb; - - /* Fields for calculating the packfile trailer (hash of everything before it) */ - char inbuf[GIT_OID_RAWSZ]; - size_t inbuf_len; - git_hash_ctx trailer; -}; - -struct delta_info { - off64_t delta_off; -}; - -#ifndef GIT_DEPRECATE_HARD -const git_oid *git_indexer_hash(const git_indexer *idx) -{ - return (git_oid *)idx->checksum; -} -#endif - -const char *git_indexer_name(const git_indexer *idx) -{ - return idx->name; -} - -static int parse_header(struct git_pack_header *hdr, struct git_pack_file *pack) -{ - int error; - git_map map; - - if ((error = p_mmap(&map, sizeof(*hdr), GIT_PROT_READ, GIT_MAP_SHARED, pack->mwf.fd, 0)) < 0) - return error; - - memcpy(hdr, map.data, sizeof(*hdr)); - p_munmap(&map); - - /* Verify we recognize this pack file format. */ - if (hdr->hdr_signature != ntohl(PACK_SIGNATURE)) { - git_error_set(GIT_ERROR_INDEXER, "wrong pack signature"); - return -1; - } - - if (!pack_version_ok(hdr->hdr_version)) { - git_error_set(GIT_ERROR_INDEXER, "wrong pack version"); - return -1; - } - - return 0; -} - -static int objects_cmp(const void *a, const void *b) -{ - const struct entry *entrya = a; - const struct entry *entryb = b; - - return git_oid__cmp(&entrya->oid, &entryb->oid); -} - -int git_indexer_options_init(git_indexer_options *opts, unsigned int version) -{ - GIT_INIT_STRUCTURE_FROM_TEMPLATE( - opts, version, git_indexer_options, GIT_INDEXER_OPTIONS_INIT); - return 0; -} - -#ifndef GIT_DEPRECATE_HARD -int git_indexer_init_options(git_indexer_options *opts, unsigned int version) -{ - return git_indexer_options_init(opts, version); -} -#endif - -int git_indexer_new( - git_indexer **out, - const char *prefix, - unsigned int mode, - git_odb *odb, - git_indexer_options *in_opts) -{ - git_indexer_options opts = GIT_INDEXER_OPTIONS_INIT; - git_indexer *idx; - git_str path = GIT_STR_INIT, tmp_path = GIT_STR_INIT; - static const char suff[] = "/pack"; - int error, fd = -1; - - if (in_opts) - memcpy(&opts, in_opts, sizeof(opts)); - - idx = git__calloc(1, sizeof(git_indexer)); - GIT_ERROR_CHECK_ALLOC(idx); - idx->odb = odb; - idx->progress_cb = opts.progress_cb; - idx->progress_payload = opts.progress_cb_payload; - idx->mode = mode ? mode : GIT_PACK_FILE_MODE; - git_str_init(&idx->entry_data, 0); - - if ((error = git_hash_ctx_init(&idx->hash_ctx, GIT_HASH_ALGORITHM_SHA1)) < 0 || - (error = git_hash_ctx_init(&idx->trailer, GIT_HASH_ALGORITHM_SHA1)) < 0 || - (error = git_oidmap_new(&idx->expected_oids)) < 0) - goto cleanup; - - idx->do_verify = opts.verify; - - if (git_repository__fsync_gitdir) - idx->do_fsync = 1; - - error = git_str_joinpath(&path, prefix, suff); - if (error < 0) - goto cleanup; - - fd = git_futils_mktmp(&tmp_path, git_str_cstr(&path), idx->mode); - git_str_dispose(&path); - if (fd < 0) - goto cleanup; - - error = git_packfile_alloc(&idx->pack, git_str_cstr(&tmp_path)); - git_str_dispose(&tmp_path); - - if (error < 0) - goto cleanup; - - idx->pack->mwf.fd = fd; - if ((error = git_mwindow_file_register(&idx->pack->mwf)) < 0) - goto cleanup; - - *out = idx; - return 0; - -cleanup: - if (fd != -1) - p_close(fd); - - if (git_str_len(&tmp_path) > 0) - p_unlink(git_str_cstr(&tmp_path)); - - if (idx->pack != NULL) - p_unlink(idx->pack->pack_name); - - git_str_dispose(&path); - git_str_dispose(&tmp_path); - git__free(idx); - return -1; -} - -void git_indexer__set_fsync(git_indexer *idx, int do_fsync) -{ - idx->do_fsync = !!do_fsync; -} - -/* Try to store the delta so we can try to resolve it later */ -static int store_delta(git_indexer *idx) -{ - struct delta_info *delta; - - delta = git__calloc(1, sizeof(struct delta_info)); - GIT_ERROR_CHECK_ALLOC(delta); - delta->delta_off = idx->entry_start; - - if (git_vector_insert(&idx->deltas, delta) < 0) - return -1; - - return 0; -} - -static int hash_header(git_hash_ctx *ctx, off64_t len, git_object_t type) -{ - char buffer[64]; - size_t hdrlen; - int error; - - if ((error = git_odb__format_object_header(&hdrlen, - buffer, sizeof(buffer), (size_t)len, type)) < 0) - return error; - - return git_hash_update(ctx, buffer, hdrlen); -} - -static int hash_object_stream(git_indexer*idx, git_packfile_stream *stream) -{ - ssize_t read; - - GIT_ASSERT_ARG(idx); - GIT_ASSERT_ARG(stream); - - do { - if ((read = git_packfile_stream_read(stream, idx->objbuf, sizeof(idx->objbuf))) < 0) - break; - - if (idx->do_verify) - git_str_put(&idx->entry_data, idx->objbuf, read); - - git_hash_update(&idx->hash_ctx, idx->objbuf, read); - } while (read > 0); - - if (read < 0) - return (int)read; - - return 0; -} - -/* In order to create the packfile stream, we need to skip over the delta base description */ -static int advance_delta_offset(git_indexer *idx, git_object_t type) -{ - git_mwindow *w = NULL; - - GIT_ASSERT_ARG(type == GIT_OBJECT_REF_DELTA || type == GIT_OBJECT_OFS_DELTA); - - if (type == GIT_OBJECT_REF_DELTA) { - idx->off += GIT_OID_RAWSZ; - } else { - off64_t base_off; - int error = get_delta_base(&base_off, idx->pack, &w, &idx->off, type, idx->entry_start); - git_mwindow_close(&w); - if (error < 0) - return error; - } - - return 0; -} - -/* Read from the stream and discard any output */ -static int read_object_stream(git_indexer *idx, git_packfile_stream *stream) -{ - ssize_t read; - - GIT_ASSERT_ARG(stream); - - do { - read = git_packfile_stream_read(stream, idx->objbuf, sizeof(idx->objbuf)); - } while (read > 0); - - if (read < 0) - return (int)read; - - return 0; -} - -static int crc_object(uint32_t *crc_out, git_mwindow_file *mwf, off64_t start, off64_t size) -{ - void *ptr; - uint32_t crc; - unsigned int left, len; - git_mwindow *w = NULL; - - crc = crc32(0L, Z_NULL, 0); - while (size) { - ptr = git_mwindow_open(mwf, &w, start, (size_t)size, &left); - if (ptr == NULL) - return -1; - - len = min(left, (unsigned int)size); - crc = crc32(crc, ptr, len); - size -= len; - start += len; - git_mwindow_close(&w); - } - - *crc_out = htonl(crc); - return 0; -} - -static int add_expected_oid(git_indexer *idx, const git_oid *oid) -{ - /* - * If we know about that object because it is stored in our ODB or - * because we have already processed it as part of our pack file, we do - * not have to expect it. - */ - if ((!idx->odb || !git_odb_exists(idx->odb, oid)) && - !git_oidmap_exists(idx->pack->idx_cache, oid) && - !git_oidmap_exists(idx->expected_oids, oid)) { - git_oid *dup = git__malloc(sizeof(*oid)); - GIT_ERROR_CHECK_ALLOC(dup); - git_oid_cpy(dup, oid); - return git_oidmap_set(idx->expected_oids, dup, dup); - } - - return 0; -} - -static int check_object_connectivity(git_indexer *idx, const git_rawobj *obj) -{ - git_object *object; - git_oid *expected; - int error = 0; - - if (obj->type != GIT_OBJECT_BLOB && - obj->type != GIT_OBJECT_TREE && - obj->type != GIT_OBJECT_COMMIT && - obj->type != GIT_OBJECT_TAG) - return 0; - - if (git_object__from_raw(&object, obj->data, obj->len, obj->type) < 0) { - /* - * parse_raw returns EINVALID on invalid data; downgrade - * that to a normal -1 error code. - */ - error = -1; - goto out; - } - - if ((expected = git_oidmap_get(idx->expected_oids, &object->cached.oid)) != NULL) { - git_oidmap_delete(idx->expected_oids, &object->cached.oid); - git__free(expected); - } - - /* - * Check whether this is a known object. If so, we can just continue as - * we assume that the ODB has a complete graph. - */ - if (idx->odb && git_odb_exists(idx->odb, &object->cached.oid)) - return 0; - - switch (obj->type) { - case GIT_OBJECT_TREE: - { - git_tree *tree = (git_tree *) object; - git_tree_entry *entry; - size_t i; - - git_array_foreach(tree->entries, i, entry) - if (add_expected_oid(idx, entry->oid) < 0) - goto out; - - break; - } - case GIT_OBJECT_COMMIT: - { - git_commit *commit = (git_commit *) object; - git_oid *parent_oid; - size_t i; - - git_array_foreach(commit->parent_ids, i, parent_oid) - if (add_expected_oid(idx, parent_oid) < 0) - goto out; - - if (add_expected_oid(idx, &commit->tree_id) < 0) - goto out; - - break; - } - case GIT_OBJECT_TAG: - { - git_tag *tag = (git_tag *) object; - - if (add_expected_oid(idx, &tag->target) < 0) - goto out; - - break; - } - case GIT_OBJECT_BLOB: - default: - break; - } - -out: - git_object_free(object); - - return error; -} - -static int store_object(git_indexer *idx) -{ - int i, error; - git_oid oid; - struct entry *entry; - off64_t entry_size; - struct git_pack_entry *pentry; - off64_t entry_start = idx->entry_start; - - entry = git__calloc(1, sizeof(*entry)); - GIT_ERROR_CHECK_ALLOC(entry); - - pentry = git__calloc(1, sizeof(struct git_pack_entry)); - GIT_ERROR_CHECK_ALLOC(pentry); - - if (git_hash_final(oid.id, &idx->hash_ctx)) { - git__free(pentry); - goto on_error; - } - entry_size = idx->off - entry_start; - if (entry_start > UINT31_MAX) { - entry->offset = UINT32_MAX; - entry->offset_long = entry_start; - } else { - entry->offset = (uint32_t)entry_start; - } - - if (idx->do_verify) { - git_rawobj rawobj = { - idx->entry_data.ptr, - idx->entry_data.size, - idx->entry_type - }; - - if ((error = check_object_connectivity(idx, &rawobj)) < 0) - goto on_error; - } - - git_oid_cpy(&pentry->sha1, &oid); - pentry->offset = entry_start; - - if (git_oidmap_exists(idx->pack->idx_cache, &pentry->sha1)) { - git_error_set(GIT_ERROR_INDEXER, "duplicate object %s found in pack", git_oid_tostr_s(&pentry->sha1)); - git__free(pentry); - goto on_error; - } - - if ((error = git_oidmap_set(idx->pack->idx_cache, &pentry->sha1, pentry)) < 0) { - git__free(pentry); - git_error_set_oom(); - goto on_error; - } - - git_oid_cpy(&entry->oid, &oid); - - if (crc_object(&entry->crc, &idx->pack->mwf, entry_start, entry_size) < 0) - goto on_error; - - /* Add the object to the list */ - if (git_vector_insert(&idx->objects, entry) < 0) - goto on_error; - - for (i = oid.id[0]; i < 256; ++i) { - idx->fanout[i]++; - } - - return 0; - -on_error: - git__free(entry); - - return -1; -} - -GIT_INLINE(bool) has_entry(git_indexer *idx, git_oid *id) -{ - return git_oidmap_exists(idx->pack->idx_cache, id); -} - -static int save_entry(git_indexer *idx, struct entry *entry, struct git_pack_entry *pentry, off64_t entry_start) -{ - int i; - - if (entry_start > UINT31_MAX) { - entry->offset = UINT32_MAX; - entry->offset_long = entry_start; - } else { - entry->offset = (uint32_t)entry_start; - } - - pentry->offset = entry_start; - - if (git_oidmap_exists(idx->pack->idx_cache, &pentry->sha1) || - git_oidmap_set(idx->pack->idx_cache, &pentry->sha1, pentry) < 0) { - git_error_set(GIT_ERROR_INDEXER, "cannot insert object into pack"); - return -1; - } - - /* Add the object to the list */ - if (git_vector_insert(&idx->objects, entry) < 0) - return -1; - - for (i = entry->oid.id[0]; i < 256; ++i) { - idx->fanout[i]++; - } - - return 0; -} - -static int hash_and_save(git_indexer *idx, git_rawobj *obj, off64_t entry_start) -{ - git_oid oid; - size_t entry_size; - struct entry *entry; - struct git_pack_entry *pentry = NULL; - - entry = git__calloc(1, sizeof(*entry)); - GIT_ERROR_CHECK_ALLOC(entry); - - if (git_odb__hashobj(&oid, obj) < 0) { - git_error_set(GIT_ERROR_INDEXER, "failed to hash object"); - goto on_error; - } - - pentry = git__calloc(1, sizeof(struct git_pack_entry)); - GIT_ERROR_CHECK_ALLOC(pentry); - - git_oid_cpy(&pentry->sha1, &oid); - git_oid_cpy(&entry->oid, &oid); - entry->crc = crc32(0L, Z_NULL, 0); - - entry_size = (size_t)(idx->off - entry_start); - if (crc_object(&entry->crc, &idx->pack->mwf, entry_start, entry_size) < 0) - goto on_error; - - return save_entry(idx, entry, pentry, entry_start); - -on_error: - git__free(pentry); - git__free(entry); - git__free(obj->data); - return -1; -} - -static int do_progress_callback(git_indexer *idx, git_indexer_progress *stats) -{ - if (idx->progress_cb) - return git_error_set_after_callback_function( - idx->progress_cb(stats, idx->progress_payload), - "indexer progress"); - return 0; -} - -/* Hash everything but the last 20B of input */ -static void hash_partially(git_indexer *idx, const uint8_t *data, size_t size) -{ - size_t to_expell, to_keep; - - if (size == 0) - return; - - /* Easy case, dump the buffer and the data minus the last 20 bytes */ - if (size >= GIT_OID_RAWSZ) { - git_hash_update(&idx->trailer, idx->inbuf, idx->inbuf_len); - git_hash_update(&idx->trailer, data, size - GIT_OID_RAWSZ); - - data += size - GIT_OID_RAWSZ; - memcpy(idx->inbuf, data, GIT_OID_RAWSZ); - idx->inbuf_len = GIT_OID_RAWSZ; - return; - } - - /* We can just append */ - if (idx->inbuf_len + size <= GIT_OID_RAWSZ) { - memcpy(idx->inbuf + idx->inbuf_len, data, size); - idx->inbuf_len += size; - return; - } - - /* We need to partially drain the buffer and then append */ - to_keep = GIT_OID_RAWSZ - size; - to_expell = idx->inbuf_len - to_keep; - - git_hash_update(&idx->trailer, idx->inbuf, to_expell); - - memmove(idx->inbuf, idx->inbuf + to_expell, to_keep); - memcpy(idx->inbuf + to_keep, data, size); - idx->inbuf_len += size - to_expell; -} - -#if defined(NO_MMAP) || !defined(GIT_WIN32) - -static int write_at(git_indexer *idx, const void *data, off64_t offset, size_t size) -{ - size_t remaining_size = size; - const char *ptr = (const char *)data; - - /* Handle data size larger that ssize_t */ - while (remaining_size > 0) { - ssize_t nb; - HANDLE_EINTR(nb, p_pwrite(idx->pack->mwf.fd, (void *)ptr, - remaining_size, offset)); - if (nb <= 0) - return -1; - - ptr += nb; - offset += nb; - remaining_size -= nb; - } - - return 0; -} - -static int append_to_pack(git_indexer *idx, const void *data, size_t size) -{ - if (write_at(idx, data, idx->pack->mwf.size, size) < 0) { - git_error_set(GIT_ERROR_OS, "cannot extend packfile '%s'", idx->pack->pack_name); - return -1; - } - - return 0; -} - -#else - -/* - * Windows may keep different views to a networked file for the mmap- and - * open-accessed versions of a file, so any writes done through - * `write(2)`/`pwrite(2)` may not be reflected on the data that `mmap(2)` is - * able to read. - */ - -static int write_at(git_indexer *idx, const void *data, off64_t offset, size_t size) -{ - git_file fd = idx->pack->mwf.fd; - size_t mmap_alignment; - size_t page_offset; - off64_t page_start; - unsigned char *map_data; - git_map map; - int error; - - GIT_ASSERT_ARG(data); - GIT_ASSERT_ARG(size); - - if ((error = git__mmap_alignment(&mmap_alignment)) < 0) - return error; - - /* the offset needs to be at the mmap boundary for the platform */ - page_offset = offset % mmap_alignment; - page_start = offset - page_offset; - - if ((error = p_mmap(&map, page_offset + size, GIT_PROT_WRITE, GIT_MAP_SHARED, fd, page_start)) < 0) - return error; - - map_data = (unsigned char *)map.data; - memcpy(map_data + page_offset, data, size); - p_munmap(&map); - - return 0; -} - -static int append_to_pack(git_indexer *idx, const void *data, size_t size) -{ - off64_t new_size; - size_t mmap_alignment; - size_t page_offset; - off64_t page_start; - off64_t current_size = idx->pack->mwf.size; - int error; - - if (!size) - return 0; - - if ((error = git__mmap_alignment(&mmap_alignment)) < 0) - return error; - - /* Write a single byte to force the file system to allocate space now or - * report an error, since we can't report errors when writing using mmap. - * Round the size up to the nearest page so that we only need to perform file - * I/O when we add a page, instead of whenever we write even a single byte. */ - new_size = current_size + size; - page_offset = new_size % mmap_alignment; - page_start = new_size - page_offset; - - if (p_pwrite(idx->pack->mwf.fd, data, 1, page_start + mmap_alignment - 1) < 0) { - git_error_set(GIT_ERROR_OS, "cannot extend packfile '%s'", idx->pack->pack_name); - return -1; - } - - return write_at(idx, data, idx->pack->mwf.size, size); -} - -#endif - -static int read_stream_object(git_indexer *idx, git_indexer_progress *stats) -{ - git_packfile_stream *stream = &idx->stream; - off64_t entry_start = idx->off; - size_t entry_size; - git_object_t type; - git_mwindow *w = NULL; - int error; - - if (idx->pack->mwf.size <= idx->off + 20) - return GIT_EBUFS; - - if (!idx->have_stream) { - error = git_packfile_unpack_header(&entry_size, &type, idx->pack, &w, &idx->off); - if (error == GIT_EBUFS) { - idx->off = entry_start; - return error; - } - if (error < 0) - return error; - - git_mwindow_close(&w); - idx->entry_start = entry_start; - git_hash_init(&idx->hash_ctx); - git_str_clear(&idx->entry_data); - - if (type == GIT_OBJECT_REF_DELTA || type == GIT_OBJECT_OFS_DELTA) { - error = advance_delta_offset(idx, type); - if (error == GIT_EBUFS) { - idx->off = entry_start; - return error; - } - if (error < 0) - return error; - - idx->have_delta = 1; - } else { - idx->have_delta = 0; - - error = hash_header(&idx->hash_ctx, entry_size, type); - if (error < 0) - return error; - } - - idx->have_stream = 1; - idx->entry_type = type; - - error = git_packfile_stream_open(stream, idx->pack, idx->off); - if (error < 0) - return error; - } - - if (idx->have_delta) { - error = read_object_stream(idx, stream); - } else { - error = hash_object_stream(idx, stream); - } - - idx->off = stream->curpos; - if (error == GIT_EBUFS) - return error; - - /* We want to free the stream reasorces no matter what here */ - idx->have_stream = 0; - git_packfile_stream_dispose(stream); - - if (error < 0) - return error; - - if (idx->have_delta) { - error = store_delta(idx); - } else { - error = store_object(idx); - } - - if (error < 0) - return error; - - if (!idx->have_delta) { - stats->indexed_objects++; - } - stats->received_objects++; - - if ((error = do_progress_callback(idx, stats)) != 0) - return error; - - return 0; -} - -int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_indexer_progress *stats) -{ - int error = -1; - struct git_pack_header *hdr = &idx->hdr; - git_mwindow_file *mwf = &idx->pack->mwf; - - GIT_ASSERT_ARG(idx); - GIT_ASSERT_ARG(data); - GIT_ASSERT_ARG(stats); - - if ((error = append_to_pack(idx, data, size)) < 0) - return error; - - hash_partially(idx, data, (int)size); - - /* Make sure we set the new size of the pack */ - idx->pack->mwf.size += size; - - if (!idx->parsed_header) { - unsigned int total_objects; - - if ((unsigned)idx->pack->mwf.size < sizeof(struct git_pack_header)) - return 0; - - if ((error = parse_header(&idx->hdr, idx->pack)) < 0) - return error; - - idx->parsed_header = 1; - idx->nr_objects = ntohl(hdr->hdr_entries); - idx->off = sizeof(struct git_pack_header); - - if (idx->nr_objects <= git_indexer__max_objects) { - total_objects = (unsigned int)idx->nr_objects; - } else { - git_error_set(GIT_ERROR_INDEXER, "too many objects"); - return -1; - } - - if (git_oidmap_new(&idx->pack->idx_cache) < 0) - return -1; - - idx->pack->has_cache = 1; - if (git_vector_init(&idx->objects, total_objects, objects_cmp) < 0) - return -1; - - if (git_vector_init(&idx->deltas, total_objects / 2, NULL) < 0) - return -1; - - stats->received_objects = 0; - stats->local_objects = 0; - stats->total_deltas = 0; - stats->indexed_deltas = 0; - stats->indexed_objects = 0; - stats->total_objects = total_objects; - - if ((error = do_progress_callback(idx, stats)) != 0) - return error; - } - - /* Now that we have data in the pack, let's try to parse it */ - - /* As the file grows any windows we try to use will be out of date */ - if ((error = git_mwindow_free_all(mwf)) < 0) - goto on_error; - - while (stats->indexed_objects < idx->nr_objects) { - if ((error = read_stream_object(idx, stats)) != 0) { - if (error == GIT_EBUFS) - break; - else - goto on_error; - } - } - - return 0; - -on_error: - git_mwindow_free_all(mwf); - return error; -} - -static int index_path(git_str *path, git_indexer *idx, const char *suffix) -{ - const char prefix[] = "pack-"; - size_t slash = (size_t)path->size; - - /* search backwards for '/' */ - while (slash > 0 && path->ptr[slash - 1] != '/') - slash--; - - if (git_str_grow(path, slash + 1 + strlen(prefix) + - GIT_OID_HEXSZ + strlen(suffix) + 1) < 0) - return -1; - - git_str_truncate(path, slash); - git_str_puts(path, prefix); - git_str_puts(path, idx->name); - git_str_puts(path, suffix); - - return git_str_oom(path) ? -1 : 0; -} - -/** - * Rewind the packfile by the trailer, as we might need to fix the - * packfile by injecting objects at the tail and must overwrite it. - */ -static int seek_back_trailer(git_indexer *idx) -{ - idx->pack->mwf.size -= GIT_OID_RAWSZ; - return git_mwindow_free_all(&idx->pack->mwf); -} - -static int inject_object(git_indexer *idx, git_oid *id) -{ - git_odb_object *obj = NULL; - struct entry *entry = NULL; - struct git_pack_entry *pentry = NULL; - unsigned char empty_checksum[GIT_HASH_SHA1_SIZE] = {0}; - unsigned char hdr[64]; - git_str buf = GIT_STR_INIT; - off64_t entry_start; - const void *data; - size_t len, hdr_len; - size_t checksum_size = GIT_HASH_SHA1_SIZE; - int error; - - if ((error = seek_back_trailer(idx)) < 0) - goto cleanup; - - entry_start = idx->pack->mwf.size; - - if ((error = git_odb_read(&obj, idx->odb, id)) < 0) { - git_error_set(GIT_ERROR_INDEXER, "missing delta bases"); - goto cleanup; - } - - data = git_odb_object_data(obj); - len = git_odb_object_size(obj); - - entry = git__calloc(1, sizeof(*entry)); - GIT_ERROR_CHECK_ALLOC(entry); - - entry->crc = crc32(0L, Z_NULL, 0); - - /* Write out the object header */ - if ((error = git_packfile__object_header(&hdr_len, hdr, len, git_odb_object_type(obj))) < 0 || - (error = append_to_pack(idx, hdr, hdr_len)) < 0) - goto cleanup; - - idx->pack->mwf.size += hdr_len; - entry->crc = crc32(entry->crc, hdr, (uInt)hdr_len); - - if ((error = git_zstream_deflatebuf(&buf, data, len)) < 0) - goto cleanup; - - /* And then the compressed object */ - if ((error = append_to_pack(idx, buf.ptr, buf.size)) < 0) - goto cleanup; - - idx->pack->mwf.size += buf.size; - entry->crc = htonl(crc32(entry->crc, (unsigned char *)buf.ptr, (uInt)buf.size)); - git_str_dispose(&buf); - - /* Write a fake trailer so the pack functions play ball */ - - if ((error = append_to_pack(idx, empty_checksum, checksum_size)) < 0) - goto cleanup; - - idx->pack->mwf.size += GIT_OID_RAWSZ; - - pentry = git__calloc(1, sizeof(struct git_pack_entry)); - GIT_ERROR_CHECK_ALLOC(pentry); - - git_oid_cpy(&pentry->sha1, id); - git_oid_cpy(&entry->oid, id); - idx->off = entry_start + hdr_len + len; - - error = save_entry(idx, entry, pentry, entry_start); - -cleanup: - if (error) { - git__free(entry); - git__free(pentry); - } - - git_odb_object_free(obj); - return error; -} - -static int fix_thin_pack(git_indexer *idx, git_indexer_progress *stats) -{ - int error, found_ref_delta = 0; - unsigned int i; - struct delta_info *delta; - size_t size; - git_object_t type; - git_mwindow *w = NULL; - off64_t curpos = 0; - unsigned char *base_info; - unsigned int left = 0; - git_oid base; - - GIT_ASSERT(git_vector_length(&idx->deltas) > 0); - - if (idx->odb == NULL) { - git_error_set(GIT_ERROR_INDEXER, "cannot fix a thin pack without an ODB"); - return -1; - } - - /* Loop until we find the first REF delta */ - git_vector_foreach(&idx->deltas, i, delta) { - if (!delta) - continue; - - curpos = delta->delta_off; - error = git_packfile_unpack_header(&size, &type, idx->pack, &w, &curpos); - if (error < 0) - return error; - - if (type == GIT_OBJECT_REF_DELTA) { - found_ref_delta = 1; - break; - } - } - - if (!found_ref_delta) { - git_error_set(GIT_ERROR_INDEXER, "no REF_DELTA found, cannot inject object"); - return -1; - } - - /* curpos now points to the base information, which is an OID */ - base_info = git_mwindow_open(&idx->pack->mwf, &w, curpos, GIT_OID_RAWSZ, &left); - if (base_info == NULL) { - git_error_set(GIT_ERROR_INDEXER, "failed to map delta information"); - return -1; - } - - git_oid_fromraw(&base, base_info); - git_mwindow_close(&w); - - if (has_entry(idx, &base)) - return 0; - - if (inject_object(idx, &base) < 0) - return -1; - - stats->local_objects++; - - return 0; -} - -static int resolve_deltas(git_indexer *idx, git_indexer_progress *stats) -{ - unsigned int i; - int error; - struct delta_info *delta; - int progressed = 0, non_null = 0, progress_cb_result; - - while (idx->deltas.length > 0) { - progressed = 0; - non_null = 0; - git_vector_foreach(&idx->deltas, i, delta) { - git_rawobj obj = {0}; - - if (!delta) - continue; - - non_null = 1; - idx->off = delta->delta_off; - if ((error = git_packfile_unpack(&obj, idx->pack, &idx->off)) < 0) { - if (error == GIT_PASSTHROUGH) { - /* We have not seen the base object, we'll try again later. */ - continue; - } - return -1; - } - - if (idx->do_verify && check_object_connectivity(idx, &obj) < 0) - /* TODO: error? continue? */ - continue; - - if (hash_and_save(idx, &obj, delta->delta_off) < 0) - continue; - - git__free(obj.data); - stats->indexed_objects++; - stats->indexed_deltas++; - progressed = 1; - if ((progress_cb_result = do_progress_callback(idx, stats)) < 0) - return progress_cb_result; - - /* remove from the list */ - git_vector_set(NULL, &idx->deltas, i, NULL); - git__free(delta); - } - - /* if none were actually set, we're done */ - if (!non_null) - break; - - if (!progressed && (fix_thin_pack(idx, stats) < 0)) { - return -1; - } - } - - return 0; -} - -static int update_header_and_rehash(git_indexer *idx, git_indexer_progress *stats) -{ - void *ptr; - size_t chunk = 1024*1024; - off64_t hashed = 0; - git_mwindow *w = NULL; - git_mwindow_file *mwf; - unsigned int left; - - mwf = &idx->pack->mwf; - - git_hash_init(&idx->trailer); - - - /* Update the header to include the number of local objects we injected */ - idx->hdr.hdr_entries = htonl(stats->total_objects + stats->local_objects); - if (write_at(idx, &idx->hdr, 0, sizeof(struct git_pack_header)) < 0) - return -1; - - /* - * We now use the same technique as before to determine the - * hash. We keep reading up to the end and let - * hash_partially() keep the existing trailer out of the - * calculation. - */ - if (git_mwindow_free_all(mwf) < 0) - return -1; - - idx->inbuf_len = 0; - while (hashed < mwf->size) { - ptr = git_mwindow_open(mwf, &w, hashed, chunk, &left); - if (ptr == NULL) - return -1; - - hash_partially(idx, ptr, left); - hashed += left; - - git_mwindow_close(&w); - } - - return 0; -} - -int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats) -{ - git_mwindow *w = NULL; - unsigned int i, long_offsets = 0, left; - int error; - struct git_pack_idx_header hdr; - git_str filename = GIT_STR_INIT; - struct entry *entry; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; - git_filebuf index_file = {0}; - void *packfile_trailer; - size_t checksum_size = GIT_HASH_SHA1_SIZE; - bool mismatch; - - if (!idx->parsed_header) { - git_error_set(GIT_ERROR_INDEXER, "incomplete pack header"); - return -1; - } - - /* Test for this before resolve_deltas(), as it plays with idx->off */ - if (idx->off + (ssize_t)checksum_size < idx->pack->mwf.size) { - git_error_set(GIT_ERROR_INDEXER, "unexpected data at the end of the pack"); - return -1; - } - if (idx->off + (ssize_t)checksum_size > idx->pack->mwf.size) { - git_error_set(GIT_ERROR_INDEXER, "missing trailer at the end of the pack"); - return -1; - } - - packfile_trailer = git_mwindow_open(&idx->pack->mwf, &w, idx->pack->mwf.size - checksum_size, checksum_size, &left); - if (packfile_trailer == NULL) { - git_mwindow_close(&w); - goto on_error; - } - - /* Compare the packfile trailer as it was sent to us and what we calculated */ - git_hash_final(checksum, &idx->trailer); - mismatch = !!memcmp(checksum, packfile_trailer, checksum_size); - git_mwindow_close(&w); - - if (mismatch) { - git_error_set(GIT_ERROR_INDEXER, "packfile trailer mismatch"); - return -1; - } - - /* Freeze the number of deltas */ - stats->total_deltas = stats->total_objects - stats->indexed_objects; - - if ((error = resolve_deltas(idx, stats)) < 0) - return error; - - if (stats->indexed_objects != stats->total_objects) { - git_error_set(GIT_ERROR_INDEXER, "early EOF"); - return -1; - } - - if (stats->local_objects > 0) { - if (update_header_and_rehash(idx, stats) < 0) - return -1; - - git_hash_final(checksum, &idx->trailer); - write_at(idx, checksum, idx->pack->mwf.size - checksum_size, checksum_size); - } - - /* - * Is the resulting graph fully connected or are we still - * missing some objects? In the second case, we can - * bail out due to an incomplete and thus corrupt - * packfile. - */ - if (git_oidmap_size(idx->expected_oids) > 0) { - git_error_set(GIT_ERROR_INDEXER, "packfile is missing %"PRIuZ" objects", - git_oidmap_size(idx->expected_oids)); - return -1; - } - - git_vector_sort(&idx->objects); - - /* Use the trailer hash as the pack file name to ensure - * files with different contents have different names */ - memcpy(idx->checksum, checksum, checksum_size); - if (git_hash_fmt(idx->name, checksum, checksum_size) < 0) - return -1; - - git_str_sets(&filename, idx->pack->pack_name); - git_str_shorten(&filename, strlen("pack")); - git_str_puts(&filename, "idx"); - if (git_str_oom(&filename)) - return -1; - - if (git_filebuf_open(&index_file, filename.ptr, - GIT_FILEBUF_HASH_CONTENTS | - (idx->do_fsync ? GIT_FILEBUF_FSYNC : 0), - idx->mode) < 0) - goto on_error; - - /* Write out the header */ - hdr.idx_signature = htonl(PACK_IDX_SIGNATURE); - hdr.idx_version = htonl(2); - git_filebuf_write(&index_file, &hdr, sizeof(hdr)); - - /* Write out the fanout table */ - for (i = 0; i < 256; ++i) { - uint32_t n = htonl(idx->fanout[i]); - git_filebuf_write(&index_file, &n, sizeof(n)); - } - - /* Write out the object names (SHA-1 hashes) */ - git_vector_foreach(&idx->objects, i, entry) { - git_filebuf_write(&index_file, &entry->oid, sizeof(git_oid)); - } - - /* Write out the CRC32 values */ - git_vector_foreach(&idx->objects, i, entry) { - git_filebuf_write(&index_file, &entry->crc, sizeof(uint32_t)); - } - - /* Write out the offsets */ - git_vector_foreach(&idx->objects, i, entry) { - uint32_t n; - - if (entry->offset == UINT32_MAX) - n = htonl(0x80000000 | long_offsets++); - else - n = htonl(entry->offset); - - git_filebuf_write(&index_file, &n, sizeof(uint32_t)); - } - - /* Write out the long offsets */ - git_vector_foreach(&idx->objects, i, entry) { - uint32_t split[2]; - - if (entry->offset != UINT32_MAX) - continue; - - split[0] = htonl(entry->offset_long >> 32); - split[1] = htonl(entry->offset_long & 0xffffffff); - - git_filebuf_write(&index_file, &split, sizeof(uint32_t) * 2); - } - - /* Write out the packfile trailer to the index */ - if (git_filebuf_write(&index_file, checksum, checksum_size) < 0) - goto on_error; - - /* Write out the hash of the idx */ - if (git_filebuf_hash(checksum, &index_file) < 0) - goto on_error; - - git_filebuf_write(&index_file, checksum, checksum_size); - - /* Figure out what the final name should be */ - if (index_path(&filename, idx, ".idx") < 0) - goto on_error; - - /* Commit file */ - if (git_filebuf_commit_at(&index_file, filename.ptr) < 0) - goto on_error; - - if (git_mwindow_free_all(&idx->pack->mwf) < 0) - goto on_error; - -#if !defined(NO_MMAP) && defined(GIT_WIN32) - /* - * Some non-Windows remote filesystems fail when truncating files if the - * file permissions change after opening the file (done by p_mkstemp). - * - * Truncation is only needed when mmap is used to undo rounding up to next - * page_size in append_to_pack. - */ - if (p_ftruncate(idx->pack->mwf.fd, idx->pack->mwf.size) < 0) { - git_error_set(GIT_ERROR_OS, "failed to truncate pack file '%s'", idx->pack->pack_name); - return -1; - } -#endif - - if (idx->do_fsync && p_fsync(idx->pack->mwf.fd) < 0) { - git_error_set(GIT_ERROR_OS, "failed to fsync packfile"); - goto on_error; - } - - /* We need to close the descriptor here so Windows doesn't choke on commit_at */ - if (p_close(idx->pack->mwf.fd) < 0) { - git_error_set(GIT_ERROR_OS, "failed to close packfile"); - goto on_error; - } - - idx->pack->mwf.fd = -1; - - if (index_path(&filename, idx, ".pack") < 0) - goto on_error; - - /* And don't forget to rename the packfile to its new place. */ - if (p_rename(idx->pack->pack_name, git_str_cstr(&filename)) < 0) - goto on_error; - - /* And fsync the parent directory if we're asked to. */ - if (idx->do_fsync && - git_futils_fsync_parent(git_str_cstr(&filename)) < 0) - goto on_error; - - idx->pack_committed = 1; - - git_str_dispose(&filename); - return 0; - -on_error: - git_mwindow_free_all(&idx->pack->mwf); - git_filebuf_cleanup(&index_file); - git_str_dispose(&filename); - return -1; -} - -void git_indexer_free(git_indexer *idx) -{ - const git_oid *key; - git_oid *value; - size_t iter; - - if (idx == NULL) - return; - - if (idx->have_stream) - git_packfile_stream_dispose(&idx->stream); - - git_vector_free_deep(&idx->objects); - - if (idx->pack->idx_cache) { - struct git_pack_entry *pentry; - git_oidmap_foreach_value(idx->pack->idx_cache, pentry, { - git__free(pentry); - }); - - git_oidmap_free(idx->pack->idx_cache); - } - - git_vector_free_deep(&idx->deltas); - - git_packfile_free(idx->pack, !idx->pack_committed); - - iter = 0; - while (git_oidmap_iterate((void **) &value, idx->expected_oids, &iter, &key) == 0) - git__free(value); - - git_hash_ctx_cleanup(&idx->trailer); - git_hash_ctx_cleanup(&idx->hash_ctx); - git_str_dispose(&idx->entry_data); - git_oidmap_free(idx->expected_oids); - git__free(idx); -} diff --git a/vendor/libgit2/src/iterator.c b/vendor/libgit2/src/iterator.c deleted file mode 100644 index 15bb63dc..00000000 --- a/vendor/libgit2/src/iterator.c +++ /dev/null @@ -1,2439 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "iterator.h" - -#include "tree.h" -#include "index.h" -#include "path.h" - -#define GIT_ITERATOR_FIRST_ACCESS (1 << 15) -#define GIT_ITERATOR_HONOR_IGNORES (1 << 16) -#define GIT_ITERATOR_IGNORE_DOT_GIT (1 << 17) - -#define iterator__flag(I,F) ((((git_iterator *)(I))->flags & GIT_ITERATOR_ ## F) != 0) -#define iterator__ignore_case(I) iterator__flag(I,IGNORE_CASE) -#define iterator__include_trees(I) iterator__flag(I,INCLUDE_TREES) -#define iterator__dont_autoexpand(I) iterator__flag(I,DONT_AUTOEXPAND) -#define iterator__do_autoexpand(I) !iterator__flag(I,DONT_AUTOEXPAND) -#define iterator__include_conflicts(I) iterator__flag(I,INCLUDE_CONFLICTS) -#define iterator__has_been_accessed(I) iterator__flag(I,FIRST_ACCESS) -#define iterator__honor_ignores(I) iterator__flag(I,HONOR_IGNORES) -#define iterator__ignore_dot_git(I) iterator__flag(I,IGNORE_DOT_GIT) -#define iterator__descend_symlinks(I) iterator__flag(I,DESCEND_SYMLINKS) - - -static void iterator_set_ignore_case(git_iterator *iter, bool ignore_case) -{ - if (ignore_case) - iter->flags |= GIT_ITERATOR_IGNORE_CASE; - else - iter->flags &= ~GIT_ITERATOR_IGNORE_CASE; - - iter->strcomp = ignore_case ? git__strcasecmp : git__strcmp; - iter->strncomp = ignore_case ? git__strncasecmp : git__strncmp; - iter->prefixcomp = ignore_case ? git__prefixcmp_icase : git__prefixcmp; - iter->entry_srch = ignore_case ? git_index_entry_isrch : git_index_entry_srch; - - git_vector_set_cmp(&iter->pathlist, (git_vector_cmp)iter->strcomp); -} - -static int iterator_range_init( - git_iterator *iter, const char *start, const char *end) -{ - if (start && *start) { - iter->start = git__strdup(start); - GIT_ERROR_CHECK_ALLOC(iter->start); - - iter->start_len = strlen(iter->start); - } - - if (end && *end) { - iter->end = git__strdup(end); - GIT_ERROR_CHECK_ALLOC(iter->end); - - iter->end_len = strlen(iter->end); - } - - iter->started = (iter->start == NULL); - iter->ended = false; - - return 0; -} - -static void iterator_range_free(git_iterator *iter) -{ - if (iter->start) { - git__free(iter->start); - iter->start = NULL; - iter->start_len = 0; - } - - if (iter->end) { - git__free(iter->end); - iter->end = NULL; - iter->end_len = 0; - } -} - -static int iterator_reset_range( - git_iterator *iter, const char *start, const char *end) -{ - iterator_range_free(iter); - return iterator_range_init(iter, start, end); -} - -static int iterator_pathlist_init(git_iterator *iter, git_strarray *pathlist) -{ - size_t i; - - if (git_vector_init(&iter->pathlist, pathlist->count, NULL) < 0) - return -1; - - for (i = 0; i < pathlist->count; i++) { - if (!pathlist->strings[i]) - continue; - - if (git_vector_insert(&iter->pathlist, pathlist->strings[i]) < 0) - return -1; - } - - return 0; -} - -static int iterator_init_common( - git_iterator *iter, - git_repository *repo, - git_index *index, - git_iterator_options *given_opts) -{ - static git_iterator_options default_opts = GIT_ITERATOR_OPTIONS_INIT; - git_iterator_options *options = given_opts ? given_opts : &default_opts; - bool ignore_case; - int precompose; - int error; - - iter->repo = repo; - iter->index = index; - iter->flags = options->flags; - - if ((iter->flags & GIT_ITERATOR_IGNORE_CASE) != 0) { - ignore_case = true; - } else if ((iter->flags & GIT_ITERATOR_DONT_IGNORE_CASE) != 0) { - ignore_case = false; - } else if (repo) { - git_index *index; - - if ((error = git_repository_index__weakptr(&index, iter->repo)) < 0) - return error; - - ignore_case = !!index->ignore_case; - - if (ignore_case == 1) - iter->flags |= GIT_ITERATOR_IGNORE_CASE; - else - iter->flags |= GIT_ITERATOR_DONT_IGNORE_CASE; - } else { - ignore_case = false; - } - - /* try to look up precompose and set flag if appropriate */ - if (repo && - (iter->flags & GIT_ITERATOR_PRECOMPOSE_UNICODE) == 0 && - (iter->flags & GIT_ITERATOR_DONT_PRECOMPOSE_UNICODE) == 0) { - - if (git_repository__configmap_lookup(&precompose, repo, GIT_CONFIGMAP_PRECOMPOSE) < 0) - git_error_clear(); - else if (precompose) - iter->flags |= GIT_ITERATOR_PRECOMPOSE_UNICODE; - } - - if ((iter->flags & GIT_ITERATOR_DONT_AUTOEXPAND)) - iter->flags |= GIT_ITERATOR_INCLUDE_TREES; - - if ((error = iterator_range_init(iter, options->start, options->end)) < 0 || - (error = iterator_pathlist_init(iter, &options->pathlist)) < 0) - return error; - - iterator_set_ignore_case(iter, ignore_case); - return 0; -} - -static void iterator_clear(git_iterator *iter) -{ - iter->started = false; - iter->ended = false; - iter->stat_calls = 0; - iter->pathlist_walk_idx = 0; - iter->flags &= ~GIT_ITERATOR_FIRST_ACCESS; -} - -GIT_INLINE(bool) iterator_has_started( - git_iterator *iter, const char *path, bool is_submodule) -{ - size_t path_len; - - if (iter->start == NULL || iter->started == true) - return true; - - /* the starting path is generally a prefix - we have started once we - * are prefixed by this path - */ - iter->started = (iter->prefixcomp(path, iter->start) >= 0); - - if (iter->started) - return true; - - path_len = strlen(path); - - /* if, however, we are a submodule, then we support `start` being - * suffixed with a `/` for crazy legacy reasons. match `submod` - * with a start path of `submod/`. - */ - if (is_submodule && iter->start_len && path_len == iter->start_len - 1 && - iter->start[iter->start_len-1] == '/') - return true; - - /* if, however, our current path is a directory, and our starting path - * is _beneath_ that directory, then recurse into the directory (even - * though we have not yet "started") - */ - if (path_len > 0 && path[path_len-1] == '/' && - iter->strncomp(path, iter->start, path_len) == 0) - return true; - - return false; -} - -GIT_INLINE(bool) iterator_has_ended(git_iterator *iter, const char *path) -{ - if (iter->end == NULL) - return false; - else if (iter->ended) - return true; - - iter->ended = (iter->prefixcomp(path, iter->end) > 0); - return iter->ended; -} - -/* walker for the index and tree iterator that allows it to walk the sorted - * pathlist entries alongside sorted iterator entries. - */ -static bool iterator_pathlist_next_is(git_iterator *iter, const char *path) -{ - char *p; - size_t path_len, p_len, cmp_len, i; - int cmp; - - if (iter->pathlist.length == 0) - return true; - - git_vector_sort(&iter->pathlist); - - path_len = strlen(path); - - /* for comparison, drop the trailing slash on the current '/' */ - if (path_len && path[path_len-1] == '/') - path_len--; - - for (i = iter->pathlist_walk_idx; i < iter->pathlist.length; i++) { - p = iter->pathlist.contents[i]; - p_len = strlen(p); - - if (p_len && p[p_len-1] == '/') - p_len--; - - cmp_len = min(path_len, p_len); - - /* see if the pathlist entry is a prefix of this path */ - cmp = iter->strncomp(p, path, cmp_len); - - /* prefix match - see if there's an exact match, or if we were - * given a path that matches the directory - */ - if (cmp == 0) { - /* if this pathlist entry is not suffixed with a '/' then - * it matches a path that is a file or a directory. - * (eg, pathlist = "foo" and path is "foo" or "foo/" or - * "foo/something") - */ - if (p[cmp_len] == '\0' && - (path[cmp_len] == '\0' || path[cmp_len] == '/')) - return true; - - /* if this pathlist entry _is_ suffixed with a '/' then - * it matches only paths that are directories. - * (eg, pathlist = "foo/" and path is "foo/" or "foo/something") - */ - if (p[cmp_len] == '/' && path[cmp_len] == '/') - return true; - } - - /* this pathlist entry sorts before the given path, try the next */ - else if (cmp < 0) { - iter->pathlist_walk_idx++; - continue; - } - - /* this pathlist sorts after the given path, no match. */ - else if (cmp > 0) { - break; - } - } - - return false; -} - -typedef enum { - ITERATOR_PATHLIST_NONE = 0, - ITERATOR_PATHLIST_IS_FILE = 1, - ITERATOR_PATHLIST_IS_DIR = 2, - ITERATOR_PATHLIST_IS_PARENT = 3, - ITERATOR_PATHLIST_FULL = 4 -} iterator_pathlist_search_t; - -static iterator_pathlist_search_t iterator_pathlist_search( - git_iterator *iter, const char *path, size_t path_len) -{ - const char *p; - size_t idx; - int error; - - if (iter->pathlist.length == 0) - return ITERATOR_PATHLIST_FULL; - - git_vector_sort(&iter->pathlist); - - error = git_vector_bsearch2(&idx, &iter->pathlist, - (git_vector_cmp)iter->strcomp, path); - - /* the given path was found in the pathlist. since the pathlist only - * matches directories when they're suffixed with a '/', analyze the - * path string to determine whether it's a directory or not. - */ - if (error == 0) { - if (path_len && path[path_len-1] == '/') - return ITERATOR_PATHLIST_IS_DIR; - - return ITERATOR_PATHLIST_IS_FILE; - } - - /* at this point, the path we're examining may be a directory (though we - * don't know that yet, since we're avoiding a stat unless it's necessary) - * so walk the pathlist looking for the given path with a '/' after it, - */ - while ((p = git_vector_get(&iter->pathlist, idx)) != NULL) { - if (iter->prefixcomp(p, path) != 0) - break; - - /* an exact match would have been matched by the bsearch above */ - GIT_ASSERT_WITH_RETVAL(p[path_len], ITERATOR_PATHLIST_NONE); - - /* is this a literal directory entry (eg `foo/`) or a file beneath */ - if (p[path_len] == '/') { - return (p[path_len+1] == '\0') ? - ITERATOR_PATHLIST_IS_DIR : - ITERATOR_PATHLIST_IS_PARENT; - } - - if (p[path_len] > '/') - break; - - idx++; - } - - return ITERATOR_PATHLIST_NONE; -} - -/* Empty iterator */ - -static int empty_iterator_noop(const git_index_entry **e, git_iterator *i) -{ - GIT_UNUSED(i); - - if (e) - *e = NULL; - - return GIT_ITEROVER; -} - -static int empty_iterator_advance_over( - const git_index_entry **e, - git_iterator_status_t *s, - git_iterator *i) -{ - *s = GIT_ITERATOR_STATUS_EMPTY; - return empty_iterator_noop(e, i); -} - -static int empty_iterator_reset(git_iterator *i) -{ - GIT_UNUSED(i); - return 0; -} - -static void empty_iterator_free(git_iterator *i) -{ - GIT_UNUSED(i); -} - -typedef struct { - git_iterator base; - git_iterator_callbacks cb; -} empty_iterator; - -int git_iterator_for_nothing( - git_iterator **out, - git_iterator_options *options) -{ - empty_iterator *iter; - - static git_iterator_callbacks callbacks = { - empty_iterator_noop, - empty_iterator_noop, - empty_iterator_noop, - empty_iterator_advance_over, - empty_iterator_reset, - empty_iterator_free - }; - - *out = NULL; - - iter = git__calloc(1, sizeof(empty_iterator)); - GIT_ERROR_CHECK_ALLOC(iter); - - iter->base.type = GIT_ITERATOR_EMPTY; - iter->base.cb = &callbacks; - iter->base.flags = options->flags; - - *out = &iter->base; - return 0; -} - -/* Tree iterator */ - -typedef struct { - git_tree_entry *tree_entry; - const char *parent_path; -} tree_iterator_entry; - -typedef struct { - git_tree *tree; - - /* path to this particular frame (folder) */ - git_str path; - - /* a sorted list of the entries for this frame (folder), these are - * actually pointers to the iterator's entry pool. - */ - git_vector entries; - tree_iterator_entry *current; - - size_t next_idx; - - /* on case insensitive iterations, we also have an array of other - * paths that were case insensitively equal to this one, and their - * tree objects. we have coalesced the tree entries into this frame. - * a child `tree_iterator_entry` will contain a pointer to its actual - * parent path. - */ - git_vector similar_trees; - git_array_t(git_str) similar_paths; -} tree_iterator_frame; - -typedef struct { - git_iterator base; - git_tree *root; - git_array_t(tree_iterator_frame) frames; - - git_index_entry entry; - git_str entry_path; - - /* a pool of entries to reduce the number of allocations */ - git_pool entry_pool; -} tree_iterator; - -GIT_INLINE(tree_iterator_frame *) tree_iterator_parent_frame( - tree_iterator *iter) -{ - return iter->frames.size > 1 ? - &iter->frames.ptr[iter->frames.size-2] : NULL; -} - -GIT_INLINE(tree_iterator_frame *) tree_iterator_current_frame( - tree_iterator *iter) -{ - return iter->frames.size ? &iter->frames.ptr[iter->frames.size-1] : NULL; -} - -GIT_INLINE(int) tree_entry_cmp( - const git_tree_entry *a, const git_tree_entry *b, bool icase) -{ - return git_fs_path_cmp( - a->filename, a->filename_len, a->attr == GIT_FILEMODE_TREE, - b->filename, b->filename_len, b->attr == GIT_FILEMODE_TREE, - icase ? git__strncasecmp : git__strncmp); -} - -GIT_INLINE(int) tree_iterator_entry_cmp_icase( - const void *ptr_a, const void *ptr_b) -{ - const tree_iterator_entry *a = (const tree_iterator_entry *)ptr_a; - const tree_iterator_entry *b = (const tree_iterator_entry *)ptr_b; - - return tree_entry_cmp(a->tree_entry, b->tree_entry, true); -} - -static int tree_iterator_entry_sort_icase(const void *ptr_a, const void *ptr_b) -{ - const tree_iterator_entry *a = (const tree_iterator_entry *)ptr_a; - const tree_iterator_entry *b = (const tree_iterator_entry *)ptr_b; - - int c = tree_entry_cmp(a->tree_entry, b->tree_entry, true); - - /* stabilize the sort order for filenames that are (case insensitively) - * the same by examining the parent path (case sensitively) before - * falling back to a case sensitive sort of the filename. - */ - if (!c && a->parent_path != b->parent_path) - c = git__strcmp(a->parent_path, b->parent_path); - - if (!c) - c = tree_entry_cmp(a->tree_entry, b->tree_entry, false); - - return c; -} - -static int tree_iterator_compute_path( - git_str *out, - tree_iterator_entry *entry) -{ - git_str_clear(out); - - if (entry->parent_path) - git_str_joinpath(out, entry->parent_path, entry->tree_entry->filename); - else - git_str_puts(out, entry->tree_entry->filename); - - if (git_tree_entry__is_tree(entry->tree_entry)) - git_str_putc(out, '/'); - - if (git_str_oom(out)) - return -1; - - return 0; -} - -static int tree_iterator_frame_init( - tree_iterator *iter, - git_tree *tree, - tree_iterator_entry *frame_entry) -{ - tree_iterator_frame *new_frame = NULL; - tree_iterator_entry *new_entry; - git_tree *dup = NULL; - git_tree_entry *tree_entry; - git_vector_cmp cmp; - size_t i; - int error = 0; - - new_frame = git_array_alloc(iter->frames); - GIT_ERROR_CHECK_ALLOC(new_frame); - - if ((error = git_tree_dup(&dup, tree)) < 0) - goto done; - - memset(new_frame, 0x0, sizeof(tree_iterator_frame)); - new_frame->tree = dup; - - if (frame_entry && - (error = tree_iterator_compute_path(&new_frame->path, frame_entry)) < 0) - goto done; - - cmp = iterator__ignore_case(&iter->base) ? - tree_iterator_entry_sort_icase : NULL; - - if ((error = git_vector_init(&new_frame->entries, - dup->entries.size, cmp)) < 0) - goto done; - - git_array_foreach(dup->entries, i, tree_entry) { - if ((new_entry = git_pool_malloc(&iter->entry_pool, 1)) == NULL) { - git_error_set_oom(); - error = -1; - goto done; - } - - new_entry->tree_entry = tree_entry; - new_entry->parent_path = new_frame->path.ptr; - - if ((error = git_vector_insert(&new_frame->entries, new_entry)) < 0) - goto done; - } - - git_vector_set_sorted(&new_frame->entries, - !iterator__ignore_case(&iter->base)); - -done: - if (error < 0) { - git_tree_free(dup); - git_array_pop(iter->frames); - } - - return error; -} - -GIT_INLINE(tree_iterator_entry *) tree_iterator_current_entry( - tree_iterator_frame *frame) -{ - return frame->current; -} - -GIT_INLINE(int) tree_iterator_frame_push_neighbors( - tree_iterator *iter, - tree_iterator_frame *parent_frame, - tree_iterator_frame *frame, - const char *filename) -{ - tree_iterator_entry *entry, *new_entry; - git_tree *tree = NULL; - git_tree_entry *tree_entry; - git_str *path; - size_t new_size, i; - int error = 0; - - while (parent_frame->next_idx < parent_frame->entries.length) { - entry = parent_frame->entries.contents[parent_frame->next_idx]; - - if (strcasecmp(filename, entry->tree_entry->filename) != 0) - break; - - if ((error = git_tree_lookup(&tree, - iter->base.repo, entry->tree_entry->oid)) < 0) - break; - - if (git_vector_insert(&parent_frame->similar_trees, tree) < 0) - break; - - path = git_array_alloc(parent_frame->similar_paths); - GIT_ERROR_CHECK_ALLOC(path); - - memset(path, 0, sizeof(git_str)); - - if ((error = tree_iterator_compute_path(path, entry)) < 0) - break; - - GIT_ERROR_CHECK_ALLOC_ADD(&new_size, - frame->entries.length, tree->entries.size); - git_vector_size_hint(&frame->entries, new_size); - - git_array_foreach(tree->entries, i, tree_entry) { - new_entry = git_pool_malloc(&iter->entry_pool, 1); - GIT_ERROR_CHECK_ALLOC(new_entry); - - new_entry->tree_entry = tree_entry; - new_entry->parent_path = path->ptr; - - if ((error = git_vector_insert(&frame->entries, new_entry)) < 0) - break; - } - - if (error) - break; - - parent_frame->next_idx++; - } - - return error; -} - -GIT_INLINE(int) tree_iterator_frame_push( - tree_iterator *iter, tree_iterator_entry *entry) -{ - tree_iterator_frame *parent_frame, *frame; - git_tree *tree = NULL; - int error; - - if ((error = git_tree_lookup(&tree, - iter->base.repo, entry->tree_entry->oid)) < 0 || - (error = tree_iterator_frame_init(iter, tree, entry)) < 0) - goto done; - - parent_frame = tree_iterator_parent_frame(iter); - frame = tree_iterator_current_frame(iter); - - /* if we're case insensitive, then we may have another directory that - * is (case insensitively) equal to this one. coalesce those children - * into this tree. - */ - if (iterator__ignore_case(&iter->base)) - error = tree_iterator_frame_push_neighbors(iter, - parent_frame, frame, entry->tree_entry->filename); - -done: - git_tree_free(tree); - return error; -} - -static int tree_iterator_frame_pop(tree_iterator *iter) -{ - tree_iterator_frame *frame; - git_str *buf = NULL; - git_tree *tree; - size_t i; - - GIT_ASSERT(iter->frames.size); - - frame = git_array_pop(iter->frames); - - git_vector_free(&frame->entries); - git_tree_free(frame->tree); - - do { - buf = git_array_pop(frame->similar_paths); - git_str_dispose(buf); - } while (buf != NULL); - - git_array_clear(frame->similar_paths); - - git_vector_foreach(&frame->similar_trees, i, tree) - git_tree_free(tree); - - git_vector_free(&frame->similar_trees); - - git_str_dispose(&frame->path); - - return 0; -} - -static int tree_iterator_current( - const git_index_entry **out, git_iterator *i) -{ - tree_iterator *iter = (tree_iterator *)i; - - if (!iterator__has_been_accessed(i)) - return iter->base.cb->advance(out, i); - - if (!iter->frames.size) { - *out = NULL; - return GIT_ITEROVER; - } - - *out = &iter->entry; - return 0; -} - -static void tree_iterator_set_current( - tree_iterator *iter, - tree_iterator_frame *frame, - tree_iterator_entry *entry) -{ - git_tree_entry *tree_entry = entry->tree_entry; - - frame->current = entry; - - memset(&iter->entry, 0x0, sizeof(git_index_entry)); - - iter->entry.mode = tree_entry->attr; - iter->entry.path = iter->entry_path.ptr; - git_oid_cpy(&iter->entry.id, tree_entry->oid); -} - -static int tree_iterator_advance(const git_index_entry **out, git_iterator *i) -{ - tree_iterator *iter = (tree_iterator *)i; - int error = 0; - - iter->base.flags |= GIT_ITERATOR_FIRST_ACCESS; - - /* examine tree entries until we find the next one to return */ - while (true) { - tree_iterator_entry *prev_entry, *entry; - tree_iterator_frame *frame; - bool is_tree; - - if ((frame = tree_iterator_current_frame(iter)) == NULL) { - error = GIT_ITEROVER; - break; - } - - /* no more entries in this frame. pop the frame out */ - if (frame->next_idx == frame->entries.length) { - if ((error = tree_iterator_frame_pop(iter)) < 0) - break; - - continue; - } - - /* we may have coalesced the contents of case-insensitively same-named - * directories, so do the sort now. - */ - if (frame->next_idx == 0 && !git_vector_is_sorted(&frame->entries)) - git_vector_sort(&frame->entries); - - /* we have more entries in the current frame, that's our next entry */ - prev_entry = tree_iterator_current_entry(frame); - entry = frame->entries.contents[frame->next_idx]; - frame->next_idx++; - - /* we can have collisions when iterating case insensitively. (eg, - * 'A/a' and 'a/A'). squash this one if it's already been seen. - */ - if (iterator__ignore_case(&iter->base) && - prev_entry && - tree_iterator_entry_cmp_icase(prev_entry, entry) == 0) - continue; - - if ((error = tree_iterator_compute_path(&iter->entry_path, entry)) < 0) - break; - - /* if this path is before our start, advance over this entry */ - if (!iterator_has_started(&iter->base, iter->entry_path.ptr, false)) - continue; - - /* if this path is after our end, stop */ - if (iterator_has_ended(&iter->base, iter->entry_path.ptr)) { - error = GIT_ITEROVER; - break; - } - - /* if we have a list of paths we're interested in, examine it */ - if (!iterator_pathlist_next_is(&iter->base, iter->entry_path.ptr)) - continue; - - is_tree = git_tree_entry__is_tree(entry->tree_entry); - - /* if we are *not* including trees then advance over this entry */ - if (is_tree && !iterator__include_trees(iter)) { - - /* if we've found a tree (and are not returning it to the caller) - * and we are autoexpanding, then we want to return the first - * child. push the new directory and advance. - */ - if (iterator__do_autoexpand(iter)) { - if ((error = tree_iterator_frame_push(iter, entry)) < 0) - break; - } - - continue; - } - - tree_iterator_set_current(iter, frame, entry); - - /* if we are autoexpanding, then push this as a new frame, so that - * the next call to `advance` will dive into this directory. - */ - if (is_tree && iterator__do_autoexpand(iter)) - error = tree_iterator_frame_push(iter, entry); - - break; - } - - if (out) - *out = (error == 0) ? &iter->entry : NULL; - - return error; -} - -static int tree_iterator_advance_into( - const git_index_entry **out, git_iterator *i) -{ - tree_iterator *iter = (tree_iterator *)i; - tree_iterator_frame *frame; - tree_iterator_entry *prev_entry; - int error; - - if (out) - *out = NULL; - - if ((frame = tree_iterator_current_frame(iter)) == NULL) - return GIT_ITEROVER; - - /* get the last seen entry */ - prev_entry = tree_iterator_current_entry(frame); - - /* it's legal to call advance_into when auto-expand is on. in this case, - * we will have pushed a new (empty) frame on to the stack for this - * new directory. since it's empty, its current_entry should be null. - */ - GIT_ASSERT(iterator__do_autoexpand(i) ^ (prev_entry != NULL)); - - if (prev_entry) { - if (!git_tree_entry__is_tree(prev_entry->tree_entry)) - return 0; - - if ((error = tree_iterator_frame_push(iter, prev_entry)) < 0) - return error; - } - - /* we've advanced into the directory in question, let advance - * find the first entry - */ - return tree_iterator_advance(out, i); -} - -static int tree_iterator_advance_over( - const git_index_entry **out, - git_iterator_status_t *status, - git_iterator *i) -{ - *status = GIT_ITERATOR_STATUS_NORMAL; - return git_iterator_advance(out, i); -} - -static void tree_iterator_clear(tree_iterator *iter) -{ - while (iter->frames.size) - tree_iterator_frame_pop(iter); - - git_array_clear(iter->frames); - - git_pool_clear(&iter->entry_pool); - git_str_clear(&iter->entry_path); - - iterator_clear(&iter->base); -} - -static int tree_iterator_init(tree_iterator *iter) -{ - int error; - - if ((error = git_pool_init(&iter->entry_pool, sizeof(tree_iterator_entry))) < 0 || - (error = tree_iterator_frame_init(iter, iter->root, NULL)) < 0) - return error; - - iter->base.flags &= ~GIT_ITERATOR_FIRST_ACCESS; - - return 0; -} - -static int tree_iterator_reset(git_iterator *i) -{ - tree_iterator *iter = (tree_iterator *)i; - - tree_iterator_clear(iter); - return tree_iterator_init(iter); -} - -static void tree_iterator_free(git_iterator *i) -{ - tree_iterator *iter = (tree_iterator *)i; - - tree_iterator_clear(iter); - - git_tree_free(iter->root); - git_str_dispose(&iter->entry_path); -} - -int git_iterator_for_tree( - git_iterator **out, - git_tree *tree, - git_iterator_options *options) -{ - tree_iterator *iter; - int error; - - static git_iterator_callbacks callbacks = { - tree_iterator_current, - tree_iterator_advance, - tree_iterator_advance_into, - tree_iterator_advance_over, - tree_iterator_reset, - tree_iterator_free - }; - - *out = NULL; - - if (tree == NULL) - return git_iterator_for_nothing(out, options); - - iter = git__calloc(1, sizeof(tree_iterator)); - GIT_ERROR_CHECK_ALLOC(iter); - - iter->base.type = GIT_ITERATOR_TREE; - iter->base.cb = &callbacks; - - if ((error = iterator_init_common(&iter->base, - git_tree_owner(tree), NULL, options)) < 0 || - (error = git_tree_dup(&iter->root, tree)) < 0 || - (error = tree_iterator_init(iter)) < 0) - goto on_error; - - *out = &iter->base; - return 0; - -on_error: - git_iterator_free(&iter->base); - return error; -} - -int git_iterator_current_tree_entry( - const git_tree_entry **tree_entry, git_iterator *i) -{ - tree_iterator *iter; - tree_iterator_frame *frame; - tree_iterator_entry *entry; - - GIT_ASSERT(i->type == GIT_ITERATOR_TREE); - - iter = (tree_iterator *)i; - - frame = tree_iterator_current_frame(iter); - entry = tree_iterator_current_entry(frame); - - *tree_entry = entry->tree_entry; - return 0; -} - -int git_iterator_current_parent_tree( - const git_tree **parent_tree, git_iterator *i, size_t depth) -{ - tree_iterator *iter; - tree_iterator_frame *frame; - - GIT_ASSERT(i->type == GIT_ITERATOR_TREE); - - iter = (tree_iterator *)i; - - GIT_ASSERT(depth < iter->frames.size); - frame = &iter->frames.ptr[iter->frames.size-depth-1]; - - *parent_tree = frame->tree; - return 0; -} - -/* Filesystem iterator */ - -typedef struct { - struct stat st; - size_t path_len; - iterator_pathlist_search_t match; - git_oid id; - char path[GIT_FLEX_ARRAY]; -} filesystem_iterator_entry; - -typedef struct { - git_vector entries; - git_pool entry_pool; - size_t next_idx; - - size_t path_len; - int is_ignored; -} filesystem_iterator_frame; - -typedef struct { - git_iterator base; - char *root; - size_t root_len; - - unsigned int dirload_flags; - - git_tree *tree; - git_index *index; - git_vector index_snapshot; - - git_array_t(filesystem_iterator_frame) frames; - git_ignores ignores; - - /* info about the current entry */ - git_index_entry entry; - git_str current_path; - int current_is_ignored; - - /* temporary buffer for advance_over */ - git_str tmp_buf; -} filesystem_iterator; - - -GIT_INLINE(filesystem_iterator_frame *) filesystem_iterator_parent_frame( - filesystem_iterator *iter) -{ - return iter->frames.size > 1 ? - &iter->frames.ptr[iter->frames.size-2] : NULL; -} - -GIT_INLINE(filesystem_iterator_frame *) filesystem_iterator_current_frame( - filesystem_iterator *iter) -{ - return iter->frames.size ? &iter->frames.ptr[iter->frames.size-1] : NULL; -} - -GIT_INLINE(filesystem_iterator_entry *) filesystem_iterator_current_entry( - filesystem_iterator_frame *frame) -{ - return frame->next_idx == 0 ? - NULL : frame->entries.contents[frame->next_idx-1]; -} - -static int filesystem_iterator_entry_cmp(const void *_a, const void *_b) -{ - const filesystem_iterator_entry *a = (const filesystem_iterator_entry *)_a; - const filesystem_iterator_entry *b = (const filesystem_iterator_entry *)_b; - - return git__strcmp(a->path, b->path); -} - -static int filesystem_iterator_entry_cmp_icase(const void *_a, const void *_b) -{ - const filesystem_iterator_entry *a = (const filesystem_iterator_entry *)_a; - const filesystem_iterator_entry *b = (const filesystem_iterator_entry *)_b; - - return git__strcasecmp(a->path, b->path); -} - -#define FILESYSTEM_MAX_DEPTH 100 - -/** - * Figure out if an entry is a submodule. - * - * We consider it a submodule if the path is listed as a submodule in - * either the tree or the index. - */ -static int filesystem_iterator_is_submodule( - bool *out, filesystem_iterator *iter, const char *path, size_t path_len) -{ - bool is_submodule = false; - int error; - - *out = false; - - /* first see if this path is a submodule in HEAD */ - if (iter->tree) { - git_tree_entry *entry; - - error = git_tree_entry_bypath(&entry, iter->tree, path); - - if (error < 0 && error != GIT_ENOTFOUND) - return error; - - if (!error) { - is_submodule = (entry->attr == GIT_FILEMODE_COMMIT); - git_tree_entry_free(entry); - } - } - - if (!is_submodule && iter->base.index) { - size_t pos; - - error = git_index_snapshot_find(&pos, - &iter->index_snapshot, iter->base.entry_srch, path, path_len, 0); - - if (error < 0 && error != GIT_ENOTFOUND) - return error; - - if (!error) { - git_index_entry *e = git_vector_get(&iter->index_snapshot, pos); - is_submodule = (e->mode == GIT_FILEMODE_COMMIT); - } - } - - *out = is_submodule; - return 0; -} - -static void filesystem_iterator_frame_push_ignores( - filesystem_iterator *iter, - filesystem_iterator_entry *frame_entry, - filesystem_iterator_frame *new_frame) -{ - filesystem_iterator_frame *previous_frame; - const char *path = frame_entry ? frame_entry->path : ""; - - if (!iterator__honor_ignores(&iter->base)) - return; - - if (git_ignore__lookup(&new_frame->is_ignored, - &iter->ignores, path, GIT_DIR_FLAG_TRUE) < 0) { - git_error_clear(); - new_frame->is_ignored = GIT_IGNORE_NOTFOUND; - } - - /* if this is not the top level directory... */ - if (frame_entry) { - const char *relative_path; - - previous_frame = filesystem_iterator_parent_frame(iter); - - /* push new ignores for files in this directory */ - relative_path = frame_entry->path + previous_frame->path_len; - - /* inherit ignored from parent if no rule specified */ - if (new_frame->is_ignored <= GIT_IGNORE_NOTFOUND) - new_frame->is_ignored = previous_frame->is_ignored; - - git_ignore__push_dir(&iter->ignores, relative_path); - } -} - -static void filesystem_iterator_frame_pop_ignores( - filesystem_iterator *iter) -{ - if (iterator__honor_ignores(&iter->base)) - git_ignore__pop_dir(&iter->ignores); -} - -GIT_INLINE(bool) filesystem_iterator_examine_path( - bool *is_dir_out, - iterator_pathlist_search_t *match_out, - filesystem_iterator *iter, - filesystem_iterator_entry *frame_entry, - const char *path, - size_t path_len) -{ - bool is_dir = 0; - iterator_pathlist_search_t match = ITERATOR_PATHLIST_FULL; - - *is_dir_out = false; - *match_out = ITERATOR_PATHLIST_NONE; - - if (iter->base.start_len) { - int cmp = iter->base.strncomp(path, iter->base.start, path_len); - - /* we haven't stat'ed `path` yet, so we don't yet know if it's a - * directory or not. special case if the current path may be a - * directory that matches the start prefix. - */ - if (cmp == 0) { - if (iter->base.start[path_len] == '/') - is_dir = true; - - else if (iter->base.start[path_len] != '\0') - cmp = -1; - } - - if (cmp < 0) - return false; - } - - if (iter->base.end_len) { - int cmp = iter->base.strncomp(path, iter->base.end, iter->base.end_len); - - if (cmp > 0) - return false; - } - - /* if we have a pathlist that we're limiting to, examine this path now - * to avoid a `stat` if we're not interested in the path. - */ - if (iter->base.pathlist.length) { - /* if our parent was explicitly included, so too are we */ - if (frame_entry && frame_entry->match != ITERATOR_PATHLIST_IS_PARENT) - match = ITERATOR_PATHLIST_FULL; - else - match = iterator_pathlist_search(&iter->base, path, path_len); - - if (match == ITERATOR_PATHLIST_NONE) - return false; - - /* Ensure that the pathlist entry lines up with what we expected */ - if (match == ITERATOR_PATHLIST_IS_DIR || - match == ITERATOR_PATHLIST_IS_PARENT) - is_dir = true; - } - - *is_dir_out = is_dir; - *match_out = match; - return true; -} - -GIT_INLINE(bool) filesystem_iterator_is_dot_git( - filesystem_iterator *iter, const char *path, size_t path_len) -{ - size_t len; - - if (!iterator__ignore_dot_git(&iter->base)) - return false; - - if ((len = path_len) < 4) - return false; - - if (path[len - 1] == '/') - len--; - - if (git__tolower(path[len - 1]) != 't' || - git__tolower(path[len - 2]) != 'i' || - git__tolower(path[len - 3]) != 'g' || - git__tolower(path[len - 4]) != '.') - return false; - - return (len == 4 || path[len - 5] == '/'); -} - -static int filesystem_iterator_entry_hash( - filesystem_iterator *iter, - filesystem_iterator_entry *entry) -{ - git_str fullpath = GIT_STR_INIT; - int error; - - if (S_ISDIR(entry->st.st_mode)) { - memset(&entry->id, 0, GIT_OID_RAWSZ); - return 0; - } - - if (iter->base.type == GIT_ITERATOR_WORKDIR) - return git_repository_hashfile(&entry->id, - iter->base.repo, entry->path, GIT_OBJECT_BLOB, NULL); - - if (!(error = git_str_joinpath(&fullpath, iter->root, entry->path)) && - !(error = git_path_validate_str_length(iter->base.repo, &fullpath))) - error = git_odb_hashfile(&entry->id, fullpath.ptr, GIT_OBJECT_BLOB); - - git_str_dispose(&fullpath); - return error; -} - -static int filesystem_iterator_entry_init( - filesystem_iterator_entry **out, - filesystem_iterator *iter, - filesystem_iterator_frame *frame, - const char *path, - size_t path_len, - struct stat *statbuf, - iterator_pathlist_search_t pathlist_match) -{ - filesystem_iterator_entry *entry; - size_t entry_size; - int error = 0; - - *out = NULL; - - /* Make sure to append two bytes, one for the path's null - * termination, one for a possible trailing '/' for folders. - */ - GIT_ERROR_CHECK_ALLOC_ADD(&entry_size, - sizeof(filesystem_iterator_entry), path_len); - GIT_ERROR_CHECK_ALLOC_ADD(&entry_size, entry_size, 2); - - entry = git_pool_malloc(&frame->entry_pool, entry_size); - GIT_ERROR_CHECK_ALLOC(entry); - - entry->path_len = path_len; - entry->match = pathlist_match; - memcpy(entry->path, path, path_len); - memcpy(&entry->st, statbuf, sizeof(struct stat)); - - /* Suffix directory paths with a '/' */ - if (S_ISDIR(entry->st.st_mode)) - entry->path[entry->path_len++] = '/'; - - entry->path[entry->path_len] = '\0'; - - if (iter->base.flags & GIT_ITERATOR_INCLUDE_HASH) - error = filesystem_iterator_entry_hash(iter, entry); - - if (!error) - *out = entry; - - return error; -} - -static int filesystem_iterator_frame_push( - filesystem_iterator *iter, - filesystem_iterator_entry *frame_entry) -{ - filesystem_iterator_frame *new_frame = NULL; - git_fs_path_diriter diriter = GIT_FS_PATH_DIRITER_INIT; - git_str root = GIT_STR_INIT; - const char *path; - filesystem_iterator_entry *entry; - struct stat statbuf; - size_t path_len; - int error; - - if (iter->frames.size == FILESYSTEM_MAX_DEPTH) { - git_error_set(GIT_ERROR_REPOSITORY, - "directory nesting too deep (%"PRIuZ")", iter->frames.size); - return -1; - } - - new_frame = git_array_alloc(iter->frames); - GIT_ERROR_CHECK_ALLOC(new_frame); - - memset(new_frame, 0, sizeof(filesystem_iterator_frame)); - - if (frame_entry) - git_str_joinpath(&root, iter->root, frame_entry->path); - else - git_str_puts(&root, iter->root); - - if (git_str_oom(&root) || - git_path_validate_str_length(iter->base.repo, &root) < 0) { - error = -1; - goto done; - } - - new_frame->path_len = frame_entry ? frame_entry->path_len : 0; - - /* Any error here is equivalent to the dir not existing, skip over it */ - if ((error = git_fs_path_diriter_init( - &diriter, root.ptr, iter->dirload_flags)) < 0) { - error = GIT_ENOTFOUND; - goto done; - } - - if ((error = git_vector_init(&new_frame->entries, 64, - iterator__ignore_case(&iter->base) ? - filesystem_iterator_entry_cmp_icase : - filesystem_iterator_entry_cmp)) < 0) - goto done; - - if ((error = git_pool_init(&new_frame->entry_pool, 1)) < 0) - goto done; - - /* check if this directory is ignored */ - filesystem_iterator_frame_push_ignores(iter, frame_entry, new_frame); - - while ((error = git_fs_path_diriter_next(&diriter)) == 0) { - iterator_pathlist_search_t pathlist_match = ITERATOR_PATHLIST_FULL; - git_str path_str = GIT_STR_INIT; - bool dir_expected = false; - - if ((error = git_fs_path_diriter_fullpath(&path, &path_len, &diriter)) < 0) - goto done; - - path_str.ptr = (char *)path; - path_str.size = path_len; - - if ((error = git_path_validate_str_length(iter->base.repo, &path_str)) < 0) - goto done; - - GIT_ASSERT(path_len > iter->root_len); - - /* remove the prefix if requested */ - path += iter->root_len; - path_len -= iter->root_len; - - /* examine start / end and the pathlist to see if this path is in it. - * note that since we haven't yet stat'ed the path, we cannot know - * whether it's a directory yet or not, so this can give us an - * expected type (S_IFDIR or S_IFREG) that we should examine) - */ - if (!filesystem_iterator_examine_path(&dir_expected, &pathlist_match, - iter, frame_entry, path, path_len)) - continue; - - /* TODO: don't need to stat if assume unchanged for this path and - * we have an index, we can just copy the data out of it. - */ - - if ((error = git_fs_path_diriter_stat(&statbuf, &diriter)) < 0) { - /* file was removed between readdir and lstat */ - if (error == GIT_ENOTFOUND) - continue; - - /* treat the file as unreadable */ - memset(&statbuf, 0, sizeof(statbuf)); - statbuf.st_mode = GIT_FILEMODE_UNREADABLE; - - error = 0; - } - - iter->base.stat_calls++; - - /* Ignore wacky things in the filesystem */ - if (!S_ISDIR(statbuf.st_mode) && - !S_ISREG(statbuf.st_mode) && - !S_ISLNK(statbuf.st_mode) && - statbuf.st_mode != GIT_FILEMODE_UNREADABLE) - continue; - - if (filesystem_iterator_is_dot_git(iter, path, path_len)) - continue; - - /* convert submodules to GITLINK and remove trailing slashes */ - if (S_ISDIR(statbuf.st_mode)) { - bool submodule = false; - - if ((error = filesystem_iterator_is_submodule(&submodule, - iter, path, path_len)) < 0) - goto done; - - if (submodule) - statbuf.st_mode = GIT_FILEMODE_COMMIT; - } - - /* Ensure that the pathlist entry lines up with what we expected */ - else if (dir_expected) - continue; - - if ((error = filesystem_iterator_entry_init(&entry, - iter, new_frame, path, path_len, &statbuf, pathlist_match)) < 0) - goto done; - - git_vector_insert(&new_frame->entries, entry); - } - - if (error == GIT_ITEROVER) - error = 0; - - /* sort now that directory suffix is added */ - git_vector_sort(&new_frame->entries); - -done: - if (error < 0) - git_array_pop(iter->frames); - - git_str_dispose(&root); - git_fs_path_diriter_free(&diriter); - return error; -} - -GIT_INLINE(int) filesystem_iterator_frame_pop(filesystem_iterator *iter) -{ - filesystem_iterator_frame *frame; - - GIT_ASSERT(iter->frames.size); - - frame = git_array_pop(iter->frames); - filesystem_iterator_frame_pop_ignores(iter); - - git_pool_clear(&frame->entry_pool); - git_vector_free(&frame->entries); - - return 0; -} - -static void filesystem_iterator_set_current( - filesystem_iterator *iter, - filesystem_iterator_entry *entry) -{ - /* - * Index entries are limited to 32 bit timestamps. We can safely - * cast this since workdir times are only used in the cache; any - * mismatch will cause a hash recomputation which is unfortunate - * but affects only people who set their filetimes to 2038. - * (Same with the file size.) - */ - iter->entry.ctime.seconds = (int32_t)entry->st.st_ctime; - iter->entry.mtime.seconds = (int32_t)entry->st.st_mtime; - -#if defined(GIT_USE_NSEC) - iter->entry.ctime.nanoseconds = entry->st.st_ctime_nsec; - iter->entry.mtime.nanoseconds = entry->st.st_mtime_nsec; -#else - iter->entry.ctime.nanoseconds = 0; - iter->entry.mtime.nanoseconds = 0; -#endif - - iter->entry.dev = entry->st.st_dev; - iter->entry.ino = entry->st.st_ino; - iter->entry.mode = git_futils_canonical_mode(entry->st.st_mode); - iter->entry.uid = entry->st.st_uid; - iter->entry.gid = entry->st.st_gid; - iter->entry.file_size = (uint32_t)entry->st.st_size; - - if (iter->base.flags & GIT_ITERATOR_INCLUDE_HASH) - git_oid_cpy(&iter->entry.id, &entry->id); - - iter->entry.path = entry->path; - - iter->current_is_ignored = GIT_IGNORE_UNCHECKED; -} - -static int filesystem_iterator_current( - const git_index_entry **out, git_iterator *i) -{ - filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base); - - if (!iterator__has_been_accessed(i)) - return iter->base.cb->advance(out, i); - - if (!iter->frames.size) { - *out = NULL; - return GIT_ITEROVER; - } - - *out = &iter->entry; - return 0; -} - -static int filesystem_iterator_is_dir( - bool *is_dir, - const filesystem_iterator *iter, - const filesystem_iterator_entry *entry) -{ - struct stat st; - git_str fullpath = GIT_STR_INIT; - int error = 0; - - if (S_ISDIR(entry->st.st_mode)) { - *is_dir = 1; - goto done; - } - - if (!iterator__descend_symlinks(iter) || !S_ISLNK(entry->st.st_mode)) { - *is_dir = 0; - goto done; - } - - if ((error = git_str_joinpath(&fullpath, iter->root, entry->path)) < 0 || - (error = git_path_validate_str_length(iter->base.repo, &fullpath)) < 0 || - (error = p_stat(fullpath.ptr, &st)) < 0) - goto done; - - *is_dir = S_ISDIR(st.st_mode); - -done: - git_str_dispose(&fullpath); - return error; -} - -static int filesystem_iterator_advance( - const git_index_entry **out, git_iterator *i) -{ - filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base); - bool is_dir; - int error = 0; - - iter->base.flags |= GIT_ITERATOR_FIRST_ACCESS; - - /* examine filesystem entries until we find the next one to return */ - while (true) { - filesystem_iterator_frame *frame; - filesystem_iterator_entry *entry; - - if ((frame = filesystem_iterator_current_frame(iter)) == NULL) { - error = GIT_ITEROVER; - break; - } - - /* no more entries in this frame. pop the frame out */ - if (frame->next_idx == frame->entries.length) { - filesystem_iterator_frame_pop(iter); - continue; - } - - /* we have more entries in the current frame, that's our next entry */ - entry = frame->entries.contents[frame->next_idx]; - frame->next_idx++; - - if ((error = filesystem_iterator_is_dir(&is_dir, iter, entry)) < 0) - break; - - if (is_dir) { - if (iterator__do_autoexpand(iter)) { - error = filesystem_iterator_frame_push(iter, entry); - - /* may get GIT_ENOTFOUND due to races or permission problems - * that we want to quietly swallow - */ - if (error == GIT_ENOTFOUND) - continue; - else if (error < 0) - break; - } - - if (!iterator__include_trees(iter)) - continue; - } - - filesystem_iterator_set_current(iter, entry); - break; - } - - if (out) - *out = (error == 0) ? &iter->entry : NULL; - - return error; -} - -static int filesystem_iterator_advance_into( - const git_index_entry **out, git_iterator *i) -{ - filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base); - filesystem_iterator_frame *frame; - filesystem_iterator_entry *prev_entry; - int error; - - if (out) - *out = NULL; - - if ((frame = filesystem_iterator_current_frame(iter)) == NULL) - return GIT_ITEROVER; - - /* get the last seen entry */ - prev_entry = filesystem_iterator_current_entry(frame); - - /* it's legal to call advance_into when auto-expand is on. in this case, - * we will have pushed a new (empty) frame on to the stack for this - * new directory. since it's empty, its current_entry should be null. - */ - GIT_ASSERT(iterator__do_autoexpand(i) ^ (prev_entry != NULL)); - - if (prev_entry) { - if (prev_entry->st.st_mode != GIT_FILEMODE_COMMIT && - !S_ISDIR(prev_entry->st.st_mode)) - return 0; - - if ((error = filesystem_iterator_frame_push(iter, prev_entry)) < 0) - return error; - } - - /* we've advanced into the directory in question, let advance - * find the first entry - */ - return filesystem_iterator_advance(out, i); -} - -int git_iterator_current_workdir_path(git_str **out, git_iterator *i) -{ - filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base); - const git_index_entry *entry; - - if (i->type != GIT_ITERATOR_FS && - i->type != GIT_ITERATOR_WORKDIR) { - *out = NULL; - return 0; - } - - git_str_truncate(&iter->current_path, iter->root_len); - - if (git_iterator_current(&entry, i) < 0 || - git_str_puts(&iter->current_path, entry->path) < 0) - return -1; - - *out = &iter->current_path; - return 0; -} - -GIT_INLINE(git_dir_flag) entry_dir_flag(git_index_entry *entry) -{ -#if defined(GIT_WIN32) && !defined(__MINGW32__) - return (entry && entry->mode) ? - (S_ISDIR(entry->mode) ? GIT_DIR_FLAG_TRUE : GIT_DIR_FLAG_FALSE) : - GIT_DIR_FLAG_UNKNOWN; -#else - GIT_UNUSED(entry); - return GIT_DIR_FLAG_UNKNOWN; -#endif -} - -static void filesystem_iterator_update_ignored(filesystem_iterator *iter) -{ - filesystem_iterator_frame *frame; - git_dir_flag dir_flag = entry_dir_flag(&iter->entry); - - if (git_ignore__lookup(&iter->current_is_ignored, - &iter->ignores, iter->entry.path, dir_flag) < 0) { - git_error_clear(); - iter->current_is_ignored = GIT_IGNORE_NOTFOUND; - } - - /* use ignore from containing frame stack */ - if (iter->current_is_ignored <= GIT_IGNORE_NOTFOUND) { - frame = filesystem_iterator_current_frame(iter); - iter->current_is_ignored = frame->is_ignored; - } -} - -GIT_INLINE(bool) filesystem_iterator_current_is_ignored( - filesystem_iterator *iter) -{ - if (iter->current_is_ignored == GIT_IGNORE_UNCHECKED) - filesystem_iterator_update_ignored(iter); - - return (iter->current_is_ignored == GIT_IGNORE_TRUE); -} - -bool git_iterator_current_is_ignored(git_iterator *i) -{ - filesystem_iterator *iter = NULL; - - if (i->type != GIT_ITERATOR_WORKDIR) - return false; - - iter = GIT_CONTAINER_OF(i, filesystem_iterator, base); - - return filesystem_iterator_current_is_ignored(iter); -} - -bool git_iterator_current_tree_is_ignored(git_iterator *i) -{ - filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base); - filesystem_iterator_frame *frame; - - if (i->type != GIT_ITERATOR_WORKDIR) - return false; - - frame = filesystem_iterator_current_frame(iter); - return (frame->is_ignored == GIT_IGNORE_TRUE); -} - -static int filesystem_iterator_advance_over( - const git_index_entry **out, - git_iterator_status_t *status, - git_iterator *i) -{ - filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base); - filesystem_iterator_frame *current_frame; - filesystem_iterator_entry *current_entry; - const git_index_entry *entry = NULL; - const char *base; - int error = 0; - - *out = NULL; - *status = GIT_ITERATOR_STATUS_NORMAL; - - GIT_ASSERT(iterator__has_been_accessed(i)); - - current_frame = filesystem_iterator_current_frame(iter); - GIT_ASSERT(current_frame); - - current_entry = filesystem_iterator_current_entry(current_frame); - GIT_ASSERT(current_entry); - - if ((error = git_iterator_current(&entry, i)) < 0) - return error; - - if (!S_ISDIR(entry->mode)) { - if (filesystem_iterator_current_is_ignored(iter)) - *status = GIT_ITERATOR_STATUS_IGNORED; - - return filesystem_iterator_advance(out, i); - } - - git_str_clear(&iter->tmp_buf); - if ((error = git_str_puts(&iter->tmp_buf, entry->path)) < 0) - return error; - - base = iter->tmp_buf.ptr; - - /* scan inside the directory looking for files. if we find nothing, - * we will remain EMPTY. if we find any ignored item, upgrade EMPTY to - * IGNORED. if we find a real actual item, upgrade all the way to NORMAL - * and then stop. - * - * however, if we're here looking for a pathlist item (but are not - * actually in the pathlist ourselves) then start at FILTERED instead of - * EMPTY. callers then know that this path was not something they asked - * about. - */ - *status = current_entry->match == ITERATOR_PATHLIST_IS_PARENT ? - GIT_ITERATOR_STATUS_FILTERED : GIT_ITERATOR_STATUS_EMPTY; - - while (entry && !iter->base.prefixcomp(entry->path, base)) { - if (filesystem_iterator_current_is_ignored(iter)) { - /* if we found an explicitly ignored item, then update from - * EMPTY to IGNORED - */ - *status = GIT_ITERATOR_STATUS_IGNORED; - } else if (S_ISDIR(entry->mode)) { - error = filesystem_iterator_advance_into(&entry, i); - - if (!error) - continue; - - /* this directory disappeared, ignore it */ - else if (error == GIT_ENOTFOUND) - error = 0; - - /* a real error occurred */ - else - break; - } else { - /* we found a non-ignored item, treat parent as untracked */ - *status = GIT_ITERATOR_STATUS_NORMAL; - break; - } - - if ((error = git_iterator_advance(&entry, i)) < 0) - break; - } - - /* wrap up scan back to base directory */ - while (entry && !iter->base.prefixcomp(entry->path, base)) { - if ((error = git_iterator_advance(&entry, i)) < 0) - break; - } - - if (!error) - *out = entry; - - return error; -} - -static void filesystem_iterator_clear(filesystem_iterator *iter) -{ - while (iter->frames.size) - filesystem_iterator_frame_pop(iter); - - git_array_clear(iter->frames); - git_ignore__free(&iter->ignores); - - git_str_dispose(&iter->tmp_buf); - - iterator_clear(&iter->base); -} - -static int filesystem_iterator_init(filesystem_iterator *iter) -{ - int error; - - if (iterator__honor_ignores(&iter->base) && - (error = git_ignore__for_path(iter->base.repo, - ".gitignore", &iter->ignores)) < 0) - return error; - - if ((error = filesystem_iterator_frame_push(iter, NULL)) < 0) - return error; - - iter->base.flags &= ~GIT_ITERATOR_FIRST_ACCESS; - - return 0; -} - -static int filesystem_iterator_reset(git_iterator *i) -{ - filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base); - - filesystem_iterator_clear(iter); - return filesystem_iterator_init(iter); -} - -static void filesystem_iterator_free(git_iterator *i) -{ - filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base); - git__free(iter->root); - git_str_dispose(&iter->current_path); - git_tree_free(iter->tree); - if (iter->index) - git_index_snapshot_release(&iter->index_snapshot, iter->index); - filesystem_iterator_clear(iter); -} - -static int iterator_for_filesystem( - git_iterator **out, - git_repository *repo, - const char *root, - git_index *index, - git_tree *tree, - git_iterator_t type, - git_iterator_options *options) -{ - filesystem_iterator *iter; - size_t root_len; - int error; - - static git_iterator_callbacks callbacks = { - filesystem_iterator_current, - filesystem_iterator_advance, - filesystem_iterator_advance_into, - filesystem_iterator_advance_over, - filesystem_iterator_reset, - filesystem_iterator_free - }; - - *out = NULL; - - if (root == NULL) - return git_iterator_for_nothing(out, options); - - iter = git__calloc(1, sizeof(filesystem_iterator)); - GIT_ERROR_CHECK_ALLOC(iter); - - iter->base.type = type; - iter->base.cb = &callbacks; - - root_len = strlen(root); - - iter->root = git__malloc(root_len+2); - GIT_ERROR_CHECK_ALLOC(iter->root); - - memcpy(iter->root, root, root_len); - - if (root_len == 0 || root[root_len-1] != '/') { - iter->root[root_len] = '/'; - root_len++; - } - iter->root[root_len] = '\0'; - iter->root_len = root_len; - - if ((error = git_str_puts(&iter->current_path, iter->root)) < 0) - goto on_error; - - if ((error = iterator_init_common(&iter->base, repo, index, options)) < 0) - goto on_error; - - if (tree && (error = git_tree_dup(&iter->tree, tree)) < 0) - goto on_error; - - if (index && - (error = git_index_snapshot_new(&iter->index_snapshot, index)) < 0) - goto on_error; - - iter->index = index; - iter->dirload_flags = - (iterator__ignore_case(&iter->base) ? - GIT_FS_PATH_DIR_IGNORE_CASE : 0) | - (iterator__flag(&iter->base, PRECOMPOSE_UNICODE) ? - GIT_FS_PATH_DIR_PRECOMPOSE_UNICODE : 0); - - if ((error = filesystem_iterator_init(iter)) < 0) - goto on_error; - - *out = &iter->base; - return 0; - -on_error: - git_iterator_free(&iter->base); - return error; -} - -int git_iterator_for_filesystem( - git_iterator **out, - const char *root, - git_iterator_options *options) -{ - return iterator_for_filesystem(out, - NULL, root, NULL, NULL, GIT_ITERATOR_FS, options); -} - -int git_iterator_for_workdir_ext( - git_iterator **out, - git_repository *repo, - const char *repo_workdir, - git_index *index, - git_tree *tree, - git_iterator_options *given_opts) -{ - git_iterator_options options = GIT_ITERATOR_OPTIONS_INIT; - - if (!repo_workdir) { - if (git_repository__ensure_not_bare(repo, "scan working directory") < 0) - return GIT_EBAREREPO; - - repo_workdir = git_repository_workdir(repo); - } - - /* upgrade to a workdir iterator, adding necessary internal flags */ - if (given_opts) - memcpy(&options, given_opts, sizeof(git_iterator_options)); - - options.flags |= GIT_ITERATOR_HONOR_IGNORES | - GIT_ITERATOR_IGNORE_DOT_GIT; - - return iterator_for_filesystem(out, - repo, repo_workdir, index, tree, GIT_ITERATOR_WORKDIR, &options); -} - - -/* Index iterator */ - - -typedef struct { - git_iterator base; - git_vector entries; - size_t next_idx; - - /* the pseudotree entry */ - git_index_entry tree_entry; - git_str tree_buf; - bool skip_tree; - - const git_index_entry *entry; -} index_iterator; - -static int index_iterator_current( - const git_index_entry **out, git_iterator *i) -{ - index_iterator *iter = (index_iterator *)i; - - if (!iterator__has_been_accessed(i)) - return iter->base.cb->advance(out, i); - - if (iter->entry == NULL) { - *out = NULL; - return GIT_ITEROVER; - } - - *out = iter->entry; - return 0; -} - -static bool index_iterator_create_pseudotree( - const git_index_entry **out, - index_iterator *iter, - const char *path) -{ - const char *prev_path, *relative_path, *dirsep; - size_t common_len; - - prev_path = iter->entry ? iter->entry->path : ""; - - /* determine if the new path is in a different directory from the old */ - common_len = git_fs_path_common_dirlen(prev_path, path); - relative_path = path + common_len; - - if ((dirsep = strchr(relative_path, '/')) == NULL) - return false; - - git_str_clear(&iter->tree_buf); - git_str_put(&iter->tree_buf, path, (dirsep - path) + 1); - - iter->tree_entry.mode = GIT_FILEMODE_TREE; - iter->tree_entry.path = iter->tree_buf.ptr; - - *out = &iter->tree_entry; - return true; -} - -static int index_iterator_skip_pseudotree(index_iterator *iter) -{ - GIT_ASSERT(iterator__has_been_accessed(&iter->base)); - GIT_ASSERT(S_ISDIR(iter->entry->mode)); - - while (true) { - const git_index_entry *next_entry = NULL; - - if (++iter->next_idx >= iter->entries.length) - return GIT_ITEROVER; - - next_entry = iter->entries.contents[iter->next_idx]; - - if (iter->base.strncomp(iter->tree_buf.ptr, next_entry->path, - iter->tree_buf.size) != 0) - break; - } - - iter->skip_tree = false; - return 0; -} - -static int index_iterator_advance( - const git_index_entry **out, git_iterator *i) -{ - index_iterator *iter = GIT_CONTAINER_OF(i, index_iterator, base); - const git_index_entry *entry = NULL; - bool is_submodule; - int error = 0; - - iter->base.flags |= GIT_ITERATOR_FIRST_ACCESS; - - while (true) { - if (iter->next_idx >= iter->entries.length) { - error = GIT_ITEROVER; - break; - } - - /* we were not asked to expand this pseudotree. advance over it. */ - if (iter->skip_tree) { - index_iterator_skip_pseudotree(iter); - continue; - } - - entry = iter->entries.contents[iter->next_idx]; - is_submodule = S_ISGITLINK(entry->mode); - - if (!iterator_has_started(&iter->base, entry->path, is_submodule)) { - iter->next_idx++; - continue; - } - - if (iterator_has_ended(&iter->base, entry->path)) { - error = GIT_ITEROVER; - break; - } - - /* if we have a list of paths we're interested in, examine it */ - if (!iterator_pathlist_next_is(&iter->base, entry->path)) { - iter->next_idx++; - continue; - } - - /* if this is a conflict, skip it unless we're including conflicts */ - if (git_index_entry_is_conflict(entry) && - !iterator__include_conflicts(&iter->base)) { - iter->next_idx++; - continue; - } - - /* we've found what will be our next _file_ entry. but if we are - * returning trees entries, we may need to return a pseudotree - * entry that will contain this. don't advance over this entry, - * though, we still need to return it on the next `advance`. - */ - if (iterator__include_trees(&iter->base) && - index_iterator_create_pseudotree(&entry, iter, entry->path)) { - - /* Note whether this pseudo tree should be expanded or not */ - iter->skip_tree = iterator__dont_autoexpand(&iter->base); - break; - } - - iter->next_idx++; - break; - } - - iter->entry = (error == 0) ? entry : NULL; - - if (out) - *out = iter->entry; - - return error; -} - -static int index_iterator_advance_into( - const git_index_entry **out, git_iterator *i) -{ - index_iterator *iter = GIT_CONTAINER_OF(i, index_iterator, base); - - if (! S_ISDIR(iter->tree_entry.mode)) { - if (out) - *out = NULL; - - return 0; - } - - iter->skip_tree = false; - return index_iterator_advance(out, i); -} - -static int index_iterator_advance_over( - const git_index_entry **out, - git_iterator_status_t *status, - git_iterator *i) -{ - index_iterator *iter = GIT_CONTAINER_OF(i, index_iterator, base); - const git_index_entry *entry; - int error; - - if ((error = index_iterator_current(&entry, i)) < 0) - return error; - - if (S_ISDIR(entry->mode)) - index_iterator_skip_pseudotree(iter); - - *status = GIT_ITERATOR_STATUS_NORMAL; - return index_iterator_advance(out, i); -} - -static void index_iterator_clear(index_iterator *iter) -{ - iterator_clear(&iter->base); -} - -static int index_iterator_init(index_iterator *iter) -{ - iter->base.flags &= ~GIT_ITERATOR_FIRST_ACCESS; - iter->next_idx = 0; - iter->skip_tree = false; - return 0; -} - -static int index_iterator_reset(git_iterator *i) -{ - index_iterator *iter = GIT_CONTAINER_OF(i, index_iterator, base); - - index_iterator_clear(iter); - return index_iterator_init(iter); -} - -static void index_iterator_free(git_iterator *i) -{ - index_iterator *iter = GIT_CONTAINER_OF(i, index_iterator, base); - - git_index_snapshot_release(&iter->entries, iter->base.index); - git_str_dispose(&iter->tree_buf); -} - -int git_iterator_for_index( - git_iterator **out, - git_repository *repo, - git_index *index, - git_iterator_options *options) -{ - index_iterator *iter; - int error; - - static git_iterator_callbacks callbacks = { - index_iterator_current, - index_iterator_advance, - index_iterator_advance_into, - index_iterator_advance_over, - index_iterator_reset, - index_iterator_free - }; - - *out = NULL; - - if (index == NULL) - return git_iterator_for_nothing(out, options); - - iter = git__calloc(1, sizeof(index_iterator)); - GIT_ERROR_CHECK_ALLOC(iter); - - iter->base.type = GIT_ITERATOR_INDEX; - iter->base.cb = &callbacks; - - if ((error = iterator_init_common(&iter->base, repo, index, options)) < 0 || - (error = git_index_snapshot_new(&iter->entries, index)) < 0 || - (error = index_iterator_init(iter)) < 0) - goto on_error; - - git_vector_set_cmp(&iter->entries, iterator__ignore_case(&iter->base) ? - git_index_entry_icmp : git_index_entry_cmp); - git_vector_sort(&iter->entries); - - *out = &iter->base; - return 0; - -on_error: - git_iterator_free(&iter->base); - return error; -} - - -/* Iterator API */ - -int git_iterator_reset_range( - git_iterator *i, const char *start, const char *end) -{ - if (iterator_reset_range(i, start, end) < 0) - return -1; - - return i->cb->reset(i); -} - -int git_iterator_set_ignore_case(git_iterator *i, bool ignore_case) -{ - GIT_ASSERT(!iterator__has_been_accessed(i)); - iterator_set_ignore_case(i, ignore_case); - return 0; -} - -void git_iterator_free(git_iterator *iter) -{ - if (iter == NULL) - return; - - iter->cb->free(iter); - - git_vector_free(&iter->pathlist); - git__free(iter->start); - git__free(iter->end); - - memset(iter, 0, sizeof(*iter)); - - git__free(iter); -} - -int git_iterator_foreach( - git_iterator *iterator, - git_iterator_foreach_cb cb, - void *data) -{ - const git_index_entry *iterator_item; - int error = 0; - - if ((error = git_iterator_current(&iterator_item, iterator)) < 0) - goto done; - - if ((error = cb(iterator_item, data)) != 0) - goto done; - - while (true) { - if ((error = git_iterator_advance(&iterator_item, iterator)) < 0) - goto done; - - if ((error = cb(iterator_item, data)) != 0) - goto done; - } - -done: - if (error == GIT_ITEROVER) - error = 0; - - return error; -} - -int git_iterator_walk( - git_iterator **iterators, - size_t cnt, - git_iterator_walk_cb cb, - void *data) -{ - const git_index_entry **iterator_item; /* next in each iterator */ - const git_index_entry **cur_items; /* current path in each iter */ - const git_index_entry *first_match; - size_t i, j; - int error = 0; - - iterator_item = git__calloc(cnt, sizeof(git_index_entry *)); - cur_items = git__calloc(cnt, sizeof(git_index_entry *)); - - GIT_ERROR_CHECK_ALLOC(iterator_item); - GIT_ERROR_CHECK_ALLOC(cur_items); - - /* Set up the iterators */ - for (i = 0; i < cnt; i++) { - error = git_iterator_current(&iterator_item[i], iterators[i]); - - if (error < 0 && error != GIT_ITEROVER) - goto done; - } - - while (true) { - for (i = 0; i < cnt; i++) - cur_items[i] = NULL; - - first_match = NULL; - - /* Find the next path(s) to consume from each iterator */ - for (i = 0; i < cnt; i++) { - if (iterator_item[i] == NULL) - continue; - - if (first_match == NULL) { - first_match = iterator_item[i]; - cur_items[i] = iterator_item[i]; - } else { - int path_diff = git_index_entry_cmp(iterator_item[i], first_match); - - if (path_diff < 0) { - /* Found an index entry that sorts before the one we're - * looking at. Forget that we've seen the other and - * look at the other iterators for this path. - */ - for (j = 0; j < i; j++) - cur_items[j] = NULL; - - first_match = iterator_item[i]; - cur_items[i] = iterator_item[i]; - } else if (path_diff == 0) { - cur_items[i] = iterator_item[i]; - } - } - } - - if (first_match == NULL) - break; - - if ((error = cb(cur_items, data)) != 0) - goto done; - - /* Advance each iterator that participated */ - for (i = 0; i < cnt; i++) { - if (cur_items[i] == NULL) - continue; - - error = git_iterator_advance(&iterator_item[i], iterators[i]); - - if (error < 0 && error != GIT_ITEROVER) - goto done; - } - } - -done: - git__free((git_index_entry **)iterator_item); - git__free((git_index_entry **)cur_items); - - if (error == GIT_ITEROVER) - error = 0; - - return error; -} diff --git a/vendor/libgit2/src/libgit2.c b/vendor/libgit2/src/libgit2.c deleted file mode 100644 index c99d5b94..00000000 --- a/vendor/libgit2/src/libgit2.c +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "libgit2.h" - -#include -#include "alloc.h" -#include "buf.h" -#include "cache.h" -#include "common.h" -#include "filter.h" -#include "hash.h" -#include "index.h" -#include "merge_driver.h" -#include "pool.h" -#include "mwindow.h" -#include "object.h" -#include "odb.h" -#include "rand.h" -#include "refs.h" -#include "runtime.h" -#include "sysdir.h" -#include "thread.h" -#include "threadstate.h" -#include "git2/global.h" -#include "streams/registry.h" -#include "streams/mbedtls.h" -#include "streams/openssl.h" -#include "transports/smart.h" -#include "transports/http.h" -#include "transports/ssh.h" - -#ifdef GIT_WIN32 -# include "win32/w32_leakcheck.h" -#endif - -/* Declarations for tuneable settings */ -extern size_t git_mwindow__window_size; -extern size_t git_mwindow__mapped_limit; -extern size_t git_mwindow__file_limit; -extern size_t git_indexer__max_objects; -extern bool git_disable_pack_keep_file_checks; -extern int git_odb__packed_priority; -extern int git_odb__loose_priority; - -char *git__user_agent; -char *git__ssl_ciphers; - -static void libgit2_settings_global_shutdown(void) -{ - git__free(git__user_agent); - git__free(git__ssl_ciphers); - git_repository__free_extensions(); -} - -static int git_libgit2_settings_global_init(void) -{ - return git_runtime_shutdown_register(libgit2_settings_global_shutdown); -} - -int git_libgit2_init(void) -{ - static git_runtime_init_fn init_fns[] = { -#ifdef GIT_WIN32 - git_win32_leakcheck_global_init, -#endif - git_allocator_global_init, - git_threadstate_global_init, - git_threads_global_init, - git_rand_global_init, - git_hash_global_init, - git_sysdir_global_init, - git_filter_global_init, - git_merge_driver_global_init, - git_transport_ssh_global_init, - git_stream_registry_global_init, - git_openssl_stream_global_init, - git_mbedtls_stream_global_init, - git_mwindow_global_init, - git_pool_global_init, - git_libgit2_settings_global_init - }; - - return git_runtime_init(init_fns, ARRAY_SIZE(init_fns)); -} - -int git_libgit2_init_count(void) -{ - return git_runtime_init_count(); -} - -int git_libgit2_shutdown(void) -{ - return git_runtime_shutdown(); -} - -int git_libgit2_version(int *major, int *minor, int *rev) -{ - *major = LIBGIT2_VER_MAJOR; - *minor = LIBGIT2_VER_MINOR; - *rev = LIBGIT2_VER_REVISION; - - return 0; -} - -int git_libgit2_features(void) -{ - return 0 -#ifdef GIT_THREADS - | GIT_FEATURE_THREADS -#endif -#ifdef GIT_HTTPS - | GIT_FEATURE_HTTPS -#endif -#if defined(GIT_SSH) - | GIT_FEATURE_SSH -#endif -#if defined(GIT_USE_NSEC) - | GIT_FEATURE_NSEC -#endif - ; -} - -static int config_level_to_sysdir(int *out, int config_level) -{ - switch (config_level) { - case GIT_CONFIG_LEVEL_SYSTEM: - *out = GIT_SYSDIR_SYSTEM; - return 0; - case GIT_CONFIG_LEVEL_XDG: - *out = GIT_SYSDIR_XDG; - return 0; - case GIT_CONFIG_LEVEL_GLOBAL: - *out = GIT_SYSDIR_GLOBAL; - return 0; - case GIT_CONFIG_LEVEL_PROGRAMDATA: - *out = GIT_SYSDIR_PROGRAMDATA; - return 0; - default: - break; - } - - git_error_set( - GIT_ERROR_INVALID, "invalid config path selector %d", config_level); - return -1; -} - -const char *git_libgit2__user_agent(void) -{ - return git__user_agent; -} - -const char *git_libgit2__ssl_ciphers(void) -{ - return git__ssl_ciphers; -} - -int git_libgit2_opts(int key, ...) -{ - int error = 0; - va_list ap; - - va_start(ap, key); - - switch (key) { - case GIT_OPT_SET_MWINDOW_SIZE: - git_mwindow__window_size = va_arg(ap, size_t); - break; - - case GIT_OPT_GET_MWINDOW_SIZE: - *(va_arg(ap, size_t *)) = git_mwindow__window_size; - break; - - case GIT_OPT_SET_MWINDOW_MAPPED_LIMIT: - git_mwindow__mapped_limit = va_arg(ap, size_t); - break; - - case GIT_OPT_GET_MWINDOW_MAPPED_LIMIT: - *(va_arg(ap, size_t *)) = git_mwindow__mapped_limit; - break; - - case GIT_OPT_SET_MWINDOW_FILE_LIMIT: - git_mwindow__file_limit = va_arg(ap, size_t); - break; - - case GIT_OPT_GET_MWINDOW_FILE_LIMIT: - *(va_arg(ap, size_t *)) = git_mwindow__file_limit; - break; - - case GIT_OPT_GET_SEARCH_PATH: - { - int sysdir = va_arg(ap, int); - git_buf *out = va_arg(ap, git_buf *); - git_str str = GIT_STR_INIT; - const git_str *tmp; - int level; - - if ((error = git_buf_tostr(&str, out)) < 0 || - (error = config_level_to_sysdir(&level, sysdir)) < 0 || - (error = git_sysdir_get(&tmp, level)) < 0 || - (error = git_str_put(&str, tmp->ptr, tmp->size)) < 0) - break; - - error = git_buf_fromstr(out, &str); - } - break; - - case GIT_OPT_SET_SEARCH_PATH: - { - int level; - - if ((error = config_level_to_sysdir(&level, va_arg(ap, int))) >= 0) - error = git_sysdir_set(level, va_arg(ap, const char *)); - } - break; - - case GIT_OPT_SET_CACHE_OBJECT_LIMIT: - { - git_object_t type = (git_object_t)va_arg(ap, int); - size_t size = va_arg(ap, size_t); - error = git_cache_set_max_object_size(type, size); - break; - } - - case GIT_OPT_SET_CACHE_MAX_SIZE: - git_cache__max_storage = va_arg(ap, ssize_t); - break; - - case GIT_OPT_ENABLE_CACHING: - git_cache__enabled = (va_arg(ap, int) != 0); - break; - - case GIT_OPT_GET_CACHED_MEMORY: - *(va_arg(ap, ssize_t *)) = git_cache__current_storage.val; - *(va_arg(ap, ssize_t *)) = git_cache__max_storage; - break; - - case GIT_OPT_GET_TEMPLATE_PATH: - { - git_buf *out = va_arg(ap, git_buf *); - git_str str = GIT_STR_INIT; - const git_str *tmp; - - if ((error = git_buf_tostr(&str, out)) < 0 || - (error = git_sysdir_get(&tmp, GIT_SYSDIR_TEMPLATE)) < 0 || - (error = git_str_put(&str, tmp->ptr, tmp->size)) < 0) - break; - - error = git_buf_fromstr(out, &str); - } - break; - - case GIT_OPT_SET_TEMPLATE_PATH: - error = git_sysdir_set(GIT_SYSDIR_TEMPLATE, va_arg(ap, const char *)); - break; - - case GIT_OPT_SET_SSL_CERT_LOCATIONS: -#ifdef GIT_OPENSSL - { - const char *file = va_arg(ap, const char *); - const char *path = va_arg(ap, const char *); - error = git_openssl__set_cert_location(file, path); - } -#elif defined(GIT_MBEDTLS) - { - const char *file = va_arg(ap, const char *); - const char *path = va_arg(ap, const char *); - error = git_mbedtls__set_cert_location(file, path); - } -#else - git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support certificate locations"); - error = -1; -#endif - break; - case GIT_OPT_SET_USER_AGENT: - git__free(git__user_agent); - git__user_agent = git__strdup(va_arg(ap, const char *)); - if (!git__user_agent) { - git_error_set_oom(); - error = -1; - } - - break; - - case GIT_OPT_ENABLE_STRICT_OBJECT_CREATION: - git_object__strict_input_validation = (va_arg(ap, int) != 0); - break; - - case GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION: - git_reference__enable_symbolic_ref_target_validation = (va_arg(ap, int) != 0); - break; - - case GIT_OPT_SET_SSL_CIPHERS: -#if (GIT_OPENSSL || GIT_MBEDTLS) - { - git__free(git__ssl_ciphers); - git__ssl_ciphers = git__strdup(va_arg(ap, const char *)); - if (!git__ssl_ciphers) { - git_error_set_oom(); - error = -1; - } - } -#else - git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support custom ciphers"); - error = -1; -#endif - break; - - case GIT_OPT_GET_USER_AGENT: - { - git_buf *out = va_arg(ap, git_buf *); - git_str str = GIT_STR_INIT; - - if ((error = git_buf_tostr(&str, out)) < 0 || - (error = git_str_puts(&str, git__user_agent)) < 0) - break; - - error = git_buf_fromstr(out, &str); - } - break; - - case GIT_OPT_ENABLE_OFS_DELTA: - git_smart__ofs_delta_enabled = (va_arg(ap, int) != 0); - break; - - case GIT_OPT_ENABLE_FSYNC_GITDIR: - git_repository__fsync_gitdir = (va_arg(ap, int) != 0); - break; - - case GIT_OPT_GET_WINDOWS_SHAREMODE: -#ifdef GIT_WIN32 - *(va_arg(ap, unsigned long *)) = git_win32__createfile_sharemode; -#endif - break; - - case GIT_OPT_SET_WINDOWS_SHAREMODE: -#ifdef GIT_WIN32 - git_win32__createfile_sharemode = va_arg(ap, unsigned long); -#endif - break; - - case GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION: - git_odb__strict_hash_verification = (va_arg(ap, int) != 0); - break; - - case GIT_OPT_SET_ALLOCATOR: - error = git_allocator_setup(va_arg(ap, git_allocator *)); - break; - - case GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY: - git_index__enforce_unsaved_safety = (va_arg(ap, int) != 0); - break; - - case GIT_OPT_SET_PACK_MAX_OBJECTS: - git_indexer__max_objects = va_arg(ap, size_t); - break; - - case GIT_OPT_GET_PACK_MAX_OBJECTS: - *(va_arg(ap, size_t *)) = git_indexer__max_objects; - break; - - case GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS: - git_disable_pack_keep_file_checks = (va_arg(ap, int) != 0); - break; - - case GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE: - git_http__expect_continue = (va_arg(ap, int) != 0); - break; - - case GIT_OPT_SET_ODB_PACKED_PRIORITY: - git_odb__packed_priority = va_arg(ap, int); - break; - - case GIT_OPT_SET_ODB_LOOSE_PRIORITY: - git_odb__loose_priority = va_arg(ap, int); - break; - - case GIT_OPT_SET_EXTENSIONS: - { - const char **extensions = va_arg(ap, const char **); - size_t len = va_arg(ap, size_t); - error = git_repository__set_extensions(extensions, len); - } - break; - - case GIT_OPT_GET_EXTENSIONS: - { - git_strarray *out = va_arg(ap, git_strarray *); - char **extensions; - size_t len; - - if ((error = git_repository__extensions(&extensions, &len)) < 0) - break; - - out->strings = extensions; - out->count = len; - } - break; - - case GIT_OPT_GET_OWNER_VALIDATION: - *(va_arg(ap, int *)) = git_repository__validate_ownership; - break; - - case GIT_OPT_SET_OWNER_VALIDATION: - git_repository__validate_ownership = (va_arg(ap, int) != 0); - break; - - default: - git_error_set(GIT_ERROR_INVALID, "invalid option key"); - error = -1; - } - - va_end(ap); - - return error; -} diff --git a/vendor/libgit2/src/libgit2.h b/vendor/libgit2/src/libgit2.h deleted file mode 100644 index a898367a..00000000 --- a/vendor/libgit2/src/libgit2.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_libgit2_h__ -#define INCLUDE_libgit2_h__ - -extern int git_libgit2_init_count(void); - -extern const char *git_libgit2__user_agent(void); -extern const char *git_libgit2__ssl_ciphers(void); - -#endif diff --git a/vendor/libgit2/src/libgit2/CMakeLists.txt b/vendor/libgit2/src/libgit2/CMakeLists.txt new file mode 100644 index 00000000..bc7cb5b3 --- /dev/null +++ b/vendor/libgit2/src/libgit2/CMakeLists.txt @@ -0,0 +1,116 @@ +# libgit2: the shared library: this CMakeLists.txt compiles the core +# git library functionality. + +add_library(libgit2 OBJECT) +set_target_properties(libgit2 PROPERTIES C_STANDARD 90) +set_target_properties(libgit2 PROPERTIES C_EXTENSIONS OFF) + +include(PkgBuildConfig) + +set(LIBGIT2_INCLUDES + "${PROJECT_BINARY_DIR}/src/util" + "${PROJECT_BINARY_DIR}/include" + "${PROJECT_SOURCE_DIR}/src/libgit2" + "${PROJECT_SOURCE_DIR}/src/util" + "${PROJECT_SOURCE_DIR}/include") + +# Collect sourcefiles +file(GLOB SRC_H + "${PROJECT_SOURCE_DIR}/include/git2.h" + "${PROJECT_SOURCE_DIR}/include/git2/*.h" + "${PROJECT_SOURCE_DIR}/include/git2/sys/*.h") +list(SORT SRC_H) +target_sources(libgit2 PRIVATE ${SRC_H}) + +file(GLOB SRC_GIT2 *.c *.h + streams/*.c streams/*.h + transports/*.c transports/*.h) +list(SORT SRC_GIT2) +target_sources(libgit2 PRIVATE ${SRC_GIT2}) + +if(WIN32 AND NOT CYGWIN) + # Add resource information on Windows + set(SRC_RC "git2.rc") +endif() + +if(APPLE) + # The old Secure Transport API has been deprecated in macOS 10.15. + set_source_files_properties(streams/stransport.c PROPERTIES COMPILE_FLAGS -Wno-deprecated) +endif() + +ide_split_sources(libgit2) +list(APPEND LIBGIT2_OBJECTS $ $ ${LIBGIT2_DEPENDENCY_OBJECTS}) +list(APPEND LIBGIT2_INCLUDES ${LIBGIT2_DEPENDENCY_INCLUDES}) + +target_include_directories(libgit2 PRIVATE ${LIBGIT2_INCLUDES} ${LIBGIT2_DEPENDENCY_INCLUDES} PUBLIC ${PROJECT_SOURCE_DIR}/include) +target_include_directories(libgit2 SYSTEM PRIVATE ${LIBGIT2_SYSTEM_INCLUDES}) + +set(LIBGIT2_INCLUDES ${LIBGIT2_INCLUDES} PARENT_SCOPE) +set(LIBGIT2_OBJECTS ${LIBGIT2_OBJECTS} PARENT_SCOPE) +set(LIBGIT2_DEPENDENCY_INCLUDES ${LIBGIT2_DEPENDENCY_INCLUDES} PARENT_SCOPE) +set(LIBGIT2_DEPENDENCY_OBJECTS ${LIBGIT2_DEPENDENCY_OBJECTS} PARENT_SCOPE) +set(LIBGIT2_SYSTEM_INCLUDES ${LIBGIT2_SYSTEM_INCLUDES} PARENT_SCOPE) +set(LIBGIT2_SYSTEM_LIBS ${LIBGIT2_SYSTEM_LIBS} PARENT_SCOPE) + +# +# Compile and link libgit2 +# + +add_library(libgit2package ${SRC_RC} ${LIBGIT2_OBJECTS}) +target_link_libraries(libgit2package ${LIBGIT2_SYSTEM_LIBS}) +target_include_directories(libgit2package SYSTEM PRIVATE ${LIBGIT2_INCLUDES}) + +set_target_properties(libgit2package PROPERTIES C_STANDARD 90) +set_target_properties(libgit2package PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) +set_target_properties(libgit2package PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) +set_target_properties(libgit2package PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) + +ide_split_sources(libgit2package) + +if(SONAME) + set_target_properties(libgit2package PROPERTIES VERSION ${libgit2_VERSION}) + set_target_properties(libgit2package PROPERTIES SOVERSION "${libgit2_VERSION_MAJOR}.${libgit2_VERSION_MINOR}") + if(LIBGIT2_FILENAME) + target_compile_definitions(libgit2package PRIVATE LIBGIT2_FILENAME=\"${LIBGIT2_FILENAME}\") + set_target_properties(libgit2package PROPERTIES OUTPUT_NAME ${LIBGIT2_FILENAME}) + elseif(DEFINED LIBGIT2_PREFIX) + set_target_properties(libgit2package PROPERTIES PREFIX "${LIBGIT2_PREFIX}") + endif() +endif() + +pkg_build_config(NAME "lib${LIBGIT2_FILENAME}" + VERSION ${libgit2_VERSION} + DESCRIPTION "The git library, take 2" + LIBS_SELF ${LIBGIT2_FILENAME} + PRIVATE_LIBS ${LIBGIT2_PC_LIBS} + REQUIRES ${LIBGIT2_PC_REQUIRES}) + +if(MSVC_IDE) + # Precompiled headers + set_target_properties(libgit2package PROPERTIES COMPILE_FLAGS "/Yuprecompiled.h /FIprecompiled.h") + set_source_files_properties(win32/precompiled.c COMPILE_FLAGS "/Ycprecompiled.h") +endif() + +# support experimental features and functionality + +configure_file(experimental.h.in "${PROJECT_BINARY_DIR}/include/git2/experimental.h") + +# translate filenames in the git2.h so that they match the install directory +# (allows for side-by-side installs of libgit2 and libgit2-experimental.) + +FILE(READ "${PROJECT_SOURCE_DIR}/include/git2.h" LIBGIT2_INCLUDE) +STRING(REGEX REPLACE "#include \"git2\/" "#include \"${LIBGIT2_FILENAME}/" LIBGIT2_INCLUDE "${LIBGIT2_INCLUDE}") +FILE(WRITE "${PROJECT_BINARY_DIR}/include/${LIBGIT2_FILENAME}.h" ${LIBGIT2_INCLUDE}) + +# Install + +install(TARGETS libgit2package + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/git2/ + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${LIBGIT2_FILENAME}") +install(FILES ${PROJECT_BINARY_DIR}/include/git2/experimental.h + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${LIBGIT2_FILENAME}") +install(FILES "${PROJECT_BINARY_DIR}/include/${LIBGIT2_FILENAME}.h" + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/vendor/libgit2/src/annotated_commit.c b/vendor/libgit2/src/libgit2/annotated_commit.c similarity index 97% rename from vendor/libgit2/src/annotated_commit.c rename to vendor/libgit2/src/libgit2/annotated_commit.c index e4894767..c5c8ace7 100644 --- a/vendor/libgit2/src/annotated_commit.c +++ b/vendor/libgit2/src/libgit2/annotated_commit.c @@ -39,8 +39,8 @@ static int annotated_commit_init( if ((error = git_commit_dup(&annotated_commit->commit, commit)) < 0) goto done; - git_oid_fmt(annotated_commit->id_str, git_commit_id(commit)); - annotated_commit->id_str[GIT_OID_HEXSZ] = '\0'; + git_oid_tostr(annotated_commit->id_str, GIT_OID_MAX_HEXSIZE + 1, + git_commit_id(commit)); if (!description) description = annotated_commit->id_str; diff --git a/vendor/libgit2/src/annotated_commit.h b/vendor/libgit2/src/libgit2/annotated_commit.h similarity index 96% rename from vendor/libgit2/src/annotated_commit.h rename to vendor/libgit2/src/libgit2/annotated_commit.h index 444a2ed1..1f805fe9 100644 --- a/vendor/libgit2/src/annotated_commit.h +++ b/vendor/libgit2/src/libgit2/annotated_commit.h @@ -41,7 +41,7 @@ struct git_annotated_commit { const char *ref_name; const char *remote_url; - char id_str[GIT_OID_HEXSZ+1]; + char id_str[GIT_OID_MAX_HEXSIZE + 1]; }; extern int git_annotated_commit_from_head(git_annotated_commit **out, diff --git a/vendor/libgit2/src/apply.c b/vendor/libgit2/src/libgit2/apply.c similarity index 99% rename from vendor/libgit2/src/apply.c rename to vendor/libgit2/src/libgit2/apply.c index 18304da4..6b55b812 100644 --- a/vendor/libgit2/src/apply.c +++ b/vendor/libgit2/src/libgit2/apply.c @@ -19,6 +19,7 @@ #include "zstream.h" #include "reader.h" #include "index.h" +#include "repository.h" #include "apply.h" typedef struct { @@ -644,7 +645,7 @@ int git_apply_to_tree( * put the current tree into the postimage as-is - the diff will * replace any entries contained therein */ - if ((error = git_index_new(&postimage)) < 0 || + if ((error = git_index__new(&postimage, repo->oid_type)) < 0 || (error = git_index_read_tree(postimage, preimage)) < 0 || (error = git_reader_for_index(&post_reader, repo, postimage)) < 0) goto done; @@ -851,8 +852,8 @@ int git_apply( * having the full repo index, so we will limit our checkout * to only write these files that were affected by the diff. */ - if ((error = git_index_new(&preimage)) < 0 || - (error = git_index_new(&postimage)) < 0 || + if ((error = git_index__new(&preimage, repo->oid_type)) < 0 || + (error = git_index__new(&postimage, repo->oid_type)) < 0 || (error = git_reader_for_index(&post_reader, repo, postimage)) < 0) goto done; diff --git a/vendor/libgit2/src/apply.h b/vendor/libgit2/src/libgit2/apply.h similarity index 100% rename from vendor/libgit2/src/apply.h rename to vendor/libgit2/src/libgit2/apply.h diff --git a/vendor/libgit2/src/attr.c b/vendor/libgit2/src/libgit2/attr.c similarity index 99% rename from vendor/libgit2/src/attr.c rename to vendor/libgit2/src/libgit2/attr.c index 1623b1d4..1db90b59 100644 --- a/vendor/libgit2/src/attr.c +++ b/vendor/libgit2/src/libgit2/attr.c @@ -424,9 +424,13 @@ static int attr_setup( goto out; if ((error = git_repository_index__weakptr(&idx, repo)) < 0 || - (error = preload_attr_source(repo, attr_session, &index_source)) < 0) + (error = preload_attr_source(repo, attr_session, &index_source)) < 0) { + if (error != GIT_ENOTFOUND) goto out; + error = 0; + } + if ((opts && (opts->flags & GIT_ATTR_CHECK_INCLUDE_HEAD) != 0) && (error = preload_attr_source(repo, attr_session, &head_source)) < 0) goto out; diff --git a/vendor/libgit2/src/attr.h b/vendor/libgit2/src/libgit2/attr.h similarity index 100% rename from vendor/libgit2/src/attr.h rename to vendor/libgit2/src/libgit2/attr.h diff --git a/vendor/libgit2/src/attr_file.c b/vendor/libgit2/src/libgit2/attr_file.c similarity index 99% rename from vendor/libgit2/src/attr_file.c rename to vendor/libgit2/src/libgit2/attr_file.c index 0eb881a9..afa8ec7b 100644 --- a/vendor/libgit2/src/attr_file.c +++ b/vendor/libgit2/src/libgit2/attr_file.c @@ -135,7 +135,7 @@ int git_attr_file__load( break; case GIT_ATTR_FILE_SOURCE_INDEX: { if ((error = attr_file_oid_from_index(&id, repo, entry->path)) < 0 || - (error = git_blob_lookup(&blob, repo, &id)) < 0) + (error = git_blob_lookup(&blob, repo, &id)) < 0) return error; /* Do not assume that data straight from the ODB is NULL-terminated; diff --git a/vendor/libgit2/src/attr_file.h b/vendor/libgit2/src/libgit2/attr_file.h similarity index 100% rename from vendor/libgit2/src/attr_file.h rename to vendor/libgit2/src/libgit2/attr_file.h diff --git a/vendor/libgit2/src/attrcache.c b/vendor/libgit2/src/libgit2/attrcache.c similarity index 99% rename from vendor/libgit2/src/attrcache.c rename to vendor/libgit2/src/libgit2/attrcache.c index b16d95c3..405944ed 100644 --- a/vendor/libgit2/src/attrcache.c +++ b/vendor/libgit2/src/libgit2/attrcache.c @@ -300,7 +300,7 @@ static int attr_cache__lookup_path( /* expand leading ~/ as needed */ if (cfgval && cfgval[0] == '~' && cfgval[1] == '/') { - if (! (error = git_sysdir_expand_global_file(&buf, &cfgval[2]))) + if (! (error = git_sysdir_expand_homedir_file(&buf, &cfgval[2]))) *out = git_str_detach(&buf); } else if (cfgval) { *out = git__strdup(cfgval); diff --git a/vendor/libgit2/src/attrcache.h b/vendor/libgit2/src/libgit2/attrcache.h similarity index 100% rename from vendor/libgit2/src/attrcache.h rename to vendor/libgit2/src/libgit2/attrcache.h diff --git a/vendor/libgit2/src/blame.c b/vendor/libgit2/src/libgit2/blame.c similarity index 91% rename from vendor/libgit2/src/blame.c rename to vendor/libgit2/src/libgit2/blame.c index a6ab43ef..2ed7d201 100644 --- a/vendor/libgit2/src/blame.c +++ b/vendor/libgit2/src/libgit2/blame.c @@ -60,10 +60,11 @@ static bool hunk_starts_at_or_after_line(git_blame_hunk *hunk, size_t line) } static git_blame_hunk *new_hunk( - size_t start, - size_t lines, - size_t orig_start, - const char *path) + size_t start, + size_t lines, + size_t orig_start, + const char *path, + git_blame *blame) { git_blame_hunk *hunk = git__calloc(1, sizeof(git_blame_hunk)); if (!hunk) return NULL; @@ -72,6 +73,8 @@ static git_blame_hunk *new_hunk( hunk->final_start_line_number = start; hunk->orig_start_line_number = orig_start; hunk->orig_path = path ? git__strdup(path) : NULL; + git_oid_clear(&hunk->orig_commit_id, blame->repository->oid_type); + git_oid_clear(&hunk->final_commit_id, blame->repository->oid_type); return hunk; } @@ -84,13 +87,14 @@ static void free_hunk(git_blame_hunk *hunk) git__free(hunk); } -static git_blame_hunk *dup_hunk(git_blame_hunk *hunk) +static git_blame_hunk *dup_hunk(git_blame_hunk *hunk, git_blame *blame) { git_blame_hunk *newhunk = new_hunk( hunk->final_start_line_number, hunk->lines_in_hunk, hunk->orig_start_line_number, - hunk->orig_path); + hunk->orig_path, + blame); if (!newhunk) return NULL; @@ -113,12 +117,12 @@ static git_blame_hunk *dup_hunk(git_blame_hunk *hunk) static void shift_hunks_by(git_vector *v, size_t start_line, int shift_by) { size_t i; - - if (!git_vector_bsearch2(&i, v, hunk_byfinalline_search_cmp, &start_line)) { - for (; i < v->length; i++) { - git_blame_hunk *hunk = (git_blame_hunk*)v->contents[i]; - hunk->final_start_line_number += shift_by; + for (i = 0; i < v->length; i++) { + git_blame_hunk *hunk = (git_blame_hunk*)v->contents[i]; + if(hunk->final_start_line_number < start_line){ + continue; } + hunk->final_start_line_number += shift_by; } } @@ -235,7 +239,8 @@ static git_blame_hunk *split_hunk_in_vector( git_vector *vec, git_blame_hunk *hunk, size_t rel_line, - bool return_new) + bool return_new, + git_blame *blame) { size_t new_line_count; git_blame_hunk *nh; @@ -248,8 +253,9 @@ static git_blame_hunk *split_hunk_in_vector( } new_line_count = hunk->lines_in_hunk - rel_line; - nh = new_hunk(hunk->final_start_line_number + rel_line, new_line_count, - hunk->orig_start_line_number + rel_line, hunk->orig_path); + nh = new_hunk(hunk->final_start_line_number + rel_line, + new_line_count, hunk->orig_start_line_number + rel_line, + hunk->orig_path, blame); if (!nh) return NULL; @@ -302,7 +308,8 @@ static int index_blob_lines(git_blame *blame) static git_blame_hunk *hunk_from_entry(git_blame__entry *e, git_blame *blame) { git_blame_hunk *h = new_hunk( - e->lno+1, e->num_lines, e->s_lno+1, e->suspect->path); + e->lno+1, e->num_lines, e->s_lno+1, e->suspect->path, + blame); if (!h) return NULL; @@ -437,20 +444,21 @@ static int buffer_hunk_cb( GIT_UNUSED(delta); - wedge_line = (hunk->old_lines == 0) ? hunk->new_start : hunk->old_start; + wedge_line = (hunk->new_start >= hunk->old_start || hunk->old_lines==0) ? hunk->new_start : hunk->old_start; blame->current_diff_line = wedge_line; - blame->current_hunk = (git_blame_hunk*)git_blame_get_hunk_byline(blame, wedge_line); if (!blame->current_hunk) { /* Line added at the end of the file */ - blame->current_hunk = new_hunk(wedge_line, 0, wedge_line, blame->path); + blame->current_hunk = new_hunk(wedge_line, 0, wedge_line, + blame->path, blame); + blame->current_diff_line++; GIT_ERROR_CHECK_ALLOC(blame->current_hunk); - git_vector_insert(&blame->hunks, blame->current_hunk); } else if (!hunk_starts_at_or_after_line(blame->current_hunk, wedge_line)){ /* If this hunk doesn't start between existing hunks, split a hunk up so it does */ blame->current_hunk = split_hunk_in_vector(&blame->hunks, blame->current_hunk, - wedge_line - blame->current_hunk->orig_start_line_number, true); + wedge_line - blame->current_hunk->final_start_line_number, true, + blame); GIT_ERROR_CHECK_ALLOC(blame->current_hunk); } @@ -475,13 +483,12 @@ static int buffer_line_cb( hunk_ends_at_or_before_line(blame->current_hunk, blame->current_diff_line)) { /* Append to the current buffer-blame hunk */ blame->current_hunk->lines_in_hunk++; - shift_hunks_by(&blame->hunks, blame->current_diff_line+1, 1); + shift_hunks_by(&blame->hunks, blame->current_diff_line, 1); } else { /* Create a new buffer-blame hunk with this line */ shift_hunks_by(&blame->hunks, blame->current_diff_line, 1); - blame->current_hunk = new_hunk(blame->current_diff_line, 1, 0, blame->path); + blame->current_hunk = new_hunk(blame->current_diff_line, 1, 0, blame->path, blame); GIT_ERROR_CHECK_ALLOC(blame->current_hunk); - git_vector_insert_sorted(&blame->hunks, blame->current_hunk, NULL); } blame->current_diff_line++; @@ -489,15 +496,16 @@ static int buffer_line_cb( if (line->origin == GIT_DIFF_LINE_DELETION) { /* Trim the line from the current hunk; remove it if it's now empty */ - size_t shift_base = blame->current_diff_line + blame->current_hunk->lines_in_hunk+1; + size_t shift_base = blame->current_diff_line + blame->current_hunk->lines_in_hunk; if (--(blame->current_hunk->lines_in_hunk) == 0) { size_t i; - shift_base--; + size_t i_next; if (!git_vector_search2(&i, &blame->hunks, ptrs_equal_cmp, blame->current_hunk)) { git_vector_remove(&blame->hunks, i); free_hunk(blame->current_hunk); - blame->current_hunk = (git_blame_hunk*)git_blame_get_hunk_byindex(blame, (uint32_t)i); + i_next = min( i , blame->hunks.length -1); + blame->current_hunk = (git_blame_hunk*)git_blame_get_hunk_byindex(blame, (uint32_t)i_next); } } shift_hunks_by(&blame->hunks, shift_base, -1); @@ -527,7 +535,7 @@ int git_blame_buffer( /* Duplicate all of the hunk structures in the reference blame */ git_vector_foreach(&reference->hunks, i, hunk) { - git_blame_hunk *h = dup_hunk(hunk); + git_blame_hunk *h = dup_hunk(hunk, blame); GIT_ERROR_CHECK_ALLOC(h); git_vector_insert(&blame->hunks, h); diff --git a/vendor/libgit2/src/blame.h b/vendor/libgit2/src/libgit2/blame.h similarity index 100% rename from vendor/libgit2/src/blame.h rename to vendor/libgit2/src/libgit2/blame.h diff --git a/vendor/libgit2/src/blame_git.c b/vendor/libgit2/src/libgit2/blame_git.c similarity index 99% rename from vendor/libgit2/src/blame_git.c rename to vendor/libgit2/src/libgit2/blame_git.c index 2504b338..69897b38 100644 --- a/vendor/libgit2/src/blame_git.c +++ b/vendor/libgit2/src/libgit2/blame_git.c @@ -9,7 +9,6 @@ #include "commit.h" #include "blob.h" -#include "xdiff/xinclude.h" #include "diff_xdiff.h" /* diff --git a/vendor/libgit2/src/blame_git.h b/vendor/libgit2/src/libgit2/blame_git.h similarity index 100% rename from vendor/libgit2/src/blame_git.h rename to vendor/libgit2/src/libgit2/blame_git.h diff --git a/vendor/libgit2/src/libgit2/blob.c b/vendor/libgit2/src/libgit2/blob.c new file mode 100644 index 00000000..5cfd7474 --- /dev/null +++ b/vendor/libgit2/src/libgit2/blob.c @@ -0,0 +1,530 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "blob.h" + +#include "git2/common.h" +#include "git2/object.h" +#include "git2/repository.h" +#include "git2/odb_backend.h" + +#include "buf.h" +#include "filebuf.h" +#include "filter.h" + +const void *git_blob_rawcontent(const git_blob *blob) +{ + GIT_ASSERT_ARG_WITH_RETVAL(blob, NULL); + + if (blob->raw) + return blob->data.raw.data; + else + return git_odb_object_data(blob->data.odb); +} + +git_object_size_t git_blob_rawsize(const git_blob *blob) +{ + GIT_ASSERT_ARG(blob); + + if (blob->raw) + return blob->data.raw.size; + else + return (git_object_size_t)git_odb_object_size(blob->data.odb); +} + +int git_blob__getbuf(git_str *buffer, git_blob *blob) +{ + git_object_size_t size = git_blob_rawsize(blob); + + GIT_ERROR_CHECK_BLOBSIZE(size); + return git_str_set(buffer, git_blob_rawcontent(blob), (size_t)size); +} + +void git_blob__free(void *_blob) +{ + git_blob *blob = (git_blob *) _blob; + if (!blob->raw) + git_odb_object_free(blob->data.odb); + git__free(blob); +} + +int git_blob__parse_raw(void *_blob, const char *data, size_t size, git_oid_t oid_type) +{ + git_blob *blob = (git_blob *) _blob; + + GIT_ASSERT_ARG(blob); + GIT_UNUSED(oid_type); + + blob->raw = 1; + blob->data.raw.data = data; + blob->data.raw.size = size; + return 0; +} + +int git_blob__parse(void *_blob, git_odb_object *odb_obj, git_oid_t oid_type) +{ + git_blob *blob = (git_blob *) _blob; + + GIT_ASSERT_ARG(blob); + GIT_UNUSED(oid_type); + + git_cached_obj_incref((git_cached_obj *)odb_obj); + blob->raw = 0; + blob->data.odb = odb_obj; + return 0; +} + +int git_blob_create_from_buffer( + git_oid *id, git_repository *repo, const void *buffer, size_t len) +{ + int error; + git_odb *odb; + git_odb_stream *stream; + + GIT_ASSERT_ARG(id); + GIT_ASSERT_ARG(repo); + + if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 || + (error = git_odb_open_wstream(&stream, odb, len, GIT_OBJECT_BLOB)) < 0) + return error; + + if ((error = git_odb_stream_write(stream, buffer, len)) == 0) + error = git_odb_stream_finalize_write(id, stream); + + git_odb_stream_free(stream); + return error; +} + +static int write_file_stream( + git_oid *id, git_odb *odb, const char *path, git_object_size_t file_size) +{ + int fd, error; + char buffer[GIT_BUFSIZE_FILEIO]; + git_odb_stream *stream = NULL; + ssize_t read_len = -1; + git_object_size_t written = 0; + + if ((error = git_odb_open_wstream( + &stream, odb, file_size, GIT_OBJECT_BLOB)) < 0) + return error; + + if ((fd = git_futils_open_ro(path)) < 0) { + git_odb_stream_free(stream); + return -1; + } + + while (!error && (read_len = p_read(fd, buffer, sizeof(buffer))) > 0) { + error = git_odb_stream_write(stream, buffer, read_len); + written += read_len; + } + + p_close(fd); + + if (written != file_size || read_len < 0) { + git_error_set(GIT_ERROR_OS, "failed to read file into stream"); + error = -1; + } + + if (!error) + error = git_odb_stream_finalize_write(id, stream); + + git_odb_stream_free(stream); + return error; +} + +static int write_file_filtered( + git_oid *id, + git_object_size_t *size, + git_odb *odb, + const char *full_path, + git_filter_list *fl, + git_repository* repo) +{ + int error; + git_str tgt = GIT_STR_INIT; + + error = git_filter_list__apply_to_file(&tgt, fl, repo, full_path); + + /* Write the file to disk if it was properly filtered */ + if (!error) { + *size = tgt.size; + + error = git_odb_write(id, odb, tgt.ptr, tgt.size, GIT_OBJECT_BLOB); + } + + git_str_dispose(&tgt); + return error; +} + +static int write_symlink( + git_oid *id, git_odb *odb, const char *path, size_t link_size) +{ + char *link_data; + ssize_t read_len; + int error; + + link_data = git__malloc(link_size); + GIT_ERROR_CHECK_ALLOC(link_data); + + read_len = p_readlink(path, link_data, link_size); + if (read_len != (ssize_t)link_size) { + git_error_set(GIT_ERROR_OS, "failed to create blob: cannot read symlink '%s'", path); + git__free(link_data); + return -1; + } + + error = git_odb_write(id, odb, (void *)link_data, link_size, GIT_OBJECT_BLOB); + git__free(link_data); + return error; +} + +int git_blob__create_from_paths( + git_oid *id, + struct stat *out_st, + git_repository *repo, + const char *content_path, + const char *hint_path, + mode_t hint_mode, + bool try_load_filters) +{ + int error; + struct stat st; + git_odb *odb = NULL; + git_object_size_t size; + mode_t mode; + git_str path = GIT_STR_INIT; + + GIT_ASSERT_ARG(hint_path || !try_load_filters); + + if (!content_path) { + if (git_repository_workdir_path(&path, repo, hint_path) < 0) + return -1; + + content_path = path.ptr; + } + + if ((error = git_fs_path_lstat(content_path, &st)) < 0 || + (error = git_repository_odb(&odb, repo)) < 0) + goto done; + + if (S_ISDIR(st.st_mode)) { + git_error_set(GIT_ERROR_ODB, "cannot create blob from '%s': it is a directory", content_path); + error = GIT_EDIRECTORY; + goto done; + } + + if (out_st) + memcpy(out_st, &st, sizeof(st)); + + size = st.st_size; + mode = hint_mode ? hint_mode : st.st_mode; + + if (S_ISLNK(mode)) { + error = write_symlink(id, odb, content_path, (size_t)size); + } else { + git_filter_list *fl = NULL; + + if (try_load_filters) + /* Load the filters for writing this file to the ODB */ + error = git_filter_list_load( + &fl, repo, NULL, hint_path, + GIT_FILTER_TO_ODB, GIT_FILTER_DEFAULT); + + if (error < 0) + /* well, that didn't work */; + else if (fl == NULL) + /* No filters need to be applied to the document: we can stream + * directly from disk */ + error = write_file_stream(id, odb, content_path, size); + else { + /* We need to apply one or more filters */ + error = write_file_filtered(id, &size, odb, content_path, fl, repo); + + git_filter_list_free(fl); + } + + /* + * TODO: eventually support streaming filtered files, for files + * which are bigger than a given threshold. This is not a priority + * because applying a filter in streaming mode changes the final + * size of the blob, and without knowing its final size, the blob + * cannot be written in stream mode to the ODB. + * + * The plan is to do streaming writes to a tempfile on disk and then + * opening streaming that file to the ODB, using + * `write_file_stream`. + * + * CAREFULLY DESIGNED APIS YO + */ + } + +done: + git_odb_free(odb); + git_str_dispose(&path); + + return error; +} + +int git_blob_create_from_workdir( + git_oid *id, git_repository *repo, const char *path) +{ + return git_blob__create_from_paths(id, NULL, repo, NULL, path, 0, true); +} + +int git_blob_create_from_disk( + git_oid *id, git_repository *repo, const char *path) +{ + int error; + git_str full_path = GIT_STR_INIT; + const char *workdir, *hintpath = NULL; + + if ((error = git_fs_path_prettify(&full_path, path, NULL)) < 0) { + git_str_dispose(&full_path); + return error; + } + + workdir = git_repository_workdir(repo); + + if (workdir && !git__prefixcmp(full_path.ptr, workdir)) + hintpath = full_path.ptr + strlen(workdir); + + error = git_blob__create_from_paths( + id, NULL, repo, git_str_cstr(&full_path), hintpath, 0, !!hintpath); + + git_str_dispose(&full_path); + return error; +} + +typedef struct { + git_writestream parent; + git_filebuf fbuf; + git_repository *repo; + char *hintpath; +} blob_writestream; + +static int blob_writestream_close(git_writestream *_stream) +{ + blob_writestream *stream = (blob_writestream *) _stream; + + git_filebuf_cleanup(&stream->fbuf); + return 0; +} + +static void blob_writestream_free(git_writestream *_stream) +{ + blob_writestream *stream = (blob_writestream *) _stream; + + git_filebuf_cleanup(&stream->fbuf); + git__free(stream->hintpath); + git__free(stream); +} + +static int blob_writestream_write(git_writestream *_stream, const char *buffer, size_t len) +{ + blob_writestream *stream = (blob_writestream *) _stream; + + return git_filebuf_write(&stream->fbuf, buffer, len); +} + +int git_blob_create_from_stream(git_writestream **out, git_repository *repo, const char *hintpath) +{ + int error; + git_str path = GIT_STR_INIT; + blob_writestream *stream; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(repo); + + stream = git__calloc(1, sizeof(blob_writestream)); + GIT_ERROR_CHECK_ALLOC(stream); + + if (hintpath) { + stream->hintpath = git__strdup(hintpath); + GIT_ERROR_CHECK_ALLOC(stream->hintpath); + } + + stream->repo = repo; + stream->parent.write = blob_writestream_write; + stream->parent.close = blob_writestream_close; + stream->parent.free = blob_writestream_free; + + if ((error = git_repository__item_path(&path, repo, GIT_REPOSITORY_ITEM_OBJECTS)) < 0 + || (error = git_str_joinpath(&path, path.ptr, "streamed")) < 0) + goto cleanup; + + if ((error = git_filebuf_open_withsize(&stream->fbuf, git_str_cstr(&path), GIT_FILEBUF_TEMPORARY, + 0666, 2 * 1024 * 1024)) < 0) + goto cleanup; + + *out = (git_writestream *) stream; + +cleanup: + if (error < 0) + blob_writestream_free((git_writestream *) stream); + + git_str_dispose(&path); + return error; +} + +int git_blob_create_from_stream_commit(git_oid *out, git_writestream *_stream) +{ + int error; + blob_writestream *stream = (blob_writestream *) _stream; + + /* + * We can make this more officient by avoiding writing to + * disk, but for now let's re-use the helper functions we + * have. + */ + if ((error = git_filebuf_flush(&stream->fbuf)) < 0) + goto cleanup; + + error = git_blob__create_from_paths(out, NULL, stream->repo, stream->fbuf.path_lock, + stream->hintpath, 0, !!stream->hintpath); + +cleanup: + blob_writestream_free(_stream); + return error; + +} + +int git_blob_is_binary(const git_blob *blob) +{ + git_str content = GIT_STR_INIT; + git_object_size_t size; + + GIT_ASSERT_ARG(blob); + + size = git_blob_rawsize(blob); + + git_str_attach_notowned(&content, git_blob_rawcontent(blob), + (size_t)min(size, GIT_FILTER_BYTES_TO_CHECK_NUL)); + return git_str_is_binary(&content); +} + +int git_blob_data_is_binary(const char *str, size_t len) +{ + git_str content = GIT_STR_INIT; + + git_str_attach_notowned(&content, str, len); + + return git_str_is_binary(&content); +} + +int git_blob_filter_options_init( + git_blob_filter_options *opts, + unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE(opts, version, + git_blob_filter_options, GIT_BLOB_FILTER_OPTIONS_INIT); + return 0; +} + +int git_blob_filter( + git_buf *out, + git_blob *blob, + const char *path, + git_blob_filter_options *given_opts) +{ + git_blob_filter_options opts = GIT_BLOB_FILTER_OPTIONS_INIT; + git_filter_options filter_opts = GIT_FILTER_OPTIONS_INIT; + git_filter_list *fl = NULL; + int error = 0; + + GIT_ASSERT_ARG(blob); + GIT_ASSERT_ARG(path); + GIT_ASSERT_ARG(out); + + GIT_ERROR_CHECK_VERSION( + given_opts, GIT_BLOB_FILTER_OPTIONS_VERSION, "git_blob_filter_options"); + + if (given_opts != NULL) + memcpy(&opts, given_opts, sizeof(git_blob_filter_options)); + + if ((opts.flags & GIT_BLOB_FILTER_CHECK_FOR_BINARY) != 0 && + git_blob_is_binary(blob)) + return 0; + + if ((opts.flags & GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES) != 0) + filter_opts.flags |= GIT_FILTER_NO_SYSTEM_ATTRIBUTES; + + if ((opts.flags & GIT_BLOB_FILTER_ATTRIBUTES_FROM_HEAD) != 0) + filter_opts.flags |= GIT_FILTER_ATTRIBUTES_FROM_HEAD; + + if ((opts.flags & GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT) != 0) { + filter_opts.flags |= GIT_FILTER_ATTRIBUTES_FROM_COMMIT; + +#ifndef GIT_DEPRECATE_HARD + if (opts.commit_id) + git_oid_cpy(&filter_opts.attr_commit_id, opts.commit_id); + else +#endif + git_oid_cpy(&filter_opts.attr_commit_id, &opts.attr_commit_id); + } + + if (!(error = git_filter_list_load_ext( + &fl, git_blob_owner(blob), blob, path, + GIT_FILTER_TO_WORKTREE, &filter_opts))) { + + error = git_filter_list_apply_to_blob(out, fl, blob); + + git_filter_list_free(fl); + } + + return error; +} + +/* Deprecated functions */ + +#ifndef GIT_DEPRECATE_HARD +int git_blob_create_frombuffer( + git_oid *id, git_repository *repo, const void *buffer, size_t len) +{ + return git_blob_create_from_buffer(id, repo, buffer, len); +} + +int git_blob_create_fromworkdir(git_oid *id, git_repository *repo, const char *relative_path) +{ + return git_blob_create_from_workdir(id, repo, relative_path); +} + +int git_blob_create_fromdisk(git_oid *id, git_repository *repo, const char *path) +{ + return git_blob_create_from_disk(id, repo, path); +} + +int git_blob_create_fromstream( + git_writestream **out, + git_repository *repo, + const char *hintpath) +{ + return git_blob_create_from_stream(out, repo, hintpath); +} + +int git_blob_create_fromstream_commit( + git_oid *out, + git_writestream *stream) +{ + return git_blob_create_from_stream_commit(out, stream); +} + +int git_blob_filtered_content( + git_buf *out, + git_blob *blob, + const char *path, + int check_for_binary_data) +{ + git_blob_filter_options opts = GIT_BLOB_FILTER_OPTIONS_INIT; + + if (check_for_binary_data) + opts.flags |= GIT_BLOB_FILTER_CHECK_FOR_BINARY; + else + opts.flags &= ~GIT_BLOB_FILTER_CHECK_FOR_BINARY; + + return git_blob_filter(out, blob, path, &opts); +} +#endif diff --git a/vendor/libgit2/src/blob.h b/vendor/libgit2/src/libgit2/blob.h similarity index 91% rename from vendor/libgit2/src/blob.h rename to vendor/libgit2/src/libgit2/blob.h index 9a5dda22..d6c9dd99 100644 --- a/vendor/libgit2/src/blob.h +++ b/vendor/libgit2/src/libgit2/blob.h @@ -36,8 +36,8 @@ struct git_blob { } while(0) void git_blob__free(void *blob); -int git_blob__parse(void *blob, git_odb_object *obj); -int git_blob__parse_raw(void *blob, const char *data, size_t size); +int git_blob__parse(void *blob, git_odb_object *obj, git_oid_t oid_type); +int git_blob__parse_raw(void *blob, const char *data, size_t size, git_oid_t oid_type); int git_blob__getbuf(git_str *buffer, git_blob *blob); extern int git_blob__create_from_paths( diff --git a/vendor/libgit2/src/branch.c b/vendor/libgit2/src/libgit2/branch.c similarity index 97% rename from vendor/libgit2/src/branch.c rename to vendor/libgit2/src/libgit2/branch.c index 2e29af99..9a31c9c6 100644 --- a/vendor/libgit2/src/branch.c +++ b/vendor/libgit2/src/libgit2/branch.c @@ -53,6 +53,17 @@ static int not_a_local_branch(const char *reference_name) return -1; } +static bool branch_name_is_valid(const char *branch_name) +{ + /* + * Discourage branch name starting with dash, + * https://github.com/git/git/commit/6348624010888b + * and discourage HEAD as branch name, + * https://github.com/git/git/commit/a625b092cc5994 + */ + return branch_name[0] != '-' && git__strcmp(branch_name, "HEAD"); +} + static int create_branch( git_reference **ref_out, git_repository *repository, @@ -73,8 +84,8 @@ static int create_branch( GIT_ASSERT_ARG(ref_out); GIT_ASSERT_ARG(git_commit_owner(commit) == repository); - if (!git__strcmp(branch_name, "HEAD")) { - git_error_set(GIT_ERROR_REFERENCE, "'HEAD' is not a valid branch name"); + if (!branch_name_is_valid(branch_name)) { + git_error_set(GIT_ERROR_REFERENCE, "'%s' is not a valid branch name", branch_name); error = -1; goto cleanup; } @@ -123,9 +134,9 @@ int git_branch_create( const git_commit *commit, int force) { - char commit_id[GIT_OID_HEXSZ + 1]; + char commit_id[GIT_OID_MAX_HEXSIZE + 1]; - git_oid_tostr(commit_id, GIT_OID_HEXSZ + 1, git_commit_id(commit)); + git_oid_tostr(commit_id, GIT_OID_MAX_HEXSIZE + 1, git_commit_id(commit)); return create_branch(ref_out, repository, branch_name, commit, commit_id, force); } @@ -797,13 +808,7 @@ int git_branch_name_is_valid(int *valid, const char *name) *valid = 0; - /* - * Discourage branch name starting with dash, - * https://github.com/git/git/commit/6348624010888b - * and discourage HEAD as branch name, - * https://github.com/git/git/commit/a625b092cc5994 - */ - if (!name || name[0] == '-' || !git__strcmp(name, "HEAD")) + if (!name || !branch_name_is_valid(name)) goto done; if ((error = git_str_puts(&ref_name, GIT_REFS_HEADS_DIR)) < 0 || diff --git a/vendor/libgit2/src/branch.h b/vendor/libgit2/src/libgit2/branch.h similarity index 100% rename from vendor/libgit2/src/branch.h rename to vendor/libgit2/src/libgit2/branch.h diff --git a/vendor/libgit2/src/buf.c b/vendor/libgit2/src/libgit2/buf.c similarity index 100% rename from vendor/libgit2/src/buf.c rename to vendor/libgit2/src/libgit2/buf.c diff --git a/vendor/libgit2/src/buf.h b/vendor/libgit2/src/libgit2/buf.h similarity index 100% rename from vendor/libgit2/src/buf.h rename to vendor/libgit2/src/libgit2/buf.h diff --git a/vendor/libgit2/src/cache.c b/vendor/libgit2/src/libgit2/cache.c similarity index 100% rename from vendor/libgit2/src/cache.c rename to vendor/libgit2/src/libgit2/cache.c diff --git a/vendor/libgit2/src/cache.h b/vendor/libgit2/src/libgit2/cache.h similarity index 100% rename from vendor/libgit2/src/cache.h rename to vendor/libgit2/src/libgit2/cache.h diff --git a/vendor/libgit2/src/checkout.c b/vendor/libgit2/src/libgit2/checkout.c similarity index 100% rename from vendor/libgit2/src/checkout.c rename to vendor/libgit2/src/libgit2/checkout.c diff --git a/vendor/libgit2/src/checkout.h b/vendor/libgit2/src/libgit2/checkout.h similarity index 100% rename from vendor/libgit2/src/checkout.h rename to vendor/libgit2/src/libgit2/checkout.h diff --git a/vendor/libgit2/src/cherrypick.c b/vendor/libgit2/src/libgit2/cherrypick.c similarity index 97% rename from vendor/libgit2/src/cherrypick.c rename to vendor/libgit2/src/libgit2/cherrypick.c index 9ec4962b..3ef42d5e 100644 --- a/vendor/libgit2/src/cherrypick.c +++ b/vendor/libgit2/src/libgit2/cherrypick.c @@ -106,10 +106,10 @@ static int cherrypick_state_cleanup(git_repository *repo) static int cherrypick_seterr(git_commit *commit, const char *fmt) { - char commit_oidstr[GIT_OID_HEXSZ + 1]; + char commit_oidstr[GIT_OID_MAX_HEXSIZE + 1]; git_error_set(GIT_ERROR_CHERRYPICK, fmt, - git_oid_tostr(commit_oidstr, GIT_OID_HEXSZ + 1, git_commit_id(commit))); + git_oid_tostr(commit_oidstr, GIT_OID_MAX_HEXSIZE + 1, git_commit_id(commit))); return -1; } @@ -173,7 +173,7 @@ int git_cherrypick( git_cherrypick_options opts; git_reference *our_ref = NULL; git_commit *our_commit = NULL; - char commit_oidstr[GIT_OID_HEXSZ + 1]; + char commit_oidstr[GIT_OID_MAX_HEXSIZE + 1]; const char *commit_msg, *commit_summary; git_str their_label = GIT_STR_INIT; git_index *index = NULL; diff --git a/vendor/libgit2/src/libgit2/clone.c b/vendor/libgit2/src/libgit2/clone.c new file mode 100644 index 00000000..d62c77ac --- /dev/null +++ b/vendor/libgit2/src/libgit2/clone.c @@ -0,0 +1,697 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "clone.h" + +#include "git2/clone.h" +#include "git2/remote.h" +#include "git2/revparse.h" +#include "git2/branch.h" +#include "git2/config.h" +#include "git2/checkout.h" +#include "git2/commit.h" +#include "git2/tree.h" + +#include "remote.h" +#include "futils.h" +#include "refs.h" +#include "fs_path.h" +#include "repository.h" +#include "odb.h" +#include "net.h" + +static int clone_local_into(git_repository *repo, git_remote *remote, const git_fetch_options *fetch_opts, const git_checkout_options *co_opts, const char *branch, int link); + +static int create_branch( + git_reference **branch, + git_repository *repo, + const git_oid *target, + const char *name, + const char *log_message) +{ + git_commit *head_obj = NULL; + git_reference *branch_ref = NULL; + git_str refname = GIT_STR_INIT; + int error; + + /* Find the target commit */ + if ((error = git_commit_lookup(&head_obj, repo, target)) < 0) + return error; + + /* Create the new branch */ + if ((error = git_str_printf(&refname, GIT_REFS_HEADS_DIR "%s", name)) < 0) + return error; + + error = git_reference_create(&branch_ref, repo, git_str_cstr(&refname), target, 0, log_message); + git_str_dispose(&refname); + git_commit_free(head_obj); + + if (!error) + *branch = branch_ref; + else + git_reference_free(branch_ref); + + return error; +} + +static int setup_tracking_config( + git_repository *repo, + const char *branch_name, + const char *remote_name, + const char *merge_target) +{ + git_config *cfg; + git_str remote_key = GIT_STR_INIT, merge_key = GIT_STR_INIT; + int error = -1; + + if (git_repository_config__weakptr(&cfg, repo) < 0) + return -1; + + if (git_str_printf(&remote_key, "branch.%s.remote", branch_name) < 0) + goto cleanup; + + if (git_str_printf(&merge_key, "branch.%s.merge", branch_name) < 0) + goto cleanup; + + if (git_config_set_string(cfg, git_str_cstr(&remote_key), remote_name) < 0) + goto cleanup; + + if (git_config_set_string(cfg, git_str_cstr(&merge_key), merge_target) < 0) + goto cleanup; + + error = 0; + +cleanup: + git_str_dispose(&remote_key); + git_str_dispose(&merge_key); + return error; +} + +static int create_tracking_branch( + git_reference **branch, + git_repository *repo, + const git_oid *target, + const char *branch_name, + const char *log_message) +{ + int error; + + if ((error = create_branch(branch, repo, target, branch_name, log_message)) < 0) + return error; + + return setup_tracking_config( + repo, + branch_name, + GIT_REMOTE_ORIGIN, + git_reference_name(*branch)); +} + +static int update_head_to_new_branch( + git_repository *repo, + const git_oid *target, + const char *name, + const char *reflog_message) +{ + git_reference *tracking_branch = NULL; + int error; + + if (!git__prefixcmp(name, GIT_REFS_HEADS_DIR)) + name += strlen(GIT_REFS_HEADS_DIR); + + error = create_tracking_branch(&tracking_branch, repo, target, name, + reflog_message); + + if (!error) + error = git_repository_set_head( + repo, git_reference_name(tracking_branch)); + + git_reference_free(tracking_branch); + + /* if it already existed, then the user's refspec created it for us, ignore it' */ + if (error == GIT_EEXISTS) + error = 0; + + return error; +} + +static int update_head_to_default(git_repository *repo) +{ + git_str initialbranch = GIT_STR_INIT; + const char *branch_name; + int error = 0; + + if ((error = git_repository_initialbranch(&initialbranch, repo)) < 0) + goto done; + + if (git__prefixcmp(initialbranch.ptr, GIT_REFS_HEADS_DIR) != 0) { + git_error_set(GIT_ERROR_INVALID, "invalid initial branch '%s'", initialbranch.ptr); + error = -1; + goto done; + } + + branch_name = initialbranch.ptr + strlen(GIT_REFS_HEADS_DIR); + + error = setup_tracking_config(repo, branch_name, GIT_REMOTE_ORIGIN, + initialbranch.ptr); + +done: + git_str_dispose(&initialbranch); + return error; +} + +static int update_remote_head( + git_repository *repo, + git_remote *remote, + git_str *target, + const char *reflog_message) +{ + git_refspec *refspec; + git_reference *remote_head = NULL; + git_str remote_head_name = GIT_STR_INIT; + git_str remote_branch_name = GIT_STR_INIT; + int error; + + /* Determine the remote tracking ref name from the local branch */ + refspec = git_remote__matching_refspec(remote, git_str_cstr(target)); + + if (refspec == NULL) { + git_error_set(GIT_ERROR_NET, "the remote's default branch does not fit the refspec configuration"); + error = GIT_EINVALIDSPEC; + goto cleanup; + } + + if ((error = git_refspec__transform( + &remote_branch_name, + refspec, + git_str_cstr(target))) < 0) + goto cleanup; + + if ((error = git_str_printf(&remote_head_name, + "%s%s/%s", + GIT_REFS_REMOTES_DIR, + git_remote_name(remote), + GIT_HEAD_FILE)) < 0) + goto cleanup; + + error = git_reference_symbolic_create( + &remote_head, + repo, + git_str_cstr(&remote_head_name), + git_str_cstr(&remote_branch_name), + true, + reflog_message); + +cleanup: + git_reference_free(remote_head); + git_str_dispose(&remote_branch_name); + git_str_dispose(&remote_head_name); + return error; +} + +static int update_head_to_remote( + git_repository *repo, + git_remote *remote, + const char *reflog_message) +{ + int error = 0; + size_t refs_len; + const git_remote_head *remote_head, **refs; + const git_oid *remote_head_id; + git_str branch = GIT_STR_INIT; + + if ((error = git_remote_ls(&refs, &refs_len, remote)) < 0) + return error; + + /* We cloned an empty repository or one with an unborn HEAD */ + if (refs_len == 0 || strcmp(refs[0]->name, GIT_HEAD_FILE)) + return update_head_to_default(repo); + + /* We know we have HEAD, let's see where it points */ + remote_head = refs[0]; + GIT_ASSERT(remote_head); + + remote_head_id = &remote_head->oid; + + error = git_remote__default_branch(&branch, remote); + if (error == GIT_ENOTFOUND) { + error = git_repository_set_head_detached( + repo, remote_head_id); + goto cleanup; + } + + if ((error = update_remote_head(repo, remote, &branch, reflog_message)) < 0) + goto cleanup; + + error = update_head_to_new_branch( + repo, + remote_head_id, + git_str_cstr(&branch), + reflog_message); + +cleanup: + git_str_dispose(&branch); + + return error; +} + +static int update_head_to_branch( + git_repository *repo, + git_remote *remote, + const char *branch, + const char *reflog_message) +{ + int retcode; + git_str remote_branch_name = GIT_STR_INIT; + git_reference *remote_ref = NULL; + git_str default_branch = GIT_STR_INIT; + + GIT_ASSERT_ARG(remote); + GIT_ASSERT_ARG(branch); + + if ((retcode = git_str_printf(&remote_branch_name, GIT_REFS_REMOTES_DIR "%s/%s", + git_remote_name(remote), branch)) < 0 ) + goto cleanup; + + if ((retcode = git_reference_lookup(&remote_ref, repo, git_str_cstr(&remote_branch_name))) < 0) + goto cleanup; + + if ((retcode = update_head_to_new_branch(repo, git_reference_target(remote_ref), branch, + reflog_message)) < 0) + goto cleanup; + + retcode = git_remote__default_branch(&default_branch, remote); + + if (retcode == GIT_ENOTFOUND) + retcode = 0; + else if (retcode) + goto cleanup; + + if (!git_remote__matching_refspec(remote, git_str_cstr(&default_branch))) + goto cleanup; + + retcode = update_remote_head(repo, remote, &default_branch, reflog_message); + +cleanup: + git_reference_free(remote_ref); + git_str_dispose(&remote_branch_name); + git_str_dispose(&default_branch); + return retcode; +} + +static int default_repository_create(git_repository **out, const char *path, int bare, void *payload) +{ + GIT_UNUSED(payload); + + return git_repository_init(out, path, bare); +} + +static int default_remote_create( + git_remote **out, + git_repository *repo, + const char *name, + const char *url, + void *payload) +{ + GIT_UNUSED(payload); + + return git_remote_create(out, repo, name, url); +} + +/* + * submodules? + */ + +static int create_and_configure_origin( + git_remote **out, + git_repository *repo, + const char *url, + const git_clone_options *options) +{ + int error; + git_remote *origin = NULL; + char buf[GIT_PATH_MAX]; + git_remote_create_cb remote_create = options->remote_cb; + void *payload = options->remote_cb_payload; + + /* If the path is local and exists it should be the absolute path. */ + if (!git_net_str_is_url(url) && git_fs_path_root(url) < 0 && + git_fs_path_exists(url)) { + if (p_realpath(url, buf) == NULL) + return -1; + + url = buf; + } + + if (!remote_create) { + remote_create = default_remote_create; + payload = NULL; + } + + if ((error = remote_create(&origin, repo, "origin", url, payload)) < 0) + goto on_error; + + *out = origin; + return 0; + +on_error: + git_remote_free(origin); + return error; +} + +static int should_checkout( + bool *out, + git_repository *repo, + bool is_bare, + const git_checkout_options *opts) +{ + int error; + + if (!opts || is_bare || opts->checkout_strategy == GIT_CHECKOUT_NONE) { + *out = 0; + return 0; + } + + if ((error = git_repository_head_unborn(repo)) < 0) + return error; + + *out = !error; + return 0; +} + +static int checkout_branch(git_repository *repo, git_remote *remote, const git_checkout_options *co_opts, const char *branch, const char *reflog_message) +{ + bool checkout; + int error; + + if (branch) + error = update_head_to_branch(repo, remote, branch, reflog_message); + /* Point HEAD to the same ref as the remote's head */ + else + error = update_head_to_remote(repo, remote, reflog_message); + + if (error < 0) + return error; + + if ((error = should_checkout(&checkout, repo, git_repository_is_bare(repo), co_opts)) < 0) + return error; + + if (checkout) + error = git_checkout_head(repo, co_opts); + + return error; +} + +static int clone_into( + git_repository *repo, + git_remote *_remote, + const git_fetch_options *opts, + const git_checkout_options *co_opts, + const char *branch) +{ + int error; + git_str reflog_message = GIT_STR_INIT; + git_remote_connect_options connect_opts = GIT_REMOTE_CONNECT_OPTIONS_INIT; + git_fetch_options fetch_opts; + git_remote *remote; + git_oid_t oid_type; + + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(_remote); + + if (!git_repository_is_empty(repo)) { + git_error_set(GIT_ERROR_INVALID, "the repository is not empty"); + return -1; + } + + if ((error = git_remote_dup(&remote, _remote)) < 0) + return error; + + memcpy(&fetch_opts, opts, sizeof(git_fetch_options)); + fetch_opts.update_fetchhead = 0; + + if (!opts->depth) + fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL; + + if ((error = git_remote_connect_options__from_fetch_opts(&connect_opts, remote, &fetch_opts)) < 0) + goto cleanup; + + git_str_printf(&reflog_message, "clone: from %s", git_remote_url(remote)); + + /* + * Connect to the server so that we can identify the remote + * object format. + */ + + if ((error = git_remote_connect_ext(remote, GIT_DIRECTION_FETCH, + &connect_opts)) < 0) + goto cleanup; + + if ((error = git_remote_oid_type(&oid_type, remote)) < 0 || + (error = git_repository__set_objectformat(repo, oid_type)) < 0) + goto cleanup; + + if ((error = git_remote_fetch(remote, NULL, &fetch_opts, git_str_cstr(&reflog_message))) != 0) + goto cleanup; + + error = checkout_branch(repo, remote, co_opts, branch, git_str_cstr(&reflog_message)); + +cleanup: + git_remote_free(remote); + git_remote_connect_options_dispose(&connect_opts); + git_str_dispose(&reflog_message); + + return error; +} + +int git_clone__should_clone_local(const char *url_or_path, git_clone_local_t local) +{ + git_str fromurl = GIT_STR_INIT; + bool is_local; + + if (local == GIT_CLONE_NO_LOCAL) + return 0; + + if (git_net_str_is_url(url_or_path)) { + /* If GIT_CLONE_LOCAL_AUTO is specified, any url should be treated as remote */ + if (local == GIT_CLONE_LOCAL_AUTO || + !git_fs_path_is_local_file_url(url_or_path)) + return 0; + + if (git_fs_path_fromurl(&fromurl, url_or_path) == 0) + is_local = git_fs_path_isdir(git_str_cstr(&fromurl)); + else + is_local = -1; + git_str_dispose(&fromurl); + } else { + is_local = git_fs_path_isdir(url_or_path); + } + return is_local; +} + +static int git__clone( + git_repository **out, + const char *url, + const char *local_path, + const git_clone_options *_options, + int use_existing) +{ + int error = 0; + git_repository *repo = NULL; + git_remote *origin; + git_clone_options options = GIT_CLONE_OPTIONS_INIT; + uint32_t rmdir_flags = GIT_RMDIR_REMOVE_FILES; + git_repository_create_cb repository_cb; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(url); + GIT_ASSERT_ARG(local_path); + + if (_options) + memcpy(&options, _options, sizeof(git_clone_options)); + + GIT_ERROR_CHECK_VERSION(&options, GIT_CLONE_OPTIONS_VERSION, "git_clone_options"); + + /* Only clone to a new directory or an empty directory */ + if (git_fs_path_exists(local_path) && !use_existing && !git_fs_path_is_empty_dir(local_path)) { + git_error_set(GIT_ERROR_INVALID, + "'%s' exists and is not an empty directory", local_path); + return GIT_EEXISTS; + } + + /* Only remove the root directory on failure if we create it */ + if (git_fs_path_exists(local_path)) + rmdir_flags |= GIT_RMDIR_SKIP_ROOT; + + if (options.repository_cb) + repository_cb = options.repository_cb; + else + repository_cb = default_repository_create; + + if ((error = repository_cb(&repo, local_path, options.bare, options.repository_cb_payload)) < 0) + return error; + + if (!(error = create_and_configure_origin(&origin, repo, url, &options))) { + int clone_local = git_clone__should_clone_local(url, options.local); + int link = options.local != GIT_CLONE_LOCAL_NO_LINKS; + + if (clone_local == 1) + error = clone_local_into( + repo, origin, &options.fetch_opts, &options.checkout_opts, + options.checkout_branch, link); + else if (clone_local == 0) + error = clone_into( + repo, origin, &options.fetch_opts, &options.checkout_opts, + options.checkout_branch); + else + error = -1; + + git_remote_free(origin); + } + + if (error != 0) { + git_error *last_error; + git_error_save(&last_error); + + git_repository_free(repo); + repo = NULL; + + (void)git_futils_rmdir_r(local_path, NULL, rmdir_flags); + + git_error_restore(last_error); + } + + *out = repo; + return error; +} + +int git_clone( + git_repository **out, + const char *url, + const char *local_path, + const git_clone_options *_options) +{ + return git__clone(out, url, local_path, _options, 0); +} + +int git_clone__submodule( + git_repository **out, + const char *url, + const char *local_path, + const git_clone_options *_options) +{ + return git__clone(out, url, local_path, _options, 1); +} + +int git_clone_options_init(git_clone_options *opts, unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE( + opts, version, git_clone_options, GIT_CLONE_OPTIONS_INIT); + return 0; +} + +#ifndef GIT_DEPRECATE_HARD +int git_clone_init_options(git_clone_options *opts, unsigned int version) +{ + return git_clone_options_init(opts, version); +} +#endif + +static bool can_link(const char *src, const char *dst, int link) +{ +#ifdef GIT_WIN32 + GIT_UNUSED(src); + GIT_UNUSED(dst); + GIT_UNUSED(link); + return false; +#else + + struct stat st_src, st_dst; + + if (!link) + return false; + + if (p_stat(src, &st_src) < 0) + return false; + + if (p_stat(dst, &st_dst) < 0) + return false; + + return st_src.st_dev == st_dst.st_dev; +#endif +} + +static int clone_local_into(git_repository *repo, git_remote *remote, const git_fetch_options *fetch_opts, const git_checkout_options *co_opts, const char *branch, int link) +{ + int error, flags; + git_repository *src; + git_str src_odb = GIT_STR_INIT, dst_odb = GIT_STR_INIT, src_path = GIT_STR_INIT; + git_str reflog_message = GIT_STR_INIT; + + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(remote); + + if (!git_repository_is_empty(repo)) { + git_error_set(GIT_ERROR_INVALID, "the repository is not empty"); + return -1; + } + + /* + * Let's figure out what path we should use for the source + * repo, if it's not rooted, the path should be relative to + * the repository's worktree/gitdir. + */ + if ((error = git_fs_path_from_url_or_path(&src_path, git_remote_url(remote))) < 0) + return error; + + /* Copy .git/objects/ from the source to the target */ + if ((error = git_repository_open(&src, git_str_cstr(&src_path))) < 0) { + git_str_dispose(&src_path); + return error; + } + + if (git_repository__item_path(&src_odb, src, GIT_REPOSITORY_ITEM_OBJECTS) < 0 || + git_repository__item_path(&dst_odb, repo, GIT_REPOSITORY_ITEM_OBJECTS) < 0) { + error = -1; + goto cleanup; + } + + flags = 0; + if (can_link(git_repository_path(src), git_repository_path(repo), link)) + flags |= GIT_CPDIR_LINK_FILES; + + error = git_futils_cp_r(git_str_cstr(&src_odb), git_str_cstr(&dst_odb), + flags, GIT_OBJECT_DIR_MODE); + + /* + * can_link() doesn't catch all variations, so if we hit an + * error and did want to link, let's try again without trying + * to link. + */ + if (error < 0 && link) { + flags &= ~GIT_CPDIR_LINK_FILES; + error = git_futils_cp_r(git_str_cstr(&src_odb), git_str_cstr(&dst_odb), + flags, GIT_OBJECT_DIR_MODE); + } + + if (error < 0) + goto cleanup; + + git_str_printf(&reflog_message, "clone: from %s", git_remote_url(remote)); + + if ((error = git_remote_fetch(remote, NULL, fetch_opts, git_str_cstr(&reflog_message))) != 0) + goto cleanup; + + error = checkout_branch(repo, remote, co_opts, branch, git_str_cstr(&reflog_message)); + +cleanup: + git_str_dispose(&reflog_message); + git_str_dispose(&src_path); + git_str_dispose(&src_odb); + git_str_dispose(&dst_odb); + git_repository_free(src); + return error; +} diff --git a/vendor/libgit2/src/clone.h b/vendor/libgit2/src/libgit2/clone.h similarity index 100% rename from vendor/libgit2/src/clone.h rename to vendor/libgit2/src/libgit2/clone.h diff --git a/vendor/libgit2/src/libgit2/commit.c b/vendor/libgit2/src/libgit2/commit.c new file mode 100644 index 00000000..10df4362 --- /dev/null +++ b/vendor/libgit2/src/libgit2/commit.c @@ -0,0 +1,1191 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "commit.h" + +#include "git2/common.h" +#include "git2/object.h" +#include "git2/repository.h" +#include "git2/signature.h" +#include "git2/mailmap.h" +#include "git2/sys/commit.h" + +#include "buf.h" +#include "odb.h" +#include "commit.h" +#include "signature.h" +#include "refs.h" +#include "object.h" +#include "array.h" +#include "oidarray.h" +#include "grafts.h" + +void git_commit__free(void *_commit) +{ + git_commit *commit = _commit; + + git_array_clear(commit->parent_ids); + + git_signature_free(commit->author); + git_signature_free(commit->committer); + + git__free(commit->raw_header); + git__free(commit->raw_message); + git__free(commit->message_encoding); + git__free(commit->summary); + git__free(commit->body); + + git__free(commit); +} + +static int git_commit__create_buffer_internal( + git_str *out, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_oid *tree, + git_array_oid_t *parents) +{ + size_t i = 0; + const git_oid *parent; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(tree); + + if (git_object__write_oid_header(out, "tree ", tree) < 0) + goto on_error; + + for (i = 0; i < git_array_size(*parents); i++) { + parent = git_array_get(*parents, i); + if (git_object__write_oid_header(out, "parent ", parent) < 0) + goto on_error; + } + + git_signature__writebuf(out, "author ", author); + git_signature__writebuf(out, "committer ", committer); + + if (message_encoding != NULL) + git_str_printf(out, "encoding %s\n", message_encoding); + + git_str_putc(out, '\n'); + + if (git_str_puts(out, message) < 0) + goto on_error; + + return 0; + +on_error: + git_str_dispose(out); + return -1; +} + +static int validate_tree_and_parents(git_array_oid_t *parents, git_repository *repo, const git_oid *tree, + git_commit_parent_callback parent_cb, void *parent_payload, + const git_oid *current_id, bool validate) +{ + size_t i; + int error; + git_oid *parent_cpy; + const git_oid *parent; + + if (validate && !git_object__is_valid(repo, tree, GIT_OBJECT_TREE)) + return -1; + + i = 0; + while ((parent = parent_cb(i, parent_payload)) != NULL) { + if (validate && !git_object__is_valid(repo, parent, GIT_OBJECT_COMMIT)) { + error = -1; + goto on_error; + } + + parent_cpy = git_array_alloc(*parents); + GIT_ERROR_CHECK_ALLOC(parent_cpy); + + git_oid_cpy(parent_cpy, parent); + i++; + } + + if (current_id && (parents->size == 0 || git_oid_cmp(current_id, git_array_get(*parents, 0)))) { + git_error_set(GIT_ERROR_OBJECT, "failed to create commit: current tip is not the first parent"); + error = GIT_EMODIFIED; + goto on_error; + } + + return 0; + +on_error: + git_array_clear(*parents); + return error; +} + +static int git_commit__create_internal( + git_oid *id, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_oid *tree, + git_commit_parent_callback parent_cb, + void *parent_payload, + bool validate) +{ + int error; + git_odb *odb; + git_reference *ref = NULL; + git_str buf = GIT_STR_INIT; + const git_oid *current_id = NULL; + git_array_oid_t parents = GIT_ARRAY_INIT; + + if (update_ref) { + error = git_reference_lookup_resolved(&ref, repo, update_ref, 10); + if (error < 0 && error != GIT_ENOTFOUND) + return error; + } + git_error_clear(); + + if (ref) + current_id = git_reference_target(ref); + + if ((error = validate_tree_and_parents(&parents, repo, tree, parent_cb, parent_payload, current_id, validate)) < 0) + goto cleanup; + + error = git_commit__create_buffer_internal(&buf, author, committer, + message_encoding, message, tree, + &parents); + + if (error < 0) + goto cleanup; + + if (git_repository_odb__weakptr(&odb, repo) < 0) + goto cleanup; + + if (git_odb__freshen(odb, tree) < 0) + goto cleanup; + + if (git_odb_write(id, odb, buf.ptr, buf.size, GIT_OBJECT_COMMIT) < 0) + goto cleanup; + + + if (update_ref != NULL) { + error = git_reference__update_for_commit( + repo, ref, update_ref, id, "commit"); + goto cleanup; + } + +cleanup: + git_array_clear(parents); + git_reference_free(ref); + git_str_dispose(&buf); + return error; +} + +int git_commit_create_from_callback( + git_oid *id, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_oid *tree, + git_commit_parent_callback parent_cb, + void *parent_payload) +{ + return git_commit__create_internal( + id, repo, update_ref, author, committer, message_encoding, message, + tree, parent_cb, parent_payload, true); +} + +typedef struct { + size_t total; + va_list args; +} commit_parent_varargs; + +static const git_oid *commit_parent_from_varargs(size_t curr, void *payload) +{ + commit_parent_varargs *data = payload; + const git_commit *commit; + if (curr >= data->total) + return NULL; + commit = va_arg(data->args, const git_commit *); + return commit ? git_commit_id(commit) : NULL; +} + +int git_commit_create_v( + git_oid *id, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_tree *tree, + size_t parent_count, + ...) +{ + int error = 0; + commit_parent_varargs data; + + GIT_ASSERT_ARG(tree); + GIT_ASSERT_ARG(git_tree_owner(tree) == repo); + + data.total = parent_count; + va_start(data.args, parent_count); + + error = git_commit__create_internal( + id, repo, update_ref, author, committer, + message_encoding, message, git_tree_id(tree), + commit_parent_from_varargs, &data, false); + + va_end(data.args); + return error; +} + +typedef struct { + size_t total; + const git_oid **parents; +} commit_parent_oids; + +static const git_oid *commit_parent_from_ids(size_t curr, void *payload) +{ + commit_parent_oids *data = payload; + return (curr < data->total) ? data->parents[curr] : NULL; +} + +int git_commit_create_from_ids( + git_oid *id, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_oid *tree, + size_t parent_count, + const git_oid *parents[]) +{ + commit_parent_oids data = { parent_count, parents }; + + return git_commit__create_internal( + id, repo, update_ref, author, committer, + message_encoding, message, tree, + commit_parent_from_ids, &data, true); +} + +typedef struct { + size_t total; + const git_commit **parents; + git_repository *repo; +} commit_parent_data; + +static const git_oid *commit_parent_from_array(size_t curr, void *payload) +{ + commit_parent_data *data = payload; + const git_commit *commit; + if (curr >= data->total) + return NULL; + commit = data->parents[curr]; + if (git_commit_owner(commit) != data->repo) + return NULL; + return git_commit_id(commit); +} + +int git_commit_create( + git_oid *id, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_tree *tree, + size_t parent_count, + const git_commit *parents[]) +{ + commit_parent_data data = { parent_count, parents, repo }; + + GIT_ASSERT_ARG(tree); + GIT_ASSERT_ARG(git_tree_owner(tree) == repo); + + return git_commit__create_internal( + id, repo, update_ref, author, committer, + message_encoding, message, git_tree_id(tree), + commit_parent_from_array, &data, false); +} + +static const git_oid *commit_parent_for_amend(size_t curr, void *payload) +{ + const git_commit *commit_to_amend = payload; + if (curr >= git_array_size(commit_to_amend->parent_ids)) + return NULL; + return git_array_get(commit_to_amend->parent_ids, curr); +} + +int git_commit_amend( + git_oid *id, + const git_commit *commit_to_amend, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_tree *tree) +{ + git_repository *repo; + git_oid tree_id; + git_reference *ref; + int error; + + GIT_ASSERT_ARG(id); + GIT_ASSERT_ARG(commit_to_amend); + + repo = git_commit_owner(commit_to_amend); + + if (!author) + author = git_commit_author(commit_to_amend); + if (!committer) + committer = git_commit_committer(commit_to_amend); + if (!message_encoding) + message_encoding = git_commit_message_encoding(commit_to_amend); + if (!message) + message = git_commit_message(commit_to_amend); + + if (!tree) { + git_tree *old_tree; + GIT_ERROR_CHECK_ERROR( git_commit_tree(&old_tree, commit_to_amend) ); + git_oid_cpy(&tree_id, git_tree_id(old_tree)); + git_tree_free(old_tree); + } else { + GIT_ASSERT_ARG(git_tree_owner(tree) == repo); + git_oid_cpy(&tree_id, git_tree_id(tree)); + } + + if (update_ref) { + if ((error = git_reference_lookup_resolved(&ref, repo, update_ref, 5)) < 0) + return error; + + if (git_oid_cmp(git_commit_id(commit_to_amend), git_reference_target(ref))) { + git_reference_free(ref); + git_error_set(GIT_ERROR_REFERENCE, "commit to amend is not the tip of the given branch"); + return -1; + } + } + + error = git_commit__create_internal( + id, repo, NULL, author, committer, message_encoding, message, + &tree_id, commit_parent_for_amend, (void *)commit_to_amend, false); + + if (!error && update_ref) { + error = git_reference__update_for_commit( + repo, ref, NULL, id, "commit"); + git_reference_free(ref); + } + + return error; +} + +static int commit_parse( + git_commit *commit, + const char *data, + size_t size, + git_commit__parse_options *opts) +{ + const char *buffer_start = data, *buffer; + const char *buffer_end = buffer_start + size; + git_oid parent_id; + size_t header_len; + git_signature dummy_sig; + int error; + + GIT_ASSERT_ARG(commit); + GIT_ASSERT_ARG(data); + GIT_ASSERT_ARG(opts); + + buffer = buffer_start; + + /* Allocate for one, which will allow not to realloc 90% of the time */ + git_array_init_to_size(commit->parent_ids, 1); + GIT_ERROR_CHECK_ARRAY(commit->parent_ids); + + /* The tree is always the first field */ + if (!(opts->flags & GIT_COMMIT_PARSE_QUICK)) { + if (git_object__parse_oid_header(&commit->tree_id, + &buffer, buffer_end, "tree ", + opts->oid_type) < 0) + goto bad_buffer; + } else { + size_t tree_len = strlen("tree ") + git_oid_hexsize(opts->oid_type) + 1; + + if (buffer + tree_len > buffer_end) + goto bad_buffer; + buffer += tree_len; + } + + while (git_object__parse_oid_header(&parent_id, + &buffer, buffer_end, "parent ", + opts->oid_type) == 0) { + git_oid *new_id = git_array_alloc(commit->parent_ids); + GIT_ERROR_CHECK_ALLOC(new_id); + + git_oid_cpy(new_id, &parent_id); + } + + if (!opts || !(opts->flags & GIT_COMMIT_PARSE_QUICK)) { + commit->author = git__malloc(sizeof(git_signature)); + GIT_ERROR_CHECK_ALLOC(commit->author); + + if ((error = git_signature__parse(commit->author, &buffer, buffer_end, "author ", '\n')) < 0) + return error; + } + + /* Some tools create multiple author fields, ignore the extra ones */ + while (!git__prefixncmp(buffer, buffer_end - buffer, "author ")) { + if ((error = git_signature__parse(&dummy_sig, &buffer, buffer_end, "author ", '\n')) < 0) + return error; + + git__free(dummy_sig.name); + git__free(dummy_sig.email); + } + + /* Always parse the committer; we need the commit time */ + commit->committer = git__malloc(sizeof(git_signature)); + GIT_ERROR_CHECK_ALLOC(commit->committer); + + if ((error = git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n')) < 0) + return error; + + if (opts && opts->flags & GIT_COMMIT_PARSE_QUICK) + return 0; + + /* Parse add'l header entries */ + while (buffer < buffer_end) { + const char *eoln = buffer; + if (buffer[-1] == '\n' && buffer[0] == '\n') + break; + + while (eoln < buffer_end && *eoln != '\n') + ++eoln; + + if (git__prefixncmp(buffer, buffer_end - buffer, "encoding ") == 0) { + buffer += strlen("encoding "); + + commit->message_encoding = git__strndup(buffer, eoln - buffer); + GIT_ERROR_CHECK_ALLOC(commit->message_encoding); + } + + if (eoln < buffer_end && *eoln == '\n') + ++eoln; + buffer = eoln; + } + + header_len = buffer - buffer_start; + commit->raw_header = git__strndup(buffer_start, header_len); + GIT_ERROR_CHECK_ALLOC(commit->raw_header); + + /* point "buffer" to data after header, +1 for the final LF */ + buffer = buffer_start + header_len + 1; + + /* extract commit message */ + if (buffer <= buffer_end) + commit->raw_message = git__strndup(buffer, buffer_end - buffer); + else + commit->raw_message = git__strdup(""); + GIT_ERROR_CHECK_ALLOC(commit->raw_message); + + return 0; + +bad_buffer: + git_error_set(GIT_ERROR_OBJECT, "failed to parse bad commit object"); + return GIT_EINVALID; +} + +int git_commit__parse( + void *commit, + git_odb_object *odb_obj, + git_oid_t oid_type) +{ + git_commit__parse_options parse_options = {0}; + parse_options.oid_type = oid_type; + + return git_commit__parse_ext(commit, odb_obj, &parse_options); +} + +int git_commit__parse_raw( + void *commit, + const char *data, + size_t size, + git_oid_t oid_type) +{ + git_commit__parse_options parse_options = {0}; + parse_options.oid_type = oid_type; + + return commit_parse(commit, data, size, &parse_options); +} + +static int assign_commit_parents_from_graft(git_commit *commit, git_commit_graft *graft) { + size_t idx; + git_oid *oid; + + git_array_clear(commit->parent_ids); + git_array_init_to_size(commit->parent_ids, git_array_size(graft->parents)); + git_array_foreach(graft->parents, idx, oid) { + git_oid *id = git_array_alloc(commit->parent_ids); + GIT_ERROR_CHECK_ALLOC(id); + + git_oid_cpy(id, oid); + } + + return 0; +} + +int git_commit__parse_ext( + git_commit *commit, + git_odb_object *odb_obj, + git_commit__parse_options *parse_opts) +{ + git_repository *repo = git_object_owner((git_object *)commit); + git_commit_graft *graft; + int error; + + if ((error = commit_parse(commit, git_odb_object_data(odb_obj), + git_odb_object_size(odb_obj), parse_opts)) < 0) + return error; + + /* Perform necessary grafts */ + if (git_grafts_get(&graft, repo->grafts, git_odb_object_id(odb_obj)) != 0 && + git_grafts_get(&graft, repo->shallow_grafts, git_odb_object_id(odb_obj)) != 0) + return 0; + + return assign_commit_parents_from_graft(commit, graft); +} + +#define GIT_COMMIT_GETTER(_rvalue, _name, _return, _invalid) \ + _rvalue git_commit_##_name(const git_commit *commit) \ + {\ + GIT_ASSERT_ARG_WITH_RETVAL(commit, _invalid); \ + return _return; \ + } + +GIT_COMMIT_GETTER(const git_signature *, author, commit->author, NULL) +GIT_COMMIT_GETTER(const git_signature *, committer, commit->committer, NULL) +GIT_COMMIT_GETTER(const char *, message_raw, commit->raw_message, NULL) +GIT_COMMIT_GETTER(const char *, message_encoding, commit->message_encoding, NULL) +GIT_COMMIT_GETTER(const char *, raw_header, commit->raw_header, NULL) +GIT_COMMIT_GETTER(git_time_t, time, commit->committer->when.time, INT64_MIN) +GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset, -1) +GIT_COMMIT_GETTER(unsigned int, parentcount, (unsigned int)git_array_size(commit->parent_ids), 0) +GIT_COMMIT_GETTER(const git_oid *, tree_id, &commit->tree_id, NULL) + +const char *git_commit_message(const git_commit *commit) +{ + const char *message; + + GIT_ASSERT_ARG_WITH_RETVAL(commit, NULL); + + message = commit->raw_message; + + /* trim leading newlines from raw message */ + while (*message && *message == '\n') + ++message; + + return message; +} + +const char *git_commit_summary(git_commit *commit) +{ + git_str summary = GIT_STR_INIT; + const char *msg, *space, *next; + bool space_contains_newline = false; + + GIT_ASSERT_ARG_WITH_RETVAL(commit, NULL); + + if (!commit->summary) { + for (msg = git_commit_message(commit), space = NULL; *msg; ++msg) { + char next_character = msg[0]; + /* stop processing at the end of the first paragraph */ + if (next_character == '\n') { + if (!msg[1]) + break; + if (msg[1] == '\n') + break; + /* stop processing if next line contains only whitespace */ + next = msg + 1; + while (*next && git__isspace_nonlf(*next)) { + ++next; + } + if (!*next || *next == '\n') + break; + } + /* record the beginning of contiguous whitespace runs */ + if (git__isspace(next_character)) { + if(space == NULL) { + space = msg; + space_contains_newline = false; + } + space_contains_newline |= next_character == '\n'; + } + /* the next character is non-space */ + else { + /* process any recorded whitespace */ + if (space) { + if(space_contains_newline) + git_str_putc(&summary, ' '); /* if the space contains a newline, collapse to ' ' */ + else + git_str_put(&summary, space, (msg - space)); /* otherwise copy it */ + space = NULL; + } + /* copy the next character */ + git_str_putc(&summary, next_character); + } + } + + commit->summary = git_str_detach(&summary); + if (!commit->summary) + commit->summary = git__strdup(""); + } + + return commit->summary; +} + +const char *git_commit_body(git_commit *commit) +{ + const char *msg, *end; + + GIT_ASSERT_ARG_WITH_RETVAL(commit, NULL); + + if (!commit->body) { + /* search for end of summary */ + for (msg = git_commit_message(commit); *msg; ++msg) + if (msg[0] == '\n' && (!msg[1] || msg[1] == '\n')) + break; + + /* trim leading and trailing whitespace */ + for (; *msg; ++msg) + if (!git__isspace(*msg)) + break; + for (end = msg + strlen(msg) - 1; msg <= end; --end) + if (!git__isspace(*end)) + break; + + if (*msg) + commit->body = git__strndup(msg, end - msg + 1); + } + + return commit->body; +} + +int git_commit_tree(git_tree **tree_out, const git_commit *commit) +{ + GIT_ASSERT_ARG(commit); + return git_tree_lookup(tree_out, commit->object.repo, &commit->tree_id); +} + +const git_oid *git_commit_parent_id( + const git_commit *commit, unsigned int n) +{ + GIT_ASSERT_ARG_WITH_RETVAL(commit, NULL); + + return git_array_get(commit->parent_ids, n); +} + +int git_commit_parent( + git_commit **parent, const git_commit *commit, unsigned int n) +{ + const git_oid *parent_id; + GIT_ASSERT_ARG(commit); + + parent_id = git_commit_parent_id(commit, n); + if (parent_id == NULL) { + git_error_set(GIT_ERROR_INVALID, "parent %u does not exist", n); + return GIT_ENOTFOUND; + } + + return git_commit_lookup(parent, commit->object.repo, parent_id); +} + +int git_commit_nth_gen_ancestor( + git_commit **ancestor, + const git_commit *commit, + unsigned int n) +{ + git_commit *current, *parent = NULL; + int error; + + GIT_ASSERT_ARG(ancestor); + GIT_ASSERT_ARG(commit); + + if (git_commit_dup(¤t, (git_commit *)commit) < 0) + return -1; + + if (n == 0) { + *ancestor = current; + return 0; + } + + while (n--) { + error = git_commit_parent(&parent, current, 0); + + git_commit_free(current); + + if (error < 0) + return error; + + current = parent; + } + + *ancestor = parent; + return 0; +} + +int git_commit_header_field( + git_buf *out, + const git_commit *commit, + const char *field) +{ + GIT_BUF_WRAP_PRIVATE(out, git_commit__header_field, commit, field); +} + +int git_commit__header_field( + git_str *out, + const git_commit *commit, + const char *field) +{ + const char *eol, *buf = commit->raw_header; + + git_str_clear(out); + + while ((eol = strchr(buf, '\n'))) { + /* We can skip continuations here */ + if (buf[0] == ' ') { + buf = eol + 1; + continue; + } + + /* Skip until we find the field we're after */ + if (git__prefixcmp(buf, field)) { + buf = eol + 1; + continue; + } + + buf += strlen(field); + /* Check that we're not matching a prefix but the field itself */ + if (buf[0] != ' ') { + buf = eol + 1; + continue; + } + + buf++; /* skip the SP */ + + git_str_put(out, buf, eol - buf); + if (git_str_oom(out)) + goto oom; + + /* If the next line starts with SP, it's multi-line, we must continue */ + while (eol[1] == ' ') { + git_str_putc(out, '\n'); + buf = eol + 2; + eol = strchr(buf, '\n'); + if (!eol) + goto malformed; + + git_str_put(out, buf, eol - buf); + } + + if (git_str_oom(out)) + goto oom; + + return 0; + } + + git_error_set(GIT_ERROR_OBJECT, "no such field '%s'", field); + return GIT_ENOTFOUND; + +malformed: + git_error_set(GIT_ERROR_OBJECT, "malformed header"); + return -1; +oom: + git_error_set_oom(); + return -1; +} + +int git_commit_extract_signature( + git_buf *signature_out, + git_buf *signed_data_out, + git_repository *repo, + git_oid *commit_id, + const char *field) +{ + git_str signature = GIT_STR_INIT, signed_data = GIT_STR_INIT; + int error; + + if ((error = git_buf_tostr(&signature, signature_out)) < 0 || + (error = git_buf_tostr(&signed_data, signed_data_out)) < 0 || + (error = git_commit__extract_signature(&signature, &signed_data, repo, commit_id, field)) < 0 || + (error = git_buf_fromstr(signature_out, &signature)) < 0 || + (error = git_buf_fromstr(signed_data_out, &signed_data)) < 0) + goto done; + +done: + git_str_dispose(&signature); + git_str_dispose(&signed_data); + return error; +} + +int git_commit__extract_signature( + git_str *signature, + git_str *signed_data, + git_repository *repo, + git_oid *commit_id, + const char *field) +{ + git_odb_object *obj; + git_odb *odb; + const char *buf; + const char *h, *eol; + int error; + + git_str_clear(signature); + git_str_clear(signed_data); + + if (!field) + field = "gpgsig"; + + if ((error = git_repository_odb__weakptr(&odb, repo)) < 0) + return error; + + if ((error = git_odb_read(&obj, odb, commit_id)) < 0) + return error; + + if (obj->cached.type != GIT_OBJECT_COMMIT) { + git_error_set(GIT_ERROR_INVALID, "the requested type does not match the type in the ODB"); + error = GIT_ENOTFOUND; + goto cleanup; + } + + buf = git_odb_object_data(obj); + + while ((h = strchr(buf, '\n')) && h[1] != '\0') { + h++; + if (git__prefixcmp(buf, field)) { + if (git_str_put(signed_data, buf, h - buf) < 0) + return -1; + + buf = h; + continue; + } + + h = buf; + h += strlen(field); + eol = strchr(h, '\n'); + if (h[0] != ' ') { + buf = h; + continue; + } + if (!eol) + goto malformed; + + h++; /* skip the SP */ + + git_str_put(signature, h, eol - h); + if (git_str_oom(signature)) + goto oom; + + /* If the next line starts with SP, it's multi-line, we must continue */ + while (eol[1] == ' ') { + git_str_putc(signature, '\n'); + h = eol + 2; + eol = strchr(h, '\n'); + if (!eol) + goto malformed; + + git_str_put(signature, h, eol - h); + } + + if (git_str_oom(signature)) + goto oom; + + error = git_str_puts(signed_data, eol+1); + git_odb_object_free(obj); + return error; + } + + git_error_set(GIT_ERROR_OBJECT, "this commit is not signed"); + error = GIT_ENOTFOUND; + goto cleanup; + +malformed: + git_error_set(GIT_ERROR_OBJECT, "malformed header"); + error = -1; + goto cleanup; +oom: + git_error_set_oom(); + error = -1; + goto cleanup; + +cleanup: + git_odb_object_free(obj); + git_str_clear(signature); + git_str_clear(signed_data); + return error; +} + +int git_commit_create_buffer( + git_buf *out, + git_repository *repo, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_tree *tree, + size_t parent_count, + const git_commit *parents[]) +{ + GIT_BUF_WRAP_PRIVATE(out, git_commit__create_buffer, repo, + author, committer, message_encoding, message, + tree, parent_count, parents); +} + +int git_commit__create_buffer( + git_str *out, + git_repository *repo, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_tree *tree, + size_t parent_count, + const git_commit *parents[]) +{ + int error; + commit_parent_data data = { parent_count, parents, repo }; + git_array_oid_t parents_arr = GIT_ARRAY_INIT; + const git_oid *tree_id; + + GIT_ASSERT_ARG(tree); + GIT_ASSERT_ARG(git_tree_owner(tree) == repo); + + tree_id = git_tree_id(tree); + + if ((error = validate_tree_and_parents(&parents_arr, repo, tree_id, commit_parent_from_array, &data, NULL, true)) < 0) + return error; + + error = git_commit__create_buffer_internal( + out, author, committer, + message_encoding, message, tree_id, + &parents_arr); + + git_array_clear(parents_arr); + return error; +} + +/** + * Append to 'out' properly marking continuations when there's a newline in 'content' + */ +static int format_header_field(git_str *out, const char *field, const char *content) +{ + const char *lf; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(field); + GIT_ASSERT_ARG(content); + + git_str_puts(out, field); + git_str_putc(out, ' '); + + while ((lf = strchr(content, '\n')) != NULL) { + git_str_put(out, content, lf - content); + git_str_puts(out, "\n "); + content = lf + 1; + } + + git_str_puts(out, content); + git_str_putc(out, '\n'); + + return git_str_oom(out) ? -1 : 0; +} + +static const git_oid *commit_parent_from_commit(size_t n, void *payload) +{ + const git_commit *commit = (const git_commit *) payload; + + return git_array_get(commit->parent_ids, n); + +} + +int git_commit_create_with_signature( + git_oid *out, + git_repository *repo, + const char *commit_content, + const char *signature, + const char *signature_field) +{ + git_odb *odb; + int error = 0; + const char *field; + const char *header_end; + git_str commit = GIT_STR_INIT; + git_commit *parsed; + git_array_oid_t parents = GIT_ARRAY_INIT; + git_commit__parse_options parse_opts = {0}; + + parse_opts.oid_type = repo->oid_type; + + /* The first step is to verify that all the tree and parents exist */ + parsed = git__calloc(1, sizeof(git_commit)); + GIT_ERROR_CHECK_ALLOC(parsed); + if (commit_parse(parsed, commit_content, strlen(commit_content), &parse_opts) < 0) { + error = -1; + goto cleanup; + } + + if ((error = validate_tree_and_parents(&parents, repo, &parsed->tree_id, commit_parent_from_commit, parsed, NULL, true)) < 0) + goto cleanup; + + git_array_clear(parents); + + /* Then we start appending by identifying the end of the commit header */ + header_end = strstr(commit_content, "\n\n"); + if (!header_end) { + git_error_set(GIT_ERROR_INVALID, "malformed commit contents"); + error = -1; + goto cleanup; + } + + /* The header ends after the first LF */ + header_end++; + git_str_put(&commit, commit_content, header_end - commit_content); + + if (signature != NULL) { + field = signature_field ? signature_field : "gpgsig"; + + if ((error = format_header_field(&commit, field, signature)) < 0) + goto cleanup; + } + + git_str_puts(&commit, header_end); + + if (git_str_oom(&commit)) + return -1; + + if ((error = git_repository_odb__weakptr(&odb, repo)) < 0) + goto cleanup; + + if ((error = git_odb_write(out, odb, commit.ptr, commit.size, GIT_OBJECT_COMMIT)) < 0) + goto cleanup; + +cleanup: + git_commit__free(parsed); + git_str_dispose(&commit); + return error; +} + +int git_commit_create_from_stage( + git_oid *out, + git_repository *repo, + const char *message, + const git_commit_create_options *given_opts) +{ + git_commit_create_options opts = GIT_COMMIT_CREATE_OPTIONS_INIT; + git_signature *default_signature = NULL; + const git_signature *author, *committer; + git_index *index = NULL; + git_diff *diff = NULL; + git_oid tree_id; + git_tree *head_tree = NULL, *tree = NULL; + git_commitarray parents = { 0 }; + int error = -1; + + GIT_ASSERT_ARG(out && repo); + + if (given_opts) + memcpy(&opts, given_opts, sizeof(git_commit_create_options)); + + author = opts.author; + committer = opts.committer; + + if (!author || !committer) { + if (git_signature_default(&default_signature, repo) < 0) + goto done; + + if (!author) + author = default_signature; + + if (!committer) + committer = default_signature; + } + + if (git_repository_index(&index, repo) < 0) + goto done; + + if (!opts.allow_empty_commit) { + error = git_repository_head_tree(&head_tree, repo); + + if (error && error != GIT_EUNBORNBRANCH) + goto done; + + error = -1; + + if (git_diff_tree_to_index(&diff, repo, head_tree, index, NULL) < 0) + goto done; + + if (git_diff_num_deltas(diff) == 0) { + git_error_set(GIT_ERROR_REPOSITORY, + "no changes are staged for commit"); + error = GIT_EUNCHANGED; + goto done; + } + } + + if (git_index_write_tree(&tree_id, index) < 0 || + git_tree_lookup(&tree, repo, &tree_id) < 0 || + git_repository_commit_parents(&parents, repo) < 0) + goto done; + + error = git_commit_create(out, repo, "HEAD", author, committer, + opts.message_encoding, message, + tree, parents.count, + (const git_commit **)parents.commits); + +done: + git_commitarray_dispose(&parents); + git_signature_free(default_signature); + git_tree_free(tree); + git_tree_free(head_tree); + git_diff_free(diff); + git_index_free(index); + return error; +} + +int git_commit_committer_with_mailmap( + git_signature **out, const git_commit *commit, const git_mailmap *mailmap) +{ + return git_mailmap_resolve_signature(out, mailmap, commit->committer); +} + +int git_commit_author_with_mailmap( + git_signature **out, const git_commit *commit, const git_mailmap *mailmap) +{ + return git_mailmap_resolve_signature(out, mailmap, commit->author); +} + +void git_commitarray_dispose(git_commitarray *array) +{ + size_t i; + + if (array == NULL) + return; + + for (i = 0; i < array->count; i++) + git_commit_free(array->commits[i]); + + git__free((git_commit **)array->commits); + + memset(array, 0, sizeof(*array)); +} diff --git a/vendor/libgit2/src/libgit2/commit.h b/vendor/libgit2/src/libgit2/commit.h new file mode 100644 index 00000000..c25fee32 --- /dev/null +++ b/vendor/libgit2/src/libgit2/commit.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_commit_h__ +#define INCLUDE_commit_h__ + +#include "common.h" + +#include "git2/commit.h" +#include "tree.h" +#include "repository.h" +#include "array.h" + +#include + +struct git_commit { + git_object object; + + git_array_t(git_oid) parent_ids; + git_oid tree_id; + + git_signature *author; + git_signature *committer; + + char *message_encoding; + char *raw_message; + char *raw_header; + + char *summary; + char *body; +}; + +typedef struct { + git_oid_t oid_type; + unsigned int flags; +} git_commit__parse_options; + +typedef enum { + /** Only parse parents and committer info */ + GIT_COMMIT_PARSE_QUICK = (1 << 0) +} git_commit__parse_flags; + +int git_commit__header_field( + git_str *out, + const git_commit *commit, + const char *field); + +int git_commit__extract_signature( + git_str *signature, + git_str *signed_data, + git_repository *repo, + git_oid *commit_id, + const char *field); + +int git_commit__create_buffer( + git_str *out, + git_repository *repo, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_tree *tree, + size_t parent_count, + const git_commit *parents[]); + +int git_commit__parse( + void *commit, + git_odb_object *obj, + git_oid_t oid_type); + +int git_commit__parse_raw( + void *commit, + const char *data, + size_t size, + git_oid_t oid_type); + +int git_commit__parse_ext( + git_commit *commit, + git_odb_object *odb_obj, + git_commit__parse_options *parse_opts); + +void git_commit__free(void *commit); + +#endif diff --git a/vendor/libgit2/src/commit_graph.c b/vendor/libgit2/src/libgit2/commit_graph.c similarity index 87% rename from vendor/libgit2/src/commit_graph.c rename to vendor/libgit2/src/libgit2/commit_graph.c index 70e866b9..4edd7110 100644 --- a/vendor/libgit2/src/commit_graph.c +++ b/vendor/libgit2/src/libgit2/commit_graph.c @@ -138,19 +138,22 @@ static int commit_graph_parse_oid_lookup( struct git_commit_graph_chunk *chunk_oid_lookup) { uint32_t i; - git_oid *oid, *prev_oid, zero_oid = {{0}}; + unsigned char *oid, *prev_oid, zero_oid[GIT_OID_MAX_SIZE] = {0}; + size_t oid_size; + + oid_size = git_oid_size(file->oid_type); if (chunk_oid_lookup->offset == 0) return commit_graph_error("missing OID Lookup chunk"); if (chunk_oid_lookup->length == 0) return commit_graph_error("empty OID Lookup chunk"); - if (chunk_oid_lookup->length != file->num_commits * GIT_OID_RAWSZ) + if (chunk_oid_lookup->length != file->num_commits * oid_size) return commit_graph_error("OID Lookup chunk has wrong length"); - file->oid_lookup = oid = (git_oid *)(data + chunk_oid_lookup->offset); - prev_oid = &zero_oid; - for (i = 0; i < file->num_commits; ++i, ++oid) { - if (git_oid_cmp(prev_oid, oid) >= 0) + file->oid_lookup = oid = (unsigned char *)(data + chunk_oid_lookup->offset); + prev_oid = zero_oid; + for (i = 0; i < file->num_commits; ++i, oid += oid_size) { + if (git_oid_raw_cmp(prev_oid, oid, oid_size) >= 0) return commit_graph_error("OID Lookup index is non-monotonic"); prev_oid = oid; } @@ -163,11 +166,13 @@ static int commit_graph_parse_commit_data( const unsigned char *data, struct git_commit_graph_chunk *chunk_commit_data) { + size_t oid_size = git_oid_size(file->oid_type); + if (chunk_commit_data->offset == 0) return commit_graph_error("missing Commit Data chunk"); if (chunk_commit_data->length == 0) return commit_graph_error("empty Commit Data chunk"); - if (chunk_commit_data->length != file->num_commits * (GIT_OID_RAWSZ + 16)) + if (chunk_commit_data->length != file->num_commits * (oid_size + 16)) return commit_graph_error("Commit Data chunk has wrong length"); file->commit_data = data + chunk_commit_data->offset; @@ -200,8 +205,7 @@ int git_commit_graph_file_parse( const unsigned char *chunk_hdr; struct git_commit_graph_chunk *last_chunk; uint32_t i; - off64_t last_chunk_offset, chunk_offset, trailer_offset; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; + uint64_t last_chunk_offset, chunk_offset, trailer_offset; size_t checksum_size; int error; struct git_commit_graph_chunk chunk_oid_fanout = {0}, chunk_oid_lookup = {0}, @@ -210,7 +214,9 @@ int git_commit_graph_file_parse( GIT_ASSERT_ARG(file); - if (size < sizeof(struct git_commit_graph_header) + GIT_OID_RAWSZ) + checksum_size = git_oid_size(file->oid_type); + + if (size < sizeof(struct git_commit_graph_header) + checksum_size) return commit_graph_error("commit-graph is too short"); hdr = ((struct git_commit_graph_header *)data); @@ -227,23 +233,17 @@ int git_commit_graph_file_parse( * headers, and a special zero chunk. */ last_chunk_offset = sizeof(struct git_commit_graph_header) + (1 + hdr->chunks) * 12; - trailer_offset = size - GIT_OID_RAWSZ; - checksum_size = GIT_HASH_SHA1_SIZE; + trailer_offset = size - checksum_size; if (trailer_offset < last_chunk_offset) return commit_graph_error("wrong commit-graph size"); memcpy(file->checksum, (data + trailer_offset), checksum_size); - if (git_hash_buf(checksum, data, (size_t)trailer_offset, GIT_HASH_ALGORITHM_SHA1) < 0) - return commit_graph_error("could not calculate signature"); - if (memcmp(checksum, file->checksum, checksum_size) != 0) - return commit_graph_error("index signature mismatch"); - chunk_hdr = data + sizeof(struct git_commit_graph_header); last_chunk = NULL; for (i = 0; i < hdr->chunks; ++i, chunk_hdr += 12) { - chunk_offset = ((off64_t)ntohl(*((uint32_t *)(chunk_hdr + 4)))) << 32 - | ((off64_t)ntohl(*((uint32_t *)(chunk_hdr + 8)))); + chunk_offset = ((uint64_t)ntohl(*((uint32_t *)(chunk_hdr + 4)))) << 32 + | ((uint64_t)ntohl(*((uint32_t *)(chunk_hdr + 8)))); if (chunk_offset < last_chunk_offset) return commit_graph_error("chunks are non-monotonic"); if (chunk_offset >= trailer_offset) @@ -301,25 +301,35 @@ int git_commit_graph_file_parse( return 0; } -int git_commit_graph_new(git_commit_graph **cgraph_out, const char *objects_dir, bool open_file) +int git_commit_graph_new( + git_commit_graph **cgraph_out, + const char *objects_dir, + bool open_file, + git_oid_t oid_type) { git_commit_graph *cgraph = NULL; int error = 0; GIT_ASSERT_ARG(cgraph_out); GIT_ASSERT_ARG(objects_dir); + GIT_ASSERT_ARG(oid_type); cgraph = git__calloc(1, sizeof(git_commit_graph)); GIT_ERROR_CHECK_ALLOC(cgraph); + cgraph->oid_type = oid_type; + error = git_str_joinpath(&cgraph->filename, objects_dir, "info/commit-graph"); if (error < 0) goto error; if (open_file) { - error = git_commit_graph_file_open(&cgraph->file, git_str_cstr(&cgraph->filename)); + error = git_commit_graph_file_open(&cgraph->file, + git_str_cstr(&cgraph->filename), oid_type); + if (error < 0) goto error; + cgraph->checked = 1; } @@ -331,12 +341,52 @@ int git_commit_graph_new(git_commit_graph **cgraph_out, const char *objects_dir, return error; } -int git_commit_graph_open(git_commit_graph **cgraph_out, const char *objects_dir) +int git_commit_graph_validate(git_commit_graph *cgraph) { + unsigned char checksum[GIT_HASH_MAX_SIZE]; + git_hash_algorithm_t checksum_type; + size_t checksum_size, trailer_offset; + + checksum_type = git_oid_algorithm(cgraph->oid_type); + checksum_size = git_hash_size(checksum_type); + trailer_offset = cgraph->file->graph_map.len - checksum_size; + + if (cgraph->file->graph_map.len < checksum_size) + return commit_graph_error("map length too small"); + + if (git_hash_buf(checksum, cgraph->file->graph_map.data, trailer_offset, checksum_type) < 0) + return commit_graph_error("could not calculate signature"); + if (memcmp(checksum, cgraph->file->checksum, checksum_size) != 0) + return commit_graph_error("index signature mismatch"); + + return 0; +} + +int git_commit_graph_open( + git_commit_graph **cgraph_out, + const char *objects_dir +#ifdef GIT_EXPERIMENTAL_SHA256 + , git_oid_t oid_type +#endif + ) { - return git_commit_graph_new(cgraph_out, objects_dir, true); +#ifndef GIT_EXPERIMENTAL_SHA256 + git_oid_t oid_type = GIT_OID_SHA1; +#endif + int error; + + error = git_commit_graph_new(cgraph_out, objects_dir, true, + oid_type); + + if (!error) + return git_commit_graph_validate(*cgraph_out); + + return error; } -int git_commit_graph_file_open(git_commit_graph_file **file_out, const char *path) +int git_commit_graph_file_open( + git_commit_graph_file **file_out, + const char *path, + git_oid_t oid_type) { git_commit_graph_file *file; git_file fd = -1; @@ -365,6 +415,8 @@ int git_commit_graph_file_open(git_commit_graph_file **file_out, const char *pat file = git__calloc(1, sizeof(git_commit_graph_file)); GIT_ERROR_CHECK_ALLOC(file); + file->oid_type = oid_type; + error = git_futils_mmap_ro(&file->graph_map, fd, 0, cgraph_size); p_close(fd); if (error < 0) { @@ -381,7 +433,9 @@ int git_commit_graph_file_open(git_commit_graph_file **file_out, const char *pat return 0; } -int git_commit_graph_get_file(git_commit_graph_file **file_out, git_commit_graph *cgraph) +int git_commit_graph_get_file( + git_commit_graph_file **file_out, + git_commit_graph *cgraph) { if (!cgraph->checked) { int error = 0; @@ -391,7 +445,8 @@ int git_commit_graph_get_file(git_commit_graph_file **file_out, git_commit_graph cgraph->checked = 1; /* Best effort */ - error = git_commit_graph_file_open(&result, git_str_cstr(&cgraph->filename)); + error = git_commit_graph_file_open(&result, + git_str_cstr(&cgraph->filename), cgraph->oid_type); if (error < 0) return error; @@ -427,6 +482,7 @@ static int git_commit_graph_entry_get_byindex( size_t pos) { const unsigned char *commit_data; + size_t oid_size = git_oid_size(file->oid_type); GIT_ASSERT_ARG(e); GIT_ASSERT_ARG(file); @@ -436,15 +492,15 @@ static int git_commit_graph_entry_get_byindex( return GIT_ENOTFOUND; } - commit_data = file->commit_data + pos * (GIT_OID_RAWSZ + 4 * sizeof(uint32_t)); - git_oid_cpy(&e->tree_oid, (const git_oid *)commit_data); - e->parent_indices[0] = ntohl(*((uint32_t *)(commit_data + GIT_OID_RAWSZ))); + commit_data = file->commit_data + pos * (oid_size + 4 * sizeof(uint32_t)); + git_oid__fromraw(&e->tree_oid, commit_data, file->oid_type); + e->parent_indices[0] = ntohl(*((uint32_t *)(commit_data + oid_size))); e->parent_indices[1] = ntohl( - *((uint32_t *)(commit_data + GIT_OID_RAWSZ + sizeof(uint32_t)))); + *((uint32_t *)(commit_data + oid_size + sizeof(uint32_t)))); e->parent_count = (e->parent_indices[0] != GIT_COMMIT_GRAPH_MISSING_PARENT) + (e->parent_indices[1] != GIT_COMMIT_GRAPH_MISSING_PARENT); - e->generation = ntohl(*((uint32_t *)(commit_data + GIT_OID_RAWSZ + 2 * sizeof(uint32_t)))); - e->commit_time = ntohl(*((uint32_t *)(commit_data + GIT_OID_RAWSZ + 3 * sizeof(uint32_t)))); + e->generation = ntohl(*((uint32_t *)(commit_data + oid_size + 2 * sizeof(uint32_t)))); + e->commit_time = ntohl(*((uint32_t *)(commit_data + oid_size + 3 * sizeof(uint32_t)))); e->commit_time |= (e->generation & UINT64_C(0x3)) << UINT64_C(32); e->generation >>= 2u; @@ -470,7 +526,8 @@ static int git_commit_graph_entry_get_byindex( e->parent_count++; } } - git_oid_cpy(&e->sha1, &file->oid_lookup[pos]); + + git_oid__fromraw(&e->sha1, &file->oid_lookup[pos * oid_size], file->oid_type); return 0; } @@ -479,8 +536,8 @@ bool git_commit_graph_file_needs_refresh(const git_commit_graph_file *file, cons git_file fd = -1; struct stat st; ssize_t bytes_read; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; - size_t checksum_size = GIT_HASH_SHA1_SIZE; + unsigned char checksum[GIT_HASH_MAX_SIZE]; + size_t checksum_size = git_oid_size(file->oid_type); /* TODO: properly open the file without access time using O_NOATIME */ fd = git_futils_open_ro(path); @@ -514,40 +571,44 @@ int git_commit_graph_entry_find( { int pos, found = 0; uint32_t hi, lo; - const git_oid *current = NULL; + const unsigned char *current = NULL; + size_t oid_size, oid_hexsize; GIT_ASSERT_ARG(e); GIT_ASSERT_ARG(file); GIT_ASSERT_ARG(short_oid); + oid_size = git_oid_size(file->oid_type); + oid_hexsize = git_oid_hexsize(file->oid_type); + hi = ntohl(file->oid_fanout[(int)short_oid->id[0]]); lo = ((short_oid->id[0] == 0x0) ? 0 : ntohl(file->oid_fanout[(int)short_oid->id[0] - 1])); - pos = git_pack__lookup_sha1(file->oid_lookup, GIT_OID_RAWSZ, lo, hi, short_oid->id); + pos = git_pack__lookup_id(file->oid_lookup, oid_size, lo, hi, + short_oid->id, file->oid_type); if (pos >= 0) { /* An object matching exactly the oid was found */ found = 1; - current = file->oid_lookup + pos; + current = file->oid_lookup + (pos * oid_size); } else { /* No object was found */ /* pos refers to the object with the "closest" oid to short_oid */ pos = -1 - pos; if (pos < (int)file->num_commits) { - current = file->oid_lookup + pos; + current = file->oid_lookup + (pos * oid_size); - if (!git_oid_ncmp(short_oid, current, len)) + if (!git_oid_raw_ncmp(short_oid->id, current, len)) found = 1; } } - if (found && len != GIT_OID_HEXSZ && pos + 1 < (int)file->num_commits) { + if (found && len != oid_hexsize && pos + 1 < (int)file->num_commits) { /* Check for ambiguousity */ - const git_oid *next = current + 1; + const unsigned char *next = current + oid_size; - if (!git_oid_ncmp(short_oid, next, len)) { + if (!git_oid_raw_ncmp(short_oid->id, next, len)) found = 2; - } } if (!found) @@ -623,11 +684,27 @@ static int packed_commit__cmp(const void *a_, const void *b_) return git_oid_cmp(&a->sha1, &b->sha1); } -int git_commit_graph_writer_new(git_commit_graph_writer **out, const char *objects_info_dir) +int git_commit_graph_writer_new( + git_commit_graph_writer **out, + const char *objects_info_dir +#ifdef GIT_EXPERIMENTAL_SHA256 + , git_oid_t oid_type +#endif + ) { - git_commit_graph_writer *w = git__calloc(1, sizeof(git_commit_graph_writer)); + git_commit_graph_writer *w; + +#ifndef GIT_EXPERIMENTAL_SHA256 + git_oid_t oid_type = GIT_OID_SHA1; +#endif + + GIT_ASSERT_ARG(out && objects_info_dir && oid_type); + + w = git__calloc(1, sizeof(git_commit_graph_writer)); GIT_ERROR_CHECK_ALLOC(w); + w->oid_type = oid_type; + if (git_str_sets(&w->objects_info_dir, objects_info_dir) < 0) { git__free(w); return -1; @@ -712,7 +789,8 @@ int git_commit_graph_writer_add_index_file( if (error < 0) goto cleanup; - error = git_mwindow_get_pack(&p, idx_path); + /* TODO: SHA256 */ + error = git_mwindow_get_pack(&p, idx_path, 0); if (error < 0) goto cleanup; @@ -978,8 +1056,9 @@ static int commit_graph_write( off64_t offset; git_str oid_lookup = GIT_STR_INIT, commit_data = GIT_STR_INIT, extra_edge_list = GIT_STR_INIT; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; - size_t checksum_size; + unsigned char checksum[GIT_HASH_MAX_SIZE]; + git_hash_algorithm_t checksum_type; + size_t checksum_size, oid_size; git_hash_ctx ctx; struct commit_graph_write_hash_context hash_cb_data = {0}; @@ -992,8 +1071,11 @@ static int commit_graph_write( hash_cb_data.cb_data = cb_data; hash_cb_data.ctx = &ctx; - checksum_size = GIT_HASH_SHA1_SIZE; - error = git_hash_ctx_init(&ctx, GIT_HASH_ALGORITHM_SHA1); + oid_size = git_oid_size(w->oid_type); + checksum_type = git_oid_algorithm(w->oid_type); + checksum_size = git_hash_size(checksum_type); + + error = git_hash_ctx_init(&ctx, checksum_type); if (error < 0) return error; cb_data = &hash_cb_data; @@ -1019,7 +1101,9 @@ static int commit_graph_write( /* Fill the OID Lookup table. */ git_vector_foreach (&w->commits, i, packed_commit) { error = git_str_put(&oid_lookup, - (const char *)&packed_commit->sha1, sizeof(git_oid)); + (const char *)&packed_commit->sha1.id, + oid_size); + if (error < 0) goto cleanup; } @@ -1034,8 +1118,9 @@ static int commit_graph_write( unsigned int parentcount = (unsigned int)git_array_size(packed_commit->parents); error = git_str_put(&commit_data, - (const char *)&packed_commit->tree_oid, - sizeof(git_oid)); + (const char *)&packed_commit->tree_oid.id, + oid_size); + if (error < 0) goto cleanup; diff --git a/vendor/libgit2/src/commit_graph.h b/vendor/libgit2/src/libgit2/commit_graph.h similarity index 87% rename from vendor/libgit2/src/commit_graph.h rename to vendor/libgit2/src/libgit2/commit_graph.h index 45e125b9..ecf4379b 100644 --- a/vendor/libgit2/src/commit_graph.h +++ b/vendor/libgit2/src/libgit2/commit_graph.h @@ -30,13 +30,16 @@ typedef struct git_commit_graph_file { git_map graph_map; + /* The type of object IDs in the commit graph file. */ + git_oid_t oid_type; + /* The OID Fanout table. */ const uint32_t *oid_fanout; /* The total number of commits in the graph. */ uint32_t num_commits; /* The OID Lookup table. */ - git_oid *oid_lookup; + unsigned char *oid_lookup; /* * The Commit Data table. Each entry contains the OID of the commit followed @@ -84,10 +87,10 @@ typedef struct git_commit_graph_entry { /* The index within the Extra Edge List of any parent after the first two. */ size_t extra_parents_index; - /* The SHA-1 hash of the root tree of the commit. */ + /* The object ID of the root tree of the commit. */ git_oid tree_oid; - /* The SHA-1 hash of the requested commit. */ + /* The object ID hash of the requested commit. */ git_oid sha1; } git_commit_graph_entry; @@ -99,15 +102,28 @@ struct git_commit_graph { /* The underlying commit-graph file. */ git_commit_graph_file *file; + /* The object ID types in the commit graph. */ + git_oid_t oid_type; + /* Whether the commit-graph file was already checked for validity. */ bool checked; }; /** Create a new commit-graph, optionally opening the underlying file. */ -int git_commit_graph_new(git_commit_graph **cgraph_out, const char *objects_dir, bool open_file); +int git_commit_graph_new( + git_commit_graph **cgraph_out, + const char *objects_dir, + bool open_file, + git_oid_t oid_type); + +/** Validate the checksum of a commit graph */ +int git_commit_graph_validate(git_commit_graph *cgraph); /** Open and validate a commit-graph file. */ -int git_commit_graph_file_open(git_commit_graph_file **file_out, const char *path); +int git_commit_graph_file_open( + git_commit_graph_file **file_out, + const char *path, + git_oid_t oid_type); /* * Attempt to get the git_commit_graph's commit-graph file. This object is @@ -131,6 +147,9 @@ struct git_commit_graph_writer { */ git_str objects_info_dir; + /* The object ID type of the commit graph. */ + git_oid_t oid_type; + /* The list of packed commits. */ git_vector commits; }; diff --git a/vendor/libgit2/src/commit_list.c b/vendor/libgit2/src/libgit2/commit_list.c similarity index 91% rename from vendor/libgit2/src/commit_list.c rename to vendor/libgit2/src/libgit2/commit_list.c index 4585508b..7f00c483 100644 --- a/vendor/libgit2/src/commit_list.c +++ b/vendor/libgit2/src/libgit2/commit_list.c @@ -43,13 +43,18 @@ int git_commit_list_time_cmp(const void *a, const void *b) return 0; } -git_commit_list *git_commit_list_insert(git_commit_list_node *item, git_commit_list **list_p) -{ +git_commit_list *git_commit_list_create(git_commit_list_node *item, git_commit_list *next) { git_commit_list *new_list = git__malloc(sizeof(git_commit_list)); if (new_list != NULL) { new_list->item = item; - new_list->next = *list_p; + new_list->next = next; } + return new_list; +} + +git_commit_list *git_commit_list_insert(git_commit_list_node *item, git_commit_list **list_p) +{ + git_commit_list *new_list = git_commit_list_create(item, *list_p); *list_p = new_list; return new_list; } @@ -124,13 +129,17 @@ static int commit_quick_parse( { git_oid *parent_oid; git_commit *commit; + git_commit__parse_options parse_opts = { + walk->repo->oid_type, + GIT_COMMIT_PARSE_QUICK + }; size_t i; commit = git__calloc(1, sizeof(*commit)); GIT_ERROR_CHECK_ALLOC(commit); commit->object.repo = walk->repo; - if (git_commit__parse_ext(commit, obj, GIT_COMMIT_PARSE_QUICK) < 0) { + if (git_commit__parse_ext(commit, obj, &parse_opts) < 0) { git__free(commit); return -1; } @@ -172,7 +181,9 @@ int git_commit_list_parse(git_revwalk *walk, git_commit_list_node *commit) if (cgraph_file) { git_commit_graph_entry e; - error = git_commit_graph_entry_find(&e, cgraph_file, &commit->oid, GIT_OID_RAWSZ); + error = git_commit_graph_entry_find(&e, cgraph_file, + &commit->oid, git_oid_size(walk->repo->oid_type)); + if (error == 0 && git__is_uint16(e.parent_count)) { size_t i; commit->generation = (uint32_t)e.generation; diff --git a/vendor/libgit2/src/commit_list.h b/vendor/libgit2/src/libgit2/commit_list.h similarity index 94% rename from vendor/libgit2/src/commit_list.h rename to vendor/libgit2/src/libgit2/commit_list.h index aad39f35..e2dbd2aa 100644 --- a/vendor/libgit2/src/commit_list.h +++ b/vendor/libgit2/src/libgit2/commit_list.h @@ -49,6 +49,7 @@ git_commit_list_node *git_commit_list_alloc_node(git_revwalk *walk); int git_commit_list_generation_cmp(const void *a, const void *b); int git_commit_list_time_cmp(const void *a, const void *b); void git_commit_list_free(git_commit_list **list_p); +git_commit_list *git_commit_list_create(git_commit_list_node *item, git_commit_list *next); git_commit_list *git_commit_list_insert(git_commit_list_node *item, git_commit_list **list_p); git_commit_list *git_commit_list_insert_by_date(git_commit_list_node *item, git_commit_list **list_p); int git_commit_list_parse(git_revwalk *walk, git_commit_list_node *commit); diff --git a/vendor/libgit2/src/libgit2/common.h b/vendor/libgit2/src/libgit2/common.h new file mode 100644 index 00000000..bb9ec5ac --- /dev/null +++ b/vendor/libgit2/src/libgit2/common.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_common_h__ +#define INCLUDE_common_h__ + +#include "git2_util.h" +#include "errors.h" + +/* +* Include the declarations for deprecated functions; this ensures +* that they're decorated with the proper extern/visibility attributes. +*/ +#include "git2/deprecated.h" + +#include "posix.h" + +/** + * Initialize a structure with a version. + */ +GIT_INLINE(void) git__init_structure(void *structure, size_t len, unsigned int version) +{ + memset(structure, 0, len); + *((int*)structure) = version; +} +#define GIT_INIT_STRUCTURE(S,V) git__init_structure(S, sizeof(*S), V) + +#define GIT_INIT_STRUCTURE_FROM_TEMPLATE(PTR,VERSION,TYPE,TPL) do { \ + TYPE _tmpl = TPL; \ + GIT_ERROR_CHECK_VERSION(&(VERSION), _tmpl.version, #TYPE); \ + memcpy((PTR), &_tmpl, sizeof(_tmpl)); } while (0) + +/** + * Check a versioned structure for validity + */ +GIT_INLINE(int) git_error__check_version(const void *structure, unsigned int expected_max, const char *name) +{ + unsigned int actual; + + if (!structure) + return 0; + + actual = *(const unsigned int*)structure; + if (actual > 0 && actual <= expected_max) + return 0; + + git_error_set(GIT_ERROR_INVALID, "invalid version %d on %s", actual, name); + return -1; +} +#define GIT_ERROR_CHECK_VERSION(S,V,N) if (git_error__check_version(S,V,N) < 0) return -1 + +#endif diff --git a/vendor/libgit2/src/libgit2/config.c b/vendor/libgit2/src/libgit2/config.c new file mode 100644 index 00000000..1e4e1759 --- /dev/null +++ b/vendor/libgit2/src/libgit2/config.c @@ -0,0 +1,1641 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "config.h" + +#include "git2/config.h" +#include "git2/sys/config.h" + +#include "buf.h" +#include "config_backend.h" +#include "regexp.h" +#include "sysdir.h" +#include "transaction.h" +#include "vector.h" +#if GIT_WIN32 +# include +#endif + +#include + +/* + * A refcounted instance of a config_backend that can be shared across + * a configuration instance, any snapshots, and individual configuration + * levels (from `git_config_open_level`). + */ +typedef struct { + git_refcount rc; + git_config_backend *backend; +} backend_instance; + +/* + * An entry in the readers or writers vector in the configuration. + * This is kept separate from the refcounted instance so that different + * views of the configuration can have different notions of levels or + * write orders. + * + * (eg, a standard configuration has a priority ordering of writers, a + * snapshot has *no* writers, and an individual level has a single + * writer.) + */ +typedef struct { + backend_instance *instance; + git_config_level_t level; + int write_order; +} backend_entry; + +void git_config_entry_free(git_config_entry *entry) +{ + if (!entry) + return; + + entry->free(entry); +} + +static void backend_instance_free(backend_instance *instance) +{ + git_config_backend *backend; + + backend = instance->backend; + backend->free(backend); + git__free(instance); +} + +static void config_free(git_config *config) +{ + size_t i; + backend_entry *entry; + + git_vector_foreach(&config->readers, i, entry) { + GIT_REFCOUNT_DEC(entry->instance, backend_instance_free); + git__free(entry); + } + + git_vector_free(&config->readers); + git_vector_free(&config->writers); + git__free(config); +} + +void git_config_free(git_config *config) +{ + if (config == NULL) + return; + + GIT_REFCOUNT_DEC(config, config_free); +} + +static int reader_cmp(const void *_a, const void *_b) +{ + const backend_entry *a = _a; + const backend_entry *b = _b; + + return b->level - a->level; +} + +static int writer_cmp(const void *_a, const void *_b) +{ + const backend_entry *a = _a; + const backend_entry *b = _b; + + return b->write_order - a->write_order; +} + +int git_config_new(git_config **out) +{ + git_config *config; + + config = git__calloc(1, sizeof(git_config)); + GIT_ERROR_CHECK_ALLOC(config); + + if (git_vector_init(&config->readers, 8, reader_cmp) < 0 || + git_vector_init(&config->writers, 8, writer_cmp) < 0) { + config_free(config); + return -1; + } + + GIT_REFCOUNT_INC(config); + + *out = config; + return 0; +} + +int git_config_add_file_ondisk( + git_config *config, + const char *path, + git_config_level_t level, + const git_repository *repo, + int force) +{ + git_config_backend *file = NULL; + struct stat st; + int res; + + GIT_ASSERT_ARG(config); + GIT_ASSERT_ARG(path); + + res = p_stat(path, &st); + if (res < 0 && errno != ENOENT && errno != ENOTDIR) { + git_error_set(GIT_ERROR_CONFIG, "failed to stat '%s'", path); + return -1; + } + + if (git_config_backend_from_file(&file, path) < 0) + return -1; + + if ((res = git_config_add_backend(config, file, level, repo, force)) < 0) { + /* + * free manually; the file is not owned by the config + * instance yet and will not be freed on cleanup + */ + file->free(file); + return res; + } + + return 0; +} + +int git_config_open_ondisk(git_config **out, const char *path) +{ + int error; + git_config *config; + + *out = NULL; + + if (git_config_new(&config) < 0) + return -1; + + if ((error = git_config_add_file_ondisk(config, path, GIT_CONFIG_LEVEL_LOCAL, NULL, 0)) < 0) + git_config_free(config); + else + *out = config; + + return error; +} + +int git_config_snapshot(git_config **out, git_config *in) +{ + int error = 0; + size_t i; + backend_entry *entry; + git_config *config; + + *out = NULL; + + if (git_config_new(&config) < 0) + return -1; + + git_vector_foreach(&in->readers, i, entry) { + git_config_backend *b; + + if ((error = entry->instance->backend->snapshot(&b, entry->instance->backend)) < 0) + break; + + if ((error = git_config_add_backend(config, b, entry->level, NULL, 0)) < 0) { + b->free(b); + break; + } + } + + git_config_set_writeorder(config, NULL, 0); + + if (error < 0) + git_config_free(config); + else + *out = config; + + return error; +} + +static int find_backend_by_level( + backend_instance **out, + const git_config *config, + git_config_level_t level) +{ + backend_entry *entry, *found = NULL; + size_t i; + + /* + * when passing GIT_CONFIG_HIGHEST_LEVEL, the idea is to get the + * config backend which has the highest level. As config backends + * are stored in a vector sorted by decreasing order of level, + * getting the backend at position 0 will do the job. + */ + if (level == GIT_CONFIG_HIGHEST_LEVEL) { + found = git_vector_get(&config->readers, 0); + } else { + git_vector_foreach(&config->readers, i, entry) { + if (entry->level == level) { + found = entry; + break; + } + } + } + + if (!found) { + git_error_set(GIT_ERROR_CONFIG, + "no configuration exists for the given level '%d'", level); + return GIT_ENOTFOUND; + } + + *out = found->instance; + return 0; +} + +static int duplicate_level(void **_old, void *_new) +{ + backend_entry **old = (backend_entry **)_old; + + GIT_UNUSED(_new); + + git_error_set(GIT_ERROR_CONFIG, "configuration at level %d already exists", (*old)->level); + return GIT_EEXISTS; +} + +static void try_remove_existing_backend( + git_config *config, + git_config_level_t level) +{ + backend_entry *entry, *found = NULL; + size_t i; + + git_vector_foreach(&config->readers, i, entry) { + if (entry->level == level) { + git_vector_remove(&config->readers, i); + found = entry; + break; + } + } + + if (!found) + return; + + git_vector_foreach(&config->writers, i, entry) { + if (entry->level == level) { + git_vector_remove(&config->writers, i); + break; + } + } + + GIT_REFCOUNT_DEC(found->instance, backend_instance_free); + git__free(found); +} + +static int git_config__add_instance( + git_config *config, + backend_instance *instance, + git_config_level_t level, + int force) +{ + backend_entry *entry; + int result; + + /* delete existing config backend for level if it exists */ + if (force) + try_remove_existing_backend(config, level); + + entry = git__malloc(sizeof(backend_entry)); + GIT_ERROR_CHECK_ALLOC(entry); + + entry->instance = instance; + entry->level = level; + entry->write_order = level; + + if ((result = git_vector_insert_sorted(&config->readers, + entry, &duplicate_level)) < 0 || + (result = git_vector_insert_sorted(&config->writers, + entry, NULL)) < 0) { + git__free(entry); + return result; + } + + GIT_REFCOUNT_INC(entry->instance); + + return 0; +} + +int git_config_open_global(git_config **out, git_config *config) +{ + int error; + + error = git_config_open_level(out, config, GIT_CONFIG_LEVEL_XDG); + + if (error == 0) + return 0; + else if (error != GIT_ENOTFOUND) + return error; + + return git_config_open_level(out, config, GIT_CONFIG_LEVEL_GLOBAL); +} + +int git_config_open_level( + git_config **out, + const git_config *parent, + git_config_level_t level) +{ + git_config *config; + backend_instance *instance; + int res; + + if ((res = find_backend_by_level(&instance, parent, level)) < 0) + return res; + + if ((res = git_config_new(&config)) < 0) + return res; + + if ((res = git_config__add_instance(config, instance, level, true)) < 0) { + git_config_free(config); + return res; + } + + *out = config; + + return 0; +} + +int git_config_add_backend( + git_config *config, + git_config_backend *backend, + git_config_level_t level, + const git_repository *repo, + int force) +{ + backend_instance *instance; + int result; + + GIT_ASSERT_ARG(config); + GIT_ASSERT_ARG(backend); + + GIT_ERROR_CHECK_VERSION(backend, GIT_CONFIG_BACKEND_VERSION, "git_config_backend"); + + if ((result = backend->open(backend, level, repo)) < 0) + return result; + + instance = git__calloc(1, sizeof(backend_instance)); + GIT_ERROR_CHECK_ALLOC(instance); + + instance->backend = backend; + instance->backend->cfg = config; + + if ((result = git_config__add_instance(config, instance, level, force)) < 0) { + git__free(instance); + return result; + } + + return 0; +} + +int git_config_set_writeorder( + git_config *config, + git_config_level_t *levels, + size_t len) +{ + backend_entry *entry; + size_t i, j; + + GIT_ASSERT(len < INT_MAX); + + git_vector_foreach(&config->readers, i, entry) { + bool found = false; + + for (j = 0; j < len; j++) { + if (levels[j] == entry->level) { + entry->write_order = (int)j; + found = true; + break; + } + } + + if (!found) + entry->write_order = -1; + } + + git_vector_sort(&config->writers); + + return 0; +} + +/* + * Loop over all the variables + */ + +typedef struct { + git_config_iterator parent; + git_config_iterator *current; + const git_config *config; + git_regexp regex; + size_t i; +} all_iter; + +static int all_iter_next(git_config_entry **out, git_config_iterator *_iter) +{ + all_iter *iter = (all_iter *) _iter; + backend_entry *entry; + git_config_backend *backend; + int error = 0; + + if (iter->current != NULL && + (error = iter->current->next(out, iter->current)) == 0) { + return 0; + } + + if (error < 0 && error != GIT_ITEROVER) + return error; + + do { + if (iter->i == 0) + return GIT_ITEROVER; + + entry = git_vector_get(&iter->config->readers, iter->i - 1); + GIT_ASSERT(entry && entry->instance && entry->instance->backend); + + backend = entry->instance->backend; + iter->i--; + + if (iter->current) + iter->current->free(iter->current); + + iter->current = NULL; + error = backend->iterator(&iter->current, backend); + if (error == GIT_ENOTFOUND) + continue; + + if (error < 0) + return error; + + error = iter->current->next(out, iter->current); + /* If this backend is empty, then keep going */ + if (error == GIT_ITEROVER) + continue; + + return error; + + } while(1); + + return GIT_ITEROVER; +} + +static int all_iter_glob_next(git_config_entry **entry, git_config_iterator *_iter) +{ + int error; + all_iter *iter = (all_iter *) _iter; + + /* + * We use the "normal" function to grab the next one across + * readers and then apply the regex + */ + while ((error = all_iter_next(entry, _iter)) == 0) { + /* skip non-matching keys if regexp was provided */ + if (git_regexp_match(&iter->regex, (*entry)->name) != 0) + continue; + + /* and simply return if we like the entry's name */ + return 0; + } + + return error; +} + +static void all_iter_free(git_config_iterator *_iter) +{ + all_iter *iter = (all_iter *) _iter; + + if (iter->current) + iter->current->free(iter->current); + + git__free(iter); +} + +static void all_iter_glob_free(git_config_iterator *_iter) +{ + all_iter *iter = (all_iter *) _iter; + + git_regexp_dispose(&iter->regex); + all_iter_free(_iter); +} + +int git_config_iterator_new(git_config_iterator **out, const git_config *config) +{ + all_iter *iter; + + iter = git__calloc(1, sizeof(all_iter)); + GIT_ERROR_CHECK_ALLOC(iter); + + iter->parent.free = all_iter_free; + iter->parent.next = all_iter_next; + + iter->i = config->readers.length; + iter->config = config; + + *out = (git_config_iterator *) iter; + + return 0; +} + +int git_config_iterator_glob_new(git_config_iterator **out, const git_config *config, const char *regexp) +{ + all_iter *iter; + int result; + + if (regexp == NULL) + return git_config_iterator_new(out, config); + + iter = git__calloc(1, sizeof(all_iter)); + GIT_ERROR_CHECK_ALLOC(iter); + + if ((result = git_regexp_compile(&iter->regex, regexp, 0)) < 0) { + git__free(iter); + return -1; + } + + iter->parent.next = all_iter_glob_next; + iter->parent.free = all_iter_glob_free; + iter->i = config->readers.length; + iter->config = config; + + *out = (git_config_iterator *) iter; + + return 0; +} + +int git_config_foreach( + const git_config *config, git_config_foreach_cb cb, void *payload) +{ + return git_config_foreach_match(config, NULL, cb, payload); +} + +int git_config_backend_foreach_match( + git_config_backend *backend, + const char *regexp, + git_config_foreach_cb cb, + void *payload) +{ + git_config_entry *entry; + git_config_iterator *iter; + git_regexp regex; + int error = 0; + + GIT_ASSERT_ARG(backend); + GIT_ASSERT_ARG(cb); + + if (regexp && git_regexp_compile(®ex, regexp, 0) < 0) + return -1; + + if ((error = backend->iterator(&iter, backend)) < 0) { + iter = NULL; + return -1; + } + + while (!(iter->next(&entry, iter) < 0)) { + /* skip non-matching keys if regexp was provided */ + if (regexp && git_regexp_match(®ex, entry->name) != 0) + continue; + + /* abort iterator on non-zero return value */ + if ((error = cb(entry, payload)) != 0) { + git_error_set_after_callback(error); + break; + } + } + + if (regexp != NULL) + git_regexp_dispose(®ex); + + iter->free(iter); + + return error; +} + +int git_config_foreach_match( + const git_config *config, + const char *regexp, + git_config_foreach_cb cb, + void *payload) +{ + int error; + git_config_iterator *iter; + git_config_entry *entry; + + if ((error = git_config_iterator_glob_new(&iter, config, regexp)) < 0) + return error; + + while (!(error = git_config_next(&entry, iter))) { + if ((error = cb(entry, payload)) != 0) { + git_error_set_after_callback(error); + break; + } + } + + git_config_iterator_free(iter); + + if (error == GIT_ITEROVER) + error = 0; + + return error; +} + +/************** + * Setters + **************/ + + static backend_instance *get_writer_instance(git_config *config) + { + backend_entry *entry; + size_t i; + + git_vector_foreach(&config->writers, i, entry) { + if (entry->instance->backend->readonly) + continue; + + if (entry->write_order < 0) + continue; + + return entry->instance; + } + + return NULL; + } + +static git_config_backend *get_writer(git_config *config) +{ + backend_instance *instance = get_writer_instance(config); + + return instance ? instance->backend : NULL; +} + +int git_config_delete_entry(git_config *config, const char *name) +{ + git_config_backend *backend; + + if ((backend = get_writer(config)) == NULL) + return GIT_EREADONLY; + + return backend->del(backend, name); +} + +int git_config_set_int64(git_config *config, const char *name, int64_t value) +{ + char str_value[32]; /* All numbers should fit in here */ + p_snprintf(str_value, sizeof(str_value), "%" PRId64, value); + return git_config_set_string(config, name, str_value); +} + +int git_config_set_int32(git_config *config, const char *name, int32_t value) +{ + return git_config_set_int64(config, name, (int64_t)value); +} + +int git_config_set_bool(git_config *config, const char *name, int value) +{ + return git_config_set_string(config, name, value ? "true" : "false"); +} + +int git_config_set_string(git_config *config, const char *name, const char *value) +{ + int error; + git_config_backend *backend; + + if (!value) { + git_error_set(GIT_ERROR_CONFIG, "the value to set cannot be NULL"); + return -1; + } + + if ((backend = get_writer(config)) == NULL) { + git_error_set(GIT_ERROR_CONFIG, "cannot set '%s': the configuration is read-only", name); + return GIT_EREADONLY; + } + + error = backend->set(backend, name, value); + + if (!error && GIT_REFCOUNT_OWNER(config) != NULL) + git_repository__configmap_lookup_cache_clear(GIT_REFCOUNT_OWNER(config)); + + return error; +} + +int git_config__update_entry( + git_config *config, + const char *key, + const char *value, + bool overwrite_existing, + bool only_if_existing) +{ + int error = 0; + git_config_entry *ce = NULL; + + if ((error = git_config__lookup_entry(&ce, config, key, false)) < 0) + return error; + + if (!ce && only_if_existing) /* entry doesn't exist */ + return 0; + if (ce && !overwrite_existing) /* entry would be overwritten */ + return 0; + if (value && ce && ce->value && !strcmp(ce->value, value)) /* no change */ + return 0; + if (!value && (!ce || !ce->value)) /* asked to delete absent entry */ + return 0; + + if (!value) + error = git_config_delete_entry(config, key); + else + error = git_config_set_string(config, key, value); + + git_config_entry_free(ce); + return error; +} + +/*********** + * Getters + ***********/ + +static int config_error_notfound(const char *name) +{ + git_error_set(GIT_ERROR_CONFIG, "config value '%s' was not found", name); + return GIT_ENOTFOUND; +} + +enum { + GET_ALL_ERRORS = 0, + GET_NO_MISSING = 1, + GET_NO_ERRORS = 2 +}; + +static int get_entry( + git_config_entry **out, + const git_config *config, + const char *name, + bool normalize_name, + int want_errors) +{ + backend_entry *entry; + git_config_backend *backend; + int res = GIT_ENOTFOUND; + const char *key = name; + char *normalized = NULL; + size_t i; + + *out = NULL; + + if (normalize_name) { + if ((res = git_config__normalize_name(name, &normalized)) < 0) + goto cleanup; + key = normalized; + } + + res = GIT_ENOTFOUND; + git_vector_foreach(&config->readers, i, entry) { + GIT_ASSERT(entry->instance && entry->instance->backend); + + backend = entry->instance->backend; + res = backend->get(backend, key, out); + + if (res != GIT_ENOTFOUND) + break; + } + + git__free(normalized); + +cleanup: + if (res == GIT_ENOTFOUND) { + res = (want_errors > GET_ALL_ERRORS) ? 0 : config_error_notfound(name); + } else if (res && (want_errors == GET_NO_ERRORS)) { + git_error_clear(); + res = 0; + } + + return res; +} + +int git_config_get_entry( + git_config_entry **out, const git_config *config, const char *name) +{ + return get_entry(out, config, name, true, GET_ALL_ERRORS); +} + +int git_config__lookup_entry( + git_config_entry **out, + const git_config *config, + const char *key, + bool no_errors) +{ + return get_entry( + out, config, key, false, no_errors ? GET_NO_ERRORS : GET_NO_MISSING); +} + +int git_config_get_mapped( + int *out, + const git_config *config, + const char *name, + const git_configmap *maps, + size_t map_n) +{ + git_config_entry *entry; + int ret; + + if ((ret = get_entry(&entry, config, name, true, GET_ALL_ERRORS)) < 0) + return ret; + + ret = git_config_lookup_map_value(out, maps, map_n, entry->value); + git_config_entry_free(entry); + + return ret; +} + +int git_config_get_int64(int64_t *out, const git_config *config, const char *name) +{ + git_config_entry *entry; + int ret; + + if ((ret = get_entry(&entry, config, name, true, GET_ALL_ERRORS)) < 0) + return ret; + + ret = git_config_parse_int64(out, entry->value); + git_config_entry_free(entry); + + return ret; +} + +int git_config_get_int32(int32_t *out, const git_config *config, const char *name) +{ + git_config_entry *entry; + int ret; + + if ((ret = get_entry(&entry, config, name, true, GET_ALL_ERRORS)) < 0) + return ret; + + ret = git_config_parse_int32(out, entry->value); + git_config_entry_free(entry); + + return ret; +} + +int git_config_get_bool(int *out, const git_config *config, const char *name) +{ + git_config_entry *entry; + int ret; + + if ((ret = get_entry(&entry, config, name, true, GET_ALL_ERRORS)) < 0) + return ret; + + ret = git_config_parse_bool(out, entry->value); + git_config_entry_free(entry); + + return ret; +} + +static int is_readonly(const git_config *config) +{ + backend_entry *entry; + size_t i; + + git_vector_foreach(&config->writers, i, entry) { + GIT_ASSERT(entry->instance && entry->instance->backend); + + if (!entry->instance->backend->readonly) + return 0; + } + + return 1; +} + +static int git_config__parse_path(git_str *out, const char *value) +{ + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(value); + + if (value[0] == '~') { + if (value[1] != '\0' && value[1] != '/') { + git_error_set(GIT_ERROR_CONFIG, "retrieving a homedir by name is not supported"); + return -1; + } + + return git_sysdir_expand_homedir_file(out, value[1] ? &value[2] : NULL); + } + + return git_str_sets(out, value); +} + +int git_config_parse_path(git_buf *out, const char *value) +{ + GIT_BUF_WRAP_PRIVATE(out, git_config__parse_path, value); +} + +int git_config_get_path( + git_buf *out, + const git_config *config, + const char *name) +{ + GIT_BUF_WRAP_PRIVATE(out, git_config__get_path, config, name); +} + +int git_config__get_path( + git_str *out, + const git_config *config, + const char *name) +{ + git_config_entry *entry; + int error; + + if ((error = get_entry(&entry, config, name, true, GET_ALL_ERRORS)) < 0) + return error; + + error = git_config__parse_path(out, entry->value); + git_config_entry_free(entry); + + return error; +} + +int git_config_get_string( + const char **out, const git_config *config, const char *name) +{ + git_config_entry *entry; + int ret; + + if (!is_readonly(config)) { + git_error_set(GIT_ERROR_CONFIG, "get_string called on a live config object"); + return -1; + } + + ret = get_entry(&entry, config, name, true, GET_ALL_ERRORS); + *out = !ret ? (entry->value ? entry->value : "") : NULL; + + git_config_entry_free(entry); + + return ret; +} + +int git_config_get_string_buf( + git_buf *out, const git_config *config, const char *name) +{ + GIT_BUF_WRAP_PRIVATE(out, git_config__get_string_buf, config, name); +} + +int git_config__get_string_buf( + git_str *out, const git_config *config, const char *name) +{ + git_config_entry *entry; + int ret; + const char *str; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(config); + + ret = get_entry(&entry, config, name, true, GET_ALL_ERRORS); + str = !ret ? (entry->value ? entry->value : "") : NULL; + + if (str) + ret = git_str_puts(out, str); + + git_config_entry_free(entry); + + return ret; +} + +char *git_config__get_string_force( + const git_config *config, const char *key, const char *fallback_value) +{ + git_config_entry *entry; + char *ret; + + get_entry(&entry, config, key, false, GET_NO_ERRORS); + ret = (entry && entry->value) ? git__strdup(entry->value) : fallback_value ? git__strdup(fallback_value) : NULL; + git_config_entry_free(entry); + + return ret; +} + +int git_config__get_bool_force( + const git_config *config, const char *key, int fallback_value) +{ + int val = fallback_value; + git_config_entry *entry; + + get_entry(&entry, config, key, false, GET_NO_ERRORS); + + if (entry && git_config_parse_bool(&val, entry->value) < 0) + git_error_clear(); + + git_config_entry_free(entry); + return val; +} + +int git_config__get_int_force( + const git_config *config, const char *key, int fallback_value) +{ + int32_t val = (int32_t)fallback_value; + git_config_entry *entry; + + get_entry(&entry, config, key, false, GET_NO_ERRORS); + + if (entry && git_config_parse_int32(&val, entry->value) < 0) + git_error_clear(); + + git_config_entry_free(entry); + return (int)val; +} + +int git_config_get_multivar_foreach( + const git_config *config, const char *name, const char *regexp, + git_config_foreach_cb cb, void *payload) +{ + int err, found; + git_config_iterator *iter; + git_config_entry *entry; + + if ((err = git_config_multivar_iterator_new(&iter, config, name, regexp)) < 0) + return err; + + found = 0; + while ((err = iter->next(&entry, iter)) == 0) { + found = 1; + + if ((err = cb(entry, payload)) != 0) { + git_error_set_after_callback(err); + break; + } + } + + iter->free(iter); + if (err == GIT_ITEROVER) + err = 0; + + if (found == 0 && err == 0) + err = config_error_notfound(name); + + return err; +} + +typedef struct { + git_config_iterator parent; + git_config_iterator *iter; + char *name; + git_regexp regex; + int have_regex; +} multivar_iter; + +static int multivar_iter_next(git_config_entry **entry, git_config_iterator *_iter) +{ + multivar_iter *iter = (multivar_iter *) _iter; + int error = 0; + + while ((error = iter->iter->next(entry, iter->iter)) == 0) { + if (git__strcmp(iter->name, (*entry)->name)) + continue; + + if (!iter->have_regex) + return 0; + + if (git_regexp_match(&iter->regex, (*entry)->value) == 0) + return 0; + } + + return error; +} + +static void multivar_iter_free(git_config_iterator *_iter) +{ + multivar_iter *iter = (multivar_iter *) _iter; + + iter->iter->free(iter->iter); + + git__free(iter->name); + if (iter->have_regex) + git_regexp_dispose(&iter->regex); + git__free(iter); +} + +int git_config_multivar_iterator_new(git_config_iterator **out, const git_config *config, const char *name, const char *regexp) +{ + multivar_iter *iter = NULL; + git_config_iterator *inner = NULL; + int error; + + if ((error = git_config_iterator_new(&inner, config)) < 0) + return error; + + iter = git__calloc(1, sizeof(multivar_iter)); + GIT_ERROR_CHECK_ALLOC(iter); + + if ((error = git_config__normalize_name(name, &iter->name)) < 0) + goto on_error; + + if (regexp != NULL) { + if ((error = git_regexp_compile(&iter->regex, regexp, 0)) < 0) + goto on_error; + + iter->have_regex = 1; + } + + iter->iter = inner; + iter->parent.free = multivar_iter_free; + iter->parent.next = multivar_iter_next; + + *out = (git_config_iterator *) iter; + + return 0; + +on_error: + + inner->free(inner); + git__free(iter); + return error; +} + +int git_config_set_multivar(git_config *config, const char *name, const char *regexp, const char *value) +{ + git_config_backend *backend; + + if ((backend = get_writer(config)) == NULL) { + git_error_set(GIT_ERROR_CONFIG, "cannot set '%s': the configuration is read-only", name); + return GIT_EREADONLY; + } + + return backend->set_multivar(backend, name, regexp, value); +} + +int git_config_delete_multivar(git_config *config, const char *name, const char *regexp) +{ + git_config_backend *backend; + + if ((backend = get_writer(config)) == NULL) + return GIT_EREADONLY; + + return backend->del_multivar(backend, name, regexp); +} + +int git_config_next(git_config_entry **entry, git_config_iterator *iter) +{ + return iter->next(entry, iter); +} + +void git_config_iterator_free(git_config_iterator *iter) +{ + if (iter == NULL) + return; + + iter->free(iter); +} + +int git_config_find_global(git_buf *path) +{ + GIT_BUF_WRAP_PRIVATE(path, git_sysdir_find_global_file, GIT_CONFIG_FILENAME_GLOBAL); +} + +int git_config__find_global(git_str *path) +{ + return git_sysdir_find_global_file(path, GIT_CONFIG_FILENAME_GLOBAL); +} + +int git_config_find_xdg(git_buf *path) +{ + GIT_BUF_WRAP_PRIVATE(path, git_sysdir_find_xdg_file, GIT_CONFIG_FILENAME_XDG); +} + +int git_config__find_xdg(git_str *path) +{ + return git_sysdir_find_xdg_file(path, GIT_CONFIG_FILENAME_XDG); +} + +int git_config_find_system(git_buf *path) +{ + GIT_BUF_WRAP_PRIVATE(path, git_sysdir_find_system_file, GIT_CONFIG_FILENAME_SYSTEM); +} + +int git_config__find_system(git_str *path) +{ + return git_sysdir_find_system_file(path, GIT_CONFIG_FILENAME_SYSTEM); +} + +int git_config_find_programdata(git_buf *path) +{ + git_str str = GIT_STR_INIT; + int error; + + if ((error = git_buf_tostr(&str, path)) == 0 && + (error = git_config__find_programdata(&str)) == 0) + error = git_buf_fromstr(path, &str); + + git_str_dispose(&str); + return error; +} + +int git_config__find_programdata(git_str *path) +{ + git_fs_path_owner_t owner_level = + GIT_FS_PATH_OWNER_CURRENT_USER | + GIT_FS_PATH_OWNER_ADMINISTRATOR; + bool is_safe; + int error; + + if ((error = git_sysdir_find_programdata_file(path, GIT_CONFIG_FILENAME_PROGRAMDATA)) < 0) + return error; + + if (git_fs_path_owner_is(&is_safe, path->ptr, owner_level) < 0) + return -1; + + if (!is_safe) { + git_error_set(GIT_ERROR_CONFIG, "programdata path has invalid ownership"); + return -1; + } + + return 0; +} + +int git_config__global_location(git_str *buf) +{ + const git_str *paths; + const char *sep, *start; + + if (git_sysdir_get(&paths, GIT_SYSDIR_GLOBAL) < 0) + return -1; + + /* no paths, so give up */ + if (!paths || !git_str_len(paths)) + return -1; + + /* find unescaped separator or end of string */ + for (sep = start = git_str_cstr(paths); *sep; ++sep) { + if (*sep == GIT_PATH_LIST_SEPARATOR && + (sep <= start || sep[-1] != '\\')) + break; + } + + if (git_str_set(buf, start, (size_t)(sep - start)) < 0) + return -1; + + return git_str_joinpath(buf, buf->ptr, GIT_CONFIG_FILENAME_GLOBAL); +} + +int git_config_open_default(git_config **out) +{ + int error; + git_config *config = NULL; + git_str buf = GIT_STR_INIT; + + if ((error = git_config_new(&config)) < 0) + return error; + + if (!git_config__find_global(&buf) || + !git_config__global_location(&buf)) { + error = git_config_add_file_ondisk(config, buf.ptr, + GIT_CONFIG_LEVEL_GLOBAL, NULL, 0); + } + + if (!error && !git_config__find_xdg(&buf)) + error = git_config_add_file_ondisk(config, buf.ptr, + GIT_CONFIG_LEVEL_XDG, NULL, 0); + + if (!error && !git_config__find_system(&buf)) + error = git_config_add_file_ondisk(config, buf.ptr, + GIT_CONFIG_LEVEL_SYSTEM, NULL, 0); + + if (!error && !git_config__find_programdata(&buf)) + error = git_config_add_file_ondisk(config, buf.ptr, + GIT_CONFIG_LEVEL_PROGRAMDATA, NULL, 0); + + git_str_dispose(&buf); + + if (error) { + git_config_free(config); + config = NULL; + } + + *out = config; + + return error; +} + +int git_config_lock(git_transaction **out, git_config *config) +{ + backend_instance *instance; + int error; + + GIT_ASSERT_ARG(config); + + if ((instance = get_writer_instance(config)) == NULL) { + git_error_set(GIT_ERROR_CONFIG, "cannot lock: the configuration is read-only"); + return GIT_EREADONLY; + } + + if ((error = instance->backend->lock(instance->backend)) < 0 || + (error = git_transaction_config_new(out, config, instance)) < 0) + return error; + + GIT_REFCOUNT_INC(instance); + return 0; +} + +int git_config_unlock( + git_config *config, + void *data, + int commit) +{ + backend_instance *instance = data; + int error; + + GIT_ASSERT_ARG(config && data); + GIT_UNUSED(config); + + error = instance->backend->unlock(instance->backend, commit); + GIT_REFCOUNT_DEC(instance, backend_instance_free); + + return error; +} + +/*********** + * Parsers + ***********/ + +int git_config_lookup_map_value( + int *out, + const git_configmap *maps, + size_t map_n, + const char *value) +{ + size_t i; + + for (i = 0; i < map_n; ++i) { + const git_configmap *m = maps + i; + + switch (m->type) { + case GIT_CONFIGMAP_FALSE: + case GIT_CONFIGMAP_TRUE: { + int bool_val; + + if (git_config_parse_bool(&bool_val, value) == 0 && + bool_val == (int)m->type) { + *out = m->map_value; + return 0; + } + break; + } + + case GIT_CONFIGMAP_INT32: + if (git_config_parse_int32(out, value) == 0) + return 0; + break; + + case GIT_CONFIGMAP_STRING: + if (value && strcasecmp(value, m->str_match) == 0) { + *out = m->map_value; + return 0; + } + break; + } + } + + git_error_set(GIT_ERROR_CONFIG, "failed to map '%s'", value); + return -1; +} + +int git_config_lookup_map_enum(git_configmap_t *type_out, const char **str_out, + const git_configmap *maps, size_t map_n, int enum_val) +{ + size_t i; + + for (i = 0; i < map_n; i++) { + const git_configmap *m = &maps[i]; + + if (m->map_value != enum_val) + continue; + + *type_out = m->type; + *str_out = m->str_match; + return 0; + } + + git_error_set(GIT_ERROR_CONFIG, "invalid enum value"); + return GIT_ENOTFOUND; +} + +int git_config_parse_bool(int *out, const char *value) +{ + if (git__parse_bool(out, value) == 0) + return 0; + + if (git_config_parse_int32(out, value) == 0) { + *out = !!(*out); + return 0; + } + + git_error_set(GIT_ERROR_CONFIG, "failed to parse '%s' as a boolean value", value); + return -1; +} + +int git_config_parse_int64(int64_t *out, const char *value) +{ + const char *num_end; + int64_t num; + + if (!value || git__strntol64(&num, value, strlen(value), &num_end, 0) < 0) + goto fail_parse; + + switch (*num_end) { + case 'g': + case 'G': + num *= 1024; + /* fallthrough */ + + case 'm': + case 'M': + num *= 1024; + /* fallthrough */ + + case 'k': + case 'K': + num *= 1024; + + /* check that that there are no more characters after the + * given modifier suffix */ + if (num_end[1] != '\0') + return -1; + + /* fallthrough */ + + case '\0': + *out = num; + return 0; + + default: + goto fail_parse; + } + +fail_parse: + git_error_set(GIT_ERROR_CONFIG, "failed to parse '%s' as an integer", value ? value : "(null)"); + return -1; +} + +int git_config_parse_int32(int32_t *out, const char *value) +{ + int64_t tmp; + int32_t truncate; + + if (git_config_parse_int64(&tmp, value) < 0) + goto fail_parse; + + truncate = tmp & 0xFFFFFFFF; + if (truncate != tmp) + goto fail_parse; + + *out = truncate; + return 0; + +fail_parse: + git_error_set(GIT_ERROR_CONFIG, "failed to parse '%s' as a 32-bit integer", value ? value : "(null)"); + return -1; +} + +static int normalize_section(char *start, char *end) +{ + char *scan; + + if (start == end) + return GIT_EINVALIDSPEC; + + /* Validate and downcase range */ + for (scan = start; *scan; ++scan) { + if (end && scan >= end) + break; + if (git__isalnum(*scan)) + *scan = (char)git__tolower(*scan); + else if (*scan != '-' || scan == start) + return GIT_EINVALIDSPEC; + } + + if (scan == start) + return GIT_EINVALIDSPEC; + + return 0; +} + + +/* Take something the user gave us and make it nice for our hash function */ +int git_config__normalize_name(const char *in, char **out) +{ + char *name, *fdot, *ldot; + + GIT_ASSERT_ARG(in); + GIT_ASSERT_ARG(out); + + name = git__strdup(in); + GIT_ERROR_CHECK_ALLOC(name); + + fdot = strchr(name, '.'); + ldot = strrchr(name, '.'); + + if (fdot == NULL || fdot == name || ldot == NULL || !ldot[1]) + goto invalid; + + /* Validate and downcase up to first dot and after last dot */ + if (normalize_section(name, fdot) < 0 || + normalize_section(ldot + 1, NULL) < 0) + goto invalid; + + /* If there is a middle range, make sure it doesn't have newlines */ + while (fdot < ldot) + if (*fdot++ == '\n') + goto invalid; + + *out = name; + return 0; + +invalid: + git__free(name); + git_error_set(GIT_ERROR_CONFIG, "invalid config item name '%s'", in); + return GIT_EINVALIDSPEC; +} + +struct rename_data { + git_config *config; + git_str *name; + size_t old_len; +}; + +static int rename_config_entries_cb( + const git_config_entry *entry, + void *payload) +{ + int error = 0; + struct rename_data *data = (struct rename_data *)payload; + size_t base_len = git_str_len(data->name); + git_str value = GIT_STR_INIT; + + if (base_len > 0) { + if ((error = git_str_puts(data->name, + entry->name + data->old_len)) < 0 || + (error = git_config_set_multivar( + data->config, git_str_cstr(data->name), "^$", + entry->value)) < 0) + goto cleanup; + } + + git_str_putc(&value, '^'); + git_str_puts_escape_regex(&value, entry->value); + git_str_putc(&value, '$'); + + if (git_str_oom(&value)) { + error = -1; + goto cleanup; + } + + error = git_config_delete_multivar( + data->config, entry->name, git_str_cstr(&value)); + + cleanup: + git_str_truncate(data->name, base_len); + git_str_dispose(&value); + return error; +} + +int git_config_rename_section( + git_repository *repo, + const char *old_section_name, + const char *new_section_name) +{ + git_config *config; + git_str pattern = GIT_STR_INIT, replace = GIT_STR_INIT; + int error = 0; + struct rename_data data; + + git_str_puts_escape_regex(&pattern, old_section_name); + + if ((error = git_str_puts(&pattern, "\\..+")) < 0) + goto cleanup; + + if ((error = git_repository_config__weakptr(&config, repo)) < 0) + goto cleanup; + + data.config = config; + data.name = &replace; + data.old_len = strlen(old_section_name) + 1; + + if ((error = git_str_join(&replace, '.', new_section_name, "")) < 0) + goto cleanup; + + if (new_section_name != NULL && + (error = normalize_section(replace.ptr, strchr(replace.ptr, '.'))) < 0) + { + git_error_set( + GIT_ERROR_CONFIG, "invalid config section '%s'", new_section_name); + goto cleanup; + } + + error = git_config_foreach_match( + config, git_str_cstr(&pattern), rename_config_entries_cb, &data); + +cleanup: + git_str_dispose(&pattern); + git_str_dispose(&replace); + + return error; +} + +int git_config_init_backend(git_config_backend *backend, unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE( + backend, version, git_config_backend, GIT_CONFIG_BACKEND_INIT); + return 0; +} diff --git a/vendor/libgit2/src/config.h b/vendor/libgit2/src/libgit2/config.h similarity index 91% rename from vendor/libgit2/src/config.h rename to vendor/libgit2/src/libgit2/config.h index 01b84b15..5003cbf9 100644 --- a/vendor/libgit2/src/config.h +++ b/vendor/libgit2/src/libgit2/config.h @@ -24,7 +24,8 @@ struct git_config { git_refcount rc; - git_vector backends; + git_vector readers; + git_vector writers; }; extern int git_config__global_location(git_str *buf); @@ -94,17 +95,21 @@ int git_config_lookup_map_enum(git_configmap_t *type_out, size_t map_n, int enum_val); /** - * Unlock the backend with the highest priority + * Unlock the given backend that was previously locked. * * Unlocking will allow other writers to update the configuration * file. Optionally, any changes performed since the lock will be * applied to the configuration. * - * @param cfg the configuration + * @param config the config instance + * @param data the config data passed to git_transaction_new * @param commit boolean which indicates whether to commit any changes * done since locking * @return 0 or an error code */ -GIT_EXTERN(int) git_config_unlock(git_config *cfg, int commit); +GIT_EXTERN(int) git_config_unlock( + git_config *config, + void *data, + int commit); #endif diff --git a/vendor/libgit2/src/config_backend.h b/vendor/libgit2/src/libgit2/config_backend.h similarity index 88% rename from vendor/libgit2/src/config_backend.h rename to vendor/libgit2/src/libgit2/config_backend.h index dbb19051..37d25abe 100644 --- a/vendor/libgit2/src/config_backend.h +++ b/vendor/libgit2/src/libgit2/config_backend.h @@ -37,15 +37,6 @@ extern int git_config_backend_from_file(git_config_backend **out, const char *pa */ extern int git_config_backend_snapshot(git_config_backend **out, git_config_backend *source); -/** - * Create an in-memory configuration file backend - * - * @param out the new backend - * @param cfg the configuration that is to be parsed - * @param len the length of the string pointed to by `cfg` - */ -extern int git_config_backend_from_string(git_config_backend **out, const char *cfg, size_t len); - GIT_INLINE(int) git_config_backend_open(git_config_backend *cfg, unsigned int level, const git_repository *repo) { return cfg->open(cfg, level, repo); diff --git a/vendor/libgit2/src/config_cache.c b/vendor/libgit2/src/libgit2/config_cache.c similarity index 100% rename from vendor/libgit2/src/config_cache.c rename to vendor/libgit2/src/libgit2/config_cache.c diff --git a/vendor/libgit2/src/config_file.c b/vendor/libgit2/src/libgit2/config_file.c similarity index 83% rename from vendor/libgit2/src/config_file.c rename to vendor/libgit2/src/libgit2/config_file.c index 66fcb8ae..340e8569 100644 --- a/vendor/libgit2/src/config_file.c +++ b/vendor/libgit2/src/libgit2/config_file.c @@ -13,7 +13,7 @@ #include "array.h" #include "str.h" #include "config_backend.h" -#include "config_entries.h" +#include "config_list.h" #include "config_parse.h" #include "filebuf.h" #include "regexp.h" @@ -24,9 +24,11 @@ /* Max depth for [include] directives */ #define MAX_INCLUDE_DEPTH 10 +#define CONFIG_FILE_TYPE "file" + typedef struct config_file { git_futils_filestamp stamp; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; + unsigned char checksum[GIT_HASH_SHA256_SIZE]; char *path; git_array_t(struct config_file) includes; } config_file; @@ -34,7 +36,7 @@ typedef struct config_file { typedef struct { git_config_backend parent; git_mutex values_mutex; - git_config_entries *entries; + git_config_list *config_list; const git_repository *repo; git_config_level_t level; @@ -50,13 +52,13 @@ typedef struct { typedef struct { const git_repository *repo; config_file *file; - git_config_entries *entries; + git_config_list *config_list; git_config_level_t level; unsigned int depth; } config_file_parse_data; -static int config_file_read(git_config_entries *entries, const git_repository *repo, config_file *file, git_config_level_t level, int depth); -static int config_file_read_buffer(git_config_entries *entries, const git_repository *repo, config_file *file, git_config_level_t level, int depth, const char *buf, size_t buflen); +static int config_file_read(git_config_list *config_list, const git_repository *repo, config_file *file, git_config_level_t level, int depth); +static int config_file_read_buffer(git_config_list *config_list, const git_repository *repo, config_file *file, git_config_level_t level, int depth, const char *buf, size_t buflen); static int config_file_write(config_file_backend *cfg, const char *orig_key, const char *key, const git_regexp *preg, const char *value); static char *escape_value(const char *ptr); @@ -65,7 +67,7 @@ static char *escape_value(const char *ptr); * refcount. This is its own function to make sure we use the mutex to * avoid the map pointer from changing under us. */ -static int config_file_entries_take(git_config_entries **out, config_file_backend *b) +static int config_file_take_list(git_config_list **out, config_file_backend *b) { int error; @@ -74,8 +76,8 @@ static int config_file_entries_take(git_config_entries **out, config_file_backen return error; } - git_config_entries_incref(b->entries); - *out = b->entries; + git_config_list_incref(b->config_list); + *out = b->config_list; git_mutex_unlock(&b->values_mutex); @@ -106,7 +108,7 @@ static int config_file_open(git_config_backend *cfg, git_config_level_t level, c b->level = level; b->repo = repo; - if ((res = git_config_entries_new(&b->entries)) < 0) + if ((res = git_config_list_new(&b->config_list)) < 0) return res; if (!git_fs_path_exists(b->file.path)) @@ -121,9 +123,9 @@ static int config_file_open(git_config_backend *cfg, git_config_level_t level, c if (p_access(b->file.path, R_OK) < 0) return GIT_ENOTFOUND; - if (res < 0 || (res = config_file_read(b->entries, repo, &b->file, level, 0)) < 0) { - git_config_entries_free(b->entries); - b->entries = NULL; + if (res < 0 || (res = config_file_read(b->config_list, repo, &b->file, level, 0)) < 0) { + git_config_list_free(b->config_list); + b->config_list = NULL; } return res; @@ -133,7 +135,7 @@ static int config_file_is_modified(int *modified, config_file *file) { config_file *include; git_str buf = GIT_STR_INIT; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; + unsigned char checksum[GIT_HASH_SHA256_SIZE]; uint32_t i; int error = 0; @@ -145,10 +147,10 @@ static int config_file_is_modified(int *modified, config_file *file) if ((error = git_futils_readbuffer(&buf, file->path)) < 0) goto out; - if ((error = git_hash_buf(checksum, buf.ptr, buf.size, GIT_HASH_ALGORITHM_SHA1)) < 0) + if ((error = git_hash_buf(checksum, buf.ptr, buf.size, GIT_HASH_ALGORITHM_SHA256)) < 0) goto out; - if (memcmp(checksum, file->checksum, GIT_HASH_SHA1_SIZE) != 0) { + if (memcmp(checksum, file->checksum, GIT_HASH_SHA256_SIZE) != 0) { *modified = 1; goto out; } @@ -175,10 +177,10 @@ static void config_file_clear_includes(config_file_backend *cfg) git_array_clear(cfg->file.includes); } -static int config_file_set_entries(git_config_backend *cfg, git_config_entries *entries) +static int config_file_set_entries(git_config_backend *cfg, git_config_list *config_list) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *old = NULL; + git_config_list *old = NULL; int error; if (b->parent.readonly) { @@ -191,40 +193,40 @@ static int config_file_set_entries(git_config_backend *cfg, git_config_entries * goto out; } - old = b->entries; - b->entries = entries; + old = b->config_list; + b->config_list = config_list; git_mutex_unlock(&b->values_mutex); out: - git_config_entries_free(old); + git_config_list_free(old); return error; } static int config_file_refresh_from_buffer(git_config_backend *cfg, const char *buf, size_t buflen) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *entries = NULL; + git_config_list *config_list = NULL; int error; config_file_clear_includes(b); - if ((error = git_config_entries_new(&entries)) < 0 || - (error = config_file_read_buffer(entries, b->repo, &b->file, + if ((error = git_config_list_new(&config_list)) < 0 || + (error = config_file_read_buffer(config_list, b->repo, &b->file, b->level, 0, buf, buflen)) < 0 || - (error = config_file_set_entries(cfg, entries)) < 0) + (error = config_file_set_entries(cfg, config_list)) < 0) goto out; - entries = NULL; + config_list = NULL; out: - git_config_entries_free(entries); + git_config_list_free(config_list); return error; } static int config_file_refresh(git_config_backend *cfg) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *entries = NULL; + git_config_list *config_list = NULL; int error, modified; if (cfg->readonly) @@ -238,14 +240,14 @@ static int config_file_refresh(git_config_backend *cfg) config_file_clear_includes(b); - if ((error = git_config_entries_new(&entries)) < 0 || - (error = config_file_read(entries, b->repo, &b->file, b->level, 0)) < 0 || - (error = config_file_set_entries(cfg, entries)) < 0) + if ((error = git_config_list_new(&config_list)) < 0 || + (error = config_file_read(config_list, b->repo, &b->file, b->level, 0)) < 0 || + (error = config_file_set_entries(cfg, config_list)) < 0) goto out; - entries = NULL; + config_list = NULL; out: - git_config_entries_free(entries); + git_config_list_free(config_list); return (error == GIT_ENOTFOUND) ? 0 : error; } @@ -258,7 +260,7 @@ static void config_file_free(git_config_backend *_backend) return; config_file_clear(&backend->file); - git_config_entries_free(backend->entries); + git_config_list_free(backend->config_list); git_mutex_free(&backend->values_mutex); git__free(backend); } @@ -268,19 +270,19 @@ static int config_file_iterator( struct git_config_backend *backend) { config_file_backend *b = GIT_CONTAINER_OF(backend, config_file_backend, parent); - git_config_entries *dupped = NULL, *entries = NULL; + git_config_list *dupped = NULL, *config_list = NULL; int error; if ((error = config_file_refresh(backend)) < 0 || - (error = config_file_entries_take(&entries, b)) < 0 || - (error = git_config_entries_dup(&dupped, entries)) < 0 || - (error = git_config_entries_iterator_new(iter, dupped)) < 0) + (error = config_file_take_list(&config_list, b)) < 0 || + (error = git_config_list_dup(&dupped, config_list)) < 0 || + (error = git_config_list_iterator_new(iter, dupped)) < 0) goto out; out: - /* Let iterator delete duplicated entries when it's done */ - git_config_entries_free(entries); - git_config_entries_free(dupped); + /* Let iterator delete duplicated config_list when it's done */ + git_config_list_free(config_list); + git_config_list_free(dupped); return error; } @@ -292,24 +294,24 @@ static int config_file_snapshot(git_config_backend **out, git_config_backend *ba static int config_file_set(git_config_backend *cfg, const char *name, const char *value) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *entries; - git_config_entry *existing; + git_config_list *config_list; + git_config_list_entry *existing; char *key, *esc_value = NULL; int error; if ((error = git_config__normalize_name(name, &key)) < 0) return error; - if ((error = config_file_entries_take(&entries, b)) < 0) + if ((error = config_file_take_list(&config_list, b)) < 0) return error; /* Check whether we'd be modifying an included or multivar key */ - if ((error = git_config_entries_get_unique(&existing, entries, key)) < 0) { + if ((error = git_config_list_get_unique(&existing, config_list, key)) < 0) { if (error != GIT_ENOTFOUND) goto out; error = 0; - } else if ((!existing->value && !value) || - (existing->value && value && !strcmp(existing->value, value))) { + } else if ((!existing->base.value && !value) || + (existing->base.value && value && !strcmp(existing->base.value, value))) { /* don't update if old and new values already match */ error = 0; goto out; @@ -325,43 +327,34 @@ static int config_file_set(git_config_backend *cfg, const char *name, const char goto out; out: - git_config_entries_free(entries); + git_config_list_free(config_list); git__free(esc_value); git__free(key); return error; } -/* release the map containing the entry as an equivalent to freeing it */ -static void config_file_entry_free(git_config_entry *entry) -{ - git_config_entries *entries = (git_config_entries *) entry->payload; - git_config_entries_free(entries); -} - /* * Internal function that actually gets the value in string form */ static int config_file_get(git_config_backend *cfg, const char *key, git_config_entry **out) { config_file_backend *h = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *entries = NULL; - git_config_entry *entry; + git_config_list *config_list = NULL; + git_config_list_entry *entry; int error = 0; if (!h->parent.readonly && ((error = config_file_refresh(cfg)) < 0)) return error; - if ((error = config_file_entries_take(&entries, h)) < 0) + if ((error = config_file_take_list(&config_list, h)) < 0) return error; - if ((error = (git_config_entries_get(&entry, entries, key))) < 0) { - git_config_entries_free(entries); + if ((error = (git_config_list_get(&entry, config_list, key))) < 0) { + git_config_list_free(config_list); return error; } - entry->free = config_file_entry_free; - entry->payload = entries; - *out = entry; + *out = &entry->base; return 0; } @@ -396,29 +389,29 @@ static int config_file_set_multivar( static int config_file_delete(git_config_backend *cfg, const char *name) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *entries = NULL; - git_config_entry *entry; + git_config_list *config_list = NULL; + git_config_list_entry *entry; char *key = NULL; int error; if ((error = git_config__normalize_name(name, &key)) < 0) goto out; - if ((error = config_file_entries_take(&entries, b)) < 0) + if ((error = config_file_take_list(&config_list, b)) < 0) goto out; /* Check whether we'd be modifying an included or multivar key */ - if ((error = git_config_entries_get_unique(&entry, entries, key)) < 0) { + if ((error = git_config_list_get_unique(&entry, config_list, key)) < 0) { if (error == GIT_ENOTFOUND) git_error_set(GIT_ERROR_CONFIG, "could not find key '%s' to delete", name); goto out; } - if ((error = config_file_write(b, name, entry->name, NULL, NULL)) < 0) + if ((error = config_file_write(b, name, entry->base.name, NULL, NULL)) < 0) goto out; out: - git_config_entries_free(entries); + git_config_list_free(config_list); git__free(key); return error; } @@ -426,8 +419,8 @@ static int config_file_delete(git_config_backend *cfg, const char *name) static int config_file_delete_multivar(git_config_backend *cfg, const char *name, const char *regexp) { config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent); - git_config_entries *entries = NULL; - git_config_entry *entry = NULL; + git_config_list *config_list = NULL; + git_config_list_entry *entry = NULL; git_regexp preg = GIT_REGEX_INIT; char *key = NULL; int result; @@ -435,10 +428,10 @@ static int config_file_delete_multivar(git_config_backend *cfg, const char *name if ((result = git_config__normalize_name(name, &key)) < 0) goto out; - if ((result = config_file_entries_take(&entries, b)) < 0) + if ((result = config_file_take_list(&config_list, b)) < 0) goto out; - if ((result = git_config_entries_get(&entry, entries, key)) < 0) { + if ((result = git_config_list_get(&entry, config_list, key)) < 0) { if (result == GIT_ENOTFOUND) git_error_set(GIT_ERROR_CONFIG, "could not find key '%s' to delete", name); goto out; @@ -451,7 +444,7 @@ static int config_file_delete_multivar(git_config_backend *cfg, const char *name goto out; out: - git_config_entries_free(entries); + git_config_list_free(config_list); git__free(key); git_regexp_dispose(&preg); return result; @@ -528,7 +521,7 @@ static int included_path(git_str *out, const char *dir, const char *path) { /* From the user's home */ if (path[0] == '~' && path[1] == '/') - return git_sysdir_expand_global_file(out, &path[1]); + return git_sysdir_expand_homedir_file(out, &path[1]); return git_fs_path_join_unrooted(out, path, dir, NULL); } @@ -591,7 +584,7 @@ static int parse_include(config_file_parse_data *parse_data, const char *file) git_array_init(include->includes); include->path = git_str_detach(&path); - result = config_file_read(parse_data->entries, parse_data->repo, include, + result = config_file_read(parse_data->config_list, parse_data->repo, include, parse_data->level, parse_data->depth+1); if (result == GIT_ENOTFOUND) { @@ -616,7 +609,7 @@ static int do_match_gitdir( git_fs_path_dirname_r(&pattern, cfg_file); git_str_joinpath(&pattern, pattern.ptr, condition + 2); } else if (condition[0] == '~' && git_fs_path_is_dirsep(condition[1])) - git_sysdir_expand_global_file(&pattern, condition + 1); + git_sysdir_expand_homedir_file(&pattern, condition + 1); else if (!git_fs_path_is_absolute(condition)) git_str_joinpath(&pattern, "**", condition); else @@ -776,7 +769,7 @@ static int read_on_variable( { config_file_parse_data *parse_data = (config_file_parse_data *)data; git_str buf = GIT_STR_INIT; - git_config_entry *entry; + git_config_list_entry *entry; const char *c; int result = 0; @@ -799,30 +792,45 @@ static int read_on_variable( if (git_str_oom(&buf)) return -1; - entry = git__calloc(1, sizeof(git_config_entry)); + entry = git__calloc(1, sizeof(git_config_list_entry)); GIT_ERROR_CHECK_ALLOC(entry); - entry->name = git_str_detach(&buf); - entry->value = var_value ? git__strdup(var_value) : NULL; - entry->level = parse_data->level; - entry->include_depth = parse_data->depth; - if ((result = git_config_entries_append(parse_data->entries, entry)) < 0) + entry->base.name = git_str_detach(&buf); + GIT_ERROR_CHECK_ALLOC(entry->base.name); + + if (var_value) { + entry->base.value = git__strdup(var_value); + GIT_ERROR_CHECK_ALLOC(entry->base.value); + } + + entry->base.backend_type = git_config_list_add_string(parse_data->config_list, CONFIG_FILE_TYPE); + GIT_ERROR_CHECK_ALLOC(entry->base.backend_type); + + entry->base.origin_path = git_config_list_add_string(parse_data->config_list, parse_data->file->path); + GIT_ERROR_CHECK_ALLOC(entry->base.origin_path); + + entry->base.level = parse_data->level; + entry->base.include_depth = parse_data->depth; + entry->base.free = git_config_list_entry_free; + entry->config_list = parse_data->config_list; + + if ((result = git_config_list_append(parse_data->config_list, entry)) < 0) return result; result = 0; /* Add or append the new config option */ - if (!git__strcmp(entry->name, "include.path")) - result = parse_include(parse_data, entry->value); - else if (!git__prefixcmp(entry->name, "includeif.") && - !git__suffixcmp(entry->name, ".path")) - result = parse_conditional_include(parse_data, entry->name, entry->value); + if (!git__strcmp(entry->base.name, "include.path")) + result = parse_include(parse_data, entry->base.value); + else if (!git__prefixcmp(entry->base.name, "includeif.") && + !git__suffixcmp(entry->base.name, ".path")) + result = parse_conditional_include(parse_data, entry->base.name, entry->base.value); return result; } static int config_file_read_buffer( - git_config_entries *entries, + git_config_list *config_list, const git_repository *repo, config_file *file, git_config_level_t level, @@ -851,7 +859,7 @@ static int config_file_read_buffer( parse_data.repo = repo; parse_data.file = file; - parse_data.entries = entries; + parse_data.config_list = config_list; parse_data.level = level; parse_data.depth = depth; @@ -862,7 +870,7 @@ static int config_file_read_buffer( } static int config_file_read( - git_config_entries *entries, + git_config_list *config_list, const git_repository *repo, config_file *file, git_config_level_t level, @@ -881,10 +889,10 @@ static int config_file_read( goto out; git_futils_filestamp_set_from_stat(&file->stamp, &st); - if ((error = git_hash_buf(file->checksum, contents.ptr, contents.size, GIT_HASH_ALGORITHM_SHA1)) < 0) + if ((error = git_hash_buf(file->checksum, contents.ptr, contents.size, GIT_HASH_ALGORITHM_SHA256)) < 0) goto out; - if ((error = config_file_read_buffer(entries, repo, file, level, depth, + if ((error = config_file_read_buffer(config_list, repo, file, level, depth, contents.ptr, contents.size)) < 0) goto out; @@ -1116,7 +1124,12 @@ static int write_on_eof( /* * This is pretty much the parsing, except we write out anything we don't have */ -static int config_file_write(config_file_backend *cfg, const char *orig_key, const char *key, const git_regexp *preg, const char *value) +static int config_file_write( + config_file_backend *cfg, + const char *orig_key, + const char *key, + const git_regexp *preg, + const char *value) { char *orig_section = NULL, *section = NULL, *orig_name, *name, *ldot; @@ -1131,8 +1144,9 @@ static int config_file_write(config_file_backend *cfg, const char *orig_key, con if (cfg->locked) { error = git_str_puts(&contents, git_str_cstr(&cfg->locked_content) == NULL ? "" : git_str_cstr(&cfg->locked_content)); } else { - if ((error = git_filebuf_open(&file, cfg->file.path, GIT_FILEBUF_HASH_CONTENTS, - GIT_CONFIG_FILE_MODE)) < 0) + if ((error = git_filebuf_open(&file, cfg->file.path, + GIT_FILEBUF_HASH_SHA256, + GIT_CONFIG_FILE_MODE)) < 0) goto done; /* We need to read in our own config file */ diff --git a/vendor/libgit2/src/libgit2/config_list.c b/vendor/libgit2/src/libgit2/config_list.c new file mode 100644 index 00000000..0b7a4f36 --- /dev/null +++ b/vendor/libgit2/src/libgit2/config_list.c @@ -0,0 +1,288 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "config_list.h" + +typedef struct config_entry_list { + struct config_entry_list *next; + struct config_entry_list *last; + git_config_list_entry *entry; +} config_entry_list; + +typedef struct { + git_config_list_entry *entry; + bool multivar; +} config_entry_map_head; + +typedef struct config_list_iterator { + git_config_iterator parent; + git_config_list *list; + config_entry_list *head; +} config_list_iterator; + +struct git_config_list { + git_refcount rc; + + /* Interned strings - paths to config files or backend types */ + git_strmap *strings; + + /* Config entries */ + git_strmap *map; + config_entry_list *entries; +}; + +int git_config_list_new(git_config_list **out) +{ + git_config_list *config_list; + + config_list = git__calloc(1, sizeof(git_config_list)); + GIT_ERROR_CHECK_ALLOC(config_list); + GIT_REFCOUNT_INC(config_list); + + if (git_strmap_new(&config_list->strings) < 0 || + git_strmap_new(&config_list->map) < 0) { + git_strmap_free(config_list->strings); + git_strmap_free(config_list->map); + git__free(config_list); + + return -1; + } + + *out = config_list; + return 0; +} + +int git_config_list_dup_entry(git_config_list *config_list, const git_config_entry *entry) +{ + git_config_list_entry *duplicated; + int error; + + duplicated = git__calloc(1, sizeof(git_config_list_entry)); + GIT_ERROR_CHECK_ALLOC(duplicated); + + duplicated->base.name = git__strdup(entry->name); + GIT_ERROR_CHECK_ALLOC(duplicated->base.name); + + if (entry->value) { + duplicated->base.value = git__strdup(entry->value); + GIT_ERROR_CHECK_ALLOC(duplicated->base.value); + } + + duplicated->base.backend_type = git_config_list_add_string(config_list, entry->backend_type); + GIT_ERROR_CHECK_ALLOC(duplicated->base.backend_type); + + if (entry->origin_path) { + duplicated->base.origin_path = git_config_list_add_string(config_list, entry->origin_path); + GIT_ERROR_CHECK_ALLOC(duplicated->base.origin_path); + } + + duplicated->base.level = entry->level; + duplicated->base.include_depth = entry->include_depth; + duplicated->base.free = git_config_list_entry_free; + duplicated->config_list = config_list; + + if ((error = git_config_list_append(config_list, duplicated)) < 0) + goto out; + +out: + if (error && duplicated) { + git__free((char *) duplicated->base.name); + git__free((char *) duplicated->base.value); + git__free(duplicated); + } + return error; +} + +int git_config_list_dup(git_config_list **out, git_config_list *config_list) +{ + git_config_list *result = NULL; + config_entry_list *head; + int error; + + if ((error = git_config_list_new(&result)) < 0) + goto out; + + for (head = config_list->entries; head; head = head->next) + if ((git_config_list_dup_entry(result, &head->entry->base)) < 0) + goto out; + + *out = result; + result = NULL; + +out: + git_config_list_free(result); + return error; +} + +void git_config_list_incref(git_config_list *config_list) +{ + GIT_REFCOUNT_INC(config_list); +} + +static void config_list_free(git_config_list *config_list) +{ + config_entry_list *entry_list = NULL, *next; + config_entry_map_head *head; + char *str; + + git_strmap_foreach_value(config_list->strings, str, { + git__free(str); + }); + git_strmap_free(config_list->strings); + + git_strmap_foreach_value(config_list->map, head, { + git__free((char *) head->entry->base.name); + git__free(head); + }); + git_strmap_free(config_list->map); + + entry_list = config_list->entries; + while (entry_list != NULL) { + next = entry_list->next; + git__free((char *) entry_list->entry->base.value); + git__free(entry_list->entry); + git__free(entry_list); + entry_list = next; + } + + git__free(config_list); +} + +void git_config_list_free(git_config_list *config_list) +{ + if (config_list) + GIT_REFCOUNT_DEC(config_list, config_list_free); +} + +int git_config_list_append(git_config_list *config_list, git_config_list_entry *entry) +{ + config_entry_list *list_head; + config_entry_map_head *map_head; + + if ((map_head = git_strmap_get(config_list->map, entry->base.name)) != NULL) { + map_head->multivar = true; + /* + * This is a micro-optimization for configuration files + * with a lot of same keys. As for multivars the entry's + * key will be the same for all list, we can just free + * all except the first entry's name and just re-use it. + */ + git__free((char *) entry->base.name); + entry->base.name = map_head->entry->base.name; + } else { + map_head = git__calloc(1, sizeof(*map_head)); + if ((git_strmap_set(config_list->map, entry->base.name, map_head)) < 0) + return -1; + } + map_head->entry = entry; + + list_head = git__calloc(1, sizeof(config_entry_list)); + GIT_ERROR_CHECK_ALLOC(list_head); + list_head->entry = entry; + + if (config_list->entries) + config_list->entries->last->next = list_head; + else + config_list->entries = list_head; + config_list->entries->last = list_head; + + return 0; +} + +int git_config_list_get(git_config_list_entry **out, git_config_list *config_list, const char *key) +{ + config_entry_map_head *entry; + + if ((entry = git_strmap_get(config_list->map, key)) == NULL) + return GIT_ENOTFOUND; + + *out = entry->entry; + return 0; +} + +int git_config_list_get_unique(git_config_list_entry **out, git_config_list *config_list, const char *key) +{ + config_entry_map_head *entry; + + if ((entry = git_strmap_get(config_list->map, key)) == NULL) + return GIT_ENOTFOUND; + + if (entry->multivar) { + git_error_set(GIT_ERROR_CONFIG, "entry is not unique due to being a multivar"); + return -1; + } + + if (entry->entry->base.include_depth) { + git_error_set(GIT_ERROR_CONFIG, "entry is not unique due to being included"); + return -1; + } + + *out = entry->entry; + return 0; +} + +static void config_iterator_free(git_config_iterator *iter) +{ + config_list_iterator *it = (config_list_iterator *) iter; + git_config_list_free(it->list); + git__free(it); +} + +static int config_iterator_next( + git_config_entry **entry, + git_config_iterator *iter) +{ + config_list_iterator *it = (config_list_iterator *) iter; + + if (!it->head) + return GIT_ITEROVER; + + *entry = &it->head->entry->base; + it->head = it->head->next; + + return 0; +} + +int git_config_list_iterator_new(git_config_iterator **out, git_config_list *config_list) +{ + config_list_iterator *it; + + it = git__calloc(1, sizeof(config_list_iterator)); + GIT_ERROR_CHECK_ALLOC(it); + it->parent.next = config_iterator_next; + it->parent.free = config_iterator_free; + it->head = config_list->entries; + it->list = config_list; + + git_config_list_incref(config_list); + *out = &it->parent; + + return 0; +} + +/* release the map containing the entry as an equivalent to freeing it */ +void git_config_list_entry_free(git_config_entry *e) +{ + git_config_list_entry *entry = (git_config_list_entry *)e; + git_config_list_free(entry->config_list); +} + +const char *git_config_list_add_string( + git_config_list *config_list, + const char *str) +{ + const char *s; + + if ((s = git_strmap_get(config_list->strings, str)) != NULL) + return s; + + if ((s = git__strdup(str)) == NULL || + git_strmap_set(config_list->strings, s, (void *)s) < 0) + return NULL; + + return s; +} diff --git a/vendor/libgit2/src/libgit2/config_list.h b/vendor/libgit2/src/libgit2/config_list.h new file mode 100644 index 00000000..023bca1e --- /dev/null +++ b/vendor/libgit2/src/libgit2/config_list.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "common.h" + +#include "git2/sys/config.h" +#include "config.h" + +typedef struct git_config_list git_config_list; + +typedef struct { + git_config_entry base; + git_config_list *config_list; +} git_config_list_entry; + +int git_config_list_new(git_config_list **out); +int git_config_list_dup(git_config_list **out, git_config_list *list); +int git_config_list_dup_entry(git_config_list *list, const git_config_entry *entry); +void git_config_list_incref(git_config_list *list); +void git_config_list_free(git_config_list *list); +/* Add or append the new config option */ +int git_config_list_append(git_config_list *list, git_config_list_entry *entry); +int git_config_list_get(git_config_list_entry **out, git_config_list *list, const char *key); +int git_config_list_get_unique(git_config_list_entry **out, git_config_list *list, const char *key); +int git_config_list_iterator_new(git_config_iterator **out, git_config_list *list); +const char *git_config_list_add_string(git_config_list *list, const char *str); + +void git_config_list_entry_free(git_config_entry *entry); diff --git a/vendor/libgit2/src/libgit2/config_mem.c b/vendor/libgit2/src/libgit2/config_mem.c new file mode 100644 index 00000000..406aa83e --- /dev/null +++ b/vendor/libgit2/src/libgit2/config_mem.c @@ -0,0 +1,374 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "config.h" + +#include "config_backend.h" +#include "config_parse.h" +#include "config_list.h" +#include "strlist.h" + +typedef struct { + git_config_backend parent; + + char *backend_type; + char *origin_path; + + git_config_list *config_list; + + /* Configuration data in the config file format */ + git_str cfg; + + /* Array of key=value pairs */ + char **values; + size_t values_len; +} config_memory_backend; + +typedef struct { + const char *backend_type; + const char *origin_path; + git_config_list *config_list; + git_config_level_t level; +} config_memory_parse_data; + +static int config_error_readonly(void) +{ + git_error_set(GIT_ERROR_CONFIG, "this backend is read-only"); + return -1; +} + +static int read_variable_cb( + git_config_parser *reader, + const char *current_section, + const char *var_name, + const char *var_value, + const char *line, + size_t line_len, + void *payload) +{ + config_memory_parse_data *parse_data = (config_memory_parse_data *) payload; + git_str buf = GIT_STR_INIT; + git_config_list_entry *entry; + const char *c; + int result; + + GIT_UNUSED(reader); + GIT_UNUSED(line); + GIT_UNUSED(line_len); + + if (current_section) { + /* TODO: Once warnings land, we should likely warn + * here. Git appears to warn in most cases if it sees + * un-namespaced config options. + */ + git_str_puts(&buf, current_section); + git_str_putc(&buf, '.'); + } + + for (c = var_name; *c; c++) + git_str_putc(&buf, git__tolower(*c)); + + if (git_str_oom(&buf)) + return -1; + + entry = git__calloc(1, sizeof(git_config_list_entry)); + GIT_ERROR_CHECK_ALLOC(entry); + entry->base.name = git_str_detach(&buf); + entry->base.value = var_value ? git__strdup(var_value) : NULL; + entry->base.level = parse_data->level; + entry->base.include_depth = 0; + entry->base.backend_type = parse_data->backend_type; + entry->base.origin_path = parse_data->origin_path; + entry->base.free = git_config_list_entry_free; + entry->config_list = parse_data->config_list; + + if ((result = git_config_list_append(parse_data->config_list, entry)) < 0) + return result; + + return result; +} + +static int parse_config( + config_memory_backend *memory_backend, + git_config_level_t level) +{ + git_config_parser parser = GIT_PARSE_CTX_INIT; + config_memory_parse_data parse_data; + int error; + + if ((error = git_config_parser_init(&parser, "in-memory", + memory_backend->cfg.ptr, memory_backend->cfg.size)) < 0) + goto out; + + parse_data.backend_type = git_config_list_add_string( + memory_backend->config_list, memory_backend->backend_type); + parse_data.origin_path = memory_backend->origin_path ? + git_config_list_add_string(memory_backend->config_list, + memory_backend->origin_path) : + NULL; + parse_data.config_list = memory_backend->config_list; + parse_data.level = level; + + if ((error = git_config_parse(&parser, NULL, read_variable_cb, + NULL, NULL, &parse_data)) < 0) + goto out; + +out: + git_config_parser_dispose(&parser); + return error; +} + +static int parse_values( + config_memory_backend *memory_backend, + git_config_level_t level) +{ + git_config_list_entry *entry; + const char *eql, *backend_type, *origin_path; + size_t name_len, i; + + backend_type = git_config_list_add_string( + memory_backend->config_list, memory_backend->backend_type); + GIT_ERROR_CHECK_ALLOC(backend_type); + + origin_path = memory_backend->origin_path ? + git_config_list_add_string(memory_backend->config_list, + memory_backend->origin_path) : + NULL; + + for (i = 0; i < memory_backend->values_len; i++) { + eql = strchr(memory_backend->values[i], '='); + name_len = eql - memory_backend->values[i]; + + if (name_len == 0) { + git_error_set(GIT_ERROR_CONFIG, "empty config key"); + return -1; + } + + entry = git__calloc(1, sizeof(git_config_list_entry)); + GIT_ERROR_CHECK_ALLOC(entry); + + entry->base.name = git__strndup(memory_backend->values[i], name_len); + GIT_ERROR_CHECK_ALLOC(entry->base.name); + + if (eql) { + entry->base.value = git__strdup(eql + 1); + GIT_ERROR_CHECK_ALLOC(entry->base.value); + } + + entry->base.level = level; + entry->base.include_depth = 0; + entry->base.backend_type = backend_type; + entry->base.origin_path = origin_path; + entry->base.free = git_config_list_entry_free; + entry->config_list = memory_backend->config_list; + + if (git_config_list_append(memory_backend->config_list, entry) < 0) + return -1; + } + + return 0; +} + +static int config_memory_open(git_config_backend *backend, git_config_level_t level, const git_repository *repo) +{ + config_memory_backend *memory_backend = (config_memory_backend *) backend; + + GIT_UNUSED(repo); + + if (memory_backend->cfg.size > 0 && + parse_config(memory_backend, level) < 0) + return -1; + + if (memory_backend->values_len > 0 && + parse_values(memory_backend, level) < 0) + return -1; + + return 0; +} + +static int config_memory_get(git_config_backend *backend, const char *key, git_config_entry **out) +{ + config_memory_backend *memory_backend = (config_memory_backend *) backend; + git_config_list_entry *entry; + int error; + + if ((error = git_config_list_get(&entry, memory_backend->config_list, key)) != 0) + return error; + + *out = &entry->base; + return 0; +} + +static int config_memory_iterator( + git_config_iterator **iter, + git_config_backend *backend) +{ + config_memory_backend *memory_backend = (config_memory_backend *) backend; + git_config_list *config_list; + int error; + + if ((error = git_config_list_dup(&config_list, memory_backend->config_list)) < 0) + goto out; + + if ((error = git_config_list_iterator_new(iter, config_list)) < 0) + goto out; + +out: + /* Let iterator delete duplicated config_list when it's done */ + git_config_list_free(config_list); + return error; +} + +static int config_memory_set(git_config_backend *backend, const char *name, const char *value) +{ + GIT_UNUSED(backend); + GIT_UNUSED(name); + GIT_UNUSED(value); + return config_error_readonly(); +} + +static int config_memory_set_multivar( + git_config_backend *backend, const char *name, const char *regexp, const char *value) +{ + GIT_UNUSED(backend); + GIT_UNUSED(name); + GIT_UNUSED(regexp); + GIT_UNUSED(value); + return config_error_readonly(); +} + +static int config_memory_delete(git_config_backend *backend, const char *name) +{ + GIT_UNUSED(backend); + GIT_UNUSED(name); + return config_error_readonly(); +} + +static int config_memory_delete_multivar(git_config_backend *backend, const char *name, const char *regexp) +{ + GIT_UNUSED(backend); + GIT_UNUSED(name); + GIT_UNUSED(regexp); + return config_error_readonly(); +} + +static int config_memory_lock(git_config_backend *backend) +{ + GIT_UNUSED(backend); + return config_error_readonly(); +} + +static int config_memory_unlock(git_config_backend *backend, int success) +{ + GIT_UNUSED(backend); + GIT_UNUSED(success); + return config_error_readonly(); +} + +static void config_memory_free(git_config_backend *_backend) +{ + config_memory_backend *backend = (config_memory_backend *)_backend; + + if (backend == NULL) + return; + + git__free(backend->origin_path); + git__free(backend->backend_type); + git_config_list_free(backend->config_list); + git_strlist_free(backend->values, backend->values_len); + git_str_dispose(&backend->cfg); + git__free(backend); +} + +static config_memory_backend *config_backend_new( + git_config_backend_memory_options *opts) +{ + config_memory_backend *backend; + + if ((backend = git__calloc(1, sizeof(config_memory_backend))) == NULL) + return NULL; + + if (git_config_list_new(&backend->config_list) < 0) + goto on_error; + + backend->parent.version = GIT_CONFIG_BACKEND_VERSION; + backend->parent.readonly = 1; + backend->parent.open = config_memory_open; + backend->parent.get = config_memory_get; + backend->parent.set = config_memory_set; + backend->parent.set_multivar = config_memory_set_multivar; + backend->parent.del = config_memory_delete; + backend->parent.del_multivar = config_memory_delete_multivar; + backend->parent.iterator = config_memory_iterator; + backend->parent.lock = config_memory_lock; + backend->parent.unlock = config_memory_unlock; + backend->parent.snapshot = git_config_backend_snapshot; + backend->parent.free = config_memory_free; + + backend->backend_type = git__strdup(opts && opts->backend_type ? + opts->backend_type : "in-memory"); + + if (backend->backend_type == NULL) + goto on_error; + + if (opts && opts->origin_path && + (backend->origin_path = git__strdup(opts->origin_path)) == NULL) + goto on_error; + + return backend; + +on_error: + git_config_list_free(backend->config_list); + git__free(backend->origin_path); + git__free(backend->backend_type); + git__free(backend); + return NULL; +} + +int git_config_backend_from_string( + git_config_backend **out, + const char *cfg, + size_t len, + git_config_backend_memory_options *opts) +{ + config_memory_backend *backend; + + if ((backend = config_backend_new(opts)) == NULL) + return -1; + + if (git_str_set(&backend->cfg, cfg, len) < 0) { + git_config_list_free(backend->config_list); + git__free(backend); + return -1; + } + + *out = (git_config_backend *)backend; + return 0; +} + +int git_config_backend_from_values( + git_config_backend **out, + const char **values, + size_t len, + git_config_backend_memory_options *opts) +{ + config_memory_backend *backend; + + if ((backend = config_backend_new(opts)) == NULL) + return -1; + + if (git_strlist_copy(&backend->values, values, len) < 0) { + git_config_list_free(backend->config_list); + git__free(backend); + return -1; + } + + backend->values_len = len; + + *out = (git_config_backend *)backend; + return 0; +} diff --git a/vendor/libgit2/src/config_parse.c b/vendor/libgit2/src/libgit2/config_parse.c similarity index 97% rename from vendor/libgit2/src/config_parse.c rename to vendor/libgit2/src/libgit2/config_parse.c index 06931368..7f933db4 100644 --- a/vendor/libgit2/src/config_parse.c +++ b/vendor/libgit2/src/libgit2/config_parse.c @@ -25,9 +25,9 @@ static void set_parse_error(git_config_parser *reader, int col, const char *erro } -GIT_INLINE(int) config_keychar(int c) +GIT_INLINE(int) config_keychar(char c) { - return isalnum(c) || c == '-'; + return git__isalnum(c) || c == '-'; } static int strip_comments(char *line, int in_quotes) @@ -158,9 +158,10 @@ static int parse_subsection_header(git_config_parser *reader, const char *line, static int parse_section_header(git_config_parser *reader, char **section_out) { char *name, *name_end; - int name_length, c, pos; + int name_length, pos; int result; char *line; + char c; size_t line_len; git_parse_advance_ws(&reader->ctx); @@ -279,8 +280,7 @@ static int skip_bom(git_parse_ctx *parser) */ /* '\"' -> '"' etc */ -static int unescape_line( - char **out, bool *is_multi, const char *ptr, int quote_count) +static int unescape_line(char **out, bool *is_multi, const char *ptr, int *quote_count) { char *str, *fixed, *esc; size_t ptr_len = strlen(ptr), alloc_len; @@ -296,7 +296,8 @@ static int unescape_line( while (*ptr != '\0') { if (*ptr == '"') { - quote_count++; + if (quote_count) + (*quote_count)++; } else if (*ptr != '\\') { *fixed++ = *ptr; } else { @@ -358,7 +359,7 @@ static int parse_multiline_variable(git_config_parser *reader, git_str *value, i goto next; if ((error = unescape_line(&proc_line, &multiline, - line, in_quotes)) < 0) + line, &in_quotes)) < 0) goto out; /* Add this line to the multiline var */ @@ -382,7 +383,7 @@ static int parse_multiline_variable(git_config_parser *reader, git_str *value, i GIT_INLINE(bool) is_namechar(char c) { - return isalnum(c) || c == '-'; + return git__isalnum(c) || c == '-'; } static int parse_name( @@ -445,7 +446,7 @@ static int parse_variable(git_config_parser *reader, char **var_name, char **var while (git__isspace(value_start[0])) value_start++; - if ((error = unescape_line(&value, &multiline, value_start, 0)) < 0) + if ((error = unescape_line(&value, &multiline, value_start, NULL)) < 0) goto out; if (multiline) { diff --git a/vendor/libgit2/src/config_parse.h b/vendor/libgit2/src/libgit2/config_parse.h similarity index 100% rename from vendor/libgit2/src/config_parse.h rename to vendor/libgit2/src/libgit2/config_parse.h diff --git a/vendor/libgit2/src/config_snapshot.c b/vendor/libgit2/src/libgit2/config_snapshot.c similarity index 78% rename from vendor/libgit2/src/config_snapshot.c rename to vendor/libgit2/src/libgit2/config_snapshot.c index e295d2f7..d8b8733a 100644 --- a/vendor/libgit2/src/config_snapshot.c +++ b/vendor/libgit2/src/libgit2/config_snapshot.c @@ -8,12 +8,12 @@ #include "config_backend.h" #include "config.h" -#include "config_entries.h" +#include "config_list.h" typedef struct { git_config_backend parent; git_mutex values_mutex; - git_config_entries *entries; + git_config_list *config_list; git_config_backend *source; } config_snapshot_backend; @@ -28,31 +28,24 @@ static int config_snapshot_iterator( struct git_config_backend *backend) { config_snapshot_backend *b = GIT_CONTAINER_OF(backend, config_snapshot_backend, parent); - git_config_entries *entries = NULL; + git_config_list *config_list = NULL; int error; - if ((error = git_config_entries_dup(&entries, b->entries)) < 0 || - (error = git_config_entries_iterator_new(iter, entries)) < 0) + if ((error = git_config_list_dup(&config_list, b->config_list)) < 0 || + (error = git_config_list_iterator_new(iter, config_list)) < 0) goto out; out: - /* Let iterator delete duplicated entries when it's done */ - git_config_entries_free(entries); + /* Let iterator delete duplicated config_list when it's done */ + git_config_list_free(config_list); return error; } -/* release the map containing the entry as an equivalent to freeing it */ -static void config_snapshot_entry_free(git_config_entry *entry) -{ - git_config_entries *entries = (git_config_entries *) entry->payload; - git_config_entries_free(entries); -} - static int config_snapshot_get(git_config_backend *cfg, const char *key, git_config_entry **out) { config_snapshot_backend *b = GIT_CONTAINER_OF(cfg, config_snapshot_backend, parent); - git_config_entries *entries = NULL; - git_config_entry *entry; + git_config_list *config_list = NULL; + git_config_list_entry *entry; int error = 0; if (git_mutex_lock(&b->values_mutex) < 0) { @@ -60,19 +53,16 @@ static int config_snapshot_get(git_config_backend *cfg, const char *key, git_con return -1; } - entries = b->entries; - git_config_entries_incref(entries); + config_list = b->config_list; + git_config_list_incref(config_list); git_mutex_unlock(&b->values_mutex); - if ((error = (git_config_entries_get(&entry, entries, key))) < 0) { - git_config_entries_free(entries); + if ((error = (git_config_list_get(&entry, config_list, key))) < 0) { + git_config_list_free(config_list); return error; } - entry->free = config_snapshot_entry_free; - entry->payload = entries; - *out = entry; - + *out = &entry->base; return 0; } @@ -135,7 +125,7 @@ static void config_snapshot_free(git_config_backend *_backend) if (backend == NULL) return; - git_config_entries_free(backend->entries); + git_config_list_free(backend->config_list); git_mutex_free(&backend->values_mutex); git__free(backend); } @@ -143,7 +133,7 @@ static void config_snapshot_free(git_config_backend *_backend) static int config_snapshot_open(git_config_backend *cfg, git_config_level_t level, const git_repository *repo) { config_snapshot_backend *b = GIT_CONTAINER_OF(cfg, config_snapshot_backend, parent); - git_config_entries *entries = NULL; + git_config_list *config_list = NULL; git_config_iterator *it = NULL; git_config_entry *entry; int error; @@ -152,12 +142,12 @@ static int config_snapshot_open(git_config_backend *cfg, git_config_level_t leve GIT_UNUSED(level); GIT_UNUSED(repo); - if ((error = git_config_entries_new(&entries)) < 0 || + if ((error = git_config_list_new(&config_list)) < 0 || (error = b->source->iterator(&it, b->source)) < 0) goto out; while ((error = git_config_next(&entry, it)) == 0) - if ((error = git_config_entries_dup_entry(entries, entry)) < 0) + if ((error = git_config_list_dup_entry(config_list, entry)) < 0) goto out; if (error < 0) { @@ -166,12 +156,12 @@ static int config_snapshot_open(git_config_backend *cfg, git_config_level_t leve error = 0; } - b->entries = entries; + b->config_list = config_list; out: git_config_iterator_free(it); if (error) - git_config_entries_free(entries); + git_config_list_free(config_list); return error; } diff --git a/vendor/libgit2/src/crlf.c b/vendor/libgit2/src/libgit2/crlf.c similarity index 100% rename from vendor/libgit2/src/crlf.c rename to vendor/libgit2/src/libgit2/crlf.c diff --git a/vendor/libgit2/src/delta.c b/vendor/libgit2/src/libgit2/delta.c similarity index 100% rename from vendor/libgit2/src/delta.c rename to vendor/libgit2/src/libgit2/delta.c diff --git a/vendor/libgit2/src/delta.h b/vendor/libgit2/src/libgit2/delta.h similarity index 100% rename from vendor/libgit2/src/delta.h rename to vendor/libgit2/src/libgit2/delta.h diff --git a/vendor/libgit2/src/describe.c b/vendor/libgit2/src/libgit2/describe.c similarity index 98% rename from vendor/libgit2/src/describe.c rename to vendor/libgit2/src/libgit2/describe.c index 1033eac5..04453472 100644 --- a/vendor/libgit2/src/describe.c +++ b/vendor/libgit2/src/libgit2/describe.c @@ -8,7 +8,6 @@ #include "common.h" #include "git2/describe.h" -#include "git2/strarray.h" #include "git2/diff.h" #include "git2/status.h" @@ -19,6 +18,7 @@ #include "refs.h" #include "repository.h" #include "revwalk.h" +#include "strarray.h" #include "tag.h" #include "vector.h" #include "wildmatch.h" @@ -363,12 +363,15 @@ static int find_unique_abbrev_size( size_t size = abbreviated_size; git_odb *odb; git_oid dummy; + size_t hexsize; int error; if ((error = git_repository_odb__weakptr(&odb, repo)) < 0) return error; - while (size < GIT_OID_HEXSZ) { + hexsize = git_oid_hexsize(repo->oid_type); + + while (size < hexsize) { if ((error = git_odb_exists_prefix(&dummy, odb, oid_in, size)) == 0) { *out = (int) size; return 0; @@ -383,7 +386,7 @@ static int find_unique_abbrev_size( } /* If we didn't find any shorter prefix, we have to do the whole thing */ - *out = GIT_OID_HEXSZ; + *out = (int)hexsize; return 0; } @@ -397,7 +400,7 @@ static int show_suffix( { int error, size = 0; - char hex_oid[GIT_OID_HEXSZ]; + char hex_oid[GIT_OID_MAX_HEXSIZE]; if ((error = find_unique_abbrev_size(&size, repo, id, abbrev_size)) < 0) return error; @@ -414,7 +417,7 @@ static int show_suffix( #define MAX_CANDIDATES_TAGS FLAG_BITS - 1 static int describe_not_found(const git_oid *oid, const char *message_format) { - char oid_str[GIT_OID_HEXSZ + 1]; + char oid_str[GIT_OID_MAX_HEXSIZE + 1]; git_oid_tostr(oid_str, sizeof(oid_str), oid); git_error_set(GIT_ERROR_DESCRIBE, message_format, oid_str); @@ -525,7 +528,7 @@ static int describe( if (annotated_cnt && (git_pqueue_size(&list) == 0)) { /* if (debug) { - char oid_str[GIT_OID_HEXSZ + 1]; + char oid_str[GIT_OID_MAX_HEXSIZE + 1]; git_oid_tostr(oid_str, sizeof(oid_str), &c->oid); fprintf(stderr, "finished search at %s\n", oid_str); @@ -592,7 +595,7 @@ static int describe( "head", "lightweight", "annotated", }; - char oid_str[GIT_OID_HEXSZ + 1]; + char oid_str[GIT_OID_MAX_HEXSIZE + 1]; if (debug) { for (cur_match = 0; cur_match < match_cnt; cur_match++) { @@ -816,7 +819,7 @@ static int git_describe__format( /* If we didn't find *any* tags, we fall back to the commit's id */ if (result->fallback_to_id) { - char hex_oid[GIT_OID_HEXSZ + 1] = {0}; + char hex_oid[GIT_OID_MAX_HEXSIZE + 1] = {0}; int size = 0; if ((error = find_unique_abbrev_size( diff --git a/vendor/libgit2/src/diff.c b/vendor/libgit2/src/libgit2/diff.c similarity index 93% rename from vendor/libgit2/src/diff.c rename to vendor/libgit2/src/libgit2/diff.c index 9840d605..db12ccd6 100644 --- a/vendor/libgit2/src/diff.c +++ b/vendor/libgit2/src/libgit2/diff.c @@ -19,8 +19,10 @@ #include "git2/email.h" struct patch_id_args { + git_diff *diff; git_hash_ctx ctx; git_oid result; + git_oid_t oid_type; int first_file; }; @@ -280,17 +282,19 @@ int git_diff_find_options_init( return 0; } -static int flush_hunk(git_oid *result, git_hash_ctx *ctx) +static int flush_hunk(git_oid *result, struct patch_id_args *args) { + git_hash_ctx *ctx = &args->ctx; git_oid hash; unsigned short carry = 0; - int error, i; + size_t i; + int error; if ((error = git_hash_final(hash.id, ctx)) < 0 || (error = git_hash_init(ctx)) < 0) return error; - for (i = 0; i < GIT_OID_RAWSZ; i++) { + for (i = 0; i < git_oid_size(args->oid_type); i++) { carry += result->id[i] + hash.id[i]; result->id[i] = (unsigned char)carry; carry >>= 8; @@ -338,7 +342,7 @@ static int diff_patchid_print_callback_to_buf( if (line->origin == GIT_DIFF_LINE_FILE_HDR && !args->first_file && - (error = flush_hunk(&args->result, &args->ctx) < 0)) + (error = flush_hunk(&args->result, args) < 0)) goto out; if ((error = git_hash_update(&args->ctx, buf.ptr, buf.size)) < 0) @@ -362,14 +366,19 @@ int git_diff_patchid_options_init(git_diff_patchid_options *opts, unsigned int v int git_diff_patchid(git_oid *out, git_diff *diff, git_diff_patchid_options *opts) { struct patch_id_args args; + git_hash_algorithm_t algorithm; int error; GIT_ERROR_CHECK_VERSION( opts, GIT_DIFF_PATCHID_OPTIONS_VERSION, "git_diff_patchid_options"); + algorithm = git_oid_algorithm(diff->opts.oid_type); + memset(&args, 0, sizeof(args)); + args.diff = diff; args.first_file = 1; - if ((error = git_hash_ctx_init(&args.ctx, GIT_HASH_ALGORITHM_SHA1)) < 0) + args.oid_type = diff->opts.oid_type; + if ((error = git_hash_ctx_init(&args.ctx, algorithm)) < 0) goto out; if ((error = git_diff_print(diff, @@ -378,9 +387,13 @@ int git_diff_patchid(git_oid *out, git_diff *diff, git_diff_patchid_options *opt &args)) < 0) goto out; - if ((error = (flush_hunk(&args.result, &args.ctx))) < 0) + if ((error = (flush_hunk(&args.result, &args))) < 0) goto out; +#ifdef GIT_EXPERIMENTAL_SHA256 + args.result.type = diff->opts.oid_type; +#endif + git_oid_cpy(out, &args.result); out: diff --git a/vendor/libgit2/src/diff.h b/vendor/libgit2/src/libgit2/diff.h similarity index 88% rename from vendor/libgit2/src/diff.h rename to vendor/libgit2/src/libgit2/diff.h index 2cc35e65..f21b2764 100644 --- a/vendor/libgit2/src/diff.h +++ b/vendor/libgit2/src/libgit2/diff.h @@ -30,15 +30,15 @@ typedef enum { } git_diff_origin_t; struct git_diff { - git_refcount rc; + git_refcount rc; git_repository *repo; - git_attr_session attrsession; + git_attr_session attrsession; git_diff_origin_t type; - git_diff_options opts; - git_vector deltas; /* vector of git_diff_delta */ + git_diff_options opts; + git_vector deltas; /* vector of git_diff_delta */ git_pool pool; - git_iterator_t old_src; - git_iterator_t new_src; + git_iterator_t old_src; + git_iterator_t new_src; git_diff_perfdata perf; int (*strcomp)(const char *, const char *); diff --git a/vendor/libgit2/src/diff_driver.c b/vendor/libgit2/src/libgit2/diff_driver.c similarity index 100% rename from vendor/libgit2/src/diff_driver.c rename to vendor/libgit2/src/libgit2/diff_driver.c diff --git a/vendor/libgit2/src/diff_driver.h b/vendor/libgit2/src/libgit2/diff_driver.h similarity index 100% rename from vendor/libgit2/src/diff_driver.h rename to vendor/libgit2/src/libgit2/diff_driver.h diff --git a/vendor/libgit2/src/diff_file.c b/vendor/libgit2/src/libgit2/diff_file.c similarity index 94% rename from vendor/libgit2/src/diff_file.c rename to vendor/libgit2/src/libgit2/diff_file.c index c7e9fbee..a792834c 100644 --- a/vendor/libgit2/src/diff_file.c +++ b/vendor/libgit2/src/libgit2/diff_file.c @@ -112,7 +112,7 @@ int git_diff_file_content__init_from_diff( case GIT_DELTA_DELETED: has_data = use_old; break; case GIT_DELTA_UNTRACKED: - has_data = !use_old && + has_data = (use_old == (diff->opts.flags & GIT_DIFF_REVERSE)) && (diff->opts.flags & GIT_DIFF_SHOW_UNTRACKED_CONTENT) != 0; break; case GIT_DELTA_UNREADABLE: @@ -144,6 +144,7 @@ int git_diff_file_content__init_from_src( if (!src->blob && !src->buf) { fc->flags |= GIT_DIFF_FLAG__NO_DATA; + git_oid_clear(&fc->file->id, opts->oid_type); } else { fc->flags |= GIT_DIFF_FLAG__LOADED; fc->file->flags |= GIT_DIFF_FLAG_VALID_ID; @@ -153,7 +154,7 @@ int git_diff_file_content__init_from_src( git_blob_dup((git_blob **)&fc->blob, (git_blob *) src->blob); fc->file->size = git_blob_rawsize(src->blob); git_oid_cpy(&fc->file->id, git_blob_id(src->blob)); - fc->file->id_abbrev = GIT_OID_HEXSZ; + fc->file->id_abbrev = (uint16_t)git_oid_hexsize(repo->oid_type); fc->map.len = (size_t)fc->file->size; fc->map.data = (char *)git_blob_rawcontent(src->blob); @@ -161,10 +162,10 @@ int git_diff_file_content__init_from_src( fc->flags |= GIT_DIFF_FLAG__FREE_BLOB; } else { int error; - if ((error = git_odb_hash(&fc->file->id, src->buf, src->buflen, GIT_OBJECT_BLOB)) < 0) + if ((error = git_odb__hash(&fc->file->id, src->buf, src->buflen, GIT_OBJECT_BLOB, opts->oid_type)) < 0) return error; fc->file->size = src->buflen; - fc->file->id_abbrev = GIT_OID_HEXSZ; + fc->file->id_abbrev = (uint16_t)git_oid_hexsize(opts->oid_type); fc->map.len = src->buflen; fc->map.data = (char *)src->buf; @@ -177,7 +178,7 @@ int git_diff_file_content__init_from_src( static int diff_file_content_commit_to_str( git_diff_file_content *fc, bool check_status) { - char oid[GIT_OID_HEXSZ+1]; + char oid[GIT_OID_MAX_HEXSIZE+1]; git_str content = GIT_STR_INIT; const char *status = ""; @@ -347,6 +348,13 @@ static int diff_file_content_load_workdir_file( goto cleanup; } + /* if file is empty, don't attempt to mmap or readbuffer */ + if (fc->file->size == 0) { + fc->map.len = 0; + fc->map.data = git_str__initstr; + goto cleanup; + } + if ((diff_opts->flags & GIT_DIFF_SHOW_BINARY) == 0 && diff_file_content_binary_by_size(fc)) goto cleanup; @@ -410,8 +418,9 @@ static int diff_file_content_load_workdir( /* once data is loaded, update OID if we didn't have it previously */ if (!error && (fc->file->flags & GIT_DIFF_FLAG_VALID_ID) == 0) { - error = git_odb_hash( - &fc->file->id, fc->map.data, fc->map.len, GIT_OBJECT_BLOB); + error = git_odb__hash( + &fc->file->id, fc->map.data, fc->map.len, + GIT_OBJECT_BLOB, diff_opts->oid_type); fc->file->flags |= GIT_DIFF_FLAG_VALID_ID; } diff --git a/vendor/libgit2/src/diff_file.h b/vendor/libgit2/src/libgit2/diff_file.h similarity index 100% rename from vendor/libgit2/src/diff_file.h rename to vendor/libgit2/src/libgit2/diff_file.h diff --git a/vendor/libgit2/src/diff_generate.c b/vendor/libgit2/src/libgit2/diff_generate.c similarity index 97% rename from vendor/libgit2/src/diff_generate.c rename to vendor/libgit2/src/libgit2/diff_generate.c index cfaefba6..78fe510e 100644 --- a/vendor/libgit2/src/diff_generate.c +++ b/vendor/libgit2/src/libgit2/diff_generate.c @@ -61,6 +61,9 @@ static git_diff_delta *diff_delta__alloc( } delta->status = status; + git_oid_clear(&delta->old_file.id, diff->base.opts.oid_type); + git_oid_clear(&delta->new_file.id, diff->base.opts.oid_type); + return delta; } @@ -146,10 +149,13 @@ static int diff_delta__from_one( const git_index_entry *entry = nitem; bool has_old = false; git_diff_delta *delta; + git_oid_t oid_type; const char *matched_pathspec; GIT_ASSERT_ARG((oitem != NULL) ^ (nitem != NULL)); + oid_type = diff->base.opts.oid_type; + if (oitem) { entry = oitem; has_old = true; @@ -183,18 +189,23 @@ static int diff_delta__from_one( GIT_ASSERT(status != GIT_DELTA_MODIFIED); delta->nfiles = 1; + git_oid_clear(&delta->old_file.id, diff->base.opts.oid_type); + git_oid_clear(&delta->new_file.id, diff->base.opts.oid_type); + if (has_old) { delta->old_file.mode = entry->mode; delta->old_file.size = entry->file_size; delta->old_file.flags |= GIT_DIFF_FLAG_EXISTS; git_oid_cpy(&delta->old_file.id, &entry->id); - delta->old_file.id_abbrev = GIT_OID_HEXSZ; + git_oid_clear(&delta->new_file.id, oid_type); + delta->old_file.id_abbrev = (uint16_t)git_oid_hexsize(oid_type); } else /* ADDED, IGNORED, UNTRACKED */ { delta->new_file.mode = entry->mode; delta->new_file.size = entry->file_size; delta->new_file.flags |= GIT_DIFF_FLAG_EXISTS; + git_oid_clear(&delta->old_file.id, oid_type); git_oid_cpy(&delta->new_file.id, &entry->id); - delta->new_file.id_abbrev = GIT_OID_HEXSZ; + delta->new_file.id_abbrev = (uint16_t)git_oid_hexsize(oid_type); } delta->old_file.flags |= GIT_DIFF_FLAG_VALID_ID; @@ -220,6 +231,9 @@ static int diff_delta__from_two( const git_oid *old_id = &old_entry->id; git_diff_delta *delta; const char *canonical_path = old_entry->path; + git_oid_t oid_type; + + oid_type = diff->base.opts.oid_type; if (status == GIT_DELTA_UNMODIFIED && DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_UNMODIFIED)) @@ -249,14 +263,14 @@ static int diff_delta__from_two( delta->old_file.size = old_entry->file_size; delta->old_file.mode = old_mode; git_oid_cpy(&delta->old_file.id, old_id); - delta->old_file.id_abbrev = GIT_OID_HEXSZ; + delta->old_file.id_abbrev = (uint16_t)git_oid_hexsize(oid_type); delta->old_file.flags |= GIT_DIFF_FLAG_VALID_ID | GIT_DIFF_FLAG_EXISTS; } if (!git_index_entry_is_conflict(new_entry)) { git_oid_cpy(&delta->new_file.id, new_id); - delta->new_file.id_abbrev = GIT_OID_HEXSZ; + delta->new_file.id_abbrev = (uint16_t)git_oid_hexsize(oid_type); delta->new_file.size = new_entry->file_size; delta->new_file.mode = new_mode; delta->old_file.flags |= GIT_DIFF_FLAG_EXISTS; @@ -485,6 +499,14 @@ static int diff_generated_apply_options( return -1; } + if (!diff->base.opts.oid_type) { + diff->base.opts.oid_type = repo->oid_type; + } else if (diff->base.opts.oid_type != repo->oid_type) { + git_error_set(GIT_ERROR_INVALID, + "specified object ID type does not match repository object ID type"); + return -1; + } + /* flag INCLUDE_TYPECHANGE_TREES implies INCLUDE_TYPECHANGE */ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES)) diff->base.opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE; @@ -598,6 +620,7 @@ int git_diff__oid_for_file( entry.mode = mode; entry.file_size = (uint32_t)size; entry.path = (char *)path; + git_oid_clear(&entry.id, diff->opts.oid_type); return git_diff__oid_for_entry(out, diff, &entry, mode, NULL); } @@ -618,7 +641,7 @@ int git_diff__oid_for_entry( GIT_ASSERT(d->type == GIT_DIFF_TYPE_GENERATED); diff = (git_diff_generated *)d; - memset(out, 0, sizeof(*out)); + git_oid_clear(out, diff->base.opts.oid_type); if (git_repository_workdir_path(&full_path, diff->base.repo, entry.path) < 0) return -1; @@ -654,7 +677,8 @@ int git_diff__oid_for_entry( git_error_clear(); } } else if (S_ISLNK(mode)) { - error = git_odb__hashlink(out, full_path.ptr); + error = git_odb__hashlink(out, full_path.ptr, + diff->base.opts.oid_type); diff->base.perf.oid_calculations++; } else if (!git__is_sizet(entry.file_size)) { git_error_set(GIT_ERROR_NOMEMORY, "file size overflow (for 32-bits) on '%s'", @@ -669,7 +693,9 @@ int git_diff__oid_for_entry( error = fd; else { error = git_odb__hashfd_filtered( - out, fd, (size_t)entry.file_size, GIT_OBJECT_BLOB, fl); + out, fd, (size_t)entry.file_size, + GIT_OBJECT_BLOB, diff->base.opts.oid_type, + fl); p_close(fd); diff->base.perf.oid_calculations++; } @@ -789,11 +815,11 @@ static int maybe_modified( const char *matched_pathspec; int error = 0; + git_oid_clear(&noid, diff->base.opts.oid_type); + if (!diff_pathspec_match(&matched_pathspec, diff, oitem)) return 0; - memset(&noid, 0, sizeof(noid)); - /* on platforms with no symlinks, preserve mode of existing symlinks */ if (S_ISLNK(omode) && S_ISREG(nmode) && new_is_workdir && !(diff->diffcaps & GIT_DIFFCAPS_HAS_SYMLINKS)) @@ -1695,11 +1721,11 @@ int git_diff__commit( *out = NULL; if ((parents = git_commit_parentcount(commit)) > 1) { - char commit_oidstr[GIT_OID_HEXSZ + 1]; + char commit_oidstr[GIT_OID_MAX_HEXSIZE + 1]; error = -1; git_error_set(GIT_ERROR_INVALID, "commit %s is a merge commit", - git_oid_tostr(commit_oidstr, GIT_OID_HEXSZ + 1, git_commit_id(commit))); + git_oid_tostr(commit_oidstr, GIT_OID_MAX_HEXSIZE + 1, git_commit_id(commit))); goto on_error; } diff --git a/vendor/libgit2/src/diff_generate.h b/vendor/libgit2/src/libgit2/diff_generate.h similarity index 100% rename from vendor/libgit2/src/diff_generate.h rename to vendor/libgit2/src/libgit2/diff_generate.h diff --git a/vendor/libgit2/src/diff_parse.c b/vendor/libgit2/src/libgit2/diff_parse.c similarity index 79% rename from vendor/libgit2/src/diff_parse.c rename to vendor/libgit2/src/libgit2/diff_parse.c index 75e41a54..04603969 100644 --- a/vendor/libgit2/src/diff_parse.c +++ b/vendor/libgit2/src/libgit2/diff_parse.c @@ -29,7 +29,7 @@ static void diff_parsed_free(git_diff *d) git__free(diff); } -static git_diff_parsed *diff_parsed_alloc(void) +static git_diff_parsed *diff_parsed_alloc(git_oid_t oid_type) { git_diff_parsed *diff; @@ -51,6 +51,7 @@ static git_diff_parsed *diff_parsed_alloc(void) } diff->base.opts.flags &= ~GIT_DIFF_IGNORE_CASE; + diff->base.opts.oid_type = oid_type; if (git_pool_init(&diff->base.pool, 1) < 0 || git_vector_init(&diff->patches, 0, NULL) < 0 || @@ -67,19 +68,34 @@ static git_diff_parsed *diff_parsed_alloc(void) int git_diff_from_buffer( git_diff **out, const char *content, - size_t content_len) + size_t content_len +#ifdef GIT_EXPERIMENTAL_SHA256 + , git_diff_parse_options *opts +#endif + ) { git_diff_parsed *diff; git_patch *patch; git_patch_parse_ctx *ctx = NULL; + git_patch_options patch_opts = GIT_PATCH_OPTIONS_INIT; + git_oid_t oid_type; int error = 0; *out = NULL; - diff = diff_parsed_alloc(); +#ifdef GIT_EXPERIMENTAL_SHA256 + oid_type = (opts && opts->oid_type) ? opts->oid_type : + GIT_OID_DEFAULT; +#else + oid_type = GIT_OID_DEFAULT; +#endif + + patch_opts.oid_type = oid_type; + + diff = diff_parsed_alloc(oid_type); GIT_ERROR_CHECK_ALLOC(diff); - ctx = git_patch_parse_ctx_init(content, content_len, NULL); + ctx = git_patch_parse_ctx_init(content, content_len, &patch_opts); GIT_ERROR_CHECK_ALLOC(ctx); while (ctx->parse_ctx.remain_len) { diff --git a/vendor/libgit2/src/diff_parse.h b/vendor/libgit2/src/libgit2/diff_parse.h similarity index 100% rename from vendor/libgit2/src/diff_parse.h rename to vendor/libgit2/src/libgit2/diff_parse.h diff --git a/vendor/libgit2/src/diff_print.c b/vendor/libgit2/src/libgit2/diff_print.c similarity index 91% rename from vendor/libgit2/src/diff_print.c rename to vendor/libgit2/src/libgit2/diff_print.c index 6c5a2cdc..daeefca5 100644 --- a/vendor/libgit2/src/diff_print.c +++ b/vendor/libgit2/src/libgit2/diff_print.c @@ -29,6 +29,8 @@ typedef struct { const char *new_prefix; uint32_t flags; int id_strlen; + unsigned int sent_file_header; + git_oid_t oid_type; int (*strcomp)(const char *, const char *); } diff_print_info; @@ -46,6 +48,8 @@ static int diff_print_info_init__common( pi->payload = payload; pi->buf = out; + GIT_ASSERT(pi->oid_type); + if (!pi->id_strlen) { if (!repo) pi->id_strlen = GIT_ABBREV_DEFAULT; @@ -53,8 +57,9 @@ static int diff_print_info_init__common( return -1; } - if (pi->id_strlen > GIT_OID_HEXSZ) - pi->id_strlen = GIT_OID_HEXSZ; + if (pi->id_strlen > 0 && + (size_t)pi->id_strlen > git_oid_hexsize(pi->oid_type)) + pi->id_strlen = (int)git_oid_hexsize(pi->oid_type); memset(&pi->line, 0, sizeof(pi->line)); pi->line.old_lineno = -1; @@ -78,6 +83,7 @@ static int diff_print_info_init_fromdiff( if (diff) { pi->flags = diff->opts.flags; + pi->oid_type = diff->opts.oid_type; pi->id_strlen = diff->opts.id_abbrev; pi->old_prefix = diff->opts.old_prefix; pi->new_prefix = diff->opts.new_prefix; @@ -101,6 +107,7 @@ static int diff_print_info_init_frompatch( memset(pi, 0, sizeof(diff_print_info)); pi->flags = patch->diff_opts.flags; + pi->oid_type = patch->diff_opts.oid_type; pi->id_strlen = patch->diff_opts.id_abbrev; pi->old_prefix = patch->diff_opts.old_prefix; pi->new_prefix = patch->diff_opts.new_prefix; @@ -212,7 +219,10 @@ static int diff_print_one_raw( git_str *out = pi->buf; int id_abbrev; char code = git_diff_status_char(delta->status); - char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1]; + char start_oid[GIT_OID_MAX_HEXSIZE + 1], + end_oid[GIT_OID_MAX_HEXSIZE + 1]; + size_t oid_hexsize; + bool id_is_abbrev; GIT_UNUSED(progress); @@ -231,12 +241,21 @@ static int diff_print_one_raw( return -1; } +#ifdef GIT_EXPERIMENTAL_SHA256 + GIT_ASSERT(delta->old_file.id.type == delta->new_file.id.type); + oid_hexsize = git_oid_hexsize(delta->old_file.id.type); +#else + oid_hexsize = GIT_OID_SHA1_HEXSIZE; +#endif + + id_is_abbrev = (pi->id_strlen > 0 && + (size_t)pi->id_strlen <= oid_hexsize); + git_oid_tostr(start_oid, pi->id_strlen + 1, &delta->old_file.id); git_oid_tostr(end_oid, pi->id_strlen + 1, &delta->new_file.id); - git_str_printf( - out, (pi->id_strlen <= GIT_OID_HEXSZ) ? - ":%06o %06o %s... %s... %c" : ":%06o %06o %s %s %c", + git_str_printf(out, + id_is_abbrev ? ":%06o %06o %s... %s... %c" : ":%06o %06o %s %s %c", delta->old_file.mode, delta->new_file.mode, start_oid, end_oid, code); if (delta->similarity > 0) @@ -273,7 +292,8 @@ static int diff_print_oid_range( git_str *out, const git_diff_delta *delta, int id_strlen, bool print_index) { - char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1]; + char start_oid[GIT_OID_MAX_HEXSIZE + 1], + end_oid[GIT_OID_MAX_HEXSIZE + 1]; if (delta->old_file.mode && id_strlen > delta->old_file.id_abbrev) { @@ -560,6 +580,30 @@ static int diff_print_patch_file_binary( return error; } +GIT_INLINE(int) should_force_header(const git_diff_delta *delta) +{ + if (delta->old_file.mode != delta->new_file.mode) + return 1; + + if (delta->status == GIT_DELTA_RENAMED || delta->status == GIT_DELTA_COPIED) + return 1; + + return 0; +} + +GIT_INLINE(int) flush_file_header(const git_diff_delta *delta, diff_print_info *pi) +{ + if (pi->sent_file_header) + return 0; + + pi->line.origin = GIT_DIFF_LINE_FILE_HDR; + pi->line.content = git_str_cstr(pi->buf); + pi->line.content_len = git_str_len(pi->buf); + pi->sent_file_header = 1; + + return pi->print_cb(delta, NULL, &pi->line, pi->payload); +} + static int diff_print_patch_file( const git_diff_delta *delta, float progress, void *data) { @@ -590,15 +634,22 @@ static int diff_print_patch_file( (pi->flags & GIT_DIFF_SHOW_UNTRACKED_CONTENT) == 0)) return 0; + pi->sent_file_header = 0; + if ((error = git_diff_delta__format_file_header(pi->buf, delta, oldpfx, newpfx, id_strlen, print_index)) < 0) return error; - pi->line.origin = GIT_DIFF_LINE_FILE_HDR; - pi->line.content = git_str_cstr(pi->buf); - pi->line.content_len = git_str_len(pi->buf); + /* + * pi->buf now contains the file header data. Go ahead and send it + * if there's useful data in there, like similarity. Otherwise, we + * should queue it to send when we see the first hunk. This prevents + * us from sending a header when all hunks were ignored. + */ + if (should_force_header(delta) && (error = flush_file_header(delta, pi)) < 0) + return error; - return pi->print_cb(delta, NULL, &pi->line, pi->payload); + return 0; } static int diff_print_patch_binary( @@ -613,6 +664,9 @@ static int diff_print_patch_binary( pi->new_prefix ? pi->new_prefix : DIFF_NEW_PREFIX_DEFAULT; int error; + if ((error = flush_file_header(delta, pi)) < 0) + return error; + git_str_clear(pi->buf); if ((error = diff_print_patch_file_binary( @@ -632,10 +686,14 @@ static int diff_print_patch_hunk( void *data) { diff_print_info *pi = data; + int error; if (S_ISDIR(d->new_file.mode)) return 0; + if ((error = flush_file_header(d, pi)) < 0) + return error; + pi->line.origin = GIT_DIFF_LINE_HUNK_HDR; pi->line.content = h->header; pi->line.content_len = h->header_len; @@ -650,10 +708,14 @@ static int diff_print_patch_line( void *data) { diff_print_info *pi = data; + int error; if (S_ISDIR(delta->new_file.mode)) return 0; + if ((error = flush_file_header(delta, pi)) < 0) + return error; + return pi->print_cb(delta, hunk, line, pi->payload); } diff --git a/vendor/libgit2/src/diff_stats.c b/vendor/libgit2/src/libgit2/diff_stats.c similarity index 100% rename from vendor/libgit2/src/diff_stats.c rename to vendor/libgit2/src/libgit2/diff_stats.c diff --git a/vendor/libgit2/src/diff_stats.h b/vendor/libgit2/src/libgit2/diff_stats.h similarity index 100% rename from vendor/libgit2/src/diff_stats.h rename to vendor/libgit2/src/libgit2/diff_stats.h diff --git a/vendor/libgit2/src/diff_tform.c b/vendor/libgit2/src/libgit2/diff_tform.c similarity index 96% rename from vendor/libgit2/src/diff_tform.c rename to vendor/libgit2/src/libgit2/diff_tform.c index 913d649b..9fa3cef8 100644 --- a/vendor/libgit2/src/diff_tform.c +++ b/vendor/libgit2/src/libgit2/diff_tform.c @@ -364,6 +364,7 @@ static int insert_delete_side_of_split( memset(&deleted->new_file, 0, sizeof(deleted->new_file)); deleted->new_file.path = deleted->old_file.path; deleted->new_file.flags |= GIT_DIFF_FLAG_VALID_ID; + git_oid_clear(&deleted->new_file.id, diff->opts.oid_type); return git_vector_insert(onto, deleted); } @@ -397,6 +398,7 @@ static int apply_splits_and_deletes( memset(&delta->old_file, 0, sizeof(delta->old_file)); delta->old_file.path = delta->new_file.path; delta->old_file.flags |= GIT_DIFF_FLAG_VALID_ID; + git_oid_clear(&delta->old_file.id, diff->opts.oid_type); } /* clean up delta before inserting into new list */ @@ -651,6 +653,23 @@ static int calc_self_similarity( return 0; } +static void handle_non_blob( + git_diff *diff, + const git_diff_find_options *opts, + size_t delta_idx) +{ + git_diff_delta *delta = GIT_VECTOR_GET(&diff->deltas, delta_idx); + + /* skip things that are blobs */ + if (GIT_MODE_ISBLOB(delta->old_file.mode)) + return; + + /* honor "remove unmodified" flag for non-blobs (eg submodules) */ + if (delta->status == GIT_DELTA_UNMODIFIED && + FLAG_SET(opts, GIT_DIFF_FIND_REMOVE_UNMODIFIED)) + delta->flags |= GIT_DIFF_FLAG__TO_DELETE; +} + static bool is_rename_target( git_diff *diff, const git_diff_find_options *opts, @@ -808,7 +827,8 @@ int git_diff_find_similar( git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; size_t num_deltas, num_srcs = 0, num_tgts = 0; size_t tried_srcs = 0, tried_tgts = 0; - size_t num_rewrites = 0, num_updates = 0, num_bumped = 0; + size_t num_rewrites = 0, num_updates = 0, num_bumped = 0, + num_to_delete = 0; size_t sigcache_size; void **sigcache = NULL; /* cache of similarity metric file signatures */ diff_find_match *tgt2src = NULL; @@ -842,6 +862,8 @@ int git_diff_find_similar( * mark them for splitting if break-rewrites is enabled */ git_vector_foreach(&diff->deltas, t, tgt) { + handle_non_blob(diff, &opts, t); + if (is_rename_source(diff, &opts, t, sigcache)) ++num_srcs; @@ -850,11 +872,14 @@ int git_diff_find_similar( if ((tgt->flags & GIT_DIFF_FLAG__TO_SPLIT) != 0) num_rewrites++; + + if ((tgt->flags & GIT_DIFF_FLAG__TO_DELETE) != 0) + num_to_delete++; } - /* if there are no candidate srcs or tgts, we're done */ + /* If there are no candidate srcs or tgts, no need to find matches */ if (!num_srcs || !num_tgts) - goto cleanup; + goto split_and_delete; src2tgt = git__calloc(num_deltas, sizeof(diff_find_match)); GIT_ERROR_CHECK_ALLOC(src2tgt); @@ -995,6 +1020,7 @@ int git_diff_find_similar( memset(&src->new_file, 0, sizeof(src->new_file)); src->new_file.path = src->old_file.path; src->new_file.flags |= GIT_DIFF_FLAG_VALID_ID; + git_oid_clear(&src->new_file.id, diff->opts.oid_type); num_updates++; @@ -1020,6 +1046,7 @@ int git_diff_find_similar( memset(&src->old_file, 0, sizeof(src->old_file)); src->old_file.path = src->new_file.path; src->old_file.flags |= GIT_DIFF_FLAG_VALID_ID; + git_oid_clear(&src->old_file.id, diff->opts.oid_type); src->flags &= ~GIT_DIFF_FLAG__TO_SPLIT; num_rewrites--; @@ -1089,15 +1116,20 @@ int git_diff_find_similar( } } +split_and_delete: /* * Actually split and delete entries as needed */ - if (num_rewrites > 0 || num_updates > 0) + if (num_rewrites > 0 || num_updates > 0 || num_to_delete > 0) { + size_t apply_len = diff->deltas.length - + num_rewrites - num_to_delete; + error = apply_splits_and_deletes( - diff, diff->deltas.length - num_rewrites, + diff, apply_len, FLAG_SET(&opts, GIT_DIFF_BREAK_REWRITES) && !FLAG_SET(&opts, GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY)); + } cleanup: git__free(tgt2src); diff --git a/vendor/libgit2/src/diff_tform.h b/vendor/libgit2/src/libgit2/diff_tform.h similarity index 100% rename from vendor/libgit2/src/diff_tform.h rename to vendor/libgit2/src/libgit2/diff_tform.h diff --git a/vendor/libgit2/src/diff_xdiff.c b/vendor/libgit2/src/libgit2/diff_xdiff.c similarity index 99% rename from vendor/libgit2/src/diff_xdiff.c rename to vendor/libgit2/src/libgit2/diff_xdiff.c index 3f6eccac..5f56c520 100644 --- a/vendor/libgit2/src/diff_xdiff.c +++ b/vendor/libgit2/src/libgit2/diff_xdiff.c @@ -11,6 +11,7 @@ #include "diff.h" #include "diff_driver.h" #include "patch_generate.h" +#include "utf8.h" static int git_xdiff_scan_int(const char **str, int *value) { diff --git a/vendor/libgit2/src/diff_xdiff.h b/vendor/libgit2/src/libgit2/diff_xdiff.h similarity index 97% rename from vendor/libgit2/src/diff_xdiff.h rename to vendor/libgit2/src/libgit2/diff_xdiff.h index 9b303e9d..327dc7c4 100644 --- a/vendor/libgit2/src/diff_xdiff.h +++ b/vendor/libgit2/src/libgit2/diff_xdiff.h @@ -10,7 +10,7 @@ #include "common.h" #include "diff.h" -#include "xdiff/xdiff.h" +#include "xdiff.h" #include "patch_generate.h" /* xdiff cannot cope with large files. these files should not be passed to diff --git a/vendor/libgit2/src/email.c b/vendor/libgit2/src/libgit2/email.c similarity index 97% rename from vendor/libgit2/src/email.c rename to vendor/libgit2/src/libgit2/email.c index e19a2928..8a10a12b 100644 --- a/vendor/libgit2/src/email.c +++ b/vendor/libgit2/src/libgit2/email.c @@ -130,11 +130,12 @@ static int append_header( const git_signature *author, git_email_create_options *opts) { - char id[GIT_OID_HEXSZ]; + char id[GIT_OID_MAX_HEXSIZE + 1]; int error; - if ((error = git_oid_fmt(id, commit_id)) < 0 || - (error = git_str_printf(out, "From %.*s %s\n", GIT_OID_HEXSZ, id, EMAIL_TIMESTAMP)) < 0 || + git_oid_tostr(id, GIT_OID_MAX_HEXSIZE + 1, commit_id); + + if ((error = git_str_printf(out, "From %s %s\n", id, EMAIL_TIMESTAMP)) < 0 || (error = git_str_printf(out, "From: %s <%s>\n", author->name, author->email)) < 0 || (error = append_date(out, &author->when)) < 0 || (error = append_subject(out, patch_idx, patch_count, summary, opts)) < 0) diff --git a/vendor/libgit2/src/email.h b/vendor/libgit2/src/libgit2/email.h similarity index 100% rename from vendor/libgit2/src/email.h rename to vendor/libgit2/src/libgit2/email.h diff --git a/vendor/libgit2/src/libgit2/experimental.h.in b/vendor/libgit2/src/libgit2/experimental.h.in new file mode 100644 index 00000000..25fb14b9 --- /dev/null +++ b/vendor/libgit2/src/libgit2/experimental.h.in @@ -0,0 +1,13 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_experimental_h__ +#define INCLUDE_experimental_h__ + +#cmakedefine GIT_EXPERIMENTAL_SHA256 1 + +#endif diff --git a/vendor/libgit2/src/libgit2/fetch.c b/vendor/libgit2/src/libgit2/fetch.c new file mode 100644 index 00000000..8e2660f2 --- /dev/null +++ b/vendor/libgit2/src/libgit2/fetch.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "fetch.h" + +#include "git2/oid.h" +#include "git2/refs.h" +#include "git2/revwalk.h" +#include "git2/transport.h" +#include "git2/sys/remote.h" + +#include "oid.h" +#include "remote.h" +#include "refspec.h" +#include "pack.h" +#include "repository.h" +#include "refs.h" +#include "transports/smart.h" + +static int maybe_want(git_remote *remote, git_remote_head *head, git_refspec *tagspec, git_remote_autotag_option_t tagopt) +{ + int match = 0, valid; + + if (git_reference_name_is_valid(&valid, head->name) < 0) + return -1; + + if (!valid) + return 0; + + if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_ALL) { + /* + * If tagopt is --tags, always request tags + * in addition to the remote's refspecs + */ + if (git_refspec_src_matches(tagspec, head->name)) + match = 1; + } + + if (!match && git_remote__matching_refspec(remote, head->name)) + match = 1; + + if (!match) + return 0; + + return git_vector_insert(&remote->refs, head); +} + +static int mark_local(git_remote *remote) +{ + git_remote_head *head; + git_odb *odb; + size_t i; + + if (git_repository_odb__weakptr(&odb, remote->repo) < 0) + return -1; + + git_vector_foreach(&remote->refs, i, head) { + /* If we have the object, mark it so we don't ask for it. + However if we are unshallowing or changing history + depth, we need to ask for it even though the head + exists locally. */ + if (remote->nego.depth == GIT_FETCH_DEPTH_FULL && + git_odb_exists(odb, &head->oid)) + head->local = 1; + else + remote->need_pack = 1; + } + + return 0; +} + +static int maybe_want_oid(git_remote *remote, git_refspec *spec) +{ + git_remote_head *oid_head; + + oid_head = git__calloc(1, sizeof(git_remote_head)); + GIT_ERROR_CHECK_ALLOC(oid_head); + + git_oid__fromstr(&oid_head->oid, spec->src, remote->repo->oid_type); + + if (spec->dst) { + oid_head->name = git__strdup(spec->dst); + GIT_ERROR_CHECK_ALLOC(oid_head->name); + } + + if (git_vector_insert(&remote->local_heads, oid_head) < 0 || + git_vector_insert(&remote->refs, oid_head) < 0) + return -1; + + return 0; +} + +static int filter_wants(git_remote *remote, const git_fetch_options *opts) +{ + git_remote_head **heads; + git_refspec tagspec, head, *spec; + int error = 0; + size_t i, heads_len; + unsigned int remote_caps; + unsigned int oid_mask = GIT_REMOTE_CAPABILITY_TIP_OID | + GIT_REMOTE_CAPABILITY_REACHABLE_OID; + git_remote_autotag_option_t tagopt = remote->download_tags; + + if (opts && opts->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED) + tagopt = opts->download_tags; + + git_vector_clear(&remote->refs); + if ((error = git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true)) < 0) + return error; + + /* + * The fetch refspec can be NULL, and what this means is that the + * user didn't specify one. This is fine, as it means that we're + * not interested in any particular branch but just the remote's + * HEAD, which will be stored in FETCH_HEAD after the fetch. + */ + if (remote->active_refspecs.length == 0) { + if ((error = git_refspec__parse(&head, "HEAD", true)) < 0) + goto cleanup; + + error = git_refspec__dwim_one(&remote->active_refspecs, &head, &remote->refs); + git_refspec__dispose(&head); + + if (error < 0) + goto cleanup; + } + + if ((error = git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote)) < 0 || + (error = git_remote_capabilities(&remote_caps, remote)) < 0) + goto cleanup; + + /* Handle remote heads */ + for (i = 0; i < heads_len; i++) { + if ((error = maybe_want(remote, heads[i], &tagspec, tagopt)) < 0) + goto cleanup; + } + + /* Handle explicitly specified OID specs */ + git_vector_foreach(&remote->active_refspecs, i, spec) { + if (!git_oid__is_hexstr(spec->src, remote->repo->oid_type)) + continue; + + if (!(remote_caps & oid_mask)) { + git_error_set(GIT_ERROR_INVALID, "cannot fetch a specific object from the remote repository"); + error = -1; + goto cleanup; + } + + if ((error = maybe_want_oid(remote, spec)) < 0) + goto cleanup; + } + + error = mark_local(remote); + +cleanup: + git_refspec__dispose(&tagspec); + + return error; +} + +/* + * In this first version, we push all our refs in and start sending + * them out. When we get an ACK we hide that commit and continue + * traversing until we're done + */ +int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts) +{ + git_transport *t = remote->transport; + int error; + + remote->need_pack = 0; + + if (opts) { + GIT_ASSERT_ARG(opts->depth >= 0); + remote->nego.depth = opts->depth; + } + + if (filter_wants(remote, opts) < 0) + return -1; + + /* Don't try to negotiate when we don't want anything */ + if (!remote->need_pack) + return 0; + + /* + * Now we have everything set up so we can start tell the + * server what we want and what we have. + */ + remote->nego.refs = (const git_remote_head * const *)remote->refs.contents; + remote->nego.refs_len = remote->refs.length; + + if (git_repository__shallow_roots(&remote->nego.shallow_roots, + &remote->nego.shallow_roots_len, + remote->repo) < 0) + return -1; + + error = t->negotiate_fetch(t, + remote->repo, + &remote->nego); + + git__free(remote->nego.shallow_roots); + + return error; +} + +int git_fetch_download_pack(git_remote *remote) +{ + git_oidarray shallow_roots = { NULL }; + git_transport *t = remote->transport; + int error; + + if (!remote->need_pack) + return 0; + + if ((error = t->download_pack(t, remote->repo, &remote->stats)) != 0 || + (error = t->shallow_roots(&shallow_roots, t)) != 0) + return error; + + error = git_repository__shallow_roots_write(remote->repo, &shallow_roots); + + git_oidarray_dispose(&shallow_roots); + return error; +} + +int git_fetch_options_init(git_fetch_options *opts, unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE( + opts, version, git_fetch_options, GIT_FETCH_OPTIONS_INIT); + return 0; +} + +#ifndef GIT_DEPRECATE_HARD +int git_fetch_init_options(git_fetch_options *opts, unsigned int version) +{ + return git_fetch_options_init(opts, version); +} +#endif diff --git a/vendor/libgit2/src/fetch.h b/vendor/libgit2/src/libgit2/fetch.h similarity index 96% rename from vendor/libgit2/src/fetch.h rename to vendor/libgit2/src/libgit2/fetch.h index 10b6731f..493366de 100644 --- a/vendor/libgit2/src/fetch.h +++ b/vendor/libgit2/src/libgit2/fetch.h @@ -11,8 +11,6 @@ #include "git2/remote.h" -#include "netops.h" - int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts); int git_fetch_download_pack(git_remote *remote); diff --git a/vendor/libgit2/src/fetchhead.c b/vendor/libgit2/src/libgit2/fetchhead.c similarity index 94% rename from vendor/libgit2/src/fetchhead.c rename to vendor/libgit2/src/libgit2/fetchhead.c index 6511124e..2f276e52 100644 --- a/vendor/libgit2/src/fetchhead.c +++ b/vendor/libgit2/src/libgit2/fetchhead.c @@ -105,15 +105,14 @@ static int fetchhead_ref_write( git_filebuf *file, git_fetchhead_ref *fetchhead_ref) { - char oid[GIT_OID_HEXSZ + 1]; + char oid[GIT_OID_MAX_HEXSIZE + 1]; const char *type, *name; int head = 0; GIT_ASSERT_ARG(file); GIT_ASSERT_ARG(fetchhead_ref); - git_oid_fmt(oid, &fetchhead_ref->oid); - oid[GIT_OID_HEXSZ] = '\0'; + git_oid_tostr(oid, GIT_OID_MAX_HEXSIZE + 1, &fetchhead_ref->oid); if (git__prefixcmp(fetchhead_ref->ref_name, GIT_REFS_HEADS_DIR) == 0) { type = "branch "; @@ -174,7 +173,8 @@ static int fetchhead_ref_parse( git_str *ref_name, const char **remote_url, char *line, - size_t line_num) + size_t line_num, + git_oid_t oid_type) { char *oid_str, *is_merge_str, *desc, *name = NULL; const char *type = NULL; @@ -196,13 +196,13 @@ static int fetchhead_ref_parse( *is_merge = 1; } - if (strlen(oid_str) != GIT_OID_HEXSZ) { + if (strlen(oid_str) != git_oid_hexsize(oid_type)) { git_error_set(GIT_ERROR_FETCHHEAD, "invalid object ID in FETCH_HEAD line %"PRIuZ, line_num); return -1; } - if (git_oid_fromstr(oid, oid_str) < 0) { + if (git_oid__fromstr(oid, oid_str, oid_type) < 0) { const git_error *oid_err = git_error_last(); const char *err_msg = oid_err ? oid_err->message : "invalid object ID"; @@ -269,7 +269,8 @@ static int fetchhead_ref_parse( return error; } -int git_repository_fetchhead_foreach(git_repository *repo, +int git_repository_fetchhead_foreach( + git_repository *repo, git_repository_fetchhead_foreach_cb cb, void *payload) { @@ -296,8 +297,9 @@ int git_repository_fetchhead_foreach(git_repository *repo, while ((line = git__strsep(&buffer, "\n")) != NULL) { ++line_num; - if ((error = fetchhead_ref_parse( - &oid, &is_merge, &name, &remote_url, line, line_num)) < 0) + if ((error = fetchhead_ref_parse(&oid, &is_merge, &name, + &remote_url, line, line_num, + repo->oid_type)) < 0) goto done; if (git_str_len(&name) > 0) diff --git a/vendor/libgit2/src/fetchhead.h b/vendor/libgit2/src/libgit2/fetchhead.h similarity index 100% rename from vendor/libgit2/src/fetchhead.h rename to vendor/libgit2/src/libgit2/fetchhead.h diff --git a/vendor/libgit2/src/filter.c b/vendor/libgit2/src/libgit2/filter.c similarity index 96% rename from vendor/libgit2/src/filter.c rename to vendor/libgit2/src/libgit2/filter.c index 2712e8c6..fdfc409a 100644 --- a/vendor/libgit2/src/filter.c +++ b/vendor/libgit2/src/libgit2/filter.c @@ -893,15 +893,45 @@ static int buffered_stream_write( return git_str_put(&buffered_stream->input, buffer, len); } +#ifndef GIT_DEPRECATE_HARD +# define BUF_TO_STRUCT(b, s) \ + (b)->ptr = (s)->ptr; \ + (b)->size = (s)->size; \ + (b)->reserved = (s)->asize; +# define STRUCT_TO_BUF(s, b) \ + (s)->ptr = (b)->ptr; \ + (s)->size = (b)->size; \ + (s)->asize = (b)->reserved; +#endif + static int buffered_stream_close(git_writestream *s) { struct buffered_stream *buffered_stream = (struct buffered_stream *)s; git_str *writebuf; - git_error_state error_state = {0}; + git_error *last_error; int error; GIT_ASSERT_ARG(buffered_stream); +#ifndef GIT_DEPRECATE_HARD + if (buffered_stream->write_fn == NULL) { + git_buf legacy_output = GIT_BUF_INIT, + legacy_input = GIT_BUF_INIT; + + BUF_TO_STRUCT(&legacy_output, buffered_stream->output); + BUF_TO_STRUCT(&legacy_input, &buffered_stream->input); + + error = buffered_stream->legacy_write_fn( + buffered_stream->filter, + buffered_stream->payload, + &legacy_output, + &legacy_input, + buffered_stream->source); + + STRUCT_TO_BUF(buffered_stream->output, &legacy_output); + STRUCT_TO_BUF(&buffered_stream->input, &legacy_input); + } else +#endif error = buffered_stream->write_fn( buffered_stream->filter, buffered_stream->payload, @@ -916,9 +946,9 @@ static int buffered_stream_close(git_writestream *s) } else { /* close stream before erroring out taking care * to preserve the original error */ - git_error_state_capture(&error_state, error); + git_error_save(&last_error); buffered_stream->target->close(buffered_stream->target); - git_error_state_restore(&error_state); + git_error_restore(last_error); return error; } @@ -1085,7 +1115,7 @@ int git_filter_list_stream_file( const char *path, git_writestream *target) { - char buf[FILTERIO_BUFSIZE]; + char buf[GIT_BUFSIZE_FILTERIO]; git_str abspath = GIT_STR_INIT; const char *base = repo ? git_repository_workdir(repo) : NULL; git_vector filter_streams = GIT_VECTOR_INIT; diff --git a/vendor/libgit2/src/filter.h b/vendor/libgit2/src/libgit2/filter.h similarity index 100% rename from vendor/libgit2/src/filter.h rename to vendor/libgit2/src/libgit2/filter.h diff --git a/vendor/libgit2/src/win32/git2.rc b/vendor/libgit2/src/libgit2/git2.rc similarity index 94% rename from vendor/libgit2/src/win32/git2.rc rename to vendor/libgit2/src/libgit2/git2.rc index d273afd7..b94ecafd 100644 --- a/vendor/libgit2/src/win32/git2.rc +++ b/vendor/libgit2/src/libgit2/git2.rc @@ -10,7 +10,7 @@ #endif #ifndef LIBGIT2_COMMENTS -# define LIBGIT2_COMMENTS "For more information visit http://libgit2.github.com/" +# define LIBGIT2_COMMENTS "For more information visit https://libgit2.org/" #endif #ifdef __GNUC__ diff --git a/vendor/libgit2/src/libgit2/grafts.c b/vendor/libgit2/src/libgit2/grafts.c new file mode 100644 index 00000000..1d9373a5 --- /dev/null +++ b/vendor/libgit2/src/libgit2/grafts.c @@ -0,0 +1,272 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "grafts.h" + +#include "futils.h" +#include "oid.h" +#include "oidarray.h" +#include "parse.h" + +struct git_grafts { + /* Map of `git_commit_graft`s */ + git_oidmap *commits; + + /* Type of object IDs */ + git_oid_t oid_type; + + /* File backing the graft. NULL if it's an in-memory graft */ + char *path; + unsigned char path_checksum[GIT_HASH_SHA256_SIZE]; +}; + +int git_grafts_new(git_grafts **out, git_oid_t oid_type) +{ + git_grafts *grafts; + + GIT_ASSERT_ARG(out && oid_type); + + grafts = git__calloc(1, sizeof(*grafts)); + GIT_ERROR_CHECK_ALLOC(grafts); + + if ((git_oidmap_new(&grafts->commits)) < 0) { + git__free(grafts); + return -1; + } + + grafts->oid_type = oid_type; + + *out = grafts; + return 0; +} + +int git_grafts_open( + git_grafts **out, + const char *path, + git_oid_t oid_type) +{ + git_grafts *grafts = NULL; + int error; + + GIT_ASSERT_ARG(out && path && oid_type); + + if ((error = git_grafts_new(&grafts, oid_type)) < 0) + goto error; + + grafts->path = git__strdup(path); + GIT_ERROR_CHECK_ALLOC(grafts->path); + + if ((error = git_grafts_refresh(grafts)) < 0) + goto error; + + *out = grafts; + +error: + if (error < 0) + git_grafts_free(grafts); + + return error; +} + +int git_grafts_open_or_refresh( + git_grafts **out, + const char *path, + git_oid_t oid_type) +{ + GIT_ASSERT_ARG(out && path && oid_type); + + return *out ? git_grafts_refresh(*out) : git_grafts_open(out, path, oid_type); +} + +void git_grafts_free(git_grafts *grafts) +{ + if (!grafts) + return; + git__free(grafts->path); + git_grafts_clear(grafts); + git_oidmap_free(grafts->commits); + git__free(grafts); +} + +void git_grafts_clear(git_grafts *grafts) +{ + git_commit_graft *graft; + + if (!grafts) + return; + + git_oidmap_foreach_value(grafts->commits, graft, { + git__free(graft->parents.ptr); + git__free(graft); + }); + + git_oidmap_clear(grafts->commits); +} + +int git_grafts_refresh(git_grafts *grafts) +{ + git_str contents = GIT_STR_INIT; + int error, updated = 0; + + GIT_ASSERT_ARG(grafts); + + if (!grafts->path) + return 0; + + if ((error = git_futils_readbuffer_updated(&contents, grafts->path, + grafts->path_checksum, &updated)) < 0) { + + if (error == GIT_ENOTFOUND) { + git_grafts_clear(grafts); + error = 0; + } + + goto cleanup; + } + + if (!updated) { + goto cleanup; + } + + if ((error = git_grafts_parse(grafts, contents.ptr, contents.size)) < 0) + goto cleanup; + +cleanup: + git_str_dispose(&contents); + return error; +} + +int git_grafts_parse(git_grafts *grafts, const char *buf, size_t len) +{ + git_array_oid_t parents = GIT_ARRAY_INIT; + git_parse_ctx parser; + int error; + + git_grafts_clear(grafts); + + if ((error = git_parse_ctx_init(&parser, buf, len)) < 0) + goto error; + + for (; parser.remain_len; git_parse_advance_line(&parser)) { + git_oid graft_oid; + + if ((error = git_parse_advance_oid(&graft_oid, &parser, grafts->oid_type)) < 0) { + git_error_set(GIT_ERROR_GRAFTS, "invalid graft OID at line %" PRIuZ, parser.line_num); + goto error; + } + + while (parser.line_len && git_parse_advance_expected(&parser, "\n", 1) != 0) { + git_oid *id = git_array_alloc(parents); + GIT_ERROR_CHECK_ALLOC(id); + + if ((error = git_parse_advance_expected(&parser, " ", 1)) < 0 || + (error = git_parse_advance_oid(id, &parser, grafts->oid_type)) < 0) { + git_error_set(GIT_ERROR_GRAFTS, "invalid parent OID at line %" PRIuZ, parser.line_num); + goto error; + } + } + + if ((error = git_grafts_add(grafts, &graft_oid, parents)) < 0) + goto error; + + git_array_clear(parents); + } + +error: + git_array_clear(parents); + return error; +} + +int git_grafts_add(git_grafts *grafts, const git_oid *oid, git_array_oid_t parents) +{ + git_commit_graft *graft; + git_oid *parent_oid; + int error; + size_t i; + + GIT_ASSERT_ARG(grafts && oid); + + graft = git__calloc(1, sizeof(*graft)); + GIT_ERROR_CHECK_ALLOC(graft); + + git_array_init_to_size(graft->parents, git_array_size(parents)); + git_array_foreach(parents, i, parent_oid) { + git_oid *id = git_array_alloc(graft->parents); + GIT_ERROR_CHECK_ALLOC(id); + + git_oid_cpy(id, parent_oid); + } + git_oid_cpy(&graft->oid, oid); + + if ((error = git_grafts_remove(grafts, &graft->oid)) < 0 && error != GIT_ENOTFOUND) + goto cleanup; + + if ((error = git_oidmap_set(grafts->commits, &graft->oid, graft)) < 0) + goto cleanup; + + return 0; + +cleanup: + git_array_clear(graft->parents); + git__free(graft); + return error; +} + +int git_grafts_remove(git_grafts *grafts, const git_oid *oid) +{ + git_commit_graft *graft; + int error; + + GIT_ASSERT_ARG(grafts && oid); + + if ((graft = git_oidmap_get(grafts->commits, oid)) == NULL) + return GIT_ENOTFOUND; + + if ((error = git_oidmap_delete(grafts->commits, oid)) < 0) + return error; + + git__free(graft->parents.ptr); + git__free(graft); + + return 0; +} + +int git_grafts_get(git_commit_graft **out, git_grafts *grafts, const git_oid *oid) +{ + GIT_ASSERT_ARG(out && grafts && oid); + if ((*out = git_oidmap_get(grafts->commits, oid)) == NULL) + return GIT_ENOTFOUND; + return 0; +} + +int git_grafts_oids(git_oid **out, size_t *out_len, git_grafts *grafts) +{ + git_array_oid_t array = GIT_ARRAY_INIT; + const git_oid *oid; + size_t existing, i = 0; + + GIT_ASSERT_ARG(out && grafts); + + if ((existing = git_oidmap_size(grafts->commits)) > 0) + git_array_init_to_size(array, existing); + + while (git_oidmap_iterate(NULL, grafts->commits, &i, &oid) == 0) { + git_oid *cpy = git_array_alloc(array); + GIT_ERROR_CHECK_ALLOC(cpy); + git_oid_cpy(cpy, oid); + } + + *out = array.ptr; + *out_len = array.size; + + return 0; +} + +size_t git_grafts_size(git_grafts *grafts) +{ + return git_oidmap_size(grafts->commits); +} diff --git a/vendor/libgit2/src/libgit2/grafts.h b/vendor/libgit2/src/libgit2/grafts.h new file mode 100644 index 00000000..394867fd --- /dev/null +++ b/vendor/libgit2/src/libgit2/grafts.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_graft_h__ +#define INCLUDE_graft_h__ + +#include "common.h" +#include "oidarray.h" +#include "oidmap.h" + +/** graft commit */ +typedef struct { + git_oid oid; + git_array_oid_t parents; +} git_commit_graft; + +typedef struct git_grafts git_grafts; + +int git_grafts_new(git_grafts **out, git_oid_t oid_type); +int git_grafts_open(git_grafts **out, const char *path, git_oid_t oid_type); +int git_grafts_open_or_refresh(git_grafts **out, const char *path, git_oid_t oid_type); +void git_grafts_free(git_grafts *grafts); +void git_grafts_clear(git_grafts *grafts); + +int git_grafts_refresh(git_grafts *grafts); +int git_grafts_parse(git_grafts *grafts, const char *buf, size_t len); +int git_grafts_add(git_grafts *grafts, const git_oid *oid, git_array_oid_t parents); +int git_grafts_remove(git_grafts *grafts, const git_oid *oid); +int git_grafts_get(git_commit_graft **out, git_grafts *grafts, const git_oid *oid); +int git_grafts_oids(git_oid **out, size_t *out_len, git_grafts *grafts); +size_t git_grafts_size(git_grafts *grafts); + +#endif diff --git a/vendor/libgit2/src/graph.c b/vendor/libgit2/src/libgit2/graph.c similarity index 100% rename from vendor/libgit2/src/graph.c rename to vendor/libgit2/src/libgit2/graph.c diff --git a/vendor/libgit2/src/hashsig.c b/vendor/libgit2/src/libgit2/hashsig.c similarity index 100% rename from vendor/libgit2/src/hashsig.c rename to vendor/libgit2/src/libgit2/hashsig.c diff --git a/vendor/libgit2/src/ident.c b/vendor/libgit2/src/libgit2/ident.c similarity index 96% rename from vendor/libgit2/src/ident.c rename to vendor/libgit2/src/libgit2/ident.c index 53095864..97110c66 100644 --- a/vendor/libgit2/src/ident.c +++ b/vendor/libgit2/src/libgit2/ident.c @@ -42,7 +42,7 @@ static int ident_find_id( static int ident_insert_id( git_str *to, const git_str *from, const git_filter_source *src) { - char oid[GIT_OID_HEXSZ+1]; + char oid[GIT_OID_MAX_HEXSIZE + 1]; const char *id_start, *id_end, *from_end = from->ptr + from->size; size_t need_size; @@ -57,7 +57,7 @@ static int ident_insert_id( return GIT_PASSTHROUGH; need_size = (size_t)(id_start - from->ptr) + - 5 /* "$Id: " */ + GIT_OID_HEXSZ + 2 /* " $" */ + + 5 /* "$Id: " */ + GIT_OID_MAX_HEXSIZE + 2 /* " $" */ + (size_t)(from_end - id_end); if (git_str_grow(to, need_size) < 0) @@ -65,7 +65,7 @@ static int ident_insert_id( git_str_set(to, from->ptr, (size_t)(id_start - from->ptr)); git_str_put(to, "$Id: ", 5); - git_str_put(to, oid, GIT_OID_HEXSZ); + git_str_puts(to, oid); git_str_put(to, " $", 2); git_str_put(to, id_end, (size_t)(from_end - id_end)); diff --git a/vendor/libgit2/src/idxmap.c b/vendor/libgit2/src/libgit2/idxmap.c similarity index 100% rename from vendor/libgit2/src/idxmap.c rename to vendor/libgit2/src/libgit2/idxmap.c diff --git a/vendor/libgit2/src/idxmap.h b/vendor/libgit2/src/libgit2/idxmap.h similarity index 100% rename from vendor/libgit2/src/idxmap.h rename to vendor/libgit2/src/libgit2/idxmap.h diff --git a/vendor/libgit2/src/ignore.c b/vendor/libgit2/src/libgit2/ignore.c similarity index 100% rename from vendor/libgit2/src/ignore.c rename to vendor/libgit2/src/libgit2/ignore.c diff --git a/vendor/libgit2/src/ignore.h b/vendor/libgit2/src/libgit2/ignore.h similarity index 100% rename from vendor/libgit2/src/ignore.h rename to vendor/libgit2/src/libgit2/ignore.h diff --git a/vendor/libgit2/src/libgit2/index.c b/vendor/libgit2/src/libgit2/index.c new file mode 100644 index 00000000..670fbc5c --- /dev/null +++ b/vendor/libgit2/src/libgit2/index.c @@ -0,0 +1,3978 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "index.h" + +#include + +#include "repository.h" +#include "tree.h" +#include "tree-cache.h" +#include "hash.h" +#include "iterator.h" +#include "pathspec.h" +#include "ignore.h" +#include "blob.h" +#include "idxmap.h" +#include "diff.h" +#include "varint.h" +#include "path.h" + +#include "git2/odb.h" +#include "git2/oid.h" +#include "git2/blob.h" +#include "git2/config.h" +#include "git2/sys/index.h" + +static int index_apply_to_wd_diff(git_index *index, int action, const git_strarray *paths, + unsigned int flags, + git_index_matched_path_cb cb, void *payload); + +static const size_t INDEX_HEADER_SIZE = 12; + +static const unsigned int INDEX_VERSION_NUMBER_DEFAULT = 2; +static const unsigned int INDEX_VERSION_NUMBER_LB = 2; +static const unsigned int INDEX_VERSION_NUMBER_EXT = 3; +static const unsigned int INDEX_VERSION_NUMBER_COMP = 4; +static const unsigned int INDEX_VERSION_NUMBER_UB = 4; + +static const unsigned int INDEX_HEADER_SIG = 0x44495243; +static const char INDEX_EXT_TREECACHE_SIG[] = {'T', 'R', 'E', 'E'}; +static const char INDEX_EXT_UNMERGED_SIG[] = {'R', 'E', 'U', 'C'}; +static const char INDEX_EXT_CONFLICT_NAME_SIG[] = {'N', 'A', 'M', 'E'}; + +#define INDEX_OWNER(idx) ((git_repository *)(GIT_REFCOUNT_OWNER(idx))) + +struct index_header { + uint32_t signature; + uint32_t version; + uint32_t entry_count; +}; + +struct index_extension { + char signature[4]; + uint32_t extension_size; +}; + +struct entry_time { + uint32_t seconds; + uint32_t nanoseconds; +}; + +struct entry_common { + struct entry_time ctime; + struct entry_time mtime; + uint32_t dev; + uint32_t ino; + uint32_t mode; + uint32_t uid; + uint32_t gid; + uint32_t file_size; +}; + +#define entry_short(oid_size) \ + struct { \ + struct entry_common common; \ + unsigned char oid[oid_size]; \ + uint16_t flags; \ + char path[1]; /* arbitrary length */ \ + } + +#define entry_long(oid_size) \ + struct { \ + struct entry_common common; \ + unsigned char oid[oid_size]; \ + uint16_t flags; \ + uint16_t flags_extended; \ + char path[1]; /* arbitrary length */ \ + } + +typedef entry_short(GIT_OID_SHA1_SIZE) index_entry_short_sha1; +typedef entry_long(GIT_OID_SHA1_SIZE) index_entry_long_sha1; + +#ifdef GIT_EXPERIMENTAL_SHA256 +typedef entry_short(GIT_OID_SHA256_SIZE) index_entry_short_sha256; +typedef entry_long(GIT_OID_SHA256_SIZE) index_entry_long_sha256; +#endif + +#undef entry_short +#undef entry_long + +struct entry_srch_key { + const char *path; + size_t pathlen; + int stage; +}; + +struct entry_internal { + git_index_entry entry; + size_t pathlen; + char path[GIT_FLEX_ARRAY]; +}; + +struct reuc_entry_internal { + git_index_reuc_entry entry; + size_t pathlen; + char path[GIT_FLEX_ARRAY]; +}; + +bool git_index__enforce_unsaved_safety = false; + +/* local declarations */ +static int read_extension(size_t *read_len, git_index *index, size_t checksum_size, const char *buffer, size_t buffer_size); +static int read_header(struct index_header *dest, const void *buffer); + +static int parse_index(git_index *index, const char *buffer, size_t buffer_size); +static bool is_index_extended(git_index *index); +static int write_index(unsigned char checksum[GIT_HASH_MAX_SIZE], size_t *checksum_size, git_index *index, git_filebuf *file); + +static void index_entry_free(git_index_entry *entry); +static void index_entry_reuc_free(git_index_reuc_entry *reuc); + +GIT_INLINE(int) index_map_set(git_idxmap *map, git_index_entry *e, bool ignore_case) +{ + if (ignore_case) + return git_idxmap_icase_set((git_idxmap_icase *) map, e, e); + else + return git_idxmap_set(map, e, e); +} + +GIT_INLINE(int) index_map_delete(git_idxmap *map, git_index_entry *e, bool ignore_case) +{ + if (ignore_case) + return git_idxmap_icase_delete((git_idxmap_icase *) map, e); + else + return git_idxmap_delete(map, e); +} + +GIT_INLINE(int) index_map_resize(git_idxmap *map, size_t count, bool ignore_case) +{ + if (ignore_case) + return git_idxmap_icase_resize((git_idxmap_icase *) map, count); + else + return git_idxmap_resize(map, count); +} + +int git_index_entry_srch(const void *key, const void *array_member) +{ + const struct entry_srch_key *srch_key = key; + const struct entry_internal *entry = array_member; + int cmp; + size_t len1, len2, len; + + len1 = srch_key->pathlen; + len2 = entry->pathlen; + len = len1 < len2 ? len1 : len2; + + cmp = memcmp(srch_key->path, entry->path, len); + if (cmp) + return cmp; + if (len1 < len2) + return -1; + if (len1 > len2) + return 1; + + if (srch_key->stage != GIT_INDEX_STAGE_ANY) + return srch_key->stage - GIT_INDEX_ENTRY_STAGE(&entry->entry); + + return 0; +} + +int git_index_entry_isrch(const void *key, const void *array_member) +{ + const struct entry_srch_key *srch_key = key; + const struct entry_internal *entry = array_member; + int cmp; + size_t len1, len2, len; + + len1 = srch_key->pathlen; + len2 = entry->pathlen; + len = len1 < len2 ? len1 : len2; + + cmp = strncasecmp(srch_key->path, entry->path, len); + + if (cmp) + return cmp; + if (len1 < len2) + return -1; + if (len1 > len2) + return 1; + + if (srch_key->stage != GIT_INDEX_STAGE_ANY) + return srch_key->stage - GIT_INDEX_ENTRY_STAGE(&entry->entry); + + return 0; +} + +static int index_entry_srch_path(const void *path, const void *array_member) +{ + const git_index_entry *entry = array_member; + + return strcmp((const char *)path, entry->path); +} + +static int index_entry_isrch_path(const void *path, const void *array_member) +{ + const git_index_entry *entry = array_member; + + return strcasecmp((const char *)path, entry->path); +} + +int git_index_entry_cmp(const void *a, const void *b) +{ + int diff; + const git_index_entry *entry_a = a; + const git_index_entry *entry_b = b; + + diff = strcmp(entry_a->path, entry_b->path); + + if (diff == 0) + diff = (GIT_INDEX_ENTRY_STAGE(entry_a) - GIT_INDEX_ENTRY_STAGE(entry_b)); + + return diff; +} + +int git_index_entry_icmp(const void *a, const void *b) +{ + int diff; + const git_index_entry *entry_a = a; + const git_index_entry *entry_b = b; + + diff = strcasecmp(entry_a->path, entry_b->path); + + if (diff == 0) + diff = (GIT_INDEX_ENTRY_STAGE(entry_a) - GIT_INDEX_ENTRY_STAGE(entry_b)); + + return diff; +} + +static int conflict_name_cmp(const void *a, const void *b) +{ + const git_index_name_entry *name_a = a; + const git_index_name_entry *name_b = b; + + if (name_a->ancestor && !name_b->ancestor) + return 1; + + if (!name_a->ancestor && name_b->ancestor) + return -1; + + if (name_a->ancestor) + return strcmp(name_a->ancestor, name_b->ancestor); + + if (!name_a->ours || !name_b->ours) + return 0; + + return strcmp(name_a->ours, name_b->ours); +} + +/** + * TODO: enable this when resolving case insensitive conflicts + */ +#if 0 +static int conflict_name_icmp(const void *a, const void *b) +{ + const git_index_name_entry *name_a = a; + const git_index_name_entry *name_b = b; + + if (name_a->ancestor && !name_b->ancestor) + return 1; + + if (!name_a->ancestor && name_b->ancestor) + return -1; + + if (name_a->ancestor) + return strcasecmp(name_a->ancestor, name_b->ancestor); + + if (!name_a->ours || !name_b->ours) + return 0; + + return strcasecmp(name_a->ours, name_b->ours); +} +#endif + +static int reuc_srch(const void *key, const void *array_member) +{ + const git_index_reuc_entry *reuc = array_member; + + return strcmp(key, reuc->path); +} + +static int reuc_isrch(const void *key, const void *array_member) +{ + const git_index_reuc_entry *reuc = array_member; + + return strcasecmp(key, reuc->path); +} + +static int reuc_cmp(const void *a, const void *b) +{ + const git_index_reuc_entry *info_a = a; + const git_index_reuc_entry *info_b = b; + + return strcmp(info_a->path, info_b->path); +} + +static int reuc_icmp(const void *a, const void *b) +{ + const git_index_reuc_entry *info_a = a; + const git_index_reuc_entry *info_b = b; + + return strcasecmp(info_a->path, info_b->path); +} + +static void index_entry_reuc_free(git_index_reuc_entry *reuc) +{ + git__free(reuc); +} + +static void index_entry_free(git_index_entry *entry) +{ + if (!entry) + return; + + memset(&entry->id, 0, sizeof(entry->id)); + git__free(entry); +} + +unsigned int git_index__create_mode(unsigned int mode) +{ + if (S_ISLNK(mode)) + return S_IFLNK; + + if (S_ISDIR(mode) || (mode & S_IFMT) == (S_IFLNK | S_IFDIR)) + return (S_IFLNK | S_IFDIR); + + return S_IFREG | GIT_PERMS_CANONICAL(mode); +} + +static unsigned int index_merge_mode( + git_index *index, git_index_entry *existing, unsigned int mode) +{ + if (index->no_symlinks && S_ISREG(mode) && + existing && S_ISLNK(existing->mode)) + return existing->mode; + + if (index->distrust_filemode && S_ISREG(mode)) + return (existing && S_ISREG(existing->mode)) ? + existing->mode : git_index__create_mode(0666); + + return git_index__create_mode(mode); +} + +GIT_INLINE(int) index_find_in_entries( + size_t *out, git_vector *entries, git_vector_cmp entry_srch, + const char *path, size_t path_len, int stage) +{ + struct entry_srch_key srch_key; + srch_key.path = path; + srch_key.pathlen = !path_len ? strlen(path) : path_len; + srch_key.stage = stage; + return git_vector_bsearch2(out, entries, entry_srch, &srch_key); +} + +GIT_INLINE(int) index_find( + size_t *out, git_index *index, + const char *path, size_t path_len, int stage) +{ + git_vector_sort(&index->entries); + + return index_find_in_entries( + out, &index->entries, index->entries_search, path, path_len, stage); +} + +void git_index__set_ignore_case(git_index *index, bool ignore_case) +{ + index->ignore_case = ignore_case; + + if (ignore_case) { + index->entries_cmp_path = git__strcasecmp_cb; + index->entries_search = git_index_entry_isrch; + index->entries_search_path = index_entry_isrch_path; + index->reuc_search = reuc_isrch; + } else { + index->entries_cmp_path = git__strcmp_cb; + index->entries_search = git_index_entry_srch; + index->entries_search_path = index_entry_srch_path; + index->reuc_search = reuc_srch; + } + + git_vector_set_cmp(&index->entries, + ignore_case ? git_index_entry_icmp : git_index_entry_cmp); + git_vector_sort(&index->entries); + + git_vector_set_cmp(&index->reuc, ignore_case ? reuc_icmp : reuc_cmp); + git_vector_sort(&index->reuc); +} + +int git_index__open( + git_index **index_out, + const char *index_path, + git_oid_t oid_type) +{ + git_index *index; + int error = -1; + + GIT_ASSERT_ARG(index_out); + + index = git__calloc(1, sizeof(git_index)); + GIT_ERROR_CHECK_ALLOC(index); + + index->oid_type = oid_type; + + if (git_pool_init(&index->tree_pool, 1) < 0) + goto fail; + + if (index_path != NULL) { + index->index_file_path = git__strdup(index_path); + if (!index->index_file_path) + goto fail; + + /* Check if index file is stored on disk already */ + if (git_fs_path_exists(index->index_file_path) == true) + index->on_disk = 1; + } + + if (git_vector_init(&index->entries, 32, git_index_entry_cmp) < 0 || + git_idxmap_new(&index->entries_map) < 0 || + git_vector_init(&index->names, 8, conflict_name_cmp) < 0 || + git_vector_init(&index->reuc, 8, reuc_cmp) < 0 || + git_vector_init(&index->deleted, 8, git_index_entry_cmp) < 0) + goto fail; + + index->entries_cmp_path = git__strcmp_cb; + index->entries_search = git_index_entry_srch; + index->entries_search_path = index_entry_srch_path; + index->reuc_search = reuc_srch; + index->version = INDEX_VERSION_NUMBER_DEFAULT; + + if (index_path != NULL && (error = git_index_read(index, true)) < 0) + goto fail; + + *index_out = index; + GIT_REFCOUNT_INC(index); + + return 0; + +fail: + git_pool_clear(&index->tree_pool); + git_index_free(index); + return error; +} + +#ifdef GIT_EXPERIMENTAL_SHA256 +int git_index_open(git_index **index_out, const char *index_path, git_oid_t oid_type) +{ + return git_index__open(index_out, index_path, oid_type); +} +#else +int git_index_open(git_index **index_out, const char *index_path) +{ + return git_index__open(index_out, index_path, GIT_OID_SHA1); +} +#endif + +int git_index__new(git_index **out, git_oid_t oid_type) +{ + return git_index__open(out, NULL, oid_type); +} + +#ifdef GIT_EXPERIMENTAL_SHA256 +int git_index_new(git_index **out, git_oid_t oid_type) +{ + return git_index__new(out, oid_type); +} +#else +int git_index_new(git_index **out) +{ + return git_index__new(out, GIT_OID_SHA1); +} +#endif + +static void index_free(git_index *index) +{ + /* index iterators increment the refcount of the index, so if we + * get here then there should be no outstanding iterators. + */ + if (git_atomic32_get(&index->readers)) + return; + + git_index_clear(index); + git_idxmap_free(index->entries_map); + git_vector_free(&index->entries); + git_vector_free(&index->names); + git_vector_free(&index->reuc); + git_vector_free(&index->deleted); + + git__free(index->index_file_path); + + git__memzero(index, sizeof(*index)); + git__free(index); +} + +void git_index_free(git_index *index) +{ + if (index == NULL) + return; + + GIT_REFCOUNT_DEC(index, index_free); +} + +/* call with locked index */ +static void index_free_deleted(git_index *index) +{ + int readers = (int)git_atomic32_get(&index->readers); + size_t i; + + if (readers > 0 || !index->deleted.length) + return; + + for (i = 0; i < index->deleted.length; ++i) { + git_index_entry *ie = git_atomic_swap(index->deleted.contents[i], NULL); + index_entry_free(ie); + } + + git_vector_clear(&index->deleted); +} + +/* call with locked index */ +static int index_remove_entry(git_index *index, size_t pos) +{ + int error = 0; + git_index_entry *entry = git_vector_get(&index->entries, pos); + + if (entry != NULL) { + git_tree_cache_invalidate_path(index->tree, entry->path); + index_map_delete(index->entries_map, entry, index->ignore_case); + } + + error = git_vector_remove(&index->entries, pos); + + if (!error) { + if (git_atomic32_get(&index->readers) > 0) { + error = git_vector_insert(&index->deleted, entry); + } else { + index_entry_free(entry); + } + + index->dirty = 1; + } + + return error; +} + +int git_index_clear(git_index *index) +{ + int error = 0; + + GIT_ASSERT_ARG(index); + + index->dirty = 1; + index->tree = NULL; + git_pool_clear(&index->tree_pool); + + git_idxmap_clear(index->entries_map); + while (!error && index->entries.length > 0) + error = index_remove_entry(index, index->entries.length - 1); + + if (error) + goto done; + + index_free_deleted(index); + + if ((error = git_index_name_clear(index)) < 0 || + (error = git_index_reuc_clear(index)) < 0) + goto done; + + git_futils_filestamp_set(&index->stamp, NULL); + +done: + return error; +} + +static int create_index_error(int error, const char *msg) +{ + git_error_set_str(GIT_ERROR_INDEX, msg); + return error; +} + +int git_index_set_caps(git_index *index, int caps) +{ + unsigned int old_ignore_case; + + GIT_ASSERT_ARG(index); + + old_ignore_case = index->ignore_case; + + if (caps == GIT_INDEX_CAPABILITY_FROM_OWNER) { + git_repository *repo = INDEX_OWNER(index); + int val; + + if (!repo) + return create_index_error( + -1, "cannot access repository to set index caps"); + + if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_IGNORECASE)) + index->ignore_case = (val != 0); + if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_FILEMODE)) + index->distrust_filemode = (val == 0); + if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_SYMLINKS)) + index->no_symlinks = (val == 0); + } + else { + index->ignore_case = ((caps & GIT_INDEX_CAPABILITY_IGNORE_CASE) != 0); + index->distrust_filemode = ((caps & GIT_INDEX_CAPABILITY_NO_FILEMODE) != 0); + index->no_symlinks = ((caps & GIT_INDEX_CAPABILITY_NO_SYMLINKS) != 0); + } + + if (old_ignore_case != index->ignore_case) { + git_index__set_ignore_case(index, (bool)index->ignore_case); + } + + return 0; +} + +int git_index_caps(const git_index *index) +{ + return ((index->ignore_case ? GIT_INDEX_CAPABILITY_IGNORE_CASE : 0) | + (index->distrust_filemode ? GIT_INDEX_CAPABILITY_NO_FILEMODE : 0) | + (index->no_symlinks ? GIT_INDEX_CAPABILITY_NO_SYMLINKS : 0)); +} + +#ifndef GIT_DEPRECATE_HARD +const git_oid *git_index_checksum(git_index *index) +{ + return (git_oid *)index->checksum; +} +#endif + +/** + * Returns 1 for changed, 0 for not changed and <0 for errors + */ +static int compare_checksum(git_index *index) +{ + int fd; + ssize_t bytes_read; + unsigned char checksum[GIT_HASH_MAX_SIZE]; + size_t checksum_size = git_oid_size(index->oid_type); + + if ((fd = p_open(index->index_file_path, O_RDONLY)) < 0) + return fd; + + if (p_lseek(fd, (0 - (ssize_t)checksum_size), SEEK_END) < 0) { + p_close(fd); + git_error_set(GIT_ERROR_OS, "failed to seek to end of file"); + return -1; + } + + bytes_read = p_read(fd, checksum, checksum_size); + p_close(fd); + + if (bytes_read < (ssize_t)checksum_size) + return -1; + + return !!memcmp(checksum, index->checksum, checksum_size); +} + +int git_index_read(git_index *index, int force) +{ + int error = 0, updated; + git_str buffer = GIT_STR_INIT; + git_futils_filestamp stamp = index->stamp; + + if (!index->index_file_path) + return create_index_error(-1, + "failed to read index: The index is in-memory only"); + + index->on_disk = git_fs_path_exists(index->index_file_path); + + if (!index->on_disk) { + if (force && (error = git_index_clear(index)) < 0) + return error; + + index->dirty = 0; + return 0; + } + + if ((updated = git_futils_filestamp_check(&stamp, index->index_file_path) < 0) || + ((updated = compare_checksum(index)) < 0)) { + git_error_set( + GIT_ERROR_INDEX, + "failed to read index: '%s' no longer exists", + index->index_file_path); + return updated; + } + + if (!updated && !force) + return 0; + + error = git_futils_readbuffer(&buffer, index->index_file_path); + if (error < 0) + return error; + + index->tree = NULL; + git_pool_clear(&index->tree_pool); + + error = git_index_clear(index); + + if (!error) + error = parse_index(index, buffer.ptr, buffer.size); + + if (!error) { + git_futils_filestamp_set(&index->stamp, &stamp); + index->dirty = 0; + } + + git_str_dispose(&buffer); + return error; +} + +int git_index_read_safely(git_index *index) +{ + if (git_index__enforce_unsaved_safety && index->dirty) { + git_error_set(GIT_ERROR_INDEX, + "the index has unsaved changes that would be overwritten by this operation"); + return GIT_EINDEXDIRTY; + } + + return git_index_read(index, false); +} + +static bool is_racy_entry(git_index *index, const git_index_entry *entry) +{ + /* Git special-cases submodules in the check */ + if (S_ISGITLINK(entry->mode)) + return false; + + return git_index_entry_newer_than_index(entry, index); +} + +/* + * Force the next diff to take a look at those entries which have the + * same timestamp as the current index. + */ +static int truncate_racily_clean(git_index *index) +{ + size_t i; + int error; + git_index_entry *entry; + git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; + git_diff *diff = NULL; + git_vector paths = GIT_VECTOR_INIT; + git_diff_delta *delta; + + /* Nothing to do if there's no repo to talk about */ + if (!INDEX_OWNER(index)) + return 0; + + /* If there's no workdir, we can't know where to even check */ + if (!git_repository_workdir(INDEX_OWNER(index))) + return 0; + + diff_opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE | GIT_DIFF_IGNORE_SUBMODULES | GIT_DIFF_DISABLE_PATHSPEC_MATCH; + git_vector_foreach(&index->entries, i, entry) { + if ((entry->flags_extended & GIT_INDEX_ENTRY_UPTODATE) == 0 && + is_racy_entry(index, entry)) + git_vector_insert(&paths, (char *)entry->path); + } + + if (paths.length == 0) + goto done; + + diff_opts.pathspec.count = paths.length; + diff_opts.pathspec.strings = (char **)paths.contents; + + if ((error = git_diff_index_to_workdir(&diff, INDEX_OWNER(index), index, &diff_opts)) < 0) + return error; + + git_vector_foreach(&diff->deltas, i, delta) { + entry = (git_index_entry *)git_index_get_bypath(index, delta->old_file.path, 0); + + /* Ensure that we have a stage 0 for this file (ie, it's not a + * conflict), otherwise smudging it is quite pointless. + */ + if (entry) { + entry->file_size = 0; + index->dirty = 1; + } + } + +done: + git_diff_free(diff); + git_vector_free(&paths); + return 0; +} + +unsigned git_index_version(git_index *index) +{ + GIT_ASSERT_ARG(index); + + return index->version; +} + +int git_index_set_version(git_index *index, unsigned int version) +{ + GIT_ASSERT_ARG(index); + + if (version < INDEX_VERSION_NUMBER_LB || + version > INDEX_VERSION_NUMBER_UB) { + git_error_set(GIT_ERROR_INDEX, "invalid version number"); + return -1; + } + + index->version = version; + + return 0; +} + +int git_index_write(git_index *index) +{ + git_indexwriter writer = GIT_INDEXWRITER_INIT; + int error; + + truncate_racily_clean(index); + + if ((error = git_indexwriter_init(&writer, index)) == 0 && + (error = git_indexwriter_commit(&writer)) == 0) + index->dirty = 0; + + git_indexwriter_cleanup(&writer); + + return error; +} + +const char *git_index_path(const git_index *index) +{ + GIT_ASSERT_ARG_WITH_RETVAL(index, NULL); + return index->index_file_path; +} + +int git_index_write_tree(git_oid *oid, git_index *index) +{ + git_repository *repo; + + GIT_ASSERT_ARG(oid); + GIT_ASSERT_ARG(index); + + repo = INDEX_OWNER(index); + + if (repo == NULL) + return create_index_error(-1, "Failed to write tree. " + "the index file is not backed up by an existing repository"); + + return git_tree__write_index(oid, index, repo); +} + +int git_index_write_tree_to( + git_oid *oid, git_index *index, git_repository *repo) +{ + GIT_ASSERT_ARG(oid); + GIT_ASSERT_ARG(index); + GIT_ASSERT_ARG(repo); + + return git_tree__write_index(oid, index, repo); +} + +size_t git_index_entrycount(const git_index *index) +{ + GIT_ASSERT_ARG(index); + + return index->entries.length; +} + +const git_index_entry *git_index_get_byindex( + git_index *index, size_t n) +{ + GIT_ASSERT_ARG_WITH_RETVAL(index, NULL); + + git_vector_sort(&index->entries); + return git_vector_get(&index->entries, n); +} + +const git_index_entry *git_index_get_bypath( + git_index *index, const char *path, int stage) +{ + git_index_entry key = {{ 0 }}; + git_index_entry *value; + + GIT_ASSERT_ARG_WITH_RETVAL(index, NULL); + + key.path = path; + GIT_INDEX_ENTRY_STAGE_SET(&key, stage); + + if (index->ignore_case) + value = git_idxmap_icase_get((git_idxmap_icase *) index->entries_map, &key); + else + value = git_idxmap_get(index->entries_map, &key); + + if (!value) { + git_error_set(GIT_ERROR_INDEX, "index does not contain '%s'", path); + return NULL; + } + + return value; +} + +void git_index_entry__init_from_stat( + git_index_entry *entry, struct stat *st, bool trust_mode) +{ + entry->ctime.seconds = (int32_t)st->st_ctime; + entry->mtime.seconds = (int32_t)st->st_mtime; +#if defined(GIT_USE_NSEC) + entry->mtime.nanoseconds = st->st_mtime_nsec; + entry->ctime.nanoseconds = st->st_ctime_nsec; +#endif + entry->dev = st->st_rdev; + entry->ino = st->st_ino; + entry->mode = (!trust_mode && S_ISREG(st->st_mode)) ? + git_index__create_mode(0666) : git_index__create_mode(st->st_mode); + entry->uid = st->st_uid; + entry->gid = st->st_gid; + entry->file_size = (uint32_t)st->st_size; +} + +static void index_entry_adjust_namemask( + git_index_entry *entry, + size_t path_length) +{ + entry->flags &= ~GIT_INDEX_ENTRY_NAMEMASK; + + if (path_length < GIT_INDEX_ENTRY_NAMEMASK) + entry->flags |= path_length & GIT_INDEX_ENTRY_NAMEMASK; + else + entry->flags |= GIT_INDEX_ENTRY_NAMEMASK; +} + +/* When `from_workdir` is true, we will validate the paths to avoid placing + * paths that are invalid for the working directory on the current filesystem + * (eg, on Windows, we will disallow `GIT~1`, `AUX`, `COM1`, etc). This + * function will *always* prevent `.git` and directory traversal `../` from + * being added to the index. + */ +static int index_entry_create( + git_index_entry **out, + git_repository *repo, + const char *path, + struct stat *st, + bool from_workdir) +{ + size_t pathlen = strlen(path), alloclen; + struct entry_internal *entry; + unsigned int path_valid_flags = GIT_PATH_REJECT_INDEX_DEFAULTS; + uint16_t mode = 0; + + /* always reject placing `.git` in the index and directory traversal. + * when requested, disallow platform-specific filenames and upgrade to + * the platform-specific `.git` tests (eg, `git~1`, etc). + */ + if (from_workdir) + path_valid_flags |= GIT_PATH_REJECT_WORKDIR_DEFAULTS; + if (st) + mode = st->st_mode; + + if (!git_path_is_valid(repo, path, mode, path_valid_flags)) { + git_error_set(GIT_ERROR_INDEX, "invalid path: '%s'", path); + return -1; + } + + GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, sizeof(struct entry_internal), pathlen); + GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1); + entry = git__calloc(1, alloclen); + GIT_ERROR_CHECK_ALLOC(entry); + + entry->pathlen = pathlen; + memcpy(entry->path, path, pathlen); + entry->entry.path = entry->path; + + *out = (git_index_entry *)entry; + return 0; +} + +static int index_entry_init( + git_index_entry **entry_out, + git_index *index, + const char *rel_path) +{ + int error = 0; + git_index_entry *entry = NULL; + git_str path = GIT_STR_INIT; + struct stat st; + git_oid oid; + git_repository *repo; + + if (INDEX_OWNER(index) == NULL) + return create_index_error(-1, + "could not initialize index entry. " + "Index is not backed up by an existing repository."); + + /* + * FIXME: this is duplicated with the work in + * git_blob__create_from_paths. It should accept an optional stat + * structure so we can pass in the one we have to do here. + */ + repo = INDEX_OWNER(index); + if (git_repository__ensure_not_bare(repo, "create blob from file") < 0) + return GIT_EBAREREPO; + + if (git_repository_workdir_path(&path, repo, rel_path) < 0) + return -1; + + error = git_fs_path_lstat(path.ptr, &st); + git_str_dispose(&path); + + if (error < 0) + return error; + + if (index_entry_create(&entry, INDEX_OWNER(index), rel_path, &st, true) < 0) + return -1; + + /* write the blob to disk and get the oid and stat info */ + error = git_blob__create_from_paths( + &oid, &st, INDEX_OWNER(index), NULL, rel_path, 0, true); + + if (error < 0) { + index_entry_free(entry); + return error; + } + + entry->id = oid; + git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode); + + *entry_out = (git_index_entry *)entry; + return 0; +} + +static git_index_reuc_entry *reuc_entry_alloc(const char *path) +{ + size_t pathlen = strlen(path), + structlen = sizeof(struct reuc_entry_internal), + alloclen; + struct reuc_entry_internal *entry; + + if (GIT_ADD_SIZET_OVERFLOW(&alloclen, structlen, pathlen) || + GIT_ADD_SIZET_OVERFLOW(&alloclen, alloclen, 1)) + return NULL; + + entry = git__calloc(1, alloclen); + if (!entry) + return NULL; + + entry->pathlen = pathlen; + memcpy(entry->path, path, pathlen); + entry->entry.path = entry->path; + + return (git_index_reuc_entry *)entry; +} + +static int index_entry_reuc_init(git_index_reuc_entry **reuc_out, + const char *path, + int ancestor_mode, const git_oid *ancestor_oid, + int our_mode, const git_oid *our_oid, + int their_mode, const git_oid *their_oid) +{ + git_index_reuc_entry *reuc = NULL; + + GIT_ASSERT_ARG(reuc_out); + GIT_ASSERT_ARG(path); + + *reuc_out = reuc = reuc_entry_alloc(path); + GIT_ERROR_CHECK_ALLOC(reuc); + + if ((reuc->mode[0] = ancestor_mode) > 0) { + GIT_ASSERT(ancestor_oid); + git_oid_cpy(&reuc->oid[0], ancestor_oid); + } + + if ((reuc->mode[1] = our_mode) > 0) { + GIT_ASSERT(our_oid); + git_oid_cpy(&reuc->oid[1], our_oid); + } + + if ((reuc->mode[2] = their_mode) > 0) { + GIT_ASSERT(their_oid); + git_oid_cpy(&reuc->oid[2], their_oid); + } + + return 0; +} + +static void index_entry_cpy( + git_index_entry *tgt, + const git_index_entry *src) +{ + const char *tgt_path = tgt->path; + memcpy(tgt, src, sizeof(*tgt)); + tgt->path = tgt_path; +} + +static int index_entry_dup( + git_index_entry **out, + git_index *index, + const git_index_entry *src) +{ + if (index_entry_create(out, INDEX_OWNER(index), src->path, NULL, false) < 0) + return -1; + + index_entry_cpy(*out, src); + return 0; +} + +static void index_entry_cpy_nocache( + git_index_entry *tgt, + const git_index_entry *src) +{ + git_oid_cpy(&tgt->id, &src->id); + tgt->mode = src->mode; + tgt->flags = src->flags; + tgt->flags_extended = (src->flags_extended & GIT_INDEX_ENTRY_EXTENDED_FLAGS); +} + +static int index_entry_dup_nocache( + git_index_entry **out, + git_index *index, + const git_index_entry *src) +{ + if (index_entry_create(out, INDEX_OWNER(index), src->path, NULL, false) < 0) + return -1; + + index_entry_cpy_nocache(*out, src); + return 0; +} + +static int has_file_name(git_index *index, + const git_index_entry *entry, size_t pos, int ok_to_replace) +{ + size_t len = strlen(entry->path); + int stage = GIT_INDEX_ENTRY_STAGE(entry); + const char *name = entry->path; + + while (pos < index->entries.length) { + struct entry_internal *p = index->entries.contents[pos++]; + + if (len >= p->pathlen) + break; + if (memcmp(name, p->path, len)) + break; + if (GIT_INDEX_ENTRY_STAGE(&p->entry) != stage) + continue; + if (p->path[len] != '/') + continue; + if (!ok_to_replace) + return -1; + + if (index_remove_entry(index, --pos) < 0) + break; + } + return 0; +} + +/* + * Do we have another file with a pathname that is a proper + * subset of the name we're trying to add? + */ +static int has_dir_name(git_index *index, + const git_index_entry *entry, int ok_to_replace) +{ + int stage = GIT_INDEX_ENTRY_STAGE(entry); + const char *name = entry->path; + const char *slash = name + strlen(name); + + for (;;) { + size_t len, pos; + + for (;;) { + slash--; + + if (slash <= entry->path) + return 0; + + if (*slash == '/') + break; + } + len = slash - name; + + if (!index_find(&pos, index, name, len, stage)) { + if (!ok_to_replace) + return -1; + + if (index_remove_entry(index, pos) < 0) + break; + continue; + } + + /* + * Trivial optimization: if we find an entry that + * already matches the sub-directory, then we know + * we're ok, and we can exit. + */ + for (; pos < index->entries.length; ++pos) { + struct entry_internal *p = index->entries.contents[pos]; + + if (p->pathlen <= len || + p->path[len] != '/' || + memcmp(p->path, name, len)) + break; /* not our subdirectory */ + + if (GIT_INDEX_ENTRY_STAGE(&p->entry) == stage) + return 0; + } + } + + return 0; +} + +static int check_file_directory_collision(git_index *index, + git_index_entry *entry, size_t pos, int ok_to_replace) +{ + if (has_file_name(index, entry, pos, ok_to_replace) < 0 || + has_dir_name(index, entry, ok_to_replace) < 0) { + git_error_set(GIT_ERROR_INDEX, + "'%s' appears as both a file and a directory", entry->path); + return -1; + } + + return 0; +} + +static int canonicalize_directory_path( + git_index *index, + git_index_entry *entry, + git_index_entry *existing) +{ + const git_index_entry *match, *best = NULL; + char *search, *sep; + size_t pos, search_len, best_len; + + if (!index->ignore_case) + return 0; + + /* item already exists in the index, simply re-use the existing case */ + if (existing) { + memcpy((char *)entry->path, existing->path, strlen(existing->path)); + return 0; + } + + /* nothing to do */ + if (strchr(entry->path, '/') == NULL) + return 0; + + if ((search = git__strdup(entry->path)) == NULL) + return -1; + + /* starting at the parent directory and descending to the root, find the + * common parent directory. + */ + while (!best && (sep = strrchr(search, '/'))) { + sep[1] = '\0'; + + search_len = strlen(search); + + git_vector_bsearch2( + &pos, &index->entries, index->entries_search_path, search); + + while ((match = git_vector_get(&index->entries, pos))) { + if (GIT_INDEX_ENTRY_STAGE(match) != 0) { + /* conflicts do not contribute to canonical paths */ + } else if (strncmp(search, match->path, search_len) == 0) { + /* prefer an exact match to the input filename */ + best = match; + best_len = search_len; + break; + } else if (strncasecmp(search, match->path, search_len) == 0) { + /* continue walking, there may be a path with an exact + * (case sensitive) match later in the index, but use this + * as the best match until that happens. + */ + if (!best) { + best = match; + best_len = search_len; + } + } else { + break; + } + + pos++; + } + + sep[0] = '\0'; + } + + if (best) + memcpy((char *)entry->path, best->path, best_len); + + git__free(search); + return 0; +} + +static int index_no_dups(void **old, void *new) +{ + const git_index_entry *entry = new; + GIT_UNUSED(old); + git_error_set(GIT_ERROR_INDEX, "'%s' appears multiple times at stage %d", + entry->path, GIT_INDEX_ENTRY_STAGE(entry)); + return GIT_EEXISTS; +} + +static void index_existing_and_best( + git_index_entry **existing, + size_t *existing_position, + git_index_entry **best, + git_index *index, + const git_index_entry *entry) +{ + git_index_entry *e; + size_t pos; + int error; + + error = index_find(&pos, + index, entry->path, 0, GIT_INDEX_ENTRY_STAGE(entry)); + + if (error == 0) { + *existing = index->entries.contents[pos]; + *existing_position = pos; + *best = index->entries.contents[pos]; + return; + } + + *existing = NULL; + *existing_position = 0; + *best = NULL; + + if (GIT_INDEX_ENTRY_STAGE(entry) == 0) { + for (; pos < index->entries.length; pos++) { + int (*strcomp)(const char *a, const char *b) = + index->ignore_case ? git__strcasecmp : git__strcmp; + + e = index->entries.contents[pos]; + + if (strcomp(entry->path, e->path) != 0) + break; + + if (GIT_INDEX_ENTRY_STAGE(e) == GIT_INDEX_STAGE_ANCESTOR) { + *best = e; + continue; + } else { + *best = e; + break; + } + } + } +} + +/* index_insert takes ownership of the new entry - if it can't insert + * it, then it will return an error **and also free the entry**. When + * it replaces an existing entry, it will update the entry_ptr with the + * actual entry in the index (and free the passed in one). + * + * trust_path is whether we use the given path, or whether (on case + * insensitive systems only) we try to canonicalize the given path to + * be within an existing directory. + * + * trust_mode is whether we trust the mode in entry_ptr. + * + * trust_id is whether we trust the id or it should be validated. + */ +static int index_insert( + git_index *index, + git_index_entry **entry_ptr, + int replace, + bool trust_path, + bool trust_mode, + bool trust_id) +{ + git_index_entry *existing, *best, *entry; + size_t path_length, position; + int error; + + GIT_ASSERT_ARG(index); + GIT_ASSERT_ARG(entry_ptr); + + entry = *entry_ptr; + + /* Make sure that the path length flag is correct */ + path_length = ((struct entry_internal *)entry)->pathlen; + index_entry_adjust_namemask(entry, path_length); + + /* This entry is now up-to-date and should not be checked for raciness */ + entry->flags_extended |= GIT_INDEX_ENTRY_UPTODATE; + + git_vector_sort(&index->entries); + + /* + * Look if an entry with this path already exists, either staged, or (if + * this entry is a regular staged item) as the "ours" side of a conflict. + */ + index_existing_and_best(&existing, &position, &best, index, entry); + + /* Update the file mode */ + entry->mode = trust_mode ? + git_index__create_mode(entry->mode) : + index_merge_mode(index, best, entry->mode); + + /* Canonicalize the directory name */ + if (!trust_path && (error = canonicalize_directory_path(index, entry, best)) < 0) + goto out; + + /* Ensure that the given id exists (unless it's a submodule) */ + if (!trust_id && INDEX_OWNER(index) && + (entry->mode & GIT_FILEMODE_COMMIT) != GIT_FILEMODE_COMMIT) { + + if (!git_object__is_valid(INDEX_OWNER(index), &entry->id, + git_object__type_from_filemode(entry->mode))) { + error = -1; + goto out; + } + } + + /* Look for tree / blob name collisions, removing conflicts if requested */ + if ((error = check_file_directory_collision(index, entry, position, replace)) < 0) + goto out; + + /* + * If we are replacing an existing item, overwrite the existing entry + * and return it in place of the passed in one. + */ + if (existing) { + if (replace) { + index_entry_cpy(existing, entry); + + if (trust_path) + memcpy((char *)existing->path, entry->path, strlen(entry->path)); + } + + index_entry_free(entry); + *entry_ptr = existing; + } else { + /* + * If replace is not requested or no existing entry exists, insert + * at the sorted position. (Since we re-sort after each insert to + * check for dups, this is actually cheaper in the long run.) + */ + if ((error = git_vector_insert_sorted(&index->entries, entry, index_no_dups)) < 0 || + (error = index_map_set(index->entries_map, entry, index->ignore_case)) < 0) + goto out; + } + + index->dirty = 1; + +out: + if (error < 0) { + index_entry_free(*entry_ptr); + *entry_ptr = NULL; + } + + return error; +} + +static int index_conflict_to_reuc(git_index *index, const char *path) +{ + const git_index_entry *conflict_entries[3]; + int ancestor_mode, our_mode, their_mode; + git_oid const *ancestor_oid, *our_oid, *their_oid; + int ret; + + if ((ret = git_index_conflict_get(&conflict_entries[0], + &conflict_entries[1], &conflict_entries[2], index, path)) < 0) + return ret; + + ancestor_mode = conflict_entries[0] == NULL ? 0 : conflict_entries[0]->mode; + our_mode = conflict_entries[1] == NULL ? 0 : conflict_entries[1]->mode; + their_mode = conflict_entries[2] == NULL ? 0 : conflict_entries[2]->mode; + + ancestor_oid = conflict_entries[0] == NULL ? NULL : &conflict_entries[0]->id; + our_oid = conflict_entries[1] == NULL ? NULL : &conflict_entries[1]->id; + their_oid = conflict_entries[2] == NULL ? NULL : &conflict_entries[2]->id; + + if ((ret = git_index_reuc_add(index, path, ancestor_mode, ancestor_oid, + our_mode, our_oid, their_mode, their_oid)) >= 0) + ret = git_index_conflict_remove(index, path); + + return ret; +} + +GIT_INLINE(bool) is_file_or_link(const int filemode) +{ + return (filemode == GIT_FILEMODE_BLOB || + filemode == GIT_FILEMODE_BLOB_EXECUTABLE || + filemode == GIT_FILEMODE_LINK); +} + +GIT_INLINE(bool) valid_filemode(const int filemode) +{ + return (is_file_or_link(filemode) || filemode == GIT_FILEMODE_COMMIT); +} + +int git_index_add_from_buffer( + git_index *index, const git_index_entry *source_entry, + const void *buffer, size_t len) +{ + git_index_entry *entry = NULL; + int error = 0; + git_oid id; + + GIT_ASSERT_ARG(index); + GIT_ASSERT_ARG(source_entry && source_entry->path); + + if (INDEX_OWNER(index) == NULL) + return create_index_error(-1, + "could not initialize index entry. " + "Index is not backed up by an existing repository."); + + if (!is_file_or_link(source_entry->mode)) { + git_error_set(GIT_ERROR_INDEX, "invalid filemode"); + return -1; + } + + if (len > UINT32_MAX) { + git_error_set(GIT_ERROR_INDEX, "buffer is too large"); + return -1; + } + + if (index_entry_dup(&entry, index, source_entry) < 0) + return -1; + + error = git_blob_create_from_buffer(&id, INDEX_OWNER(index), buffer, len); + if (error < 0) { + index_entry_free(entry); + return error; + } + + git_oid_cpy(&entry->id, &id); + entry->file_size = (uint32_t)len; + + if ((error = index_insert(index, &entry, 1, true, true, true)) < 0) + return error; + + /* Adding implies conflict was resolved, move conflict entries to REUC */ + if ((error = index_conflict_to_reuc(index, entry->path)) < 0 && error != GIT_ENOTFOUND) + return error; + + git_tree_cache_invalidate_path(index->tree, entry->path); + return 0; +} + +static int add_repo_as_submodule(git_index_entry **out, git_index *index, const char *path) +{ + git_repository *sub; + git_str abspath = GIT_STR_INIT; + git_repository *repo = INDEX_OWNER(index); + git_reference *head; + git_index_entry *entry; + struct stat st; + int error; + + if ((error = git_repository_workdir_path(&abspath, repo, path)) < 0) + return error; + + if ((error = p_stat(abspath.ptr, &st)) < 0) { + git_error_set(GIT_ERROR_OS, "failed to stat repository dir"); + return -1; + } + + if (index_entry_create(&entry, INDEX_OWNER(index), path, &st, true) < 0) + return -1; + + git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode); + + if ((error = git_repository_open(&sub, abspath.ptr)) < 0) + return error; + + if ((error = git_repository_head(&head, sub)) < 0) + return error; + + git_oid_cpy(&entry->id, git_reference_target(head)); + entry->mode = GIT_FILEMODE_COMMIT; + + git_reference_free(head); + git_repository_free(sub); + git_str_dispose(&abspath); + + *out = entry; + return 0; +} + +int git_index_add_bypath(git_index *index, const char *path) +{ + git_index_entry *entry = NULL; + int ret; + + GIT_ASSERT_ARG(index); + GIT_ASSERT_ARG(path); + + if ((ret = index_entry_init(&entry, index, path)) == 0) + ret = index_insert(index, &entry, 1, false, false, true); + + /* If we were given a directory, let's see if it's a submodule */ + if (ret < 0 && ret != GIT_EDIRECTORY) + return ret; + + if (ret == GIT_EDIRECTORY) { + git_submodule *sm; + git_error *last_error; + + git_error_save(&last_error); + + ret = git_submodule_lookup(&sm, INDEX_OWNER(index), path); + if (ret == GIT_ENOTFOUND) { + git_error_restore(last_error); + return GIT_EDIRECTORY; + } + + git_error_free(last_error); + + /* + * EEXISTS means that there is a repository at that path, but it's not known + * as a submodule. We add its HEAD as an entry and don't register it. + */ + if (ret == GIT_EEXISTS) { + if ((ret = add_repo_as_submodule(&entry, index, path)) < 0) + return ret; + + if ((ret = index_insert(index, &entry, 1, false, false, true)) < 0) + return ret; + } else if (ret < 0) { + return ret; + } else { + ret = git_submodule_add_to_index(sm, false); + git_submodule_free(sm); + return ret; + } + } + + /* Adding implies conflict was resolved, move conflict entries to REUC */ + if ((ret = index_conflict_to_reuc(index, path)) < 0 && ret != GIT_ENOTFOUND) + return ret; + + git_tree_cache_invalidate_path(index->tree, entry->path); + return 0; +} + +int git_index_remove_bypath(git_index *index, const char *path) +{ + int ret; + + GIT_ASSERT_ARG(index); + GIT_ASSERT_ARG(path); + + if (((ret = git_index_remove(index, path, 0)) < 0 && + ret != GIT_ENOTFOUND) || + ((ret = index_conflict_to_reuc(index, path)) < 0 && + ret != GIT_ENOTFOUND)) + return ret; + + if (ret == GIT_ENOTFOUND) + git_error_clear(); + + return 0; +} + +int git_index__fill(git_index *index, const git_vector *source_entries) +{ + const git_index_entry *source_entry = NULL; + int error = 0; + size_t i; + + GIT_ASSERT_ARG(index); + + if (!source_entries->length) + return 0; + + if (git_vector_size_hint(&index->entries, source_entries->length) < 0 || + index_map_resize(index->entries_map, (size_t)(source_entries->length * 1.3), + index->ignore_case) < 0) + return -1; + + git_vector_foreach(source_entries, i, source_entry) { + git_index_entry *entry = NULL; + + if ((error = index_entry_dup(&entry, index, source_entry)) < 0) + break; + + index_entry_adjust_namemask(entry, ((struct entry_internal *)entry)->pathlen); + entry->flags_extended |= GIT_INDEX_ENTRY_UPTODATE; + entry->mode = git_index__create_mode(entry->mode); + + if ((error = git_vector_insert(&index->entries, entry)) < 0) + break; + + if ((error = index_map_set(index->entries_map, entry, index->ignore_case)) < 0) + break; + + index->dirty = 1; + } + + if (!error) + git_vector_sort(&index->entries); + + return error; +} + + +int git_index_add(git_index *index, const git_index_entry *source_entry) +{ + git_index_entry *entry = NULL; + int ret; + + GIT_ASSERT_ARG(index); + GIT_ASSERT_ARG(source_entry && source_entry->path); + + if (!valid_filemode(source_entry->mode)) { + git_error_set(GIT_ERROR_INDEX, "invalid entry mode"); + return -1; + } + + if ((ret = index_entry_dup(&entry, index, source_entry)) < 0 || + (ret = index_insert(index, &entry, 1, true, true, false)) < 0) + return ret; + + git_tree_cache_invalidate_path(index->tree, entry->path); + return 0; +} + +int git_index_remove(git_index *index, const char *path, int stage) +{ + int error; + size_t position; + git_index_entry remove_key = {{ 0 }}; + + remove_key.path = path; + GIT_INDEX_ENTRY_STAGE_SET(&remove_key, stage); + + index_map_delete(index->entries_map, &remove_key, index->ignore_case); + + if (index_find(&position, index, path, 0, stage) < 0) { + git_error_set( + GIT_ERROR_INDEX, "index does not contain %s at stage %d", path, stage); + error = GIT_ENOTFOUND; + } else { + error = index_remove_entry(index, position); + } + + return error; +} + +int git_index_remove_directory(git_index *index, const char *dir, int stage) +{ + git_str pfx = GIT_STR_INIT; + int error = 0; + size_t pos; + git_index_entry *entry; + + if (!(error = git_str_sets(&pfx, dir)) && + !(error = git_fs_path_to_dir(&pfx))) + index_find(&pos, index, pfx.ptr, pfx.size, GIT_INDEX_STAGE_ANY); + + while (!error) { + entry = git_vector_get(&index->entries, pos); + if (!entry || git__prefixcmp(entry->path, pfx.ptr) != 0) + break; + + if (GIT_INDEX_ENTRY_STAGE(entry) != stage) { + ++pos; + continue; + } + + error = index_remove_entry(index, pos); + + /* removed entry at 'pos' so we don't need to increment */ + } + + git_str_dispose(&pfx); + + return error; +} + +int git_index_find_prefix(size_t *at_pos, git_index *index, const char *prefix) +{ + int error = 0; + size_t pos; + const git_index_entry *entry; + + index_find(&pos, index, prefix, strlen(prefix), GIT_INDEX_STAGE_ANY); + entry = git_vector_get(&index->entries, pos); + if (!entry || git__prefixcmp(entry->path, prefix) != 0) + error = GIT_ENOTFOUND; + + if (!error && at_pos) + *at_pos = pos; + + return error; +} + +int git_index__find_pos( + size_t *out, git_index *index, const char *path, size_t path_len, int stage) +{ + GIT_ASSERT_ARG(index); + GIT_ASSERT_ARG(path); + return index_find(out, index, path, path_len, stage); +} + +int git_index_find(size_t *at_pos, git_index *index, const char *path) +{ + size_t pos; + + GIT_ASSERT_ARG(index); + GIT_ASSERT_ARG(path); + + if (git_vector_bsearch2( + &pos, &index->entries, index->entries_search_path, path) < 0) { + git_error_set(GIT_ERROR_INDEX, "index does not contain %s", path); + return GIT_ENOTFOUND; + } + + /* Since our binary search only looked at path, we may be in the + * middle of a list of stages. + */ + for (; pos > 0; --pos) { + const git_index_entry *prev = git_vector_get(&index->entries, pos - 1); + + if (index->entries_cmp_path(prev->path, path) != 0) + break; + } + + if (at_pos) + *at_pos = pos; + + return 0; +} + +int git_index_conflict_add(git_index *index, + const git_index_entry *ancestor_entry, + const git_index_entry *our_entry, + const git_index_entry *their_entry) +{ + git_index_entry *entries[3] = { 0 }; + unsigned short i; + int ret = 0; + + GIT_ASSERT_ARG(index); + + if ((ancestor_entry && + (ret = index_entry_dup(&entries[0], index, ancestor_entry)) < 0) || + (our_entry && + (ret = index_entry_dup(&entries[1], index, our_entry)) < 0) || + (their_entry && + (ret = index_entry_dup(&entries[2], index, their_entry)) < 0)) + goto on_error; + + /* Validate entries */ + for (i = 0; i < 3; i++) { + if (entries[i] && !valid_filemode(entries[i]->mode)) { + git_error_set(GIT_ERROR_INDEX, "invalid filemode for stage %d entry", + i + 1); + ret = -1; + goto on_error; + } + } + + /* Remove existing index entries for each path */ + for (i = 0; i < 3; i++) { + if (entries[i] == NULL) + continue; + + if ((ret = git_index_remove(index, entries[i]->path, 0)) != 0) { + if (ret != GIT_ENOTFOUND) + goto on_error; + + git_error_clear(); + ret = 0; + } + } + + /* Add the conflict entries */ + for (i = 0; i < 3; i++) { + if (entries[i] == NULL) + continue; + + /* Make sure stage is correct */ + GIT_INDEX_ENTRY_STAGE_SET(entries[i], i + 1); + + if ((ret = index_insert(index, &entries[i], 1, true, true, false)) < 0) + goto on_error; + + entries[i] = NULL; /* don't free if later entry fails */ + } + + return 0; + +on_error: + for (i = 0; i < 3; i++) { + if (entries[i] != NULL) + index_entry_free(entries[i]); + } + + return ret; +} + +static int index_conflict__get_byindex( + const git_index_entry **ancestor_out, + const git_index_entry **our_out, + const git_index_entry **their_out, + git_index *index, + size_t n) +{ + const git_index_entry *conflict_entry; + const char *path = NULL; + size_t count; + int stage, len = 0; + + GIT_ASSERT_ARG(ancestor_out); + GIT_ASSERT_ARG(our_out); + GIT_ASSERT_ARG(their_out); + GIT_ASSERT_ARG(index); + + *ancestor_out = NULL; + *our_out = NULL; + *their_out = NULL; + + for (count = git_index_entrycount(index); n < count; ++n) { + conflict_entry = git_vector_get(&index->entries, n); + + if (path && index->entries_cmp_path(conflict_entry->path, path) != 0) + break; + + stage = GIT_INDEX_ENTRY_STAGE(conflict_entry); + path = conflict_entry->path; + + switch (stage) { + case 3: + *their_out = conflict_entry; + len++; + break; + case 2: + *our_out = conflict_entry; + len++; + break; + case 1: + *ancestor_out = conflict_entry; + len++; + break; + default: + break; + }; + } + + return len; +} + +int git_index_conflict_get( + const git_index_entry **ancestor_out, + const git_index_entry **our_out, + const git_index_entry **their_out, + git_index *index, + const char *path) +{ + size_t pos; + int len = 0; + + GIT_ASSERT_ARG(ancestor_out); + GIT_ASSERT_ARG(our_out); + GIT_ASSERT_ARG(their_out); + GIT_ASSERT_ARG(index); + GIT_ASSERT_ARG(path); + + *ancestor_out = NULL; + *our_out = NULL; + *their_out = NULL; + + if (git_index_find(&pos, index, path) < 0) + return GIT_ENOTFOUND; + + if ((len = index_conflict__get_byindex( + ancestor_out, our_out, their_out, index, pos)) < 0) + return len; + else if (len == 0) + return GIT_ENOTFOUND; + + return 0; +} + +static int index_conflict_remove(git_index *index, const char *path) +{ + size_t pos = 0; + git_index_entry *conflict_entry; + int error = 0; + + if (path != NULL && git_index_find(&pos, index, path) < 0) + return GIT_ENOTFOUND; + + while ((conflict_entry = git_vector_get(&index->entries, pos)) != NULL) { + + if (path != NULL && + index->entries_cmp_path(conflict_entry->path, path) != 0) + break; + + if (GIT_INDEX_ENTRY_STAGE(conflict_entry) == 0) { + pos++; + continue; + } + + if ((error = index_remove_entry(index, pos)) < 0) + break; + } + + return error; +} + +int git_index_conflict_remove(git_index *index, const char *path) +{ + GIT_ASSERT_ARG(index); + GIT_ASSERT_ARG(path); + return index_conflict_remove(index, path); +} + +int git_index_conflict_cleanup(git_index *index) +{ + GIT_ASSERT_ARG(index); + return index_conflict_remove(index, NULL); +} + +int git_index_has_conflicts(const git_index *index) +{ + size_t i; + git_index_entry *entry; + + GIT_ASSERT_ARG(index); + + git_vector_foreach(&index->entries, i, entry) { + if (GIT_INDEX_ENTRY_STAGE(entry) > 0) + return 1; + } + + return 0; +} + +int git_index_iterator_new( + git_index_iterator **iterator_out, + git_index *index) +{ + git_index_iterator *it; + int error; + + GIT_ASSERT_ARG(iterator_out); + GIT_ASSERT_ARG(index); + + it = git__calloc(1, sizeof(git_index_iterator)); + GIT_ERROR_CHECK_ALLOC(it); + + if ((error = git_index_snapshot_new(&it->snap, index)) < 0) { + git__free(it); + return error; + } + + it->index = index; + + *iterator_out = it; + return 0; +} + +int git_index_iterator_next( + const git_index_entry **out, + git_index_iterator *it) +{ + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(it); + + if (it->cur >= git_vector_length(&it->snap)) + return GIT_ITEROVER; + + *out = (git_index_entry *)git_vector_get(&it->snap, it->cur++); + return 0; +} + +void git_index_iterator_free(git_index_iterator *it) +{ + if (it == NULL) + return; + + git_index_snapshot_release(&it->snap, it->index); + git__free(it); +} + +int git_index_conflict_iterator_new( + git_index_conflict_iterator **iterator_out, + git_index *index) +{ + git_index_conflict_iterator *it = NULL; + + GIT_ASSERT_ARG(iterator_out); + GIT_ASSERT_ARG(index); + + it = git__calloc(1, sizeof(git_index_conflict_iterator)); + GIT_ERROR_CHECK_ALLOC(it); + + it->index = index; + + *iterator_out = it; + return 0; +} + +int git_index_conflict_next( + const git_index_entry **ancestor_out, + const git_index_entry **our_out, + const git_index_entry **their_out, + git_index_conflict_iterator *iterator) +{ + const git_index_entry *entry; + int len; + + GIT_ASSERT_ARG(ancestor_out); + GIT_ASSERT_ARG(our_out); + GIT_ASSERT_ARG(their_out); + GIT_ASSERT_ARG(iterator); + + *ancestor_out = NULL; + *our_out = NULL; + *their_out = NULL; + + while (iterator->cur < iterator->index->entries.length) { + entry = git_index_get_byindex(iterator->index, iterator->cur); + + if (git_index_entry_is_conflict(entry)) { + if ((len = index_conflict__get_byindex( + ancestor_out, + our_out, + their_out, + iterator->index, + iterator->cur)) < 0) + return len; + + iterator->cur += len; + return 0; + } + + iterator->cur++; + } + + return GIT_ITEROVER; +} + +void git_index_conflict_iterator_free(git_index_conflict_iterator *iterator) +{ + if (iterator == NULL) + return; + + git__free(iterator); +} + +size_t git_index_name_entrycount(git_index *index) +{ + GIT_ASSERT_ARG(index); + return index->names.length; +} + +const git_index_name_entry *git_index_name_get_byindex( + git_index *index, size_t n) +{ + GIT_ASSERT_ARG_WITH_RETVAL(index, NULL); + + git_vector_sort(&index->names); + return git_vector_get(&index->names, n); +} + +static void index_name_entry_free(git_index_name_entry *ne) +{ + if (!ne) + return; + git__free(ne->ancestor); + git__free(ne->ours); + git__free(ne->theirs); + git__free(ne); +} + +int git_index_name_add(git_index *index, + const char *ancestor, const char *ours, const char *theirs) +{ + git_index_name_entry *conflict_name; + + GIT_ASSERT_ARG((ancestor && ours) || (ancestor && theirs) || (ours && theirs)); + + conflict_name = git__calloc(1, sizeof(git_index_name_entry)); + GIT_ERROR_CHECK_ALLOC(conflict_name); + + if ((ancestor && !(conflict_name->ancestor = git__strdup(ancestor))) || + (ours && !(conflict_name->ours = git__strdup(ours))) || + (theirs && !(conflict_name->theirs = git__strdup(theirs))) || + git_vector_insert(&index->names, conflict_name) < 0) + { + index_name_entry_free(conflict_name); + return -1; + } + + index->dirty = 1; + return 0; +} + +int git_index_name_clear(git_index *index) +{ + size_t i; + git_index_name_entry *conflict_name; + + GIT_ASSERT_ARG(index); + + git_vector_foreach(&index->names, i, conflict_name) + index_name_entry_free(conflict_name); + + git_vector_clear(&index->names); + + index->dirty = 1; + + return 0; +} + +size_t git_index_reuc_entrycount(git_index *index) +{ + GIT_ASSERT_ARG(index); + return index->reuc.length; +} + +static int index_reuc_on_dup(void **old, void *new) +{ + index_entry_reuc_free(*old); + *old = new; + return GIT_EEXISTS; +} + +static int index_reuc_insert( + git_index *index, + git_index_reuc_entry *reuc) +{ + int res; + + GIT_ASSERT_ARG(index); + GIT_ASSERT_ARG(reuc && reuc->path != NULL); + GIT_ASSERT(git_vector_is_sorted(&index->reuc)); + + res = git_vector_insert_sorted(&index->reuc, reuc, &index_reuc_on_dup); + index->dirty = 1; + + return res == GIT_EEXISTS ? 0 : res; +} + +int git_index_reuc_add(git_index *index, const char *path, + int ancestor_mode, const git_oid *ancestor_oid, + int our_mode, const git_oid *our_oid, + int their_mode, const git_oid *their_oid) +{ + git_index_reuc_entry *reuc = NULL; + int error = 0; + + GIT_ASSERT_ARG(index); + GIT_ASSERT_ARG(path); + + if ((error = index_entry_reuc_init(&reuc, path, ancestor_mode, + ancestor_oid, our_mode, our_oid, their_mode, their_oid)) < 0 || + (error = index_reuc_insert(index, reuc)) < 0) + index_entry_reuc_free(reuc); + + return error; +} + +int git_index_reuc_find(size_t *at_pos, git_index *index, const char *path) +{ + return git_vector_bsearch2(at_pos, &index->reuc, index->reuc_search, path); +} + +const git_index_reuc_entry *git_index_reuc_get_bypath( + git_index *index, const char *path) +{ + size_t pos; + + GIT_ASSERT_ARG_WITH_RETVAL(index, NULL); + GIT_ASSERT_ARG_WITH_RETVAL(path, NULL); + + if (!index->reuc.length) + return NULL; + + GIT_ASSERT_WITH_RETVAL(git_vector_is_sorted(&index->reuc), NULL); + + if (git_index_reuc_find(&pos, index, path) < 0) + return NULL; + + return git_vector_get(&index->reuc, pos); +} + +const git_index_reuc_entry *git_index_reuc_get_byindex( + git_index *index, size_t n) +{ + GIT_ASSERT_ARG_WITH_RETVAL(index, NULL); + GIT_ASSERT_WITH_RETVAL(git_vector_is_sorted(&index->reuc), NULL); + + return git_vector_get(&index->reuc, n); +} + +int git_index_reuc_remove(git_index *index, size_t position) +{ + int error; + git_index_reuc_entry *reuc; + + GIT_ASSERT_ARG(index); + GIT_ASSERT(git_vector_is_sorted(&index->reuc)); + + reuc = git_vector_get(&index->reuc, position); + error = git_vector_remove(&index->reuc, position); + + if (!error) + index_entry_reuc_free(reuc); + + index->dirty = 1; + return error; +} + +int git_index_reuc_clear(git_index *index) +{ + size_t i; + + GIT_ASSERT_ARG(index); + + for (i = 0; i < index->reuc.length; ++i) + index_entry_reuc_free(git_atomic_swap(index->reuc.contents[i], NULL)); + + git_vector_clear(&index->reuc); + + index->dirty = 1; + + return 0; +} + +static int index_error_invalid(const char *message) +{ + git_error_set(GIT_ERROR_INDEX, "invalid data in index - %s", message); + return -1; +} + +static int read_reuc(git_index *index, const char *buffer, size_t size) +{ + const char *endptr; + size_t oid_size = git_oid_size(index->oid_type); + size_t len; + int i; + + /* If called multiple times, the vector might already be initialized */ + if (index->reuc._alloc_size == 0 && + git_vector_init(&index->reuc, 16, reuc_cmp) < 0) + return -1; + + while (size) { + git_index_reuc_entry *lost; + + len = p_strnlen(buffer, size) + 1; + if (size <= len) + return index_error_invalid("reading reuc entries"); + + lost = reuc_entry_alloc(buffer); + GIT_ERROR_CHECK_ALLOC(lost); + + size -= len; + buffer += len; + + /* read 3 ASCII octal numbers for stage entries */ + for (i = 0; i < 3; i++) { + int64_t tmp; + + if (git__strntol64(&tmp, buffer, size, &endptr, 8) < 0 || + !endptr || endptr == buffer || *endptr || + tmp < 0 || tmp > UINT32_MAX) { + index_entry_reuc_free(lost); + return index_error_invalid("reading reuc entry stage"); + } + + lost->mode[i] = (uint32_t)tmp; + + len = (endptr + 1) - buffer; + if (size <= len) { + index_entry_reuc_free(lost); + return index_error_invalid("reading reuc entry stage"); + } + + size -= len; + buffer += len; + } + + /* read up to 3 OIDs for stage entries */ + for (i = 0; i < 3; i++) { + if (!lost->mode[i]) + continue; + if (size < oid_size) { + index_entry_reuc_free(lost); + return index_error_invalid("reading reuc entry oid"); + } + + if (git_oid__fromraw(&lost->oid[i], (const unsigned char *) buffer, index->oid_type) < 0) + return -1; + + size -= oid_size; + buffer += oid_size; + } + + /* entry was read successfully - insert into reuc vector */ + if (git_vector_insert(&index->reuc, lost) < 0) + return -1; + } + + /* entries are guaranteed to be sorted on-disk */ + git_vector_set_sorted(&index->reuc, true); + + return 0; +} + + +static int read_conflict_names(git_index *index, const char *buffer, size_t size) +{ + size_t len; + + /* This gets called multiple times, the vector might already be initialized */ + if (index->names._alloc_size == 0 && + git_vector_init(&index->names, 16, conflict_name_cmp) < 0) + return -1; + +#define read_conflict_name(ptr) \ + len = p_strnlen(buffer, size) + 1; \ + if (size < len) { \ + index_error_invalid("reading conflict name entries"); \ + goto out_err; \ + } \ + if (len == 1) \ + ptr = NULL; \ + else { \ + ptr = git__malloc(len); \ + GIT_ERROR_CHECK_ALLOC(ptr); \ + memcpy(ptr, buffer, len); \ + } \ + \ + buffer += len; \ + size -= len; + + while (size) { + git_index_name_entry *conflict_name = git__calloc(1, sizeof(git_index_name_entry)); + GIT_ERROR_CHECK_ALLOC(conflict_name); + + read_conflict_name(conflict_name->ancestor); + read_conflict_name(conflict_name->ours); + read_conflict_name(conflict_name->theirs); + + if (git_vector_insert(&index->names, conflict_name) < 0) + goto out_err; + + continue; + +out_err: + git__free(conflict_name->ancestor); + git__free(conflict_name->ours); + git__free(conflict_name->theirs); + git__free(conflict_name); + return -1; + } + +#undef read_conflict_name + + /* entries are guaranteed to be sorted on-disk */ + git_vector_set_sorted(&index->names, true); + + return 0; +} + +GIT_INLINE(size_t) index_entry_path_offset( + git_oid_t oid_type, + uint32_t flags) +{ + if (oid_type == GIT_OID_SHA1) + return (flags & GIT_INDEX_ENTRY_EXTENDED) ? + offsetof(index_entry_long_sha1, path) : + offsetof(index_entry_short_sha1, path); + +#ifdef GIT_EXPERIMENTAL_SHA256 + else if (oid_type == GIT_OID_SHA256) + return (flags & GIT_INDEX_ENTRY_EXTENDED) ? + offsetof(index_entry_long_sha256, path) : + offsetof(index_entry_short_sha256, path); +#endif + + git_error_set(GIT_ERROR_INTERNAL, "invalid oid type"); + return 0; +} + +GIT_INLINE(size_t) index_entry_flags_offset(git_oid_t oid_type) +{ + if (oid_type == GIT_OID_SHA1) + return offsetof(index_entry_long_sha1, flags_extended); + +#ifdef GIT_EXPERIMENTAL_SHA256 + else if (oid_type == GIT_OID_SHA256) + return offsetof(index_entry_long_sha256, flags_extended); +#endif + + git_error_set(GIT_ERROR_INTERNAL, "invalid oid type"); + return 0; +} + +static size_t index_entry_size( + size_t path_len, + size_t varint_len, + git_oid_t oid_type, + uint32_t flags) +{ + size_t offset, size; + + if (!(offset = index_entry_path_offset(oid_type, flags))) + return 0; + + if (varint_len) { + if (GIT_ADD_SIZET_OVERFLOW(&size, offset, path_len) || + GIT_ADD_SIZET_OVERFLOW(&size, size, 1) || + GIT_ADD_SIZET_OVERFLOW(&size, size, varint_len)) + return 0; + } else { + if (GIT_ADD_SIZET_OVERFLOW(&size, offset, path_len) || + GIT_ADD_SIZET_OVERFLOW(&size, size, 8)) + return 0; + + size &= ~7; + } + + return size; +} + +static int read_entry( + git_index_entry **out, + size_t *out_size, + git_index *index, + size_t checksum_size, + const void *buffer, + size_t buffer_size, + const char *last) +{ + size_t path_length, path_offset, entry_size; + const char *path_ptr; + struct entry_common *source_common; + index_entry_short_sha1 source_sha1; +#ifdef GIT_EXPERIMENTAL_SHA256 + index_entry_short_sha256 source_sha256; +#endif + git_index_entry entry = {{0}}; + bool compressed = index->version >= INDEX_VERSION_NUMBER_COMP; + char *tmp_path = NULL; + + size_t minimal_entry_size = index_entry_path_offset(index->oid_type, 0); + + if (checksum_size + minimal_entry_size > buffer_size) + return -1; + + /* buffer is not guaranteed to be aligned */ + switch (index->oid_type) { + case GIT_OID_SHA1: + source_common = &source_sha1.common; + memcpy(&source_sha1, buffer, sizeof(source_sha1)); + break; +#ifdef GIT_EXPERIMENTAL_SHA256 + case GIT_OID_SHA256: + source_common = &source_sha256.common; + memcpy(&source_sha256, buffer, sizeof(source_sha256)); + break; +#endif + default: + GIT_ASSERT(!"invalid oid type"); + } + + entry.ctime.seconds = (git_time_t)ntohl(source_common->ctime.seconds); + entry.ctime.nanoseconds = ntohl(source_common->ctime.nanoseconds); + entry.mtime.seconds = (git_time_t)ntohl(source_common->mtime.seconds); + entry.mtime.nanoseconds = ntohl(source_common->mtime.nanoseconds); + entry.dev = ntohl(source_common->dev); + entry.ino = ntohl(source_common->ino); + entry.mode = ntohl(source_common->mode); + entry.uid = ntohl(source_common->uid); + entry.gid = ntohl(source_common->gid); + entry.file_size = ntohl(source_common->file_size); + + switch (index->oid_type) { + case GIT_OID_SHA1: + if (git_oid__fromraw(&entry.id, source_sha1.oid, + GIT_OID_SHA1) < 0) + return -1; + entry.flags = ntohs(source_sha1.flags); + break; +#ifdef GIT_EXPERIMENTAL_SHA256 + case GIT_OID_SHA256: + if (git_oid__fromraw(&entry.id, source_sha256.oid, + GIT_OID_SHA256) < 0) + return -1; + entry.flags = ntohs(source_sha256.flags); + break; +#endif + default: + GIT_ASSERT(!"invalid oid type"); + } + + if (!(path_offset = index_entry_path_offset(index->oid_type, entry.flags))) + return -1; + + + if (entry.flags & GIT_INDEX_ENTRY_EXTENDED) { + uint16_t flags_raw; + size_t flags_offset; + + if (!(flags_offset = index_entry_flags_offset(index->oid_type))) + return -1; + + memcpy(&flags_raw, (const char *)buffer + flags_offset, sizeof(flags_raw)); + flags_raw = ntohs(flags_raw); + + memcpy(&entry.flags_extended, &flags_raw, sizeof(flags_raw)); + path_ptr = (const char *)buffer + path_offset; + } else { + path_ptr = (const char *)buffer + path_offset; + } + + if (!compressed) { + path_length = entry.flags & GIT_INDEX_ENTRY_NAMEMASK; + + /* if this is a very long string, we must find its + * real length without overflowing */ + if (path_length == 0xFFF) { + const char *path_end; + + path_end = memchr(path_ptr, '\0', buffer_size); + if (path_end == NULL) + return index_error_invalid("invalid path name"); + + path_length = path_end - path_ptr; + } + + entry_size = index_entry_size(path_length, 0, index->oid_type, entry.flags); + entry.path = (char *)path_ptr; + } else { + size_t varint_len, last_len, prefix_len, suffix_len, path_len; + uintmax_t strip_len; + + strip_len = git_decode_varint((const unsigned char *)path_ptr, &varint_len); + last_len = strlen(last); + + if (varint_len == 0 || last_len < strip_len) + return index_error_invalid("incorrect prefix length"); + + prefix_len = last_len - (size_t)strip_len; + suffix_len = strlen(path_ptr + varint_len); + + GIT_ERROR_CHECK_ALLOC_ADD(&path_len, prefix_len, suffix_len); + GIT_ERROR_CHECK_ALLOC_ADD(&path_len, path_len, 1); + + if (path_len > GIT_PATH_MAX) + return index_error_invalid("unreasonable path length"); + + tmp_path = git__malloc(path_len); + GIT_ERROR_CHECK_ALLOC(tmp_path); + + memcpy(tmp_path, last, prefix_len); + memcpy(tmp_path + prefix_len, path_ptr + varint_len, suffix_len + 1); + + entry_size = index_entry_size(suffix_len, varint_len, index->oid_type, entry.flags); + entry.path = tmp_path; + } + + if (entry_size == 0) + return -1; + + if (checksum_size + entry_size > buffer_size) { + git_error_set(GIT_ERROR_INTERNAL, "invalid index checksum"); + return -1; + } + + if (index_entry_dup(out, index, &entry) < 0) { + git__free(tmp_path); + return -1; + } + + git__free(tmp_path); + *out_size = entry_size; + return 0; +} + +static int read_header(struct index_header *dest, const void *buffer) +{ + const struct index_header *source = buffer; + + dest->signature = ntohl(source->signature); + if (dest->signature != INDEX_HEADER_SIG) + return index_error_invalid("incorrect header signature"); + + dest->version = ntohl(source->version); + if (dest->version < INDEX_VERSION_NUMBER_LB || + dest->version > INDEX_VERSION_NUMBER_UB) + return index_error_invalid("incorrect header version"); + + dest->entry_count = ntohl(source->entry_count); + return 0; +} + +static int read_extension(size_t *read_len, git_index *index, size_t checksum_size, const char *buffer, size_t buffer_size) +{ + struct index_extension dest; + size_t total_size; + + /* buffer is not guaranteed to be aligned */ + memcpy(&dest, buffer, sizeof(struct index_extension)); + dest.extension_size = ntohl(dest.extension_size); + + total_size = dest.extension_size + sizeof(struct index_extension); + + if (dest.extension_size > total_size || + buffer_size < total_size || + buffer_size - total_size < checksum_size) { + index_error_invalid("extension is truncated"); + return -1; + } + + /* optional extension */ + if (dest.signature[0] >= 'A' && dest.signature[0] <= 'Z') { + /* tree cache */ + if (memcmp(dest.signature, INDEX_EXT_TREECACHE_SIG, 4) == 0) { + if (git_tree_cache_read(&index->tree, buffer + 8, dest.extension_size, index->oid_type, &index->tree_pool) < 0) + return -1; + } else if (memcmp(dest.signature, INDEX_EXT_UNMERGED_SIG, 4) == 0) { + if (read_reuc(index, buffer + 8, dest.extension_size) < 0) + return -1; + } else if (memcmp(dest.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4) == 0) { + if (read_conflict_names(index, buffer + 8, dest.extension_size) < 0) + return -1; + } + /* else, unsupported extension. We cannot parse this, but we can skip + * it by returning `total_size */ + } else { + /* we cannot handle non-ignorable extensions; + * in fact they aren't even defined in the standard */ + git_error_set(GIT_ERROR_INDEX, "unsupported mandatory extension: '%.4s'", dest.signature); + return -1; + } + + *read_len = total_size; + + return 0; +} + +static int parse_index(git_index *index, const char *buffer, size_t buffer_size) +{ + int error = 0; + unsigned int i; + struct index_header header = { 0 }; + unsigned char checksum[GIT_HASH_MAX_SIZE]; + unsigned char zero_checksum[GIT_HASH_MAX_SIZE] = { 0 }; + size_t checksum_size = git_hash_size(git_oid_algorithm(index->oid_type)); + const char *last = NULL; + const char *empty = ""; + +#define seek_forward(_increase) { \ + if (_increase >= buffer_size) { \ + error = index_error_invalid("ran out of data while parsing"); \ + goto done; } \ + buffer += _increase; \ + buffer_size -= _increase;\ +} + + if (buffer_size < INDEX_HEADER_SIZE + checksum_size) + return index_error_invalid("insufficient buffer space"); + + /* + * Precalculate the hash of the files's contents -- we'll match + * it to the provided checksum in the footer. + */ + git_hash_buf(checksum, buffer, buffer_size - checksum_size, + git_oid_algorithm(index->oid_type)); + + /* Parse header */ + if ((error = read_header(&header, buffer)) < 0) + return error; + + index->version = header.version; + if (index->version >= INDEX_VERSION_NUMBER_COMP) + last = empty; + + seek_forward(INDEX_HEADER_SIZE); + + GIT_ASSERT(!index->entries.length); + + if ((error = index_map_resize(index->entries_map, header.entry_count, index->ignore_case)) < 0) + return error; + + /* Parse all the entries */ + for (i = 0; i < header.entry_count && buffer_size > checksum_size; ++i) { + git_index_entry *entry = NULL; + size_t entry_size; + + if ((error = read_entry(&entry, &entry_size, index, checksum_size, buffer, buffer_size, last)) < 0) { + error = index_error_invalid("invalid entry"); + goto done; + } + + if ((error = git_vector_insert(&index->entries, entry)) < 0) { + index_entry_free(entry); + goto done; + } + + if ((error = index_map_set(index->entries_map, entry, index->ignore_case)) < 0) { + index_entry_free(entry); + goto done; + } + error = 0; + + if (index->version >= INDEX_VERSION_NUMBER_COMP) + last = entry->path; + + seek_forward(entry_size); + } + + if (i != header.entry_count) { + error = index_error_invalid("header entries changed while parsing"); + goto done; + } + + /* There's still space for some extensions! */ + while (buffer_size > checksum_size) { + size_t extension_size; + + if ((error = read_extension(&extension_size, index, checksum_size, buffer, buffer_size)) < 0) { + goto done; + } + + seek_forward(extension_size); + } + + if (buffer_size != checksum_size) { + error = index_error_invalid( + "buffer size does not match index footer size"); + goto done; + } + + /* + * SHA-1 or SHA-256 (depending on the repository's object format) + * over the content of the index file before this checksum. + * Note: checksum may be 0 if the index was written by a client + * where index.skipHash was set to true. + */ + if (memcmp(zero_checksum, buffer, checksum_size) != 0 && + memcmp(checksum, buffer, checksum_size) != 0) { + error = index_error_invalid( + "calculated checksum does not match expected"); + goto done; + } + + memcpy(index->checksum, checksum, checksum_size); + +#undef seek_forward + + /* Entries are stored case-sensitively on disk, so re-sort now if + * in-memory index is supposed to be case-insensitive + */ + git_vector_set_sorted(&index->entries, !index->ignore_case); + git_vector_sort(&index->entries); + + index->dirty = 0; +done: + return error; +} + +static bool is_index_extended(git_index *index) +{ + size_t i, extended; + git_index_entry *entry; + + extended = 0; + + git_vector_foreach(&index->entries, i, entry) { + entry->flags &= ~GIT_INDEX_ENTRY_EXTENDED; + if (entry->flags_extended & GIT_INDEX_ENTRY_EXTENDED_FLAGS) { + extended++; + entry->flags |= GIT_INDEX_ENTRY_EXTENDED; + } + } + + return (extended > 0); +} + +static int write_disk_entry( + git_index *index, + git_filebuf *file, + git_index_entry *entry, + const char *last) +{ + void *mem = NULL; + struct entry_common *ondisk_common; + size_t path_len, path_offset, disk_size; + int varint_len = 0; + char *path; + const char *path_start = entry->path; + size_t same_len = 0; + + index_entry_short_sha1 ondisk_sha1; + index_entry_long_sha1 ondisk_ext_sha1; +#ifdef GIT_EXPERIMENTAL_SHA256 + index_entry_short_sha256 ondisk_sha256; + index_entry_long_sha256 ondisk_ext_sha256; +#endif + + switch (index->oid_type) { + case GIT_OID_SHA1: + ondisk_common = &ondisk_sha1.common; + break; +#ifdef GIT_EXPERIMENTAL_SHA256 + case GIT_OID_SHA256: + ondisk_common = &ondisk_sha256.common; + break; +#endif + default: + GIT_ASSERT(!"invalid oid type"); + } + + path_len = ((struct entry_internal *)entry)->pathlen; + + if (last) { + const char *last_c = last; + + while (*path_start == *last_c) { + if (!*path_start || !*last_c) + break; + ++path_start; + ++last_c; + ++same_len; + } + path_len -= same_len; + varint_len = git_encode_varint(NULL, 0, strlen(last) - same_len); + } + + disk_size = index_entry_size(path_len, varint_len, index->oid_type, entry->flags); + + if (!disk_size || git_filebuf_reserve(file, &mem, disk_size) < 0) + return -1; + + memset(mem, 0x0, disk_size); + + /** + * Yes, we have to truncate. + * + * The on-disk format for Index entries clearly defines + * the time and size fields to be 4 bytes each -- so even if + * we store these values with 8 bytes on-memory, they must + * be truncated to 4 bytes before writing to disk. + * + * In 2038 I will be either too dead or too rich to care about this + */ + ondisk_common->ctime.seconds = htonl((uint32_t)entry->ctime.seconds); + ondisk_common->mtime.seconds = htonl((uint32_t)entry->mtime.seconds); + ondisk_common->ctime.nanoseconds = htonl(entry->ctime.nanoseconds); + ondisk_common->mtime.nanoseconds = htonl(entry->mtime.nanoseconds); + ondisk_common->dev = htonl(entry->dev); + ondisk_common->ino = htonl(entry->ino); + ondisk_common->mode = htonl(entry->mode); + ondisk_common->uid = htonl(entry->uid); + ondisk_common->gid = htonl(entry->gid); + ondisk_common->file_size = htonl((uint32_t)entry->file_size); + + switch (index->oid_type) { + case GIT_OID_SHA1: + git_oid_raw_cpy(ondisk_sha1.oid, entry->id.id, GIT_OID_SHA1_SIZE); + ondisk_sha1.flags = htons(entry->flags); + break; +#ifdef GIT_EXPERIMENTAL_SHA256 + case GIT_OID_SHA256: + git_oid_raw_cpy(ondisk_sha256.oid, entry->id.id, GIT_OID_SHA256_SIZE); + ondisk_sha256.flags = htons(entry->flags); + break; +#endif + default: + GIT_ASSERT(!"invalid oid type"); + } + + path_offset = index_entry_path_offset(index->oid_type, entry->flags); + + if (entry->flags & GIT_INDEX_ENTRY_EXTENDED) { + struct entry_common *ondisk_ext; + uint16_t flags_extended = htons(entry->flags_extended & + GIT_INDEX_ENTRY_EXTENDED_FLAGS); + + switch (index->oid_type) { + case GIT_OID_SHA1: + memcpy(&ondisk_ext_sha1, &ondisk_sha1, + sizeof(index_entry_short_sha1)); + ondisk_ext_sha1.flags_extended = flags_extended; + ondisk_ext = &ondisk_ext_sha1.common; + break; +#ifdef GIT_EXPERIMENTAL_SHA256 + case GIT_OID_SHA256: + memcpy(&ondisk_ext_sha256, &ondisk_sha256, + sizeof(index_entry_short_sha256)); + ondisk_ext_sha256.flags_extended = flags_extended; + ondisk_ext = &ondisk_ext_sha256.common; + break; +#endif + default: + GIT_ASSERT(!"invalid oid type"); + } + + memcpy(mem, ondisk_ext, path_offset); + } else { + switch (index->oid_type) { + case GIT_OID_SHA1: + memcpy(mem, &ondisk_sha1, path_offset); + break; +#ifdef GIT_EXPERIMENTAL_SHA256 + case GIT_OID_SHA256: + memcpy(mem, &ondisk_sha256, path_offset); + break; +#endif + default: + GIT_ASSERT(!"invalid oid type"); + } + } + + path = (char *)mem + path_offset; + disk_size -= path_offset; + + if (last) { + varint_len = git_encode_varint((unsigned char *) path, + disk_size, strlen(last) - same_len); + GIT_ASSERT(varint_len > 0); + + path += varint_len; + disk_size -= varint_len; + + /* + * If using path compression, we are not allowed + * to have additional trailing NULs. + */ + GIT_ASSERT(disk_size == path_len + 1); + } else { + /* + * If no path compression is used, we do have + * NULs as padding. As such, simply assert that + * we have enough space left to write the path. + */ + GIT_ASSERT(disk_size > path_len); + } + + memcpy(path, path_start, path_len + 1); + + return 0; +} + +static int write_entries(git_index *index, git_filebuf *file) +{ + int error = 0; + size_t i; + git_vector case_sorted = GIT_VECTOR_INIT, *entries = NULL; + git_index_entry *entry; + const char *last = NULL; + + /* If index->entries is sorted case-insensitively, then we need + * to re-sort it case-sensitively before writing */ + if (index->ignore_case) { + if ((error = git_vector_dup(&case_sorted, &index->entries, git_index_entry_cmp)) < 0) + goto done; + + git_vector_sort(&case_sorted); + entries = &case_sorted; + } else { + entries = &index->entries; + } + + if (index->version >= INDEX_VERSION_NUMBER_COMP) + last = ""; + + git_vector_foreach(entries, i, entry) { + if ((error = write_disk_entry(index, file, entry, last)) < 0) + break; + if (index->version >= INDEX_VERSION_NUMBER_COMP) + last = entry->path; + } + +done: + git_vector_free(&case_sorted); + return error; +} + +static int write_extension(git_filebuf *file, struct index_extension *header, git_str *data) +{ + struct index_extension ondisk; + + memset(&ondisk, 0x0, sizeof(struct index_extension)); + memcpy(&ondisk, header, 4); + ondisk.extension_size = htonl(header->extension_size); + + git_filebuf_write(file, &ondisk, sizeof(struct index_extension)); + return git_filebuf_write(file, data->ptr, data->size); +} + +static int create_name_extension_data(git_str *name_buf, git_index_name_entry *conflict_name) +{ + int error = 0; + + if (conflict_name->ancestor == NULL) + error = git_str_put(name_buf, "\0", 1); + else + error = git_str_put(name_buf, conflict_name->ancestor, strlen(conflict_name->ancestor) + 1); + + if (error != 0) + goto on_error; + + if (conflict_name->ours == NULL) + error = git_str_put(name_buf, "\0", 1); + else + error = git_str_put(name_buf, conflict_name->ours, strlen(conflict_name->ours) + 1); + + if (error != 0) + goto on_error; + + if (conflict_name->theirs == NULL) + error = git_str_put(name_buf, "\0", 1); + else + error = git_str_put(name_buf, conflict_name->theirs, strlen(conflict_name->theirs) + 1); + +on_error: + return error; +} + +static int write_name_extension(git_index *index, git_filebuf *file) +{ + git_str name_buf = GIT_STR_INIT; + git_vector *out = &index->names; + git_index_name_entry *conflict_name; + struct index_extension extension; + size_t i; + int error = 0; + + git_vector_foreach(out, i, conflict_name) { + if ((error = create_name_extension_data(&name_buf, conflict_name)) < 0) + goto done; + } + + memset(&extension, 0x0, sizeof(struct index_extension)); + memcpy(&extension.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4); + extension.extension_size = (uint32_t)name_buf.size; + + error = write_extension(file, &extension, &name_buf); + + git_str_dispose(&name_buf); + +done: + return error; +} + +static int create_reuc_extension_data(git_str *reuc_buf, git_index *index, git_index_reuc_entry *reuc) +{ + size_t oid_size = git_oid_size(index->oid_type); + int i; + int error = 0; + + if ((error = git_str_put(reuc_buf, reuc->path, strlen(reuc->path) + 1)) < 0) + return error; + + for (i = 0; i < 3; i++) { + if ((error = git_str_printf(reuc_buf, "%o", reuc->mode[i])) < 0 || + (error = git_str_put(reuc_buf, "\0", 1)) < 0) + return error; + } + + for (i = 0; i < 3; i++) { + if (reuc->mode[i] && (error = git_str_put(reuc_buf, (char *)&reuc->oid[i].id, oid_size)) < 0) + return error; + } + + return 0; +} + +static int write_reuc_extension(git_index *index, git_filebuf *file) +{ + git_str reuc_buf = GIT_STR_INIT; + git_vector *out = &index->reuc; + git_index_reuc_entry *reuc; + struct index_extension extension; + size_t i; + int error = 0; + + git_vector_foreach(out, i, reuc) { + if ((error = create_reuc_extension_data(&reuc_buf, index, reuc)) < 0) + goto done; + } + + memset(&extension, 0x0, sizeof(struct index_extension)); + memcpy(&extension.signature, INDEX_EXT_UNMERGED_SIG, 4); + extension.extension_size = (uint32_t)reuc_buf.size; + + error = write_extension(file, &extension, &reuc_buf); + + git_str_dispose(&reuc_buf); + +done: + return error; +} + +static int write_tree_extension(git_index *index, git_filebuf *file) +{ + struct index_extension extension; + git_str buf = GIT_STR_INIT; + int error; + + if (index->tree == NULL) + return 0; + + if ((error = git_tree_cache_write(&buf, index->tree)) < 0) + return error; + + memset(&extension, 0x0, sizeof(struct index_extension)); + memcpy(&extension.signature, INDEX_EXT_TREECACHE_SIG, 4); + extension.extension_size = (uint32_t)buf.size; + + error = write_extension(file, &extension, &buf); + + git_str_dispose(&buf); + + return error; +} + +static void clear_uptodate(git_index *index) +{ + git_index_entry *entry; + size_t i; + + git_vector_foreach(&index->entries, i, entry) + entry->flags_extended &= ~GIT_INDEX_ENTRY_UPTODATE; +} + +static int write_index( + unsigned char checksum[GIT_HASH_MAX_SIZE], + size_t *checksum_size, + git_index *index, + git_filebuf *file) +{ + struct index_header header; + bool is_extended; + uint32_t index_version_number; + + GIT_ASSERT_ARG(index); + GIT_ASSERT_ARG(file); + + GIT_ASSERT(index->oid_type); + + *checksum_size = git_hash_size(git_oid_algorithm(index->oid_type)); + + if (index->version <= INDEX_VERSION_NUMBER_EXT) { + is_extended = is_index_extended(index); + index_version_number = is_extended ? INDEX_VERSION_NUMBER_EXT : INDEX_VERSION_NUMBER_LB; + } else { + index_version_number = index->version; + } + + header.signature = htonl(INDEX_HEADER_SIG); + header.version = htonl(index_version_number); + header.entry_count = htonl((uint32_t)index->entries.length); + + if (git_filebuf_write(file, &header, sizeof(struct index_header)) < 0) + return -1; + + if (write_entries(index, file) < 0) + return -1; + + /* write the tree cache extension */ + if (index->tree != NULL && write_tree_extension(index, file) < 0) + return -1; + + /* write the rename conflict extension */ + if (index->names.length > 0 && write_name_extension(index, file) < 0) + return -1; + + /* write the reuc extension */ + if (index->reuc.length > 0 && write_reuc_extension(index, file) < 0) + return -1; + + /* get out the hash for all the contents we've appended to the file */ + git_filebuf_hash(checksum, file); + + /* write it at the end of the file */ + if (git_filebuf_write(file, checksum, *checksum_size) < 0) + return -1; + + /* file entries are no longer up to date */ + clear_uptodate(index); + + return 0; +} + +int git_index_entry_stage(const git_index_entry *entry) +{ + return GIT_INDEX_ENTRY_STAGE(entry); +} + +int git_index_entry_is_conflict(const git_index_entry *entry) +{ + return (GIT_INDEX_ENTRY_STAGE(entry) > 0); +} + +typedef struct read_tree_data { + git_index *index; + git_vector *old_entries; + git_vector *new_entries; + git_vector_cmp entry_cmp; + git_tree_cache *tree; +} read_tree_data; + +static int read_tree_cb( + const char *root, const git_tree_entry *tentry, void *payload) +{ + read_tree_data *data = payload; + git_index_entry *entry = NULL, *old_entry; + git_str path = GIT_STR_INIT; + size_t pos; + + if (git_tree_entry__is_tree(tentry)) + return 0; + + if (git_str_joinpath(&path, root, tentry->filename) < 0) + return -1; + + if (index_entry_create(&entry, INDEX_OWNER(data->index), path.ptr, NULL, false) < 0) + return -1; + + entry->mode = tentry->attr; + git_oid_cpy(&entry->id, git_tree_entry_id(tentry)); + + /* look for corresponding old entry and copy data to new entry */ + if (data->old_entries != NULL && + !index_find_in_entries( + &pos, data->old_entries, data->entry_cmp, path.ptr, 0, 0) && + (old_entry = git_vector_get(data->old_entries, pos)) != NULL && + entry->mode == old_entry->mode && + git_oid_equal(&entry->id, &old_entry->id)) + { + index_entry_cpy(entry, old_entry); + entry->flags_extended = 0; + } + + index_entry_adjust_namemask(entry, path.size); + git_str_dispose(&path); + + if (git_vector_insert(data->new_entries, entry) < 0) { + index_entry_free(entry); + return -1; + } + + return 0; +} + +int git_index_read_tree(git_index *index, const git_tree *tree) +{ + int error = 0; + git_vector entries = GIT_VECTOR_INIT; + git_idxmap *entries_map; + read_tree_data data; + size_t i; + git_index_entry *e; + + if (git_idxmap_new(&entries_map) < 0) + return -1; + + git_vector_set_cmp(&entries, index->entries._cmp); /* match sort */ + + data.index = index; + data.old_entries = &index->entries; + data.new_entries = &entries; + data.entry_cmp = index->entries_search; + + index->tree = NULL; + git_pool_clear(&index->tree_pool); + + git_vector_sort(&index->entries); + + if ((error = git_tree_walk(tree, GIT_TREEWALK_POST, read_tree_cb, &data)) < 0) + goto cleanup; + + if ((error = index_map_resize(entries_map, entries.length, index->ignore_case)) < 0) + goto cleanup; + + git_vector_foreach(&entries, i, e) { + if ((error = index_map_set(entries_map, e, index->ignore_case)) < 0) { + git_error_set(GIT_ERROR_INDEX, "failed to insert entry into map"); + return error; + } + } + + error = 0; + + git_vector_sort(&entries); + + if ((error = git_index_clear(index)) < 0) { + /* well, this isn't good */; + } else { + git_vector_swap(&entries, &index->entries); + entries_map = git_atomic_swap(index->entries_map, entries_map); + } + + index->dirty = 1; + +cleanup: + git_vector_free(&entries); + git_idxmap_free(entries_map); + if (error < 0) + return error; + + error = git_tree_cache_read_tree(&index->tree, tree, index->oid_type, &index->tree_pool); + + return error; +} + +static int git_index_read_iterator( + git_index *index, + git_iterator *new_iterator, + size_t new_length_hint) +{ + git_vector new_entries = GIT_VECTOR_INIT, + remove_entries = GIT_VECTOR_INIT; + git_idxmap *new_entries_map = NULL; + git_iterator *index_iterator = NULL; + git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT; + const git_index_entry *old_entry, *new_entry; + git_index_entry *entry; + size_t i; + int error; + + GIT_ASSERT((new_iterator->flags & GIT_ITERATOR_DONT_IGNORE_CASE)); + + if ((error = git_vector_init(&new_entries, new_length_hint, index->entries._cmp)) < 0 || + (error = git_vector_init(&remove_entries, index->entries.length, NULL)) < 0 || + (error = git_idxmap_new(&new_entries_map)) < 0) + goto done; + + if (new_length_hint && (error = index_map_resize(new_entries_map, new_length_hint, + index->ignore_case)) < 0) + goto done; + + opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE | + GIT_ITERATOR_INCLUDE_CONFLICTS; + + if ((error = git_iterator_for_index(&index_iterator, + git_index_owner(index), index, &opts)) < 0 || + ((error = git_iterator_current(&old_entry, index_iterator)) < 0 && + error != GIT_ITEROVER) || + ((error = git_iterator_current(&new_entry, new_iterator)) < 0 && + error != GIT_ITEROVER)) + goto done; + + while (true) { + git_index_entry + *dup_entry = NULL, + *add_entry = NULL, + *remove_entry = NULL; + int diff; + + error = 0; + + if (old_entry && new_entry) + diff = git_index_entry_cmp(old_entry, new_entry); + else if (!old_entry && new_entry) + diff = 1; + else if (old_entry && !new_entry) + diff = -1; + else + break; + + if (diff < 0) { + remove_entry = (git_index_entry *)old_entry; + } else if (diff > 0) { + dup_entry = (git_index_entry *)new_entry; + } else { + /* Path and stage are equal, if the OID is equal, keep it to + * keep the stat cache data. + */ + if (git_oid_equal(&old_entry->id, &new_entry->id) && + old_entry->mode == new_entry->mode) { + add_entry = (git_index_entry *)old_entry; + } else { + dup_entry = (git_index_entry *)new_entry; + remove_entry = (git_index_entry *)old_entry; + } + } + + if (dup_entry) { + if ((error = index_entry_dup_nocache(&add_entry, index, dup_entry)) < 0) + goto done; + + index_entry_adjust_namemask(add_entry, + ((struct entry_internal *)add_entry)->pathlen); + } + + /* invalidate this path in the tree cache if this is new (to + * invalidate the parent trees) + */ + if (dup_entry && !remove_entry && index->tree) + git_tree_cache_invalidate_path(index->tree, dup_entry->path); + + if (add_entry) { + if ((error = git_vector_insert(&new_entries, add_entry)) == 0) + error = index_map_set(new_entries_map, add_entry, + index->ignore_case); + } + + if (remove_entry && error >= 0) + error = git_vector_insert(&remove_entries, remove_entry); + + if (error < 0) { + git_error_set(GIT_ERROR_INDEX, "failed to insert entry"); + goto done; + } + + if (diff <= 0) { + if ((error = git_iterator_advance(&old_entry, index_iterator)) < 0 && + error != GIT_ITEROVER) + goto done; + } + + if (diff >= 0) { + if ((error = git_iterator_advance(&new_entry, new_iterator)) < 0 && + error != GIT_ITEROVER) + goto done; + } + } + + if ((error = git_index_name_clear(index)) < 0 || + (error = git_index_reuc_clear(index)) < 0) + goto done; + + git_vector_swap(&new_entries, &index->entries); + new_entries_map = git_atomic_swap(index->entries_map, new_entries_map); + + git_vector_foreach(&remove_entries, i, entry) { + if (index->tree) + git_tree_cache_invalidate_path(index->tree, entry->path); + + index_entry_free(entry); + } + + clear_uptodate(index); + + index->dirty = 1; + error = 0; + +done: + git_idxmap_free(new_entries_map); + git_vector_free(&new_entries); + git_vector_free(&remove_entries); + git_iterator_free(index_iterator); + return error; +} + +int git_index_read_index( + git_index *index, + const git_index *new_index) +{ + git_iterator *new_iterator = NULL; + git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT; + int error; + + opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE | + GIT_ITERATOR_INCLUDE_CONFLICTS; + + if ((error = git_iterator_for_index(&new_iterator, + git_index_owner(new_index), (git_index *)new_index, &opts)) < 0 || + (error = git_index_read_iterator(index, new_iterator, + new_index->entries.length)) < 0) + goto done; + +done: + git_iterator_free(new_iterator); + return error; +} + +git_repository *git_index_owner(const git_index *index) +{ + return INDEX_OWNER(index); +} + +enum { + INDEX_ACTION_NONE = 0, + INDEX_ACTION_UPDATE = 1, + INDEX_ACTION_REMOVE = 2, + INDEX_ACTION_ADDALL = 3 +}; + +int git_index_add_all( + git_index *index, + const git_strarray *paths, + unsigned int flags, + git_index_matched_path_cb cb, + void *payload) +{ + int error; + git_repository *repo; + git_pathspec ps; + bool no_fnmatch = (flags & GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH) != 0; + + GIT_ASSERT_ARG(index); + + repo = INDEX_OWNER(index); + if ((error = git_repository__ensure_not_bare(repo, "index add all")) < 0) + return error; + + if ((error = git_pathspec__init(&ps, paths)) < 0) + return error; + + /* optionally check that pathspec doesn't mention any ignored files */ + if ((flags & GIT_INDEX_ADD_CHECK_PATHSPEC) != 0 && + (flags & GIT_INDEX_ADD_FORCE) == 0 && + (error = git_ignore__check_pathspec_for_exact_ignores( + repo, &ps.pathspec, no_fnmatch)) < 0) + goto cleanup; + + error = index_apply_to_wd_diff(index, INDEX_ACTION_ADDALL, paths, flags, cb, payload); + + if (error) + git_error_set_after_callback(error); + +cleanup: + git_pathspec__clear(&ps); + + return error; +} + +struct foreach_diff_data { + git_index *index; + const git_pathspec *pathspec; + unsigned int flags; + git_index_matched_path_cb cb; + void *payload; +}; + +static int apply_each_file(const git_diff_delta *delta, float progress, void *payload) +{ + struct foreach_diff_data *data = payload; + const char *match, *path; + int error = 0; + + GIT_UNUSED(progress); + + path = delta->old_file.path; + + /* We only want those which match the pathspecs */ + if (!git_pathspec__match( + &data->pathspec->pathspec, path, false, (bool)data->index->ignore_case, + &match, NULL)) + return 0; + + if (data->cb) + error = data->cb(path, match, data->payload); + + if (error > 0) /* skip this entry */ + return 0; + if (error < 0) /* actual error */ + return error; + + /* If the workdir item does not exist, remove it from the index. */ + if ((delta->new_file.flags & GIT_DIFF_FLAG_EXISTS) == 0) + error = git_index_remove_bypath(data->index, path); + else + error = git_index_add_bypath(data->index, delta->new_file.path); + + return error; +} + +static int index_apply_to_wd_diff(git_index *index, int action, const git_strarray *paths, + unsigned int flags, + git_index_matched_path_cb cb, void *payload) +{ + int error; + git_diff *diff; + git_pathspec ps; + git_repository *repo; + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + struct foreach_diff_data data = { + index, + NULL, + flags, + cb, + payload, + }; + + GIT_ASSERT_ARG(index); + GIT_ASSERT_ARG(action == INDEX_ACTION_UPDATE || action == INDEX_ACTION_ADDALL); + + repo = INDEX_OWNER(index); + + if (!repo) { + return create_index_error(-1, + "cannot run update; the index is not backed up by a repository."); + } + + /* + * We do the matching ourselves instead of passing the list to + * diff because we want to tell the callback which one + * matched, which we do not know if we ask diff to filter for us. + */ + if ((error = git_pathspec__init(&ps, paths)) < 0) + return error; + + opts.flags = GIT_DIFF_INCLUDE_TYPECHANGE; + if (action == INDEX_ACTION_ADDALL) { + opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED | + GIT_DIFF_RECURSE_UNTRACKED_DIRS; + + if (flags == GIT_INDEX_ADD_FORCE) + opts.flags |= GIT_DIFF_INCLUDE_IGNORED | + GIT_DIFF_RECURSE_IGNORED_DIRS; + } + + if ((error = git_diff_index_to_workdir(&diff, repo, index, &opts)) < 0) + goto cleanup; + + data.pathspec = &ps; + error = git_diff_foreach(diff, apply_each_file, NULL, NULL, NULL, &data); + git_diff_free(diff); + + if (error) /* make sure error is set if callback stopped iteration */ + git_error_set_after_callback(error); + +cleanup: + git_pathspec__clear(&ps); + return error; +} + +static int index_apply_to_all( + git_index *index, + int action, + const git_strarray *paths, + git_index_matched_path_cb cb, + void *payload) +{ + int error = 0; + size_t i; + git_pathspec ps; + const char *match; + git_str path = GIT_STR_INIT; + + GIT_ASSERT_ARG(index); + + if ((error = git_pathspec__init(&ps, paths)) < 0) + return error; + + git_vector_sort(&index->entries); + + for (i = 0; !error && i < index->entries.length; ++i) { + git_index_entry *entry = git_vector_get(&index->entries, i); + + /* check if path actually matches */ + if (!git_pathspec__match( + &ps.pathspec, entry->path, false, (bool)index->ignore_case, + &match, NULL)) + continue; + + /* issue notification callback if requested */ + if (cb && (error = cb(entry->path, match, payload)) != 0) { + if (error > 0) { /* return > 0 means skip this one */ + error = 0; + continue; + } + if (error < 0) /* return < 0 means abort */ + break; + } + + /* index manipulation may alter entry, so don't depend on it */ + if ((error = git_str_sets(&path, entry->path)) < 0) + break; + + switch (action) { + case INDEX_ACTION_NONE: + break; + case INDEX_ACTION_UPDATE: + error = git_index_add_bypath(index, path.ptr); + + if (error == GIT_ENOTFOUND) { + git_error_clear(); + + error = git_index_remove_bypath(index, path.ptr); + + if (!error) /* back up foreach if we removed this */ + i--; + } + break; + case INDEX_ACTION_REMOVE: + if (!(error = git_index_remove_bypath(index, path.ptr))) + i--; /* back up foreach if we removed this */ + break; + default: + git_error_set(GIT_ERROR_INVALID, "unknown index action %d", action); + error = -1; + break; + } + } + + git_str_dispose(&path); + git_pathspec__clear(&ps); + + return error; +} + +int git_index_remove_all( + git_index *index, + const git_strarray *pathspec, + git_index_matched_path_cb cb, + void *payload) +{ + int error = index_apply_to_all( + index, INDEX_ACTION_REMOVE, pathspec, cb, payload); + + if (error) /* make sure error is set if callback stopped iteration */ + git_error_set_after_callback(error); + + return error; +} + +int git_index_update_all( + git_index *index, + const git_strarray *pathspec, + git_index_matched_path_cb cb, + void *payload) +{ + int error = index_apply_to_wd_diff(index, INDEX_ACTION_UPDATE, pathspec, 0, cb, payload); + if (error) /* make sure error is set if callback stopped iteration */ + git_error_set_after_callback(error); + + return error; +} + +int git_index_snapshot_new(git_vector *snap, git_index *index) +{ + int error; + + GIT_REFCOUNT_INC(index); + + git_atomic32_inc(&index->readers); + git_vector_sort(&index->entries); + + error = git_vector_dup(snap, &index->entries, index->entries._cmp); + + if (error < 0) + git_index_snapshot_release(snap, index); + + return error; +} + +void git_index_snapshot_release(git_vector *snap, git_index *index) +{ + git_vector_free(snap); + + git_atomic32_dec(&index->readers); + + git_index_free(index); +} + +int git_index_snapshot_find( + size_t *out, git_vector *entries, git_vector_cmp entry_srch, + const char *path, size_t path_len, int stage) +{ + return index_find_in_entries(out, entries, entry_srch, path, path_len, stage); +} + +int git_indexwriter_init( + git_indexwriter *writer, + git_index *index) +{ + int filebuf_hash, error; + + GIT_REFCOUNT_INC(index); + + writer->index = index; + + filebuf_hash = git_filebuf_hash_flags(git_oid_algorithm(index->oid_type)); + GIT_ASSERT(filebuf_hash); + + if (!index->index_file_path) + return create_index_error(-1, + "failed to write index: The index is in-memory only"); + + if ((error = git_filebuf_open(&writer->file, + index->index_file_path, + git_filebuf_hash_flags(filebuf_hash), + GIT_INDEX_FILE_MODE)) < 0) { + if (error == GIT_ELOCKED) + git_error_set(GIT_ERROR_INDEX, "the index is locked; this might be due to a concurrent or crashed process"); + + return error; + } + + writer->should_write = 1; + + return 0; +} + +int git_indexwriter_init_for_operation( + git_indexwriter *writer, + git_repository *repo, + unsigned int *checkout_strategy) +{ + git_index *index; + int error; + + if ((error = git_repository_index__weakptr(&index, repo)) < 0 || + (error = git_indexwriter_init(writer, index)) < 0) + return error; + + writer->should_write = (*checkout_strategy & GIT_CHECKOUT_DONT_WRITE_INDEX) == 0; + *checkout_strategy |= GIT_CHECKOUT_DONT_WRITE_INDEX; + + return 0; +} + +int git_indexwriter_commit(git_indexwriter *writer) +{ + unsigned char checksum[GIT_HASH_MAX_SIZE]; + size_t checksum_size; + int error; + + if (!writer->should_write) + return 0; + + git_vector_sort(&writer->index->entries); + git_vector_sort(&writer->index->reuc); + + if ((error = write_index(checksum, &checksum_size, writer->index, &writer->file)) < 0) { + git_indexwriter_cleanup(writer); + return error; + } + + if ((error = git_filebuf_commit(&writer->file)) < 0) + return error; + + if ((error = git_futils_filestamp_check( + &writer->index->stamp, writer->index->index_file_path)) < 0) { + git_error_set(GIT_ERROR_OS, "could not read index timestamp"); + return -1; + } + + writer->index->dirty = 0; + writer->index->on_disk = 1; + memcpy(writer->index->checksum, checksum, checksum_size); + + git_index_free(writer->index); + writer->index = NULL; + + return 0; +} + +void git_indexwriter_cleanup(git_indexwriter *writer) +{ + git_filebuf_cleanup(&writer->file); + + git_index_free(writer->index); + writer->index = NULL; +} + +/* Deprecated functions */ + +#ifndef GIT_DEPRECATE_HARD +int git_index_add_frombuffer( + git_index *index, const git_index_entry *source_entry, + const void *buffer, size_t len) +{ + return git_index_add_from_buffer(index, source_entry, buffer, len); +} +#endif diff --git a/vendor/libgit2/src/index.h b/vendor/libgit2/src/libgit2/index.h similarity index 95% rename from vendor/libgit2/src/index.h rename to vendor/libgit2/src/libgit2/index.h index 71bb096f..53c29977 100644 --- a/vendor/libgit2/src/index.h +++ b/vendor/libgit2/src/libgit2/index.h @@ -27,7 +27,7 @@ struct git_index { char *index_file_path; git_futils_filestamp stamp; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; + unsigned char checksum[GIT_HASH_MAX_SIZE]; git_vector entries; git_idxmap *entries_map; @@ -35,6 +35,8 @@ struct git_index { git_vector deleted; /* deleted entries if readers > 0 */ git_atomic32 readers; /* number of active iterators */ + git_oid_t oid_type; + unsigned int on_disk:1; unsigned int ignore_case:1; unsigned int distrust_filemode:1; @@ -141,6 +143,17 @@ GIT_INLINE(unsigned char *) git_index__checksum(git_index *index) return index->checksum; } +/* SHA256-aware internal functions */ + +extern int git_index__new( + git_index **index_out, + git_oid_t oid_type); + +extern int git_index__open( + git_index **index_out, + const char *index_path, + git_oid_t oid_type); + /* Copy the current entries vector *and* increment the index refcount. * Call `git_index__release_snapshot` when done. */ diff --git a/vendor/libgit2/src/libgit2/indexer.c b/vendor/libgit2/src/libgit2/indexer.c new file mode 100644 index 00000000..e559a194 --- /dev/null +++ b/vendor/libgit2/src/libgit2/indexer.c @@ -0,0 +1,1483 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "indexer.h" + +#include "git2/indexer.h" +#include "git2/object.h" + +#include "commit.h" +#include "tree.h" +#include "tag.h" +#include "pack.h" +#include "mwindow.h" +#include "posix.h" +#include "pack.h" +#include "filebuf.h" +#include "oid.h" +#include "oidarray.h" +#include "oidmap.h" +#include "zstream.h" +#include "object.h" + +size_t git_indexer__max_objects = UINT32_MAX; + +#define UINT31_MAX (0x7FFFFFFF) + +struct entry { + git_oid oid; + uint32_t crc; + uint32_t offset; + uint64_t offset_long; +}; + +struct git_indexer { + unsigned int parsed_header :1, + pack_committed :1, + have_stream :1, + have_delta :1, + do_fsync :1, + do_verify :1; + git_oid_t oid_type; + struct git_pack_header hdr; + struct git_pack_file *pack; + unsigned int mode; + off64_t off; + off64_t entry_start; + git_object_t entry_type; + git_str entry_data; + git_packfile_stream stream; + size_t nr_objects; + git_vector objects; + git_vector deltas; + unsigned int fanout[256]; + git_hash_ctx hash_ctx; + unsigned char checksum[GIT_HASH_MAX_SIZE]; + char name[(GIT_HASH_MAX_SIZE * 2) + 1]; + git_indexer_progress_cb progress_cb; + void *progress_payload; + char objbuf[8*1024]; + + /* OIDs referenced from pack objects. Used for verification. */ + git_oidmap *expected_oids; + + /* Needed to look up objects which we want to inject to fix a thin pack */ + git_odb *odb; + + /* Fields for calculating the packfile trailer (hash of everything before it) */ + char inbuf[GIT_HASH_MAX_SIZE]; + size_t inbuf_len; + git_hash_ctx trailer; +}; + +struct delta_info { + off64_t delta_off; +}; + +#ifndef GIT_DEPRECATE_HARD +const git_oid *git_indexer_hash(const git_indexer *idx) +{ + return (git_oid *)idx->checksum; +} +#endif + +const char *git_indexer_name(const git_indexer *idx) +{ + return idx->name; +} + +static int parse_header(struct git_pack_header *hdr, struct git_pack_file *pack) +{ + int error; + git_map map; + + if ((error = p_mmap(&map, sizeof(*hdr), GIT_PROT_READ, GIT_MAP_SHARED, pack->mwf.fd, 0)) < 0) + return error; + + memcpy(hdr, map.data, sizeof(*hdr)); + p_munmap(&map); + + /* Verify we recognize this pack file format. */ + if (hdr->hdr_signature != ntohl(PACK_SIGNATURE)) { + git_error_set(GIT_ERROR_INDEXER, "wrong pack signature"); + return -1; + } + + if (!pack_version_ok(hdr->hdr_version)) { + git_error_set(GIT_ERROR_INDEXER, "wrong pack version"); + return -1; + } + + return 0; +} + +static int objects_cmp(const void *a, const void *b) +{ + const struct entry *entrya = a; + const struct entry *entryb = b; + + return git_oid__cmp(&entrya->oid, &entryb->oid); +} + +int git_indexer_options_init(git_indexer_options *opts, unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE( + opts, version, git_indexer_options, GIT_INDEXER_OPTIONS_INIT); + return 0; +} + +#ifndef GIT_DEPRECATE_HARD +int git_indexer_init_options(git_indexer_options *opts, unsigned int version) +{ + return git_indexer_options_init(opts, version); +} +#endif + +GIT_INLINE(git_hash_algorithm_t) indexer_hash_algorithm(git_indexer *idx) +{ + switch (idx->oid_type) { + case GIT_OID_SHA1: + return GIT_HASH_ALGORITHM_SHA1; +#ifdef GIT_EXPERIMENTAL_SHA256 + case GIT_OID_SHA256: + return GIT_HASH_ALGORITHM_SHA256; +#endif + } + + return GIT_HASH_ALGORITHM_NONE; +} + +static int indexer_new( + git_indexer **out, + const char *prefix, + git_oid_t oid_type, + unsigned int mode, + git_odb *odb, + git_indexer_options *in_opts) +{ + git_indexer_options opts = GIT_INDEXER_OPTIONS_INIT; + git_indexer *idx; + git_str path = GIT_STR_INIT, tmp_path = GIT_STR_INIT; + static const char suff[] = "/pack"; + git_hash_algorithm_t checksum_type; + int error, fd = -1; + + if (in_opts) + memcpy(&opts, in_opts, sizeof(opts)); + + idx = git__calloc(1, sizeof(git_indexer)); + GIT_ERROR_CHECK_ALLOC(idx); + idx->oid_type = oid_type; + idx->odb = odb; + idx->progress_cb = opts.progress_cb; + idx->progress_payload = opts.progress_cb_payload; + idx->mode = mode ? mode : GIT_PACK_FILE_MODE; + git_str_init(&idx->entry_data, 0); + + checksum_type = indexer_hash_algorithm(idx); + + if ((error = git_hash_ctx_init(&idx->hash_ctx, checksum_type)) < 0 || + (error = git_hash_ctx_init(&idx->trailer, checksum_type)) < 0 || + (error = git_oidmap_new(&idx->expected_oids)) < 0) + goto cleanup; + + idx->do_verify = opts.verify; + + if (git_repository__fsync_gitdir) + idx->do_fsync = 1; + + error = git_str_joinpath(&path, prefix, suff); + if (error < 0) + goto cleanup; + + fd = git_futils_mktmp(&tmp_path, git_str_cstr(&path), idx->mode); + git_str_dispose(&path); + if (fd < 0) + goto cleanup; + + error = git_packfile_alloc(&idx->pack, git_str_cstr(&tmp_path), oid_type); + git_str_dispose(&tmp_path); + + if (error < 0) + goto cleanup; + + idx->pack->mwf.fd = fd; + if ((error = git_mwindow_file_register(&idx->pack->mwf)) < 0) + goto cleanup; + + *out = idx; + return 0; + +cleanup: + if (fd != -1) + p_close(fd); + + if (git_str_len(&tmp_path) > 0) + p_unlink(git_str_cstr(&tmp_path)); + + if (idx->pack != NULL) + p_unlink(idx->pack->pack_name); + + git_str_dispose(&path); + git_str_dispose(&tmp_path); + git__free(idx); + return -1; +} + +#ifdef GIT_EXPERIMENTAL_SHA256 +int git_indexer_new( + git_indexer **out, + const char *prefix, + git_oid_t oid_type, + git_indexer_options *opts) +{ + return indexer_new( + out, + prefix, + oid_type, + opts ? opts->mode : 0, + opts ? opts->odb : NULL, + opts); +} +#else +int git_indexer_new( + git_indexer **out, + const char *prefix, + unsigned int mode, + git_odb *odb, + git_indexer_options *opts) +{ + return indexer_new(out, prefix, GIT_OID_SHA1, mode, odb, opts); +} +#endif + +void git_indexer__set_fsync(git_indexer *idx, int do_fsync) +{ + idx->do_fsync = !!do_fsync; +} + +/* Try to store the delta so we can try to resolve it later */ +static int store_delta(git_indexer *idx) +{ + struct delta_info *delta; + + delta = git__calloc(1, sizeof(struct delta_info)); + GIT_ERROR_CHECK_ALLOC(delta); + delta->delta_off = idx->entry_start; + + if (git_vector_insert(&idx->deltas, delta) < 0) + return -1; + + return 0; +} + +static int hash_header(git_hash_ctx *ctx, off64_t len, git_object_t type) +{ + char buffer[64]; + size_t hdrlen; + int error; + + if ((error = git_odb__format_object_header(&hdrlen, + buffer, sizeof(buffer), (size_t)len, type)) < 0) + return error; + + return git_hash_update(ctx, buffer, hdrlen); +} + +static int hash_object_stream(git_indexer*idx, git_packfile_stream *stream) +{ + ssize_t read; + + GIT_ASSERT_ARG(idx); + GIT_ASSERT_ARG(stream); + + do { + if ((read = git_packfile_stream_read(stream, idx->objbuf, sizeof(idx->objbuf))) < 0) + break; + + if (idx->do_verify) + git_str_put(&idx->entry_data, idx->objbuf, read); + + git_hash_update(&idx->hash_ctx, idx->objbuf, read); + } while (read > 0); + + if (read < 0) + return (int)read; + + return 0; +} + +/* In order to create the packfile stream, we need to skip over the delta base description */ +static int advance_delta_offset(git_indexer *idx, git_object_t type) +{ + git_mwindow *w = NULL; + + GIT_ASSERT_ARG(type == GIT_OBJECT_REF_DELTA || type == GIT_OBJECT_OFS_DELTA); + + if (type == GIT_OBJECT_REF_DELTA) { + idx->off += git_oid_size(idx->oid_type); + } else { + off64_t base_off; + int error = get_delta_base(&base_off, idx->pack, &w, &idx->off, type, idx->entry_start); + git_mwindow_close(&w); + if (error < 0) + return error; + } + + return 0; +} + +/* Read from the stream and discard any output */ +static int read_object_stream(git_indexer *idx, git_packfile_stream *stream) +{ + ssize_t read; + + GIT_ASSERT_ARG(stream); + + do { + read = git_packfile_stream_read(stream, idx->objbuf, sizeof(idx->objbuf)); + } while (read > 0); + + if (read < 0) + return (int)read; + + return 0; +} + +static int crc_object(uint32_t *crc_out, git_mwindow_file *mwf, off64_t start, off64_t size) +{ + void *ptr; + uint32_t crc; + unsigned int left, len; + git_mwindow *w = NULL; + + crc = crc32(0L, Z_NULL, 0); + while (size) { + ptr = git_mwindow_open(mwf, &w, start, (size_t)size, &left); + if (ptr == NULL) + return -1; + + len = min(left, (unsigned int)size); + crc = crc32(crc, ptr, len); + size -= len; + start += len; + git_mwindow_close(&w); + } + + *crc_out = htonl(crc); + return 0; +} + +static int add_expected_oid(git_indexer *idx, const git_oid *oid) +{ + /* + * If we know about that object because it is stored in our ODB or + * because we have already processed it as part of our pack file, we do + * not have to expect it. + */ + if ((!idx->odb || !git_odb_exists(idx->odb, oid)) && + !git_oidmap_exists(idx->pack->idx_cache, oid) && + !git_oidmap_exists(idx->expected_oids, oid)) { + git_oid *dup = git__malloc(sizeof(*oid)); + GIT_ERROR_CHECK_ALLOC(dup); + git_oid_cpy(dup, oid); + return git_oidmap_set(idx->expected_oids, dup, dup); + } + + return 0; +} + +static int check_object_connectivity(git_indexer *idx, const git_rawobj *obj) +{ + git_object *object; + git_oid *expected; + int error = 0; + + if (obj->type != GIT_OBJECT_BLOB && + obj->type != GIT_OBJECT_TREE && + obj->type != GIT_OBJECT_COMMIT && + obj->type != GIT_OBJECT_TAG) + return 0; + + if (git_object__from_raw(&object, obj->data, obj->len, obj->type, idx->oid_type) < 0) { + /* + * parse_raw returns EINVALID on invalid data; downgrade + * that to a normal -1 error code. + */ + error = -1; + goto out; + } + + if ((expected = git_oidmap_get(idx->expected_oids, &object->cached.oid)) != NULL) { + git_oidmap_delete(idx->expected_oids, &object->cached.oid); + git__free(expected); + } + + /* + * Check whether this is a known object. If so, we can just continue as + * we assume that the ODB has a complete graph. + */ + if (idx->odb && git_odb_exists(idx->odb, &object->cached.oid)) + return 0; + + switch (obj->type) { + case GIT_OBJECT_TREE: + { + git_tree *tree = (git_tree *) object; + git_tree_entry *entry; + size_t i; + + git_array_foreach(tree->entries, i, entry) + if (add_expected_oid(idx, &entry->oid) < 0) + goto out; + + break; + } + case GIT_OBJECT_COMMIT: + { + git_commit *commit = (git_commit *) object; + git_oid *parent_oid; + size_t i; + + git_array_foreach(commit->parent_ids, i, parent_oid) + if (add_expected_oid(idx, parent_oid) < 0) + goto out; + + if (add_expected_oid(idx, &commit->tree_id) < 0) + goto out; + + break; + } + case GIT_OBJECT_TAG: + { + git_tag *tag = (git_tag *) object; + + if (add_expected_oid(idx, &tag->target) < 0) + goto out; + + break; + } + case GIT_OBJECT_BLOB: + default: + break; + } + +out: + git_object_free(object); + + return error; +} + +static int store_object(git_indexer *idx) +{ + int i, error; + git_oid oid; + struct entry *entry; + off64_t entry_size; + struct git_pack_entry *pentry; + off64_t entry_start = idx->entry_start; + + entry = git__calloc(1, sizeof(*entry)); + GIT_ERROR_CHECK_ALLOC(entry); + + pentry = git__calloc(1, sizeof(struct git_pack_entry)); + GIT_ERROR_CHECK_ALLOC(pentry); + + if (git_hash_final(oid.id, &idx->hash_ctx)) { + git__free(pentry); + goto on_error; + } + +#ifdef GIT_EXPERIMENTAL_SHA256 + oid.type = idx->oid_type; +#endif + + entry_size = idx->off - entry_start; + if (entry_start > UINT31_MAX) { + entry->offset = UINT32_MAX; + entry->offset_long = entry_start; + } else { + entry->offset = (uint32_t)entry_start; + } + + if (idx->do_verify) { + git_rawobj rawobj = { + idx->entry_data.ptr, + idx->entry_data.size, + idx->entry_type + }; + + if ((error = check_object_connectivity(idx, &rawobj)) < 0) + goto on_error; + } + + git_oid_cpy(&pentry->id, &oid); + pentry->offset = entry_start; + + if (git_oidmap_exists(idx->pack->idx_cache, &pentry->id)) { + const char *idstr = git_oid_tostr_s(&pentry->id); + + if (!idstr) + git_error_set(GIT_ERROR_INDEXER, "failed to parse object id"); + else + git_error_set(GIT_ERROR_INDEXER, "duplicate object %s found in pack", idstr); + + git__free(pentry); + goto on_error; + } + + if ((error = git_oidmap_set(idx->pack->idx_cache, &pentry->id, pentry)) < 0) { + git__free(pentry); + git_error_set_oom(); + goto on_error; + } + + git_oid_cpy(&entry->oid, &oid); + + if (crc_object(&entry->crc, &idx->pack->mwf, entry_start, entry_size) < 0) + goto on_error; + + /* Add the object to the list */ + if (git_vector_insert(&idx->objects, entry) < 0) + goto on_error; + + for (i = oid.id[0]; i < 256; ++i) { + idx->fanout[i]++; + } + + return 0; + +on_error: + git__free(entry); + + return -1; +} + +GIT_INLINE(bool) has_entry(git_indexer *idx, git_oid *id) +{ + return git_oidmap_exists(idx->pack->idx_cache, id); +} + +static int save_entry(git_indexer *idx, struct entry *entry, struct git_pack_entry *pentry, off64_t entry_start) +{ + int i; + + if (entry_start > UINT31_MAX) { + entry->offset = UINT32_MAX; + entry->offset_long = entry_start; + } else { + entry->offset = (uint32_t)entry_start; + } + + pentry->offset = entry_start; + + if (git_oidmap_exists(idx->pack->idx_cache, &pentry->id) || + git_oidmap_set(idx->pack->idx_cache, &pentry->id, pentry) < 0) { + git_error_set(GIT_ERROR_INDEXER, "cannot insert object into pack"); + return -1; + } + + /* Add the object to the list */ + if (git_vector_insert(&idx->objects, entry) < 0) + return -1; + + for (i = entry->oid.id[0]; i < 256; ++i) { + idx->fanout[i]++; + } + + return 0; +} + +static int hash_and_save(git_indexer *idx, git_rawobj *obj, off64_t entry_start) +{ + git_oid oid; + size_t entry_size; + struct entry *entry; + struct git_pack_entry *pentry = NULL; + + entry = git__calloc(1, sizeof(*entry)); + GIT_ERROR_CHECK_ALLOC(entry); + + if (git_odb__hashobj(&oid, obj, idx->oid_type) < 0) { + git_error_set(GIT_ERROR_INDEXER, "failed to hash object"); + goto on_error; + } + + pentry = git__calloc(1, sizeof(struct git_pack_entry)); + GIT_ERROR_CHECK_ALLOC(pentry); + + git_oid_cpy(&pentry->id, &oid); + git_oid_cpy(&entry->oid, &oid); + entry->crc = crc32(0L, Z_NULL, 0); + + entry_size = (size_t)(idx->off - entry_start); + if (crc_object(&entry->crc, &idx->pack->mwf, entry_start, entry_size) < 0) + goto on_error; + + return save_entry(idx, entry, pentry, entry_start); + +on_error: + git__free(pentry); + git__free(entry); + git__free(obj->data); + return -1; +} + +static int do_progress_callback(git_indexer *idx, git_indexer_progress *stats) +{ + if (idx->progress_cb) + return git_error_set_after_callback_function( + idx->progress_cb(stats, idx->progress_payload), + "indexer progress"); + return 0; +} + +/* Hash everything but the checksum trailer */ +static void hash_partially(git_indexer *idx, const uint8_t *data, size_t size) +{ + size_t to_expell, to_keep; + size_t oid_size = git_oid_size(idx->oid_type); + + if (size == 0) + return; + + /* + * Easy case, dump the buffer and the data minus the trailing + * checksum (SHA1 or SHA256). + */ + if (size >= oid_size) { + git_hash_update(&idx->trailer, idx->inbuf, idx->inbuf_len); + git_hash_update(&idx->trailer, data, size - oid_size); + + data += size - oid_size; + memcpy(idx->inbuf, data, oid_size); + idx->inbuf_len = oid_size; + return; + } + + /* We can just append */ + if (idx->inbuf_len + size <= oid_size) { + memcpy(idx->inbuf + idx->inbuf_len, data, size); + idx->inbuf_len += size; + return; + } + + /* We need to partially drain the buffer and then append */ + to_keep = oid_size - size; + to_expell = idx->inbuf_len - to_keep; + + git_hash_update(&idx->trailer, idx->inbuf, to_expell); + + memmove(idx->inbuf, idx->inbuf + to_expell, to_keep); + memcpy(idx->inbuf + to_keep, data, size); + idx->inbuf_len += size - to_expell; +} + +#if defined(NO_MMAP) || !defined(GIT_WIN32) + +static int write_at(git_indexer *idx, const void *data, off64_t offset, size_t size) +{ + size_t remaining_size = size; + const char *ptr = (const char *)data; + + /* Handle data size larger that ssize_t */ + while (remaining_size > 0) { + ssize_t nb; + HANDLE_EINTR(nb, p_pwrite(idx->pack->mwf.fd, (void *)ptr, + remaining_size, offset)); + if (nb <= 0) + return -1; + + ptr += nb; + offset += nb; + remaining_size -= nb; + } + + return 0; +} + +static int append_to_pack(git_indexer *idx, const void *data, size_t size) +{ + if (write_at(idx, data, idx->pack->mwf.size, size) < 0) { + git_error_set(GIT_ERROR_OS, "cannot extend packfile '%s'", idx->pack->pack_name); + return -1; + } + + return 0; +} + +#else + +/* + * Windows may keep different views to a networked file for the mmap- and + * open-accessed versions of a file, so any writes done through + * `write(2)`/`pwrite(2)` may not be reflected on the data that `mmap(2)` is + * able to read. + */ + +static int write_at(git_indexer *idx, const void *data, off64_t offset, size_t size) +{ + git_file fd = idx->pack->mwf.fd; + size_t mmap_alignment; + size_t page_offset; + off64_t page_start; + unsigned char *map_data; + git_map map; + int error; + + GIT_ASSERT_ARG(data); + GIT_ASSERT_ARG(size); + + if ((error = git__mmap_alignment(&mmap_alignment)) < 0) + return error; + + /* the offset needs to be at the mmap boundary for the platform */ + page_offset = offset % mmap_alignment; + page_start = offset - page_offset; + + if ((error = p_mmap(&map, page_offset + size, GIT_PROT_WRITE, GIT_MAP_SHARED, fd, page_start)) < 0) + return error; + + map_data = (unsigned char *)map.data; + memcpy(map_data + page_offset, data, size); + p_munmap(&map); + + return 0; +} + +static int append_to_pack(git_indexer *idx, const void *data, size_t size) +{ + off64_t new_size; + size_t mmap_alignment; + size_t page_offset; + off64_t page_start; + off64_t current_size = idx->pack->mwf.size; + int error; + + if (!size) + return 0; + + if ((error = git__mmap_alignment(&mmap_alignment)) < 0) + return error; + + /* Write a single byte to force the file system to allocate space now or + * report an error, since we can't report errors when writing using mmap. + * Round the size up to the nearest page so that we only need to perform file + * I/O when we add a page, instead of whenever we write even a single byte. */ + new_size = current_size + size; + page_offset = new_size % mmap_alignment; + page_start = new_size - page_offset; + + if (p_pwrite(idx->pack->mwf.fd, data, 1, page_start + mmap_alignment - 1) < 0) { + git_error_set(GIT_ERROR_OS, "cannot extend packfile '%s'", idx->pack->pack_name); + return -1; + } + + return write_at(idx, data, idx->pack->mwf.size, size); +} + +#endif + +static int read_stream_object(git_indexer *idx, git_indexer_progress *stats) +{ + git_packfile_stream *stream = &idx->stream; + off64_t entry_start = idx->off; + size_t oid_size, entry_size; + git_object_t type; + git_mwindow *w = NULL; + int error; + + oid_size = git_oid_size(idx->oid_type); + + if (idx->pack->mwf.size <= idx->off + (long long)oid_size) + return GIT_EBUFS; + + if (!idx->have_stream) { + error = git_packfile_unpack_header(&entry_size, &type, idx->pack, &w, &idx->off); + if (error == GIT_EBUFS) { + idx->off = entry_start; + return error; + } + if (error < 0) + return error; + + git_mwindow_close(&w); + idx->entry_start = entry_start; + git_hash_init(&idx->hash_ctx); + git_str_clear(&idx->entry_data); + + if (type == GIT_OBJECT_REF_DELTA || type == GIT_OBJECT_OFS_DELTA) { + error = advance_delta_offset(idx, type); + if (error == GIT_EBUFS) { + idx->off = entry_start; + return error; + } + if (error < 0) + return error; + + idx->have_delta = 1; + } else { + idx->have_delta = 0; + + error = hash_header(&idx->hash_ctx, entry_size, type); + if (error < 0) + return error; + } + + idx->have_stream = 1; + idx->entry_type = type; + + error = git_packfile_stream_open(stream, idx->pack, idx->off); + if (error < 0) + return error; + } + + if (idx->have_delta) { + error = read_object_stream(idx, stream); + } else { + error = hash_object_stream(idx, stream); + } + + idx->off = stream->curpos; + if (error == GIT_EBUFS) + return error; + + /* We want to free the stream reasorces no matter what here */ + idx->have_stream = 0; + git_packfile_stream_dispose(stream); + + if (error < 0) + return error; + + if (idx->have_delta) { + error = store_delta(idx); + } else { + error = store_object(idx); + } + + if (error < 0) + return error; + + if (!idx->have_delta) { + stats->indexed_objects++; + } + stats->received_objects++; + + if ((error = do_progress_callback(idx, stats)) != 0) + return error; + + return 0; +} + +int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_indexer_progress *stats) +{ + int error = -1; + struct git_pack_header *hdr = &idx->hdr; + git_mwindow_file *mwf = &idx->pack->mwf; + + GIT_ASSERT_ARG(idx); + GIT_ASSERT_ARG(data); + GIT_ASSERT_ARG(stats); + + if ((error = append_to_pack(idx, data, size)) < 0) + return error; + + hash_partially(idx, data, (int)size); + + /* Make sure we set the new size of the pack */ + idx->pack->mwf.size += size; + + if (!idx->parsed_header) { + unsigned int total_objects; + + if ((unsigned)idx->pack->mwf.size < sizeof(struct git_pack_header)) + return 0; + + if ((error = parse_header(&idx->hdr, idx->pack)) < 0) + return error; + + idx->parsed_header = 1; + idx->nr_objects = ntohl(hdr->hdr_entries); + idx->off = sizeof(struct git_pack_header); + + if (idx->nr_objects <= git_indexer__max_objects) { + total_objects = (unsigned int)idx->nr_objects; + } else { + git_error_set(GIT_ERROR_INDEXER, "too many objects"); + return -1; + } + + if (git_oidmap_new(&idx->pack->idx_cache) < 0) + return -1; + + idx->pack->has_cache = 1; + if (git_vector_init(&idx->objects, total_objects, objects_cmp) < 0) + return -1; + + if (git_vector_init(&idx->deltas, total_objects / 2, NULL) < 0) + return -1; + + stats->received_objects = 0; + stats->local_objects = 0; + stats->total_deltas = 0; + stats->indexed_deltas = 0; + stats->indexed_objects = 0; + stats->total_objects = total_objects; + + if ((error = do_progress_callback(idx, stats)) != 0) + return error; + } + + /* Now that we have data in the pack, let's try to parse it */ + + /* As the file grows any windows we try to use will be out of date */ + if ((error = git_mwindow_free_all(mwf)) < 0) + goto on_error; + + while (stats->indexed_objects < idx->nr_objects) { + if ((error = read_stream_object(idx, stats)) != 0) { + if (error == GIT_EBUFS) + break; + else + goto on_error; + } + } + + return 0; + +on_error: + git_mwindow_free_all(mwf); + return error; +} + +static int index_path(git_str *path, git_indexer *idx, const char *suffix) +{ + const char prefix[] = "pack-"; + size_t slash = (size_t)path->size; + + /* search backwards for '/' */ + while (slash > 0 && path->ptr[slash - 1] != '/') + slash--; + + if (git_str_grow(path, slash + 1 + strlen(prefix) + + git_oid_hexsize(idx->oid_type) + strlen(suffix) + 1) < 0) + return -1; + + git_str_truncate(path, slash); + git_str_puts(path, prefix); + git_str_puts(path, idx->name); + git_str_puts(path, suffix); + + return git_str_oom(path) ? -1 : 0; +} + +/** + * Rewind the packfile by the trailer, as we might need to fix the + * packfile by injecting objects at the tail and must overwrite it. + */ +static int seek_back_trailer(git_indexer *idx) +{ + idx->pack->mwf.size -= git_oid_size(idx->oid_type); + return git_mwindow_free_all(&idx->pack->mwf); +} + +static int inject_object(git_indexer *idx, git_oid *id) +{ + git_odb_object *obj = NULL; + struct entry *entry = NULL; + struct git_pack_entry *pentry = NULL; + unsigned char empty_checksum[GIT_HASH_MAX_SIZE] = {0}; + unsigned char hdr[64]; + git_str buf = GIT_STR_INIT; + off64_t entry_start; + const void *data; + size_t len, hdr_len; + size_t checksum_size; + int error; + + checksum_size = git_hash_size(indexer_hash_algorithm(idx)); + + if ((error = seek_back_trailer(idx)) < 0) + goto cleanup; + + entry_start = idx->pack->mwf.size; + + if ((error = git_odb_read(&obj, idx->odb, id)) < 0) { + git_error_set(GIT_ERROR_INDEXER, "missing delta bases"); + goto cleanup; + } + + data = git_odb_object_data(obj); + len = git_odb_object_size(obj); + + entry = git__calloc(1, sizeof(*entry)); + GIT_ERROR_CHECK_ALLOC(entry); + + entry->crc = crc32(0L, Z_NULL, 0); + + /* Write out the object header */ + if ((error = git_packfile__object_header(&hdr_len, hdr, len, git_odb_object_type(obj))) < 0 || + (error = append_to_pack(idx, hdr, hdr_len)) < 0) + goto cleanup; + + idx->pack->mwf.size += hdr_len; + entry->crc = crc32(entry->crc, hdr, (uInt)hdr_len); + + if ((error = git_zstream_deflatebuf(&buf, data, len)) < 0) + goto cleanup; + + /* And then the compressed object */ + if ((error = append_to_pack(idx, buf.ptr, buf.size)) < 0) + goto cleanup; + + idx->pack->mwf.size += buf.size; + entry->crc = htonl(crc32(entry->crc, (unsigned char *)buf.ptr, (uInt)buf.size)); + git_str_dispose(&buf); + + /* Write a fake trailer so the pack functions play ball */ + + if ((error = append_to_pack(idx, empty_checksum, checksum_size)) < 0) + goto cleanup; + + idx->pack->mwf.size += git_oid_size(idx->oid_type); + + pentry = git__calloc(1, sizeof(struct git_pack_entry)); + GIT_ERROR_CHECK_ALLOC(pentry); + + git_oid_cpy(&pentry->id, id); + git_oid_cpy(&entry->oid, id); + idx->off = entry_start + hdr_len + len; + + error = save_entry(idx, entry, pentry, entry_start); + +cleanup: + if (error) { + git__free(entry); + git__free(pentry); + } + + git_odb_object_free(obj); + return error; +} + +static int fix_thin_pack(git_indexer *idx, git_indexer_progress *stats) +{ + int error, found_ref_delta = 0; + unsigned int i; + struct delta_info *delta; + size_t size; + git_object_t type; + git_mwindow *w = NULL; + off64_t curpos = 0; + unsigned char *base_info; + unsigned int left = 0; + git_oid base; + + GIT_ASSERT(git_vector_length(&idx->deltas) > 0); + + if (idx->odb == NULL) { + git_error_set(GIT_ERROR_INDEXER, "cannot fix a thin pack without an ODB"); + return -1; + } + + /* Loop until we find the first REF delta */ + git_vector_foreach(&idx->deltas, i, delta) { + if (!delta) + continue; + + curpos = delta->delta_off; + error = git_packfile_unpack_header(&size, &type, idx->pack, &w, &curpos); + if (error < 0) + return error; + + if (type == GIT_OBJECT_REF_DELTA) { + found_ref_delta = 1; + break; + } + } + + if (!found_ref_delta) { + git_error_set(GIT_ERROR_INDEXER, "no REF_DELTA found, cannot inject object"); + return -1; + } + + /* curpos now points to the base information, which is an OID */ + base_info = git_mwindow_open(&idx->pack->mwf, &w, curpos, git_oid_size(idx->oid_type), &left); + if (base_info == NULL) { + git_error_set(GIT_ERROR_INDEXER, "failed to map delta information"); + return -1; + } + + git_oid__fromraw(&base, base_info, idx->oid_type); + git_mwindow_close(&w); + + if (has_entry(idx, &base)) + return 0; + + if (inject_object(idx, &base) < 0) + return -1; + + stats->local_objects++; + + return 0; +} + +static int resolve_deltas(git_indexer *idx, git_indexer_progress *stats) +{ + unsigned int i; + int error; + struct delta_info *delta; + int progressed = 0, non_null = 0, progress_cb_result; + + while (idx->deltas.length > 0) { + progressed = 0; + non_null = 0; + git_vector_foreach(&idx->deltas, i, delta) { + git_rawobj obj = {0}; + + if (!delta) + continue; + + non_null = 1; + idx->off = delta->delta_off; + if ((error = git_packfile_unpack(&obj, idx->pack, &idx->off)) < 0) { + if (error == GIT_PASSTHROUGH) { + /* We have not seen the base object, we'll try again later. */ + continue; + } + return -1; + } + + if (idx->do_verify && check_object_connectivity(idx, &obj) < 0) + /* TODO: error? continue? */ + continue; + + if (hash_and_save(idx, &obj, delta->delta_off) < 0) + continue; + + git__free(obj.data); + stats->indexed_objects++; + stats->indexed_deltas++; + progressed = 1; + if ((progress_cb_result = do_progress_callback(idx, stats)) < 0) + return progress_cb_result; + + /* remove from the list */ + git_vector_set(NULL, &idx->deltas, i, NULL); + git__free(delta); + } + + /* if none were actually set, we're done */ + if (!non_null) + break; + + if (!progressed && (fix_thin_pack(idx, stats) < 0)) { + return -1; + } + } + + return 0; +} + +static int update_header_and_rehash(git_indexer *idx, git_indexer_progress *stats) +{ + void *ptr; + size_t chunk = 1024*1024; + off64_t hashed = 0; + git_mwindow *w = NULL; + git_mwindow_file *mwf; + unsigned int left; + + mwf = &idx->pack->mwf; + + git_hash_init(&idx->trailer); + + + /* Update the header to include the number of local objects we injected */ + idx->hdr.hdr_entries = htonl(stats->total_objects + stats->local_objects); + if (write_at(idx, &idx->hdr, 0, sizeof(struct git_pack_header)) < 0) + return -1; + + /* + * We now use the same technique as before to determine the + * hash. We keep reading up to the end and let + * hash_partially() keep the existing trailer out of the + * calculation. + */ + if (git_mwindow_free_all(mwf) < 0) + return -1; + + idx->inbuf_len = 0; + while (hashed < mwf->size) { + ptr = git_mwindow_open(mwf, &w, hashed, chunk, &left); + if (ptr == NULL) + return -1; + + hash_partially(idx, ptr, left); + hashed += left; + + git_mwindow_close(&w); + } + + return 0; +} + +int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats) +{ + git_mwindow *w = NULL; + unsigned int i, long_offsets = 0, left; + int error; + struct git_pack_idx_header hdr; + git_str filename = GIT_STR_INIT; + struct entry *entry; + unsigned char checksum[GIT_HASH_MAX_SIZE]; + git_filebuf index_file = {0}; + void *packfile_trailer; + size_t checksum_size; + int filebuf_hash; + bool mismatch; + + if (!idx->parsed_header) { + git_error_set(GIT_ERROR_INDEXER, "incomplete pack header"); + return -1; + } + + checksum_size = git_hash_size(indexer_hash_algorithm(idx)); + filebuf_hash = git_filebuf_hash_flags(indexer_hash_algorithm(idx)); + GIT_ASSERT(checksum_size); + + /* Test for this before resolve_deltas(), as it plays with idx->off */ + if (idx->off + (ssize_t)checksum_size < idx->pack->mwf.size) { + git_error_set(GIT_ERROR_INDEXER, "unexpected data at the end of the pack"); + return -1; + } + if (idx->off + (ssize_t)checksum_size > idx->pack->mwf.size) { + git_error_set(GIT_ERROR_INDEXER, "missing trailer at the end of the pack"); + return -1; + } + + packfile_trailer = git_mwindow_open(&idx->pack->mwf, &w, idx->pack->mwf.size - checksum_size, checksum_size, &left); + if (packfile_trailer == NULL) { + git_mwindow_close(&w); + goto on_error; + } + + /* Compare the packfile trailer as it was sent to us and what we calculated */ + git_hash_final(checksum, &idx->trailer); + mismatch = !!memcmp(checksum, packfile_trailer, checksum_size); + git_mwindow_close(&w); + + if (mismatch) { + git_error_set(GIT_ERROR_INDEXER, "packfile trailer mismatch"); + return -1; + } + + /* Freeze the number of deltas */ + stats->total_deltas = stats->total_objects - stats->indexed_objects; + + if ((error = resolve_deltas(idx, stats)) < 0) + return error; + + if (stats->indexed_objects != stats->total_objects) { + git_error_set(GIT_ERROR_INDEXER, "early EOF"); + return -1; + } + + if (stats->local_objects > 0) { + if (update_header_and_rehash(idx, stats) < 0) + return -1; + + git_hash_final(checksum, &idx->trailer); + write_at(idx, checksum, idx->pack->mwf.size - checksum_size, checksum_size); + } + + /* + * Is the resulting graph fully connected or are we still + * missing some objects? In the second case, we can + * bail out due to an incomplete and thus corrupt + * packfile. + */ + if (git_oidmap_size(idx->expected_oids) > 0) { + git_error_set(GIT_ERROR_INDEXER, "packfile is missing %"PRIuZ" objects", + git_oidmap_size(idx->expected_oids)); + return -1; + } + + git_vector_sort(&idx->objects); + + /* Use the trailer hash as the pack file name to ensure + * files with different contents have different names */ + memcpy(idx->checksum, checksum, checksum_size); + if (git_hash_fmt(idx->name, checksum, checksum_size) < 0) + return -1; + + git_str_sets(&filename, idx->pack->pack_name); + git_str_shorten(&filename, strlen("pack")); + git_str_puts(&filename, "idx"); + if (git_str_oom(&filename)) + return -1; + + if (git_filebuf_open(&index_file, filename.ptr, + filebuf_hash | (idx->do_fsync ? GIT_FILEBUF_FSYNC : 0), + idx->mode) < 0) + goto on_error; + + /* Write out the header */ + hdr.idx_signature = htonl(PACK_IDX_SIGNATURE); + hdr.idx_version = htonl(2); + git_filebuf_write(&index_file, &hdr, sizeof(hdr)); + + /* Write out the fanout table */ + for (i = 0; i < 256; ++i) { + uint32_t n = htonl(idx->fanout[i]); + git_filebuf_write(&index_file, &n, sizeof(n)); + } + + /* Write out the object names (SHA-1 hashes) */ + git_vector_foreach(&idx->objects, i, entry) { + git_filebuf_write(&index_file, &entry->oid.id, git_oid_size(idx->oid_type)); + } + + /* Write out the CRC32 values */ + git_vector_foreach(&idx->objects, i, entry) { + git_filebuf_write(&index_file, &entry->crc, sizeof(uint32_t)); + } + + /* Write out the offsets */ + git_vector_foreach(&idx->objects, i, entry) { + uint32_t n; + + if (entry->offset == UINT32_MAX) + n = htonl(0x80000000 | long_offsets++); + else + n = htonl(entry->offset); + + git_filebuf_write(&index_file, &n, sizeof(uint32_t)); + } + + /* Write out the long offsets */ + git_vector_foreach(&idx->objects, i, entry) { + uint32_t split[2]; + + if (entry->offset != UINT32_MAX) + continue; + + split[0] = htonl(entry->offset_long >> 32); + split[1] = htonl(entry->offset_long & 0xffffffff); + + git_filebuf_write(&index_file, &split, sizeof(uint32_t) * 2); + } + + /* Write out the packfile trailer to the index */ + if (git_filebuf_write(&index_file, checksum, checksum_size) < 0) + goto on_error; + + /* Write out the hash of the idx */ + if (git_filebuf_hash(checksum, &index_file) < 0) + goto on_error; + + git_filebuf_write(&index_file, checksum, checksum_size); + + /* Figure out what the final name should be */ + if (index_path(&filename, idx, ".idx") < 0) + goto on_error; + + /* Commit file */ + if (git_filebuf_commit_at(&index_file, filename.ptr) < 0) + goto on_error; + + if (git_mwindow_free_all(&idx->pack->mwf) < 0) + goto on_error; + +#if !defined(NO_MMAP) && defined(GIT_WIN32) + /* + * Some non-Windows remote filesystems fail when truncating files if the + * file permissions change after opening the file (done by p_mkstemp). + * + * Truncation is only needed when mmap is used to undo rounding up to next + * page_size in append_to_pack. + */ + if (p_ftruncate(idx->pack->mwf.fd, idx->pack->mwf.size) < 0) { + git_error_set(GIT_ERROR_OS, "failed to truncate pack file '%s'", idx->pack->pack_name); + return -1; + } +#endif + + if (idx->do_fsync && p_fsync(idx->pack->mwf.fd) < 0) { + git_error_set(GIT_ERROR_OS, "failed to fsync packfile"); + goto on_error; + } + + /* We need to close the descriptor here so Windows doesn't choke on commit_at */ + if (p_close(idx->pack->mwf.fd) < 0) { + git_error_set(GIT_ERROR_OS, "failed to close packfile"); + goto on_error; + } + + idx->pack->mwf.fd = -1; + + if (index_path(&filename, idx, ".pack") < 0) + goto on_error; + + /* And don't forget to rename the packfile to its new place. */ + if (p_rename(idx->pack->pack_name, git_str_cstr(&filename)) < 0) + goto on_error; + + /* And fsync the parent directory if we're asked to. */ + if (idx->do_fsync && + git_futils_fsync_parent(git_str_cstr(&filename)) < 0) + goto on_error; + + idx->pack_committed = 1; + + git_str_dispose(&filename); + return 0; + +on_error: + git_mwindow_free_all(&idx->pack->mwf); + git_filebuf_cleanup(&index_file); + git_str_dispose(&filename); + return -1; +} + +void git_indexer_free(git_indexer *idx) +{ + const git_oid *key; + git_oid *value; + size_t iter; + + if (idx == NULL) + return; + + if (idx->have_stream) + git_packfile_stream_dispose(&idx->stream); + + git_vector_free_deep(&idx->objects); + + if (idx->pack->idx_cache) { + struct git_pack_entry *pentry; + git_oidmap_foreach_value(idx->pack->idx_cache, pentry, { + git__free(pentry); + }); + + git_oidmap_free(idx->pack->idx_cache); + } + + git_vector_free_deep(&idx->deltas); + + git_packfile_free(idx->pack, !idx->pack_committed); + + iter = 0; + while (git_oidmap_iterate((void **) &value, idx->expected_oids, &iter, &key) == 0) + git__free(value); + + git_hash_ctx_cleanup(&idx->trailer); + git_hash_ctx_cleanup(&idx->hash_ctx); + git_str_dispose(&idx->entry_data); + git_oidmap_free(idx->expected_oids); + git__free(idx); +} diff --git a/vendor/libgit2/src/indexer.h b/vendor/libgit2/src/libgit2/indexer.h similarity index 100% rename from vendor/libgit2/src/indexer.h rename to vendor/libgit2/src/libgit2/indexer.h diff --git a/vendor/libgit2/src/libgit2/iterator.c b/vendor/libgit2/src/libgit2/iterator.c new file mode 100644 index 00000000..bef9c609 --- /dev/null +++ b/vendor/libgit2/src/libgit2/iterator.c @@ -0,0 +1,2462 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "iterator.h" + +#include "tree.h" +#include "index.h" +#include "path.h" + +#define GIT_ITERATOR_FIRST_ACCESS (1 << 15) +#define GIT_ITERATOR_HONOR_IGNORES (1 << 16) +#define GIT_ITERATOR_IGNORE_DOT_GIT (1 << 17) + +#define iterator__flag(I,F) ((((git_iterator *)(I))->flags & GIT_ITERATOR_ ## F) != 0) +#define iterator__ignore_case(I) iterator__flag(I,IGNORE_CASE) +#define iterator__include_trees(I) iterator__flag(I,INCLUDE_TREES) +#define iterator__dont_autoexpand(I) iterator__flag(I,DONT_AUTOEXPAND) +#define iterator__do_autoexpand(I) !iterator__flag(I,DONT_AUTOEXPAND) +#define iterator__include_conflicts(I) iterator__flag(I,INCLUDE_CONFLICTS) +#define iterator__has_been_accessed(I) iterator__flag(I,FIRST_ACCESS) +#define iterator__honor_ignores(I) iterator__flag(I,HONOR_IGNORES) +#define iterator__ignore_dot_git(I) iterator__flag(I,IGNORE_DOT_GIT) +#define iterator__descend_symlinks(I) iterator__flag(I,DESCEND_SYMLINKS) + +static void iterator_set_ignore_case(git_iterator *iter, bool ignore_case) +{ + int (*vector_cmp)(const void *a, const void *b); + + if (ignore_case) + iter->flags |= GIT_ITERATOR_IGNORE_CASE; + else + iter->flags &= ~GIT_ITERATOR_IGNORE_CASE; + + iter->strcomp = ignore_case ? git__strcasecmp : git__strcmp; + iter->strncomp = ignore_case ? git__strncasecmp : git__strncmp; + iter->prefixcomp = ignore_case ? git__prefixcmp_icase : git__prefixcmp; + iter->entry_srch = ignore_case ? git_index_entry_isrch : git_index_entry_srch; + + vector_cmp = ignore_case ? git__strcasecmp_cb : git__strcmp_cb; + + git_vector_set_cmp(&iter->pathlist, vector_cmp); +} + +static int iterator_range_init( + git_iterator *iter, const char *start, const char *end) +{ + if (start && *start) { + iter->start = git__strdup(start); + GIT_ERROR_CHECK_ALLOC(iter->start); + + iter->start_len = strlen(iter->start); + } + + if (end && *end) { + iter->end = git__strdup(end); + GIT_ERROR_CHECK_ALLOC(iter->end); + + iter->end_len = strlen(iter->end); + } + + iter->started = (iter->start == NULL); + iter->ended = false; + + return 0; +} + +static void iterator_range_free(git_iterator *iter) +{ + if (iter->start) { + git__free(iter->start); + iter->start = NULL; + iter->start_len = 0; + } + + if (iter->end) { + git__free(iter->end); + iter->end = NULL; + iter->end_len = 0; + } +} + +static int iterator_reset_range( + git_iterator *iter, const char *start, const char *end) +{ + iterator_range_free(iter); + return iterator_range_init(iter, start, end); +} + +static int iterator_pathlist_init(git_iterator *iter, git_strarray *pathlist) +{ + size_t i; + + if (git_vector_init(&iter->pathlist, pathlist->count, NULL) < 0) + return -1; + + for (i = 0; i < pathlist->count; i++) { + if (!pathlist->strings[i]) + continue; + + if (git_vector_insert(&iter->pathlist, pathlist->strings[i]) < 0) + return -1; + } + + return 0; +} + +static int iterator_init_common( + git_iterator *iter, + git_repository *repo, + git_index *index, + git_iterator_options *given_opts) +{ + static git_iterator_options default_opts = GIT_ITERATOR_OPTIONS_INIT; + git_iterator_options *options = given_opts ? given_opts : &default_opts; + bool ignore_case; + int precompose; + int error; + + iter->repo = repo; + iter->index = index; + iter->flags = options->flags; + + if ((iter->flags & GIT_ITERATOR_IGNORE_CASE) != 0) { + ignore_case = true; + } else if ((iter->flags & GIT_ITERATOR_DONT_IGNORE_CASE) != 0) { + ignore_case = false; + } else if (repo) { + git_index *index; + + if ((error = git_repository_index__weakptr(&index, iter->repo)) < 0) + return error; + + ignore_case = !!index->ignore_case; + + if (ignore_case == 1) + iter->flags |= GIT_ITERATOR_IGNORE_CASE; + else + iter->flags |= GIT_ITERATOR_DONT_IGNORE_CASE; + } else { + ignore_case = false; + } + + /* try to look up precompose and set flag if appropriate */ + if (repo && + (iter->flags & GIT_ITERATOR_PRECOMPOSE_UNICODE) == 0 && + (iter->flags & GIT_ITERATOR_DONT_PRECOMPOSE_UNICODE) == 0) { + + if (git_repository__configmap_lookup(&precompose, repo, GIT_CONFIGMAP_PRECOMPOSE) < 0) + git_error_clear(); + else if (precompose) + iter->flags |= GIT_ITERATOR_PRECOMPOSE_UNICODE; + } + + if ((iter->flags & GIT_ITERATOR_DONT_AUTOEXPAND)) + iter->flags |= GIT_ITERATOR_INCLUDE_TREES; + + if ((error = iterator_range_init(iter, options->start, options->end)) < 0 || + (error = iterator_pathlist_init(iter, &options->pathlist)) < 0) + return error; + + iterator_set_ignore_case(iter, ignore_case); + return 0; +} + +static void iterator_clear(git_iterator *iter) +{ + iter->started = false; + iter->ended = false; + iter->stat_calls = 0; + iter->pathlist_walk_idx = 0; + iter->flags &= ~GIT_ITERATOR_FIRST_ACCESS; +} + +GIT_INLINE(bool) iterator_has_started( + git_iterator *iter, const char *path, bool is_submodule) +{ + size_t path_len; + + if (iter->start == NULL || iter->started == true) + return true; + + /* the starting path is generally a prefix - we have started once we + * are prefixed by this path + */ + iter->started = (iter->prefixcomp(path, iter->start) >= 0); + + if (iter->started) + return true; + + path_len = strlen(path); + + /* if, however, we are a submodule, then we support `start` being + * suffixed with a `/` for crazy legacy reasons. match `submod` + * with a start path of `submod/`. + */ + if (is_submodule && iter->start_len && path_len == iter->start_len - 1 && + iter->start[iter->start_len-1] == '/') + return true; + + /* if, however, our current path is a directory, and our starting path + * is _beneath_ that directory, then recurse into the directory (even + * though we have not yet "started") + */ + if (path_len > 0 && path[path_len-1] == '/' && + iter->strncomp(path, iter->start, path_len) == 0) + return true; + + return false; +} + +GIT_INLINE(bool) iterator_has_ended(git_iterator *iter, const char *path) +{ + if (iter->end == NULL) + return false; + else if (iter->ended) + return true; + + iter->ended = (iter->prefixcomp(path, iter->end) > 0); + return iter->ended; +} + +/* walker for the index and tree iterator that allows it to walk the sorted + * pathlist entries alongside sorted iterator entries. + */ +static bool iterator_pathlist_next_is(git_iterator *iter, const char *path) +{ + char *p; + size_t path_len, p_len, cmp_len, i; + int cmp; + + if (iter->pathlist.length == 0) + return true; + + git_vector_sort(&iter->pathlist); + + path_len = strlen(path); + + /* for comparison, drop the trailing slash on the current '/' */ + if (path_len && path[path_len-1] == '/') + path_len--; + + for (i = iter->pathlist_walk_idx; i < iter->pathlist.length; i++) { + p = iter->pathlist.contents[i]; + p_len = strlen(p); + + if (p_len && p[p_len-1] == '/') + p_len--; + + cmp_len = min(path_len, p_len); + + /* see if the pathlist entry is a prefix of this path */ + cmp = iter->strncomp(p, path, cmp_len); + + /* prefix match - see if there's an exact match, or if we were + * given a path that matches the directory + */ + if (cmp == 0) { + /* if this pathlist entry is not suffixed with a '/' then + * it matches a path that is a file or a directory. + * (eg, pathlist = "foo" and path is "foo" or "foo/" or + * "foo/something") + */ + if (p[cmp_len] == '\0' && + (path[cmp_len] == '\0' || path[cmp_len] == '/')) + return true; + + /* if this pathlist entry _is_ suffixed with a '/' then + * it matches only paths that are directories. + * (eg, pathlist = "foo/" and path is "foo/" or "foo/something") + */ + if (p[cmp_len] == '/' && path[cmp_len] == '/') + return true; + } + + /* this pathlist entry sorts before the given path, try the next */ + else if (cmp < 0) { + iter->pathlist_walk_idx++; + continue; + } + + /* this pathlist sorts after the given path, no match. */ + else if (cmp > 0) { + break; + } + } + + return false; +} + +typedef enum { + ITERATOR_PATHLIST_NONE = 0, + ITERATOR_PATHLIST_IS_FILE = 1, + ITERATOR_PATHLIST_IS_DIR = 2, + ITERATOR_PATHLIST_IS_PARENT = 3, + ITERATOR_PATHLIST_FULL = 4 +} iterator_pathlist_search_t; + +static iterator_pathlist_search_t iterator_pathlist_search( + git_iterator *iter, const char *path, size_t path_len) +{ + int (*vector_cmp)(const void *a, const void *b); + const char *p; + size_t idx; + int error; + + if (iter->pathlist.length == 0) + return ITERATOR_PATHLIST_FULL; + + git_vector_sort(&iter->pathlist); + + vector_cmp = (iter->flags & GIT_ITERATOR_IGNORE_CASE) != 0 ? + git__strcasecmp_cb : git__strcmp_cb; + + error = git_vector_bsearch2(&idx, &iter->pathlist, vector_cmp, path); + + /* the given path was found in the pathlist. since the pathlist only + * matches directories when they're suffixed with a '/', analyze the + * path string to determine whether it's a directory or not. + */ + if (error == 0) { + if (path_len && path[path_len-1] == '/') + return ITERATOR_PATHLIST_IS_DIR; + + return ITERATOR_PATHLIST_IS_FILE; + } + + /* at this point, the path we're examining may be a directory (though we + * don't know that yet, since we're avoiding a stat unless it's necessary) + * so walk the pathlist looking for the given path with a '/' after it, + */ + while ((p = git_vector_get(&iter->pathlist, idx)) != NULL) { + if (iter->prefixcomp(p, path) != 0) + break; + + /* an exact match would have been matched by the bsearch above */ + GIT_ASSERT_WITH_RETVAL(p[path_len], ITERATOR_PATHLIST_NONE); + + /* is this a literal directory entry (eg `foo/`) or a file beneath */ + if (p[path_len] == '/') { + return (p[path_len+1] == '\0') ? + ITERATOR_PATHLIST_IS_DIR : + ITERATOR_PATHLIST_IS_PARENT; + } + + if (p[path_len] > '/') + break; + + idx++; + } + + return ITERATOR_PATHLIST_NONE; +} + +/* Empty iterator */ + +static int empty_iterator_noop(const git_index_entry **e, git_iterator *i) +{ + GIT_UNUSED(i); + + if (e) + *e = NULL; + + return GIT_ITEROVER; +} + +static int empty_iterator_advance_over( + const git_index_entry **e, + git_iterator_status_t *s, + git_iterator *i) +{ + *s = GIT_ITERATOR_STATUS_EMPTY; + return empty_iterator_noop(e, i); +} + +static int empty_iterator_reset(git_iterator *i) +{ + GIT_UNUSED(i); + return 0; +} + +static void empty_iterator_free(git_iterator *i) +{ + GIT_UNUSED(i); +} + +typedef struct { + git_iterator base; + git_iterator_callbacks cb; +} empty_iterator; + +int git_iterator_for_nothing( + git_iterator **out, + git_iterator_options *options) +{ + empty_iterator *iter; + + static git_iterator_callbacks callbacks = { + empty_iterator_noop, + empty_iterator_noop, + empty_iterator_noop, + empty_iterator_advance_over, + empty_iterator_reset, + empty_iterator_free + }; + + *out = NULL; + + iter = git__calloc(1, sizeof(empty_iterator)); + GIT_ERROR_CHECK_ALLOC(iter); + + iter->base.type = GIT_ITERATOR_EMPTY; + iter->base.cb = &callbacks; + iter->base.flags = options->flags; + + *out = &iter->base; + return 0; +} + +/* Tree iterator */ + +typedef struct { + git_tree_entry *tree_entry; + const char *parent_path; +} tree_iterator_entry; + +typedef struct { + git_tree *tree; + + /* path to this particular frame (folder) */ + git_str path; + + /* a sorted list of the entries for this frame (folder), these are + * actually pointers to the iterator's entry pool. + */ + git_vector entries; + tree_iterator_entry *current; + + size_t next_idx; + + /* on case insensitive iterations, we also have an array of other + * paths that were case insensitively equal to this one, and their + * tree objects. we have coalesced the tree entries into this frame. + * a child `tree_iterator_entry` will contain a pointer to its actual + * parent path. + */ + git_vector similar_trees; + git_array_t(git_str) similar_paths; +} tree_iterator_frame; + +typedef struct { + git_iterator base; + git_tree *root; + git_array_t(tree_iterator_frame) frames; + + git_index_entry entry; + git_str entry_path; + + /* a pool of entries to reduce the number of allocations */ + git_pool entry_pool; +} tree_iterator; + +GIT_INLINE(tree_iterator_frame *) tree_iterator_parent_frame( + tree_iterator *iter) +{ + return iter->frames.size > 1 ? + &iter->frames.ptr[iter->frames.size-2] : NULL; +} + +GIT_INLINE(tree_iterator_frame *) tree_iterator_current_frame( + tree_iterator *iter) +{ + return iter->frames.size ? &iter->frames.ptr[iter->frames.size-1] : NULL; +} + +GIT_INLINE(int) tree_entry_cmp( + const git_tree_entry *a, const git_tree_entry *b, bool icase) +{ + return git_fs_path_cmp( + a->filename, a->filename_len, a->attr == GIT_FILEMODE_TREE, + b->filename, b->filename_len, b->attr == GIT_FILEMODE_TREE, + icase ? git__strncasecmp : git__strncmp); +} + +GIT_INLINE(int) tree_iterator_entry_cmp_icase( + const void *ptr_a, const void *ptr_b) +{ + const tree_iterator_entry *a = (const tree_iterator_entry *)ptr_a; + const tree_iterator_entry *b = (const tree_iterator_entry *)ptr_b; + + return tree_entry_cmp(a->tree_entry, b->tree_entry, true); +} + +static int tree_iterator_entry_sort_icase(const void *ptr_a, const void *ptr_b) +{ + const tree_iterator_entry *a = (const tree_iterator_entry *)ptr_a; + const tree_iterator_entry *b = (const tree_iterator_entry *)ptr_b; + + int c = tree_entry_cmp(a->tree_entry, b->tree_entry, true); + + /* stabilize the sort order for filenames that are (case insensitively) + * the same by examining the parent path (case sensitively) before + * falling back to a case sensitive sort of the filename. + */ + if (!c && a->parent_path != b->parent_path) + c = git__strcmp(a->parent_path, b->parent_path); + + if (!c) + c = tree_entry_cmp(a->tree_entry, b->tree_entry, false); + + return c; +} + +static int tree_iterator_compute_path( + git_str *out, + tree_iterator_entry *entry) +{ + git_str_clear(out); + + if (entry->parent_path) + git_str_joinpath(out, entry->parent_path, entry->tree_entry->filename); + else + git_str_puts(out, entry->tree_entry->filename); + + if (git_tree_entry__is_tree(entry->tree_entry)) + git_str_putc(out, '/'); + + if (git_str_oom(out)) + return -1; + + return 0; +} + +static int tree_iterator_frame_init( + tree_iterator *iter, + git_tree *tree, + tree_iterator_entry *frame_entry) +{ + tree_iterator_frame *new_frame = NULL; + tree_iterator_entry *new_entry; + git_tree *dup = NULL; + git_tree_entry *tree_entry; + git_vector_cmp cmp; + size_t i; + int error = 0; + + new_frame = git_array_alloc(iter->frames); + GIT_ERROR_CHECK_ALLOC(new_frame); + + if ((error = git_tree_dup(&dup, tree)) < 0) + goto done; + + memset(new_frame, 0x0, sizeof(tree_iterator_frame)); + new_frame->tree = dup; + + if (frame_entry && + (error = tree_iterator_compute_path(&new_frame->path, frame_entry)) < 0) + goto done; + + cmp = iterator__ignore_case(&iter->base) ? + tree_iterator_entry_sort_icase : NULL; + + if ((error = git_vector_init(&new_frame->entries, + dup->entries.size, cmp)) < 0) + goto done; + + git_array_foreach(dup->entries, i, tree_entry) { + if ((new_entry = git_pool_malloc(&iter->entry_pool, 1)) == NULL) { + git_error_set_oom(); + error = -1; + goto done; + } + + new_entry->tree_entry = tree_entry; + new_entry->parent_path = new_frame->path.ptr; + + if ((error = git_vector_insert(&new_frame->entries, new_entry)) < 0) + goto done; + } + + git_vector_set_sorted(&new_frame->entries, + !iterator__ignore_case(&iter->base)); + +done: + if (error < 0) { + git_tree_free(dup); + git_array_pop(iter->frames); + } + + return error; +} + +GIT_INLINE(tree_iterator_entry *) tree_iterator_current_entry( + tree_iterator_frame *frame) +{ + return frame->current; +} + +GIT_INLINE(int) tree_iterator_frame_push_neighbors( + tree_iterator *iter, + tree_iterator_frame *parent_frame, + tree_iterator_frame *frame, + const char *filename) +{ + tree_iterator_entry *entry, *new_entry; + git_tree *tree = NULL; + git_tree_entry *tree_entry; + git_str *path; + size_t new_size, i; + int error = 0; + + while (parent_frame->next_idx < parent_frame->entries.length) { + entry = parent_frame->entries.contents[parent_frame->next_idx]; + + if (strcasecmp(filename, entry->tree_entry->filename) != 0) + break; + + if ((error = git_tree_lookup(&tree, + iter->base.repo, &entry->tree_entry->oid)) < 0) + break; + + if (git_vector_insert(&parent_frame->similar_trees, tree) < 0) + break; + + path = git_array_alloc(parent_frame->similar_paths); + GIT_ERROR_CHECK_ALLOC(path); + + memset(path, 0, sizeof(git_str)); + + if ((error = tree_iterator_compute_path(path, entry)) < 0) + break; + + GIT_ERROR_CHECK_ALLOC_ADD(&new_size, + frame->entries.length, tree->entries.size); + git_vector_size_hint(&frame->entries, new_size); + + git_array_foreach(tree->entries, i, tree_entry) { + new_entry = git_pool_malloc(&iter->entry_pool, 1); + GIT_ERROR_CHECK_ALLOC(new_entry); + + new_entry->tree_entry = tree_entry; + new_entry->parent_path = path->ptr; + + if ((error = git_vector_insert(&frame->entries, new_entry)) < 0) + break; + } + + if (error) + break; + + parent_frame->next_idx++; + } + + return error; +} + +GIT_INLINE(int) tree_iterator_frame_push( + tree_iterator *iter, tree_iterator_entry *entry) +{ + tree_iterator_frame *parent_frame, *frame; + git_tree *tree = NULL; + int error; + + if ((error = git_tree_lookup(&tree, + iter->base.repo, &entry->tree_entry->oid)) < 0 || + (error = tree_iterator_frame_init(iter, tree, entry)) < 0) + goto done; + + parent_frame = tree_iterator_parent_frame(iter); + frame = tree_iterator_current_frame(iter); + + /* if we're case insensitive, then we may have another directory that + * is (case insensitively) equal to this one. coalesce those children + * into this tree. + */ + if (iterator__ignore_case(&iter->base)) + error = tree_iterator_frame_push_neighbors(iter, + parent_frame, frame, entry->tree_entry->filename); + +done: + git_tree_free(tree); + return error; +} + +static int tree_iterator_frame_pop(tree_iterator *iter) +{ + tree_iterator_frame *frame; + git_str *buf = NULL; + git_tree *tree; + size_t i; + + GIT_ASSERT(iter->frames.size); + + frame = git_array_pop(iter->frames); + + git_vector_free(&frame->entries); + git_tree_free(frame->tree); + + do { + buf = git_array_pop(frame->similar_paths); + git_str_dispose(buf); + } while (buf != NULL); + + git_array_clear(frame->similar_paths); + + git_vector_foreach(&frame->similar_trees, i, tree) + git_tree_free(tree); + + git_vector_free(&frame->similar_trees); + + git_str_dispose(&frame->path); + + return 0; +} + +static int tree_iterator_current( + const git_index_entry **out, git_iterator *i) +{ + tree_iterator *iter = (tree_iterator *)i; + + if (!iterator__has_been_accessed(i)) + return iter->base.cb->advance(out, i); + + if (!iter->frames.size) { + *out = NULL; + return GIT_ITEROVER; + } + + *out = &iter->entry; + return 0; +} + +static void tree_iterator_set_current( + tree_iterator *iter, + tree_iterator_frame *frame, + tree_iterator_entry *entry) +{ + git_tree_entry *tree_entry = entry->tree_entry; + + frame->current = entry; + + memset(&iter->entry, 0x0, sizeof(git_index_entry)); + + iter->entry.mode = tree_entry->attr; + iter->entry.path = iter->entry_path.ptr; + git_oid_cpy(&iter->entry.id, &tree_entry->oid); +} + +static int tree_iterator_advance(const git_index_entry **out, git_iterator *i) +{ + tree_iterator *iter = (tree_iterator *)i; + int error = 0; + + iter->base.flags |= GIT_ITERATOR_FIRST_ACCESS; + + /* examine tree entries until we find the next one to return */ + while (true) { + tree_iterator_entry *prev_entry, *entry; + tree_iterator_frame *frame; + bool is_tree; + + if ((frame = tree_iterator_current_frame(iter)) == NULL) { + error = GIT_ITEROVER; + break; + } + + /* no more entries in this frame. pop the frame out */ + if (frame->next_idx == frame->entries.length) { + if ((error = tree_iterator_frame_pop(iter)) < 0) + break; + + continue; + } + + /* we may have coalesced the contents of case-insensitively same-named + * directories, so do the sort now. + */ + if (frame->next_idx == 0 && !git_vector_is_sorted(&frame->entries)) + git_vector_sort(&frame->entries); + + /* we have more entries in the current frame, that's our next entry */ + prev_entry = tree_iterator_current_entry(frame); + entry = frame->entries.contents[frame->next_idx]; + frame->next_idx++; + + /* we can have collisions when iterating case insensitively. (eg, + * 'A/a' and 'a/A'). squash this one if it's already been seen. + */ + if (iterator__ignore_case(&iter->base) && + prev_entry && + tree_iterator_entry_cmp_icase(prev_entry, entry) == 0) + continue; + + if ((error = tree_iterator_compute_path(&iter->entry_path, entry)) < 0) + break; + + /* if this path is before our start, advance over this entry */ + if (!iterator_has_started(&iter->base, iter->entry_path.ptr, false)) + continue; + + /* if this path is after our end, stop */ + if (iterator_has_ended(&iter->base, iter->entry_path.ptr)) { + error = GIT_ITEROVER; + break; + } + + /* if we have a list of paths we're interested in, examine it */ + if (!iterator_pathlist_next_is(&iter->base, iter->entry_path.ptr)) + continue; + + is_tree = git_tree_entry__is_tree(entry->tree_entry); + + /* if we are *not* including trees then advance over this entry */ + if (is_tree && !iterator__include_trees(iter)) { + + /* if we've found a tree (and are not returning it to the caller) + * and we are autoexpanding, then we want to return the first + * child. push the new directory and advance. + */ + if (iterator__do_autoexpand(iter)) { + if ((error = tree_iterator_frame_push(iter, entry)) < 0) + break; + } + + continue; + } + + tree_iterator_set_current(iter, frame, entry); + + /* if we are autoexpanding, then push this as a new frame, so that + * the next call to `advance` will dive into this directory. + */ + if (is_tree && iterator__do_autoexpand(iter)) + error = tree_iterator_frame_push(iter, entry); + + break; + } + + if (out) + *out = (error == 0) ? &iter->entry : NULL; + + return error; +} + +static int tree_iterator_advance_into( + const git_index_entry **out, git_iterator *i) +{ + tree_iterator *iter = (tree_iterator *)i; + tree_iterator_frame *frame; + tree_iterator_entry *prev_entry; + int error; + + if (out) + *out = NULL; + + if ((frame = tree_iterator_current_frame(iter)) == NULL) + return GIT_ITEROVER; + + /* get the last seen entry */ + prev_entry = tree_iterator_current_entry(frame); + + /* it's legal to call advance_into when auto-expand is on. in this case, + * we will have pushed a new (empty) frame on to the stack for this + * new directory. since it's empty, its current_entry should be null. + */ + GIT_ASSERT(iterator__do_autoexpand(i) ^ (prev_entry != NULL)); + + if (prev_entry) { + if (!git_tree_entry__is_tree(prev_entry->tree_entry)) + return 0; + + if ((error = tree_iterator_frame_push(iter, prev_entry)) < 0) + return error; + } + + /* we've advanced into the directory in question, let advance + * find the first entry + */ + return tree_iterator_advance(out, i); +} + +static int tree_iterator_advance_over( + const git_index_entry **out, + git_iterator_status_t *status, + git_iterator *i) +{ + *status = GIT_ITERATOR_STATUS_NORMAL; + return git_iterator_advance(out, i); +} + +static void tree_iterator_clear(tree_iterator *iter) +{ + while (iter->frames.size) + tree_iterator_frame_pop(iter); + + git_array_clear(iter->frames); + + git_pool_clear(&iter->entry_pool); + git_str_clear(&iter->entry_path); + + iterator_clear(&iter->base); +} + +static int tree_iterator_init(tree_iterator *iter) +{ + int error; + + if ((error = git_pool_init(&iter->entry_pool, sizeof(tree_iterator_entry))) < 0 || + (error = tree_iterator_frame_init(iter, iter->root, NULL)) < 0) + return error; + + iter->base.flags &= ~GIT_ITERATOR_FIRST_ACCESS; + + return 0; +} + +static int tree_iterator_reset(git_iterator *i) +{ + tree_iterator *iter = (tree_iterator *)i; + + tree_iterator_clear(iter); + return tree_iterator_init(iter); +} + +static void tree_iterator_free(git_iterator *i) +{ + tree_iterator *iter = (tree_iterator *)i; + + tree_iterator_clear(iter); + + git_tree_free(iter->root); + git_str_dispose(&iter->entry_path); +} + +int git_iterator_for_tree( + git_iterator **out, + git_tree *tree, + git_iterator_options *options) +{ + tree_iterator *iter; + int error; + + static git_iterator_callbacks callbacks = { + tree_iterator_current, + tree_iterator_advance, + tree_iterator_advance_into, + tree_iterator_advance_over, + tree_iterator_reset, + tree_iterator_free + }; + + *out = NULL; + + if (tree == NULL) + return git_iterator_for_nothing(out, options); + + iter = git__calloc(1, sizeof(tree_iterator)); + GIT_ERROR_CHECK_ALLOC(iter); + + iter->base.type = GIT_ITERATOR_TREE; + iter->base.cb = &callbacks; + + if ((error = iterator_init_common(&iter->base, + git_tree_owner(tree), NULL, options)) < 0 || + (error = git_tree_dup(&iter->root, tree)) < 0 || + (error = tree_iterator_init(iter)) < 0) + goto on_error; + + *out = &iter->base; + return 0; + +on_error: + git_iterator_free(&iter->base); + return error; +} + +int git_iterator_current_tree_entry( + const git_tree_entry **tree_entry, git_iterator *i) +{ + tree_iterator *iter; + tree_iterator_frame *frame; + tree_iterator_entry *entry; + + GIT_ASSERT(i->type == GIT_ITERATOR_TREE); + + iter = (tree_iterator *)i; + + frame = tree_iterator_current_frame(iter); + entry = tree_iterator_current_entry(frame); + + *tree_entry = entry->tree_entry; + return 0; +} + +int git_iterator_current_parent_tree( + const git_tree **parent_tree, git_iterator *i, size_t depth) +{ + tree_iterator *iter; + tree_iterator_frame *frame; + + GIT_ASSERT(i->type == GIT_ITERATOR_TREE); + + iter = (tree_iterator *)i; + + GIT_ASSERT(depth < iter->frames.size); + frame = &iter->frames.ptr[iter->frames.size-depth-1]; + + *parent_tree = frame->tree; + return 0; +} + +/* Filesystem iterator */ + +typedef struct { + struct stat st; + size_t path_len; + iterator_pathlist_search_t match; + git_oid id; + char path[GIT_FLEX_ARRAY]; +} filesystem_iterator_entry; + +typedef struct { + git_vector entries; + git_pool entry_pool; + size_t next_idx; + + size_t path_len; + int is_ignored; +} filesystem_iterator_frame; + +typedef struct { + git_iterator base; + char *root; + size_t root_len; + + unsigned int dirload_flags; + + git_tree *tree; + git_index *index; + git_vector index_snapshot; + + git_oid_t oid_type; + + git_array_t(filesystem_iterator_frame) frames; + git_ignores ignores; + + /* info about the current entry */ + git_index_entry entry; + git_str current_path; + int current_is_ignored; + + /* temporary buffer for advance_over */ + git_str tmp_buf; +} filesystem_iterator; + + +GIT_INLINE(filesystem_iterator_frame *) filesystem_iterator_parent_frame( + filesystem_iterator *iter) +{ + return iter->frames.size > 1 ? + &iter->frames.ptr[iter->frames.size-2] : NULL; +} + +GIT_INLINE(filesystem_iterator_frame *) filesystem_iterator_current_frame( + filesystem_iterator *iter) +{ + return iter->frames.size ? &iter->frames.ptr[iter->frames.size-1] : NULL; +} + +GIT_INLINE(filesystem_iterator_entry *) filesystem_iterator_current_entry( + filesystem_iterator_frame *frame) +{ + return frame->next_idx == 0 ? + NULL : frame->entries.contents[frame->next_idx-1]; +} + +static int filesystem_iterator_entry_cmp(const void *_a, const void *_b) +{ + const filesystem_iterator_entry *a = (const filesystem_iterator_entry *)_a; + const filesystem_iterator_entry *b = (const filesystem_iterator_entry *)_b; + + return git__strcmp(a->path, b->path); +} + +static int filesystem_iterator_entry_cmp_icase(const void *_a, const void *_b) +{ + const filesystem_iterator_entry *a = (const filesystem_iterator_entry *)_a; + const filesystem_iterator_entry *b = (const filesystem_iterator_entry *)_b; + + return git__strcasecmp(a->path, b->path); +} + +#define FILESYSTEM_MAX_DEPTH 100 + +/** + * Figure out if an entry is a submodule. + * + * We consider it a submodule if the path is listed as a submodule in + * either the tree or the index. + */ +static int filesystem_iterator_is_submodule( + bool *out, filesystem_iterator *iter, const char *path, size_t path_len) +{ + bool is_submodule = false; + int error; + + *out = false; + + /* first see if this path is a submodule in HEAD */ + if (iter->tree) { + git_tree_entry *entry; + + error = git_tree_entry_bypath(&entry, iter->tree, path); + + if (error < 0 && error != GIT_ENOTFOUND) + return error; + + if (!error) { + is_submodule = (entry->attr == GIT_FILEMODE_COMMIT); + git_tree_entry_free(entry); + } + } + + if (!is_submodule && iter->base.index) { + size_t pos; + + error = git_index_snapshot_find(&pos, + &iter->index_snapshot, iter->base.entry_srch, path, path_len, 0); + + if (error < 0 && error != GIT_ENOTFOUND) + return error; + + if (!error) { + git_index_entry *e = git_vector_get(&iter->index_snapshot, pos); + is_submodule = (e->mode == GIT_FILEMODE_COMMIT); + } + } + + *out = is_submodule; + return 0; +} + +static void filesystem_iterator_frame_push_ignores( + filesystem_iterator *iter, + filesystem_iterator_entry *frame_entry, + filesystem_iterator_frame *new_frame) +{ + filesystem_iterator_frame *previous_frame; + const char *path = frame_entry ? frame_entry->path : ""; + + if (!iterator__honor_ignores(&iter->base)) + return; + + if (git_ignore__lookup(&new_frame->is_ignored, + &iter->ignores, path, GIT_DIR_FLAG_TRUE) < 0) { + git_error_clear(); + new_frame->is_ignored = GIT_IGNORE_NOTFOUND; + } + + /* if this is not the top level directory... */ + if (frame_entry) { + const char *relative_path; + + previous_frame = filesystem_iterator_parent_frame(iter); + + /* push new ignores for files in this directory */ + relative_path = frame_entry->path + previous_frame->path_len; + + /* inherit ignored from parent if no rule specified */ + if (new_frame->is_ignored <= GIT_IGNORE_NOTFOUND) + new_frame->is_ignored = previous_frame->is_ignored; + + git_ignore__push_dir(&iter->ignores, relative_path); + } +} + +static void filesystem_iterator_frame_pop_ignores( + filesystem_iterator *iter) +{ + if (iterator__honor_ignores(&iter->base)) + git_ignore__pop_dir(&iter->ignores); +} + +GIT_INLINE(bool) filesystem_iterator_examine_path( + bool *is_dir_out, + iterator_pathlist_search_t *match_out, + filesystem_iterator *iter, + filesystem_iterator_entry *frame_entry, + const char *path, + size_t path_len) +{ + bool is_dir = 0; + iterator_pathlist_search_t match = ITERATOR_PATHLIST_FULL; + + *is_dir_out = false; + *match_out = ITERATOR_PATHLIST_NONE; + + if (iter->base.start_len) { + int cmp = iter->base.strncomp(path, iter->base.start, path_len); + + /* we haven't stat'ed `path` yet, so we don't yet know if it's a + * directory or not. special case if the current path may be a + * directory that matches the start prefix. + */ + if (cmp == 0) { + if (iter->base.start[path_len] == '/') + is_dir = true; + + else if (iter->base.start[path_len] != '\0') + cmp = -1; + } + + if (cmp < 0) + return false; + } + + if (iter->base.end_len) { + int cmp = iter->base.strncomp(path, iter->base.end, iter->base.end_len); + + if (cmp > 0) + return false; + } + + /* if we have a pathlist that we're limiting to, examine this path now + * to avoid a `stat` if we're not interested in the path. + */ + if (iter->base.pathlist.length) { + /* if our parent was explicitly included, so too are we */ + if (frame_entry && frame_entry->match != ITERATOR_PATHLIST_IS_PARENT) + match = ITERATOR_PATHLIST_FULL; + else + match = iterator_pathlist_search(&iter->base, path, path_len); + + if (match == ITERATOR_PATHLIST_NONE) + return false; + + /* Ensure that the pathlist entry lines up with what we expected */ + if (match == ITERATOR_PATHLIST_IS_DIR || + match == ITERATOR_PATHLIST_IS_PARENT) + is_dir = true; + } + + *is_dir_out = is_dir; + *match_out = match; + return true; +} + +GIT_INLINE(bool) filesystem_iterator_is_dot_git( + filesystem_iterator *iter, const char *path, size_t path_len) +{ + size_t len; + + if (!iterator__ignore_dot_git(&iter->base)) + return false; + + if ((len = path_len) < 4) + return false; + + if (path[len - 1] == '/') + len--; + + if (git__tolower(path[len - 1]) != 't' || + git__tolower(path[len - 2]) != 'i' || + git__tolower(path[len - 3]) != 'g' || + git__tolower(path[len - 4]) != '.') + return false; + + return (len == 4 || path[len - 5] == '/'); +} + +static int filesystem_iterator_entry_hash( + filesystem_iterator *iter, + filesystem_iterator_entry *entry) +{ + git_str fullpath = GIT_STR_INIT; + int error; + + if (S_ISDIR(entry->st.st_mode)) { + memset(&entry->id, 0, git_oid_size(iter->oid_type)); + return 0; + } + + if (iter->base.type == GIT_ITERATOR_WORKDIR) + return git_repository_hashfile(&entry->id, + iter->base.repo, entry->path, GIT_OBJECT_BLOB, NULL); + + if (!(error = git_str_joinpath(&fullpath, iter->root, entry->path)) && + !(error = git_path_validate_str_length(iter->base.repo, &fullpath))) + error = git_odb__hashfile(&entry->id, fullpath.ptr, GIT_OBJECT_BLOB, iter->oid_type); + + git_str_dispose(&fullpath); + return error; +} + +static int filesystem_iterator_entry_init( + filesystem_iterator_entry **out, + filesystem_iterator *iter, + filesystem_iterator_frame *frame, + const char *path, + size_t path_len, + struct stat *statbuf, + iterator_pathlist_search_t pathlist_match) +{ + filesystem_iterator_entry *entry; + size_t entry_size; + int error = 0; + + *out = NULL; + + /* Make sure to append two bytes, one for the path's null + * termination, one for a possible trailing '/' for folders. + */ + GIT_ERROR_CHECK_ALLOC_ADD(&entry_size, + sizeof(filesystem_iterator_entry), path_len); + GIT_ERROR_CHECK_ALLOC_ADD(&entry_size, entry_size, 2); + + entry = git_pool_malloc(&frame->entry_pool, entry_size); + GIT_ERROR_CHECK_ALLOC(entry); + + entry->path_len = path_len; + entry->match = pathlist_match; + memcpy(entry->path, path, path_len); + memcpy(&entry->st, statbuf, sizeof(struct stat)); + + /* Suffix directory paths with a '/' */ + if (S_ISDIR(entry->st.st_mode)) + entry->path[entry->path_len++] = '/'; + + entry->path[entry->path_len] = '\0'; + + if (iter->base.flags & GIT_ITERATOR_INCLUDE_HASH) + error = filesystem_iterator_entry_hash(iter, entry); + + if (!error) + *out = entry; + + return error; +} + +static int filesystem_iterator_frame_push( + filesystem_iterator *iter, + filesystem_iterator_entry *frame_entry) +{ + filesystem_iterator_frame *new_frame = NULL; + git_fs_path_diriter diriter = GIT_FS_PATH_DIRITER_INIT; + git_str root = GIT_STR_INIT; + const char *path; + filesystem_iterator_entry *entry; + struct stat statbuf; + size_t path_len; + int error; + + if (iter->frames.size == FILESYSTEM_MAX_DEPTH) { + git_error_set(GIT_ERROR_REPOSITORY, + "directory nesting too deep (%"PRIuZ")", iter->frames.size); + return -1; + } + + new_frame = git_array_alloc(iter->frames); + GIT_ERROR_CHECK_ALLOC(new_frame); + + memset(new_frame, 0, sizeof(filesystem_iterator_frame)); + + if (frame_entry) + git_str_joinpath(&root, iter->root, frame_entry->path); + else + git_str_puts(&root, iter->root); + + if (git_str_oom(&root) || + git_path_validate_str_length(iter->base.repo, &root) < 0) { + error = -1; + goto done; + } + + new_frame->path_len = frame_entry ? frame_entry->path_len : 0; + + /* Any error here is equivalent to the dir not existing, skip over it */ + if ((error = git_fs_path_diriter_init( + &diriter, root.ptr, iter->dirload_flags)) < 0) { + error = GIT_ENOTFOUND; + goto done; + } + + if ((error = git_vector_init(&new_frame->entries, 64, + iterator__ignore_case(&iter->base) ? + filesystem_iterator_entry_cmp_icase : + filesystem_iterator_entry_cmp)) < 0) + goto done; + + if ((error = git_pool_init(&new_frame->entry_pool, 1)) < 0) + goto done; + + /* check if this directory is ignored */ + filesystem_iterator_frame_push_ignores(iter, frame_entry, new_frame); + + while ((error = git_fs_path_diriter_next(&diriter)) == 0) { + iterator_pathlist_search_t pathlist_match = ITERATOR_PATHLIST_FULL; + git_str path_str = GIT_STR_INIT; + bool dir_expected = false; + + if ((error = git_fs_path_diriter_fullpath(&path, &path_len, &diriter)) < 0) + goto done; + + path_str.ptr = (char *)path; + path_str.size = path_len; + + if ((error = git_path_validate_str_length(iter->base.repo, &path_str)) < 0) + goto done; + + GIT_ASSERT(path_len > iter->root_len); + + /* remove the prefix if requested */ + path += iter->root_len; + path_len -= iter->root_len; + + /* examine start / end and the pathlist to see if this path is in it. + * note that since we haven't yet stat'ed the path, we cannot know + * whether it's a directory yet or not, so this can give us an + * expected type (S_IFDIR or S_IFREG) that we should examine) + */ + if (!filesystem_iterator_examine_path(&dir_expected, &pathlist_match, + iter, frame_entry, path, path_len)) + continue; + + /* TODO: don't need to stat if assume unchanged for this path and + * we have an index, we can just copy the data out of it. + */ + + if ((error = git_fs_path_diriter_stat(&statbuf, &diriter)) < 0) { + /* file was removed between readdir and lstat */ + if (error == GIT_ENOTFOUND) + continue; + + /* treat the file as unreadable */ + memset(&statbuf, 0, sizeof(statbuf)); + statbuf.st_mode = GIT_FILEMODE_UNREADABLE; + + error = 0; + } + + iter->base.stat_calls++; + + /* Ignore wacky things in the filesystem */ + if (!S_ISDIR(statbuf.st_mode) && + !S_ISREG(statbuf.st_mode) && + !S_ISLNK(statbuf.st_mode) && + statbuf.st_mode != GIT_FILEMODE_UNREADABLE) + continue; + + if (filesystem_iterator_is_dot_git(iter, path, path_len)) + continue; + + /* convert submodules to GITLINK and remove trailing slashes */ + if (S_ISDIR(statbuf.st_mode)) { + bool submodule = false; + + if ((error = filesystem_iterator_is_submodule(&submodule, + iter, path, path_len)) < 0) + goto done; + + if (submodule) + statbuf.st_mode = GIT_FILEMODE_COMMIT; + } + + /* Ensure that the pathlist entry lines up with what we expected */ + else if (dir_expected) + continue; + + if ((error = filesystem_iterator_entry_init(&entry, + iter, new_frame, path, path_len, &statbuf, pathlist_match)) < 0) + goto done; + + git_vector_insert(&new_frame->entries, entry); + } + + if (error == GIT_ITEROVER) + error = 0; + + /* sort now that directory suffix is added */ + git_vector_sort(&new_frame->entries); + +done: + if (error < 0) + git_array_pop(iter->frames); + + git_str_dispose(&root); + git_fs_path_diriter_free(&diriter); + return error; +} + +GIT_INLINE(int) filesystem_iterator_frame_pop(filesystem_iterator *iter) +{ + filesystem_iterator_frame *frame; + + GIT_ASSERT(iter->frames.size); + + frame = git_array_pop(iter->frames); + filesystem_iterator_frame_pop_ignores(iter); + + git_pool_clear(&frame->entry_pool); + git_vector_free(&frame->entries); + + return 0; +} + +static void filesystem_iterator_set_current( + filesystem_iterator *iter, + filesystem_iterator_entry *entry) +{ + /* + * Index entries are limited to 32 bit timestamps. We can safely + * cast this since workdir times are only used in the cache; any + * mismatch will cause a hash recomputation which is unfortunate + * but affects only people who set their filetimes to 2038. + * (Same with the file size.) + */ + iter->entry.ctime.seconds = (int32_t)entry->st.st_ctime; + iter->entry.mtime.seconds = (int32_t)entry->st.st_mtime; + +#if defined(GIT_USE_NSEC) + iter->entry.ctime.nanoseconds = entry->st.st_ctime_nsec; + iter->entry.mtime.nanoseconds = entry->st.st_mtime_nsec; +#else + iter->entry.ctime.nanoseconds = 0; + iter->entry.mtime.nanoseconds = 0; +#endif + + iter->entry.dev = entry->st.st_dev; + iter->entry.ino = entry->st.st_ino; + iter->entry.mode = git_futils_canonical_mode(entry->st.st_mode); + iter->entry.uid = entry->st.st_uid; + iter->entry.gid = entry->st.st_gid; + iter->entry.file_size = (uint32_t)entry->st.st_size; + + if (iter->base.flags & GIT_ITERATOR_INCLUDE_HASH) + git_oid_cpy(&iter->entry.id, &entry->id); + else + git_oid_clear(&iter->entry.id, iter->oid_type); + + iter->entry.path = entry->path; + + iter->current_is_ignored = GIT_IGNORE_UNCHECKED; +} + +static int filesystem_iterator_current( + const git_index_entry **out, git_iterator *i) +{ + filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base); + + if (!iterator__has_been_accessed(i)) + return iter->base.cb->advance(out, i); + + if (!iter->frames.size) { + *out = NULL; + return GIT_ITEROVER; + } + + *out = &iter->entry; + return 0; +} + +static int filesystem_iterator_is_dir( + bool *is_dir, + const filesystem_iterator *iter, + const filesystem_iterator_entry *entry) +{ + struct stat st; + git_str fullpath = GIT_STR_INIT; + int error = 0; + + if (S_ISDIR(entry->st.st_mode)) { + *is_dir = 1; + goto done; + } + + if (!iterator__descend_symlinks(iter) || !S_ISLNK(entry->st.st_mode)) { + *is_dir = 0; + goto done; + } + + if ((error = git_str_joinpath(&fullpath, iter->root, entry->path)) < 0 || + (error = git_path_validate_str_length(iter->base.repo, &fullpath)) < 0 || + (error = p_stat(fullpath.ptr, &st)) < 0) + goto done; + + *is_dir = S_ISDIR(st.st_mode); + +done: + git_str_dispose(&fullpath); + return error; +} + +static int filesystem_iterator_advance( + const git_index_entry **out, git_iterator *i) +{ + filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base); + bool is_dir; + int error = 0; + + iter->base.flags |= GIT_ITERATOR_FIRST_ACCESS; + + /* examine filesystem entries until we find the next one to return */ + while (true) { + filesystem_iterator_frame *frame; + filesystem_iterator_entry *entry; + + if ((frame = filesystem_iterator_current_frame(iter)) == NULL) { + error = GIT_ITEROVER; + break; + } + + /* no more entries in this frame. pop the frame out */ + if (frame->next_idx == frame->entries.length) { + filesystem_iterator_frame_pop(iter); + continue; + } + + /* we have more entries in the current frame, that's our next entry */ + entry = frame->entries.contents[frame->next_idx]; + frame->next_idx++; + + if ((error = filesystem_iterator_is_dir(&is_dir, iter, entry)) < 0) + break; + + if (is_dir) { + if (iterator__do_autoexpand(iter)) { + error = filesystem_iterator_frame_push(iter, entry); + + /* may get GIT_ENOTFOUND due to races or permission problems + * that we want to quietly swallow + */ + if (error == GIT_ENOTFOUND) + continue; + else if (error < 0) + break; + } + + if (!iterator__include_trees(iter)) + continue; + } + + filesystem_iterator_set_current(iter, entry); + break; + } + + if (out) + *out = (error == 0) ? &iter->entry : NULL; + + return error; +} + +static int filesystem_iterator_advance_into( + const git_index_entry **out, git_iterator *i) +{ + filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base); + filesystem_iterator_frame *frame; + filesystem_iterator_entry *prev_entry; + int error; + + if (out) + *out = NULL; + + if ((frame = filesystem_iterator_current_frame(iter)) == NULL) + return GIT_ITEROVER; + + /* get the last seen entry */ + prev_entry = filesystem_iterator_current_entry(frame); + + /* it's legal to call advance_into when auto-expand is on. in this case, + * we will have pushed a new (empty) frame on to the stack for this + * new directory. since it's empty, its current_entry should be null. + */ + GIT_ASSERT(iterator__do_autoexpand(i) ^ (prev_entry != NULL)); + + if (prev_entry) { + if (prev_entry->st.st_mode != GIT_FILEMODE_COMMIT && + !S_ISDIR(prev_entry->st.st_mode)) + return 0; + + if ((error = filesystem_iterator_frame_push(iter, prev_entry)) < 0) + return error; + } + + /* we've advanced into the directory in question, let advance + * find the first entry + */ + return filesystem_iterator_advance(out, i); +} + +int git_iterator_current_workdir_path(git_str **out, git_iterator *i) +{ + filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base); + const git_index_entry *entry; + + if (i->type != GIT_ITERATOR_FS && + i->type != GIT_ITERATOR_WORKDIR) { + *out = NULL; + return 0; + } + + git_str_truncate(&iter->current_path, iter->root_len); + + if (git_iterator_current(&entry, i) < 0 || + git_str_puts(&iter->current_path, entry->path) < 0) + return -1; + + *out = &iter->current_path; + return 0; +} + +GIT_INLINE(git_dir_flag) entry_dir_flag(git_index_entry *entry) +{ +#if defined(GIT_WIN32) && !defined(__MINGW32__) + return (entry && entry->mode) ? + (S_ISDIR(entry->mode) ? GIT_DIR_FLAG_TRUE : GIT_DIR_FLAG_FALSE) : + GIT_DIR_FLAG_UNKNOWN; +#else + GIT_UNUSED(entry); + return GIT_DIR_FLAG_UNKNOWN; +#endif +} + +static void filesystem_iterator_update_ignored(filesystem_iterator *iter) +{ + filesystem_iterator_frame *frame; + git_dir_flag dir_flag = entry_dir_flag(&iter->entry); + + if (git_ignore__lookup(&iter->current_is_ignored, + &iter->ignores, iter->entry.path, dir_flag) < 0) { + git_error_clear(); + iter->current_is_ignored = GIT_IGNORE_NOTFOUND; + } + + /* use ignore from containing frame stack */ + if (iter->current_is_ignored <= GIT_IGNORE_NOTFOUND) { + frame = filesystem_iterator_current_frame(iter); + iter->current_is_ignored = frame->is_ignored; + } +} + +GIT_INLINE(bool) filesystem_iterator_current_is_ignored( + filesystem_iterator *iter) +{ + if (iter->current_is_ignored == GIT_IGNORE_UNCHECKED) + filesystem_iterator_update_ignored(iter); + + return (iter->current_is_ignored == GIT_IGNORE_TRUE); +} + +bool git_iterator_current_is_ignored(git_iterator *i) +{ + filesystem_iterator *iter = NULL; + + if (i->type != GIT_ITERATOR_WORKDIR) + return false; + + iter = GIT_CONTAINER_OF(i, filesystem_iterator, base); + + return filesystem_iterator_current_is_ignored(iter); +} + +bool git_iterator_current_tree_is_ignored(git_iterator *i) +{ + filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base); + filesystem_iterator_frame *frame; + + if (i->type != GIT_ITERATOR_WORKDIR) + return false; + + frame = filesystem_iterator_current_frame(iter); + return (frame->is_ignored == GIT_IGNORE_TRUE); +} + +static int filesystem_iterator_advance_over( + const git_index_entry **out, + git_iterator_status_t *status, + git_iterator *i) +{ + filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base); + filesystem_iterator_frame *current_frame; + filesystem_iterator_entry *current_entry; + const git_index_entry *entry = NULL; + const char *base; + int error = 0; + + *out = NULL; + *status = GIT_ITERATOR_STATUS_NORMAL; + + GIT_ASSERT(iterator__has_been_accessed(i)); + + current_frame = filesystem_iterator_current_frame(iter); + GIT_ASSERT(current_frame); + + current_entry = filesystem_iterator_current_entry(current_frame); + GIT_ASSERT(current_entry); + + if ((error = git_iterator_current(&entry, i)) < 0) + return error; + + if (!S_ISDIR(entry->mode)) { + if (filesystem_iterator_current_is_ignored(iter)) + *status = GIT_ITERATOR_STATUS_IGNORED; + + return filesystem_iterator_advance(out, i); + } + + git_str_clear(&iter->tmp_buf); + if ((error = git_str_puts(&iter->tmp_buf, entry->path)) < 0) + return error; + + base = iter->tmp_buf.ptr; + + /* scan inside the directory looking for files. if we find nothing, + * we will remain EMPTY. if we find any ignored item, upgrade EMPTY to + * IGNORED. if we find a real actual item, upgrade all the way to NORMAL + * and then stop. + * + * however, if we're here looking for a pathlist item (but are not + * actually in the pathlist ourselves) then start at FILTERED instead of + * EMPTY. callers then know that this path was not something they asked + * about. + */ + *status = current_entry->match == ITERATOR_PATHLIST_IS_PARENT ? + GIT_ITERATOR_STATUS_FILTERED : GIT_ITERATOR_STATUS_EMPTY; + + while (entry && !iter->base.prefixcomp(entry->path, base)) { + if (filesystem_iterator_current_is_ignored(iter)) { + /* if we found an explicitly ignored item, then update from + * EMPTY to IGNORED + */ + *status = GIT_ITERATOR_STATUS_IGNORED; + } else if (S_ISDIR(entry->mode)) { + error = filesystem_iterator_advance_into(&entry, i); + + if (!error) + continue; + + /* this directory disappeared, ignore it */ + else if (error == GIT_ENOTFOUND) + error = 0; + + /* a real error occurred */ + else + break; + } else { + /* we found a non-ignored item, treat parent as untracked */ + *status = GIT_ITERATOR_STATUS_NORMAL; + break; + } + + if ((error = git_iterator_advance(&entry, i)) < 0) + break; + } + + /* wrap up scan back to base directory */ + while (entry && !iter->base.prefixcomp(entry->path, base)) { + if ((error = git_iterator_advance(&entry, i)) < 0) + break; + } + + if (!error) + *out = entry; + + return error; +} + +static void filesystem_iterator_clear(filesystem_iterator *iter) +{ + while (iter->frames.size) + filesystem_iterator_frame_pop(iter); + + git_array_clear(iter->frames); + git_ignore__free(&iter->ignores); + + git_str_dispose(&iter->tmp_buf); + + iterator_clear(&iter->base); +} + +static int filesystem_iterator_init(filesystem_iterator *iter) +{ + int error; + + if (iterator__honor_ignores(&iter->base) && + (error = git_ignore__for_path(iter->base.repo, + ".gitignore", &iter->ignores)) < 0) + return error; + + if ((error = filesystem_iterator_frame_push(iter, NULL)) < 0) + return error; + + iter->base.flags &= ~GIT_ITERATOR_FIRST_ACCESS; + + return 0; +} + +static int filesystem_iterator_reset(git_iterator *i) +{ + filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base); + + filesystem_iterator_clear(iter); + return filesystem_iterator_init(iter); +} + +static void filesystem_iterator_free(git_iterator *i) +{ + filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base); + git__free(iter->root); + git_str_dispose(&iter->current_path); + git_tree_free(iter->tree); + if (iter->index) + git_index_snapshot_release(&iter->index_snapshot, iter->index); + filesystem_iterator_clear(iter); +} + +static int iterator_for_filesystem( + git_iterator **out, + git_repository *repo, + const char *root, + git_index *index, + git_tree *tree, + git_iterator_t type, + git_iterator_options *options) +{ + filesystem_iterator *iter; + size_t root_len; + int error; + + static git_iterator_callbacks callbacks = { + filesystem_iterator_current, + filesystem_iterator_advance, + filesystem_iterator_advance_into, + filesystem_iterator_advance_over, + filesystem_iterator_reset, + filesystem_iterator_free + }; + + *out = NULL; + + if (root == NULL) + return git_iterator_for_nothing(out, options); + + iter = git__calloc(1, sizeof(filesystem_iterator)); + GIT_ERROR_CHECK_ALLOC(iter); + + iter->base.type = type; + iter->base.cb = &callbacks; + + root_len = strlen(root); + + iter->root = git__malloc(root_len+2); + GIT_ERROR_CHECK_ALLOC(iter->root); + + memcpy(iter->root, root, root_len); + + if (root_len == 0 || root[root_len-1] != '/') { + iter->root[root_len] = '/'; + root_len++; + } + iter->root[root_len] = '\0'; + iter->root_len = root_len; + + if ((error = git_str_puts(&iter->current_path, iter->root)) < 0) + goto on_error; + + if ((error = iterator_init_common(&iter->base, repo, index, options)) < 0) + goto on_error; + + if (tree && (error = git_tree_dup(&iter->tree, tree)) < 0) + goto on_error; + + if (index && + (error = git_index_snapshot_new(&iter->index_snapshot, index)) < 0) + goto on_error; + + iter->index = index; + iter->dirload_flags = + (iterator__ignore_case(&iter->base) ? + GIT_FS_PATH_DIR_IGNORE_CASE : 0) | + (iterator__flag(&iter->base, PRECOMPOSE_UNICODE) ? + GIT_FS_PATH_DIR_PRECOMPOSE_UNICODE : 0); + + iter->oid_type = options->oid_type; + + if ((error = filesystem_iterator_init(iter)) < 0) + goto on_error; + + *out = &iter->base; + return 0; + +on_error: + git_iterator_free(&iter->base); + return error; +} + +int git_iterator_for_filesystem( + git_iterator **out, + const char *root, + git_iterator_options *given_opts) +{ + git_iterator_options options = GIT_ITERATOR_OPTIONS_INIT; + + if (given_opts) + memcpy(&options, given_opts, sizeof(git_iterator_options)); + + return iterator_for_filesystem(out, + NULL, root, NULL, NULL, GIT_ITERATOR_FS, &options); +} + +int git_iterator_for_workdir_ext( + git_iterator **out, + git_repository *repo, + const char *repo_workdir, + git_index *index, + git_tree *tree, + git_iterator_options *given_opts) +{ + git_iterator_options options = GIT_ITERATOR_OPTIONS_INIT; + + if (!repo_workdir) { + if (git_repository__ensure_not_bare(repo, "scan working directory") < 0) + return GIT_EBAREREPO; + + repo_workdir = git_repository_workdir(repo); + } + + /* upgrade to a workdir iterator, adding necessary internal flags */ + if (given_opts) + memcpy(&options, given_opts, sizeof(git_iterator_options)); + + options.flags |= GIT_ITERATOR_HONOR_IGNORES | + GIT_ITERATOR_IGNORE_DOT_GIT; + + if (!options.oid_type) + options.oid_type = repo->oid_type; + else if (options.oid_type != repo->oid_type) + git_error_set(GIT_ERROR_INVALID, + "specified object ID type does not match repository object ID type"); + + return iterator_for_filesystem(out, + repo, repo_workdir, index, tree, GIT_ITERATOR_WORKDIR, &options); +} + + +/* Index iterator */ + + +typedef struct { + git_iterator base; + git_vector entries; + size_t next_idx; + + /* the pseudotree entry */ + git_index_entry tree_entry; + git_str tree_buf; + bool skip_tree; + + const git_index_entry *entry; +} index_iterator; + +static int index_iterator_current( + const git_index_entry **out, git_iterator *i) +{ + index_iterator *iter = (index_iterator *)i; + + if (!iterator__has_been_accessed(i)) + return iter->base.cb->advance(out, i); + + if (iter->entry == NULL) { + *out = NULL; + return GIT_ITEROVER; + } + + *out = iter->entry; + return 0; +} + +static bool index_iterator_create_pseudotree( + const git_index_entry **out, + index_iterator *iter, + const char *path) +{ + const char *prev_path, *relative_path, *dirsep; + size_t common_len; + + prev_path = iter->entry ? iter->entry->path : ""; + + /* determine if the new path is in a different directory from the old */ + common_len = git_fs_path_common_dirlen(prev_path, path); + relative_path = path + common_len; + + if ((dirsep = strchr(relative_path, '/')) == NULL) + return false; + + git_str_clear(&iter->tree_buf); + git_str_put(&iter->tree_buf, path, (dirsep - path) + 1); + + iter->tree_entry.mode = GIT_FILEMODE_TREE; + iter->tree_entry.path = iter->tree_buf.ptr; + + *out = &iter->tree_entry; + return true; +} + +static int index_iterator_skip_pseudotree(index_iterator *iter) +{ + GIT_ASSERT(iterator__has_been_accessed(&iter->base)); + GIT_ASSERT(S_ISDIR(iter->entry->mode)); + + while (true) { + const git_index_entry *next_entry = NULL; + + if (++iter->next_idx >= iter->entries.length) + return GIT_ITEROVER; + + next_entry = iter->entries.contents[iter->next_idx]; + + if (iter->base.strncomp(iter->tree_buf.ptr, next_entry->path, + iter->tree_buf.size) != 0) + break; + } + + iter->skip_tree = false; + return 0; +} + +static int index_iterator_advance( + const git_index_entry **out, git_iterator *i) +{ + index_iterator *iter = GIT_CONTAINER_OF(i, index_iterator, base); + const git_index_entry *entry = NULL; + bool is_submodule; + int error = 0; + + iter->base.flags |= GIT_ITERATOR_FIRST_ACCESS; + + while (true) { + if (iter->next_idx >= iter->entries.length) { + error = GIT_ITEROVER; + break; + } + + /* we were not asked to expand this pseudotree. advance over it. */ + if (iter->skip_tree) { + index_iterator_skip_pseudotree(iter); + continue; + } + + entry = iter->entries.contents[iter->next_idx]; + is_submodule = S_ISGITLINK(entry->mode); + + if (!iterator_has_started(&iter->base, entry->path, is_submodule)) { + iter->next_idx++; + continue; + } + + if (iterator_has_ended(&iter->base, entry->path)) { + error = GIT_ITEROVER; + break; + } + + /* if we have a list of paths we're interested in, examine it */ + if (!iterator_pathlist_next_is(&iter->base, entry->path)) { + iter->next_idx++; + continue; + } + + /* if this is a conflict, skip it unless we're including conflicts */ + if (git_index_entry_is_conflict(entry) && + !iterator__include_conflicts(&iter->base)) { + iter->next_idx++; + continue; + } + + /* we've found what will be our next _file_ entry. but if we are + * returning trees entries, we may need to return a pseudotree + * entry that will contain this. don't advance over this entry, + * though, we still need to return it on the next `advance`. + */ + if (iterator__include_trees(&iter->base) && + index_iterator_create_pseudotree(&entry, iter, entry->path)) { + + /* Note whether this pseudo tree should be expanded or not */ + iter->skip_tree = iterator__dont_autoexpand(&iter->base); + break; + } + + iter->next_idx++; + break; + } + + iter->entry = (error == 0) ? entry : NULL; + + if (out) + *out = iter->entry; + + return error; +} + +static int index_iterator_advance_into( + const git_index_entry **out, git_iterator *i) +{ + index_iterator *iter = GIT_CONTAINER_OF(i, index_iterator, base); + + if (! S_ISDIR(iter->tree_entry.mode)) { + if (out) + *out = NULL; + + return 0; + } + + iter->skip_tree = false; + return index_iterator_advance(out, i); +} + +static int index_iterator_advance_over( + const git_index_entry **out, + git_iterator_status_t *status, + git_iterator *i) +{ + index_iterator *iter = GIT_CONTAINER_OF(i, index_iterator, base); + const git_index_entry *entry; + int error; + + if ((error = index_iterator_current(&entry, i)) < 0) + return error; + + if (S_ISDIR(entry->mode)) + index_iterator_skip_pseudotree(iter); + + *status = GIT_ITERATOR_STATUS_NORMAL; + return index_iterator_advance(out, i); +} + +static void index_iterator_clear(index_iterator *iter) +{ + iterator_clear(&iter->base); +} + +static int index_iterator_init(index_iterator *iter) +{ + iter->base.flags &= ~GIT_ITERATOR_FIRST_ACCESS; + iter->next_idx = 0; + iter->skip_tree = false; + return 0; +} + +static int index_iterator_reset(git_iterator *i) +{ + index_iterator *iter = GIT_CONTAINER_OF(i, index_iterator, base); + + index_iterator_clear(iter); + return index_iterator_init(iter); +} + +static void index_iterator_free(git_iterator *i) +{ + index_iterator *iter = GIT_CONTAINER_OF(i, index_iterator, base); + + git_index_snapshot_release(&iter->entries, iter->base.index); + git_str_dispose(&iter->tree_buf); +} + +int git_iterator_for_index( + git_iterator **out, + git_repository *repo, + git_index *index, + git_iterator_options *options) +{ + index_iterator *iter; + int error; + + static git_iterator_callbacks callbacks = { + index_iterator_current, + index_iterator_advance, + index_iterator_advance_into, + index_iterator_advance_over, + index_iterator_reset, + index_iterator_free + }; + + *out = NULL; + + if (index == NULL) + return git_iterator_for_nothing(out, options); + + iter = git__calloc(1, sizeof(index_iterator)); + GIT_ERROR_CHECK_ALLOC(iter); + + iter->base.type = GIT_ITERATOR_INDEX; + iter->base.cb = &callbacks; + + if ((error = iterator_init_common(&iter->base, repo, index, options)) < 0 || + (error = git_index_snapshot_new(&iter->entries, index)) < 0 || + (error = index_iterator_init(iter)) < 0) + goto on_error; + + git_vector_set_cmp(&iter->entries, iterator__ignore_case(&iter->base) ? + git_index_entry_icmp : git_index_entry_cmp); + git_vector_sort(&iter->entries); + + *out = &iter->base; + return 0; + +on_error: + git_iterator_free(&iter->base); + return error; +} + + +/* Iterator API */ + +int git_iterator_reset_range( + git_iterator *i, const char *start, const char *end) +{ + if (iterator_reset_range(i, start, end) < 0) + return -1; + + return i->cb->reset(i); +} + +int git_iterator_set_ignore_case(git_iterator *i, bool ignore_case) +{ + GIT_ASSERT(!iterator__has_been_accessed(i)); + iterator_set_ignore_case(i, ignore_case); + return 0; +} + +void git_iterator_free(git_iterator *iter) +{ + if (iter == NULL) + return; + + iter->cb->free(iter); + + git_vector_free(&iter->pathlist); + git__free(iter->start); + git__free(iter->end); + + memset(iter, 0, sizeof(*iter)); + + git__free(iter); +} + +int git_iterator_foreach( + git_iterator *iterator, + git_iterator_foreach_cb cb, + void *data) +{ + const git_index_entry *iterator_item; + int error = 0; + + if ((error = git_iterator_current(&iterator_item, iterator)) < 0) + goto done; + + if ((error = cb(iterator_item, data)) != 0) + goto done; + + while (true) { + if ((error = git_iterator_advance(&iterator_item, iterator)) < 0) + goto done; + + if ((error = cb(iterator_item, data)) != 0) + goto done; + } + +done: + if (error == GIT_ITEROVER) + error = 0; + + return error; +} + +int git_iterator_walk( + git_iterator **iterators, + size_t cnt, + git_iterator_walk_cb cb, + void *data) +{ + const git_index_entry **iterator_item; /* next in each iterator */ + const git_index_entry **cur_items; /* current path in each iter */ + const git_index_entry *first_match; + size_t i, j; + int error = 0; + + iterator_item = git__calloc(cnt, sizeof(git_index_entry *)); + cur_items = git__calloc(cnt, sizeof(git_index_entry *)); + + GIT_ERROR_CHECK_ALLOC(iterator_item); + GIT_ERROR_CHECK_ALLOC(cur_items); + + /* Set up the iterators */ + for (i = 0; i < cnt; i++) { + error = git_iterator_current(&iterator_item[i], iterators[i]); + + if (error < 0 && error != GIT_ITEROVER) + goto done; + } + + while (true) { + for (i = 0; i < cnt; i++) + cur_items[i] = NULL; + + first_match = NULL; + + /* Find the next path(s) to consume from each iterator */ + for (i = 0; i < cnt; i++) { + if (iterator_item[i] == NULL) + continue; + + if (first_match == NULL) { + first_match = iterator_item[i]; + cur_items[i] = iterator_item[i]; + } else { + int path_diff = git_index_entry_cmp(iterator_item[i], first_match); + + if (path_diff < 0) { + /* Found an index entry that sorts before the one we're + * looking at. Forget that we've seen the other and + * look at the other iterators for this path. + */ + for (j = 0; j < i; j++) + cur_items[j] = NULL; + + first_match = iterator_item[i]; + cur_items[i] = iterator_item[i]; + } else if (path_diff == 0) { + cur_items[i] = iterator_item[i]; + } + } + } + + if (first_match == NULL) + break; + + if ((error = cb(cur_items, data)) != 0) + goto done; + + /* Advance each iterator that participated */ + for (i = 0; i < cnt; i++) { + if (cur_items[i] == NULL) + continue; + + error = git_iterator_advance(&iterator_item[i], iterators[i]); + + if (error < 0 && error != GIT_ITEROVER) + goto done; + } + } + +done: + git__free((git_index_entry **)iterator_item); + git__free((git_index_entry **)cur_items); + + if (error == GIT_ITEROVER) + error = 0; + + return error; +} diff --git a/vendor/libgit2/src/iterator.h b/vendor/libgit2/src/libgit2/iterator.h similarity index 99% rename from vendor/libgit2/src/iterator.h rename to vendor/libgit2/src/libgit2/iterator.h index 6bb8489d..7963ce7e 100644 --- a/vendor/libgit2/src/iterator.h +++ b/vendor/libgit2/src/libgit2/iterator.h @@ -63,6 +63,9 @@ typedef struct { /* flags, from above */ unsigned int flags; + + /* oid type - necessary for non-workdir filesystem iterators */ + git_oid_t oid_type; } git_iterator_options; #define GIT_ITERATOR_OPTIONS_INIT {0} diff --git a/vendor/libgit2/src/libgit2/libgit2.c b/vendor/libgit2/src/libgit2/libgit2.c new file mode 100644 index 00000000..1b6f1a1f --- /dev/null +++ b/vendor/libgit2/src/libgit2/libgit2.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include "alloc.h" +#include "buf.h" +#include "common.h" +#include "filter.h" +#include "hash.h" +#include "merge_driver.h" +#include "pool.h" +#include "mwindow.h" +#include "oid.h" +#include "rand.h" +#include "runtime.h" +#include "settings.h" +#include "sysdir.h" +#include "thread.h" +#include "git2/global.h" +#include "streams/registry.h" +#include "streams/mbedtls.h" +#include "streams/openssl.h" +#include "streams/socket.h" +#include "transports/ssh_libssh2.h" + +#ifdef GIT_WIN32 +# include "win32/w32_leakcheck.h" +#endif + +int git_libgit2_init(void) +{ + static git_runtime_init_fn init_fns[] = { +#ifdef GIT_WIN32 + git_win32_leakcheck_global_init, +#endif + git_allocator_global_init, + git_error_global_init, + git_threads_global_init, + git_oid_global_init, + git_rand_global_init, + git_hash_global_init, + git_sysdir_global_init, + git_filter_global_init, + git_merge_driver_global_init, + git_transport_ssh_libssh2_global_init, + git_stream_registry_global_init, + git_socket_stream_global_init, + git_openssl_stream_global_init, + git_mbedtls_stream_global_init, + git_mwindow_global_init, + git_pool_global_init, + git_settings_global_init + }; + + return git_runtime_init(init_fns, ARRAY_SIZE(init_fns)); +} + +int git_libgit2_shutdown(void) +{ + return git_runtime_shutdown(); +} + +int git_libgit2_version(int *major, int *minor, int *rev) +{ + *major = LIBGIT2_VER_MAJOR; + *minor = LIBGIT2_VER_MINOR; + *rev = LIBGIT2_VER_REVISION; + + return 0; +} + +const char *git_libgit2_prerelease(void) +{ + return LIBGIT2_VER_PRERELEASE; +} + +int git_libgit2_features(void) +{ + return 0 +#ifdef GIT_THREADS + | GIT_FEATURE_THREADS +#endif +#ifdef GIT_HTTPS + | GIT_FEATURE_HTTPS +#endif +#ifdef GIT_SSH + | GIT_FEATURE_SSH +#endif +#ifdef GIT_USE_NSEC + | GIT_FEATURE_NSEC +#endif + ; +} diff --git a/vendor/libgit2/src/mailmap.c b/vendor/libgit2/src/libgit2/mailmap.c similarity index 100% rename from vendor/libgit2/src/mailmap.c rename to vendor/libgit2/src/libgit2/mailmap.c diff --git a/vendor/libgit2/src/mailmap.h b/vendor/libgit2/src/libgit2/mailmap.h similarity index 100% rename from vendor/libgit2/src/mailmap.h rename to vendor/libgit2/src/libgit2/mailmap.h diff --git a/vendor/libgit2/src/libgit2/merge.c b/vendor/libgit2/src/libgit2/merge.c new file mode 100644 index 00000000..21e5ef6a --- /dev/null +++ b/vendor/libgit2/src/libgit2/merge.c @@ -0,0 +1,3447 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "merge.h" + +#include "posix.h" +#include "str.h" +#include "repository.h" +#include "revwalk.h" +#include "commit_list.h" +#include "fs_path.h" +#include "refs.h" +#include "object.h" +#include "iterator.h" +#include "refs.h" +#include "diff.h" +#include "diff_generate.h" +#include "diff_tform.h" +#include "checkout.h" +#include "tree.h" +#include "blob.h" +#include "oid.h" +#include "index.h" +#include "filebuf.h" +#include "config.h" +#include "oidarray.h" +#include "annotated_commit.h" +#include "commit.h" +#include "oidarray.h" +#include "merge_driver.h" +#include "oidmap.h" +#include "array.h" + +#include "git2/types.h" +#include "git2/repository.h" +#include "git2/object.h" +#include "git2/commit.h" +#include "git2/merge.h" +#include "git2/refs.h" +#include "git2/reset.h" +#include "git2/checkout.h" +#include "git2/signature.h" +#include "git2/config.h" +#include "git2/tree.h" +#include "git2/oidarray.h" +#include "git2/annotated_commit.h" +#include "git2/sys/index.h" +#include "git2/sys/hashsig.h" + +#define GIT_MERGE_INDEX_ENTRY_EXISTS(X) ((X).mode != 0) +#define GIT_MERGE_INDEX_ENTRY_ISFILE(X) S_ISREG((X).mode) + + +typedef enum { + TREE_IDX_ANCESTOR = 0, + TREE_IDX_OURS = 1, + TREE_IDX_THEIRS = 2 +} merge_tree_index_t; + +/* Tracks D/F conflicts */ +struct merge_diff_df_data { + const char *df_path; + const char *prev_path; + git_merge_diff *prev_conflict; +}; + +/* + * This acts as a negative cache entry marker. In case we've tried to calculate + * similarity metrics for a given blob already but `git_hashsig` determined + * that it's too small in order to have a meaningful hash signature, we will + * insert the address of this marker instead of `NULL`. Like this, we can + * easily check whether we have checked a gien entry already and skip doing the + * calculation again and again. + */ +static int cache_invalid_marker; + +/* Merge base computation */ + +static int merge_bases_many(git_commit_list **out, git_revwalk **walk_out, git_repository *repo, size_t length, const git_oid input_array[]) +{ + git_revwalk *walk = NULL; + git_vector list; + git_commit_list *result = NULL; + git_commit_list_node *commit; + int error = -1; + unsigned int i; + + if (length < 2) { + git_error_set(GIT_ERROR_INVALID, "at least two commits are required to find an ancestor"); + return -1; + } + + if (git_vector_init(&list, length - 1, NULL) < 0) + return -1; + + if (git_revwalk_new(&walk, repo) < 0) + goto on_error; + + for (i = 1; i < length; i++) { + commit = git_revwalk__commit_lookup(walk, &input_array[i]); + if (commit == NULL) + goto on_error; + + git_vector_insert(&list, commit); + } + + commit = git_revwalk__commit_lookup(walk, &input_array[0]); + if (commit == NULL) + goto on_error; + + if (git_merge__bases_many(&result, walk, commit, &list, 0) < 0) + goto on_error; + + if (!result) { + git_error_set(GIT_ERROR_MERGE, "no merge base found"); + error = GIT_ENOTFOUND; + goto on_error; + } + + *out = result; + *walk_out = walk; + + git_vector_free(&list); + return 0; + +on_error: + git_vector_free(&list); + git_revwalk_free(walk); + return error; +} + +int git_merge_base_many(git_oid *out, git_repository *repo, size_t length, const git_oid input_array[]) +{ + git_revwalk *walk; + git_commit_list *result = NULL; + int error = 0; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(input_array); + + if ((error = merge_bases_many(&result, &walk, repo, length, input_array)) < 0) + return error; + + git_oid_cpy(out, &result->item->oid); + + git_commit_list_free(&result); + git_revwalk_free(walk); + + return 0; +} + +int git_merge_bases_many(git_oidarray *out, git_repository *repo, size_t length, const git_oid input_array[]) +{ + git_revwalk *walk; + git_commit_list *list, *result = NULL; + int error = 0; + git_array_oid_t array; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(input_array); + + if ((error = merge_bases_many(&result, &walk, repo, length, input_array)) < 0) + return error; + + git_array_init(array); + + list = result; + while (list) { + git_oid *id = git_array_alloc(array); + if (id == NULL) { + error = -1; + goto cleanup; + } + + git_oid_cpy(id, &list->item->oid); + list = list->next; + } + + git_oidarray__from_array(out, &array); + +cleanup: + git_commit_list_free(&result); + git_revwalk_free(walk); + + return error; +} + +int git_merge_base_octopus(git_oid *out, git_repository *repo, size_t length, const git_oid input_array[]) +{ + git_oid result; + unsigned int i; + int error = -1; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(input_array); + + if (length < 2) { + git_error_set(GIT_ERROR_INVALID, "at least two commits are required to find an ancestor"); + return -1; + } + + result = input_array[0]; + for (i = 1; i < length; i++) { + error = git_merge_base(&result, repo, &result, &input_array[i]); + if (error < 0) + return error; + } + + *out = result; + + return 0; +} + +static int merge_bases(git_commit_list **out, git_revwalk **walk_out, git_repository *repo, const git_oid *one, const git_oid *two) +{ + git_revwalk *walk; + git_vector list; + git_commit_list *result = NULL; + git_commit_list_node *commit; + void *contents[1]; + + if (git_revwalk_new(&walk, repo) < 0) + return -1; + + commit = git_revwalk__commit_lookup(walk, two); + if (commit == NULL) + goto on_error; + + /* This is just one value, so we can do it on the stack */ + memset(&list, 0x0, sizeof(git_vector)); + contents[0] = commit; + list.length = 1; + list.contents = contents; + + commit = git_revwalk__commit_lookup(walk, one); + if (commit == NULL) + goto on_error; + + if (git_merge__bases_many(&result, walk, commit, &list, 0) < 0) + goto on_error; + + if (!result) { + git_revwalk_free(walk); + git_error_set(GIT_ERROR_MERGE, "no merge base found"); + return GIT_ENOTFOUND; + } + + *out = result; + *walk_out = walk; + + return 0; + +on_error: + git_revwalk_free(walk); + return -1; + +} + +int git_merge_base(git_oid *out, git_repository *repo, const git_oid *one, const git_oid *two) +{ + int error; + git_revwalk *walk; + git_commit_list *result; + + if ((error = merge_bases(&result, &walk, repo, one, two)) < 0) + return error; + + git_oid_cpy(out, &result->item->oid); + git_commit_list_free(&result); + git_revwalk_free(walk); + + return 0; +} + +int git_merge_bases(git_oidarray *out, git_repository *repo, const git_oid *one, const git_oid *two) +{ + int error; + git_revwalk *walk; + git_commit_list *result, *list; + git_array_oid_t array; + + git_array_init(array); + + if ((error = merge_bases(&result, &walk, repo, one, two)) < 0) + return error; + + list = result; + while (list) { + git_oid *id = git_array_alloc(array); + if (id == NULL) + goto on_error; + + git_oid_cpy(id, &list->item->oid); + list = list->next; + } + + git_oidarray__from_array(out, &array); + git_commit_list_free(&result); + git_revwalk_free(walk); + + return 0; + +on_error: + git_commit_list_free(&result); + git_revwalk_free(walk); + return -1; +} + +static int interesting(git_pqueue *list) +{ + size_t i; + + for (i = 0; i < git_pqueue_size(list); i++) { + git_commit_list_node *commit = git_pqueue_get(list, i); + if ((commit->flags & STALE) == 0) + return 1; + } + + return 0; +} + +static int clear_commit_marks_1(git_commit_list **plist, + git_commit_list_node *commit, unsigned int mark) +{ + while (commit) { + unsigned int i; + + if (!(mark & commit->flags)) + return 0; + + commit->flags &= ~mark; + + for (i = 1; i < commit->out_degree; i++) { + git_commit_list_node *p = commit->parents[i]; + if (git_commit_list_insert(p, plist) == NULL) + return -1; + } + + commit = commit->out_degree ? commit->parents[0] : NULL; + } + + return 0; +} + +static int clear_commit_marks_many(git_vector *commits, unsigned int mark) +{ + git_commit_list *list = NULL; + git_commit_list_node *c; + unsigned int i; + + git_vector_foreach(commits, i, c) { + if (git_commit_list_insert(c, &list) == NULL) + return -1; + } + + while (list) + if (clear_commit_marks_1(&list, git_commit_list_pop(&list), mark) < 0) + return -1; + return 0; +} + +static int clear_commit_marks(git_commit_list_node *commit, unsigned int mark) +{ + git_commit_list *list = NULL; + if (git_commit_list_insert(commit, &list) == NULL) + return -1; + while (list) + if (clear_commit_marks_1(&list, git_commit_list_pop(&list), mark) < 0) + return -1; + return 0; +} + +static int paint_down_to_common( + git_commit_list **out, + git_revwalk *walk, + git_commit_list_node *one, + git_vector *twos, + uint32_t minimum_generation) +{ + git_pqueue list; + git_commit_list *result = NULL; + git_commit_list_node *two; + + int error; + unsigned int i; + + if (git_pqueue_init(&list, 0, twos->length * 2, git_commit_list_generation_cmp) < 0) + return -1; + + one->flags |= PARENT1; + if (git_pqueue_insert(&list, one) < 0) + return -1; + + git_vector_foreach(twos, i, two) { + if (git_commit_list_parse(walk, two) < 0) + return -1; + + two->flags |= PARENT2; + if (git_pqueue_insert(&list, two) < 0) + return -1; + } + + /* as long as there are non-STALE commits */ + while (interesting(&list)) { + git_commit_list_node *commit = git_pqueue_pop(&list); + int flags; + + if (commit == NULL) + break; + + flags = commit->flags & (PARENT1 | PARENT2 | STALE); + if (flags == (PARENT1 | PARENT2)) { + if (!(commit->flags & RESULT)) { + commit->flags |= RESULT; + if (git_commit_list_insert(commit, &result) == NULL) + return -1; + } + /* we mark the parents of a merge stale */ + flags |= STALE; + } + + for (i = 0; i < commit->out_degree; i++) { + git_commit_list_node *p = commit->parents[i]; + if ((p->flags & flags) == flags) + continue; + if (p->generation < minimum_generation) + continue; + + if ((error = git_commit_list_parse(walk, p)) < 0) + return error; + + p->flags |= flags; + if (git_pqueue_insert(&list, p) < 0) + return -1; + } + } + + git_pqueue_free(&list); + *out = result; + return 0; +} + +static int remove_redundant(git_revwalk *walk, git_vector *commits, uint32_t minimum_generation) +{ + git_vector work = GIT_VECTOR_INIT; + unsigned char *redundant; + unsigned int *filled_index; + unsigned int i, j; + int error = 0; + + redundant = git__calloc(commits->length, 1); + GIT_ERROR_CHECK_ALLOC(redundant); + filled_index = git__calloc((commits->length - 1), sizeof(unsigned int)); + GIT_ERROR_CHECK_ALLOC(filled_index); + + for (i = 0; i < commits->length; ++i) { + if ((error = git_commit_list_parse(walk, commits->contents[i])) < 0) + goto done; + } + + for (i = 0; i < commits->length; ++i) { + git_commit_list *common = NULL; + git_commit_list_node *commit = commits->contents[i]; + + if (redundant[i]) + continue; + + git_vector_clear(&work); + + for (j = 0; j < commits->length; j++) { + if (i == j || redundant[j]) + continue; + + filled_index[work.length] = j; + if ((error = git_vector_insert(&work, commits->contents[j])) < 0) + goto done; + } + + error = paint_down_to_common(&common, walk, commit, &work, minimum_generation); + if (error < 0) + goto done; + + if (commit->flags & PARENT2) + redundant[i] = 1; + + for (j = 0; j < work.length; j++) { + git_commit_list_node *w = work.contents[j]; + if (w->flags & PARENT1) + redundant[filled_index[j]] = 1; + } + + git_commit_list_free(&common); + + if ((error = clear_commit_marks(commit, ALL_FLAGS)) < 0 || + (error = clear_commit_marks_many(&work, ALL_FLAGS)) < 0) + goto done; + } + + for (i = 0; i < commits->length; ++i) { + if (redundant[i]) + commits->contents[i] = NULL; + } + +done: + git__free(redundant); + git__free(filled_index); + git_vector_free(&work); + return error; +} + +int git_merge__bases_many( + git_commit_list **out, + git_revwalk *walk, + git_commit_list_node *one, + git_vector *twos, + uint32_t minimum_generation) +{ + int error; + unsigned int i; + git_commit_list_node *two; + git_commit_list *result = NULL, *tmp = NULL; + + /* If there's only the one commit, there can be no merge bases */ + if (twos->length == 0) { + *out = NULL; + return 0; + } + + /* if the commit is repeated, we have a our merge base already */ + git_vector_foreach(twos, i, two) { + if (one == two) + return git_commit_list_insert(one, out) ? 0 : -1; + } + + if (git_commit_list_parse(walk, one) < 0) + return -1; + + error = paint_down_to_common(&result, walk, one, twos, minimum_generation); + if (error < 0) + return error; + + /* filter out any stale commits in the results */ + tmp = result; + result = NULL; + + while (tmp) { + git_commit_list_node *c = git_commit_list_pop(&tmp); + if (!(c->flags & STALE)) + if (git_commit_list_insert_by_date(c, &result) == NULL) + return -1; + } + + /* + * more than one merge base -- see if there are redundant merge + * bases and remove them + */ + if (result && result->next) { + git_vector redundant = GIT_VECTOR_INIT; + + while (result) + git_vector_insert(&redundant, git_commit_list_pop(&result)); + + if ((error = clear_commit_marks(one, ALL_FLAGS)) < 0 || + (error = clear_commit_marks_many(twos, ALL_FLAGS)) < 0 || + (error = remove_redundant(walk, &redundant, minimum_generation)) < 0) { + git_vector_free(&redundant); + return error; + } + + git_vector_foreach(&redundant, i, two) { + if (two != NULL) + git_commit_list_insert_by_date(two, &result); + } + + git_vector_free(&redundant); + } + + *out = result; + return 0; +} + +int git_repository_mergehead_foreach( + git_repository *repo, + git_repository_mergehead_foreach_cb cb, + void *payload) +{ + git_str merge_head_path = GIT_STR_INIT, merge_head_file = GIT_STR_INIT; + char *buffer, *line; + size_t line_num = 1; + git_oid oid; + int error = 0; + + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(cb); + + if ((error = git_str_joinpath(&merge_head_path, repo->gitdir, + GIT_MERGE_HEAD_FILE)) < 0) + return error; + + if ((error = git_futils_readbuffer(&merge_head_file, + git_str_cstr(&merge_head_path))) < 0) + goto cleanup; + + buffer = merge_head_file.ptr; + + while ((line = git__strsep(&buffer, "\n")) != NULL) { + if (strlen(line) != git_oid_hexsize(repo->oid_type)) { + git_error_set(GIT_ERROR_INVALID, "unable to parse OID - invalid length"); + error = -1; + goto cleanup; + } + + if ((error = git_oid__fromstr(&oid, line, repo->oid_type)) < 0) + goto cleanup; + + if ((error = cb(&oid, payload)) != 0) { + git_error_set_after_callback(error); + goto cleanup; + } + + ++line_num; + } + + if (*buffer) { + git_error_set(GIT_ERROR_MERGE, "no EOL at line %"PRIuZ, line_num); + error = -1; + goto cleanup; + } + +cleanup: + git_str_dispose(&merge_head_path); + git_str_dispose(&merge_head_file); + + return error; +} + +GIT_INLINE(int) index_entry_cmp(const git_index_entry *a, const git_index_entry *b) +{ + int value = 0; + + if (a->path == NULL) + return (b->path == NULL) ? 0 : 1; + + if ((value = a->mode - b->mode) == 0 && + (value = git_oid__cmp(&a->id, &b->id)) == 0) + value = strcmp(a->path, b->path); + + return value; +} + +/* Conflict resolution */ + +static int merge_conflict_resolve_trivial( + int *resolved, + git_merge_diff_list *diff_list, + const git_merge_diff *conflict) +{ + int ours_empty, theirs_empty; + int ours_changed, theirs_changed, ours_theirs_differ; + git_index_entry const *result = NULL; + int error = 0; + + GIT_ASSERT_ARG(resolved); + GIT_ASSERT_ARG(diff_list); + GIT_ASSERT_ARG(conflict); + + *resolved = 0; + + if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE || + conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) + return 0; + + if (conflict->our_status == GIT_DELTA_RENAMED || + conflict->their_status == GIT_DELTA_RENAMED) + return 0; + + ours_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry); + theirs_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry); + + ours_changed = (conflict->our_status != GIT_DELTA_UNMODIFIED); + theirs_changed = (conflict->their_status != GIT_DELTA_UNMODIFIED); + ours_theirs_differ = ours_changed && theirs_changed && + index_entry_cmp(&conflict->our_entry, &conflict->their_entry); + + /* + * Note: with only one ancestor, some cases are not distinct: + * + * 16: ancest:anc1/anc2, head:anc1, remote:anc2 = result:no merge + * 3: ancest:(empty)^, head:head, remote:(empty) = result:no merge + * 2: ancest:(empty)^, head:(empty), remote:remote = result:no merge + * + * Note that the two cases that take D/F conflicts into account + * specifically do not need to be explicitly tested, as D/F conflicts + * would fail the *empty* test: + * + * 3ALT: ancest:(empty)+, head:head, remote:*empty* = result:head + * 2ALT: ancest:(empty)+, head:*empty*, remote:remote = result:remote + * + * Note that many of these cases need not be explicitly tested, as + * they simply degrade to "all different" cases (eg, 11): + * + * 4: ancest:(empty)^, head:head, remote:remote = result:no merge + * 7: ancest:ancest+, head:(empty), remote:remote = result:no merge + * 9: ancest:ancest+, head:head, remote:(empty) = result:no merge + * 11: ancest:ancest+, head:head, remote:remote = result:no merge + */ + + /* 5ALT: ancest:*, head:head, remote:head = result:head */ + if (ours_changed && !ours_empty && !ours_theirs_differ) + result = &conflict->our_entry; + /* 6: ancest:ancest+, head:(empty), remote:(empty) = result:no merge */ + else if (ours_changed && ours_empty && theirs_empty) + *resolved = 0; + /* 8: ancest:ancest^, head:(empty), remote:ancest = result:no merge */ + else if (ours_empty && !theirs_changed) + *resolved = 0; + /* 10: ancest:ancest^, head:ancest, remote:(empty) = result:no merge */ + else if (!ours_changed && theirs_empty) + *resolved = 0; + /* 13: ancest:ancest+, head:head, remote:ancest = result:head */ + else if (ours_changed && !theirs_changed) + result = &conflict->our_entry; + /* 14: ancest:ancest+, head:ancest, remote:remote = result:remote */ + else if (!ours_changed && theirs_changed) + result = &conflict->their_entry; + else + *resolved = 0; + + if (result != NULL && + GIT_MERGE_INDEX_ENTRY_EXISTS(*result) && + (error = git_vector_insert(&diff_list->staged, (void *)result)) >= 0) + *resolved = 1; + + /* Note: trivial resolution does not update the REUC. */ + + return error; +} + +static int merge_conflict_resolve_one_removed( + int *resolved, + git_merge_diff_list *diff_list, + const git_merge_diff *conflict) +{ + int ours_empty, theirs_empty; + int ours_changed, theirs_changed; + int error = 0; + + GIT_ASSERT_ARG(resolved); + GIT_ASSERT_ARG(diff_list); + GIT_ASSERT_ARG(conflict); + + *resolved = 0; + + if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE || + conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) + return 0; + + ours_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry); + theirs_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry); + + ours_changed = (conflict->our_status != GIT_DELTA_UNMODIFIED); + theirs_changed = (conflict->their_status != GIT_DELTA_UNMODIFIED); + + /* Removed in both */ + if (ours_changed && ours_empty && theirs_empty) + *resolved = 1; + /* Removed in ours */ + else if (ours_empty && !theirs_changed) + *resolved = 1; + /* Removed in theirs */ + else if (!ours_changed && theirs_empty) + *resolved = 1; + + if (*resolved) + git_vector_insert(&diff_list->resolved, (git_merge_diff *)conflict); + + return error; +} + +static int merge_conflict_resolve_one_renamed( + int *resolved, + git_merge_diff_list *diff_list, + const git_merge_diff *conflict) +{ + int ours_renamed, theirs_renamed; + int ours_changed, theirs_changed; + git_index_entry *merged; + int error = 0; + + GIT_ASSERT_ARG(resolved); + GIT_ASSERT_ARG(diff_list); + GIT_ASSERT_ARG(conflict); + + *resolved = 0; + + if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) || + !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry)) + return 0; + + ours_renamed = (conflict->our_status == GIT_DELTA_RENAMED); + theirs_renamed = (conflict->their_status == GIT_DELTA_RENAMED); + + if (!ours_renamed && !theirs_renamed) + return 0; + + /* Reject one file in a 2->1 conflict */ + if (conflict->type == GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1 || + conflict->type == GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2 || + conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) + return 0; + + ours_changed = (git_oid__cmp(&conflict->ancestor_entry.id, &conflict->our_entry.id) != 0) || + (conflict->ancestor_entry.mode != conflict->our_entry.mode); + + theirs_changed = (git_oid__cmp(&conflict->ancestor_entry.id, &conflict->their_entry.id) != 0) || + (conflict->ancestor_entry.mode != conflict->their_entry.mode); + + /* if both are modified (and not to a common target) require a merge */ + if (ours_changed && theirs_changed && + git_oid__cmp(&conflict->our_entry.id, &conflict->their_entry.id) != 0) + return 0; + + if ((merged = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry))) == NULL) + return -1; + + if (ours_changed) + memcpy(merged, &conflict->our_entry, sizeof(git_index_entry)); + else + memcpy(merged, &conflict->their_entry, sizeof(git_index_entry)); + + if (ours_renamed) + merged->path = conflict->our_entry.path; + else + merged->path = conflict->their_entry.path; + + *resolved = 1; + + git_vector_insert(&diff_list->staged, merged); + git_vector_insert(&diff_list->resolved, (git_merge_diff *)conflict); + + return error; +} + +static bool merge_conflict_can_resolve_contents( + const git_merge_diff *conflict) +{ + if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) || + !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry)) + return false; + + /* Reject D/F conflicts */ + if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE) + return false; + + /* Reject submodules. */ + if (S_ISGITLINK(conflict->ancestor_entry.mode) || + S_ISGITLINK(conflict->our_entry.mode) || + S_ISGITLINK(conflict->their_entry.mode)) + return false; + + /* Reject link/file conflicts. */ + if ((S_ISLNK(conflict->ancestor_entry.mode) ^ + S_ISLNK(conflict->our_entry.mode)) || + (S_ISLNK(conflict->ancestor_entry.mode) ^ + S_ISLNK(conflict->their_entry.mode))) + return false; + + /* Reject name conflicts */ + if (conflict->type == GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1 || + conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) + return false; + + if ((conflict->our_status & GIT_DELTA_RENAMED) == GIT_DELTA_RENAMED && + (conflict->their_status & GIT_DELTA_RENAMED) == GIT_DELTA_RENAMED && + strcmp(conflict->ancestor_entry.path, conflict->their_entry.path) != 0) + return false; + + return true; +} + +static int merge_conflict_invoke_driver( + git_index_entry **out, + const char *name, + git_merge_driver *driver, + git_merge_diff_list *diff_list, + git_merge_driver_source *src) +{ + git_index_entry *result; + git_buf buf = {0}; + const char *path; + uint32_t mode; + git_odb *odb = NULL; + git_oid oid; + int error; + + *out = NULL; + + if ((error = driver->apply(driver, &path, &mode, &buf, name, src)) < 0 || + (error = git_repository_odb(&odb, src->repo)) < 0 || + (error = git_odb_write(&oid, odb, buf.ptr, buf.size, GIT_OBJECT_BLOB)) < 0) + goto done; + + result = git_pool_mallocz(&diff_list->pool, sizeof(git_index_entry)); + GIT_ERROR_CHECK_ALLOC(result); + + git_oid_cpy(&result->id, &oid); + result->mode = mode; + result->file_size = (uint32_t)buf.size; + + result->path = git_pool_strdup(&diff_list->pool, path); + GIT_ERROR_CHECK_ALLOC(result->path); + + *out = result; + +done: + git_buf_dispose(&buf); + git_odb_free(odb); + + return error; +} + +static int merge_conflict_resolve_contents( + int *resolved, + git_merge_diff_list *diff_list, + const git_merge_diff *conflict, + const git_merge_options *merge_opts, + const git_merge_file_options *file_opts) +{ + git_merge_driver_source source = {0}; + git_merge_file_result result = {0}; + git_merge_driver *driver; + git_merge_driver__builtin builtin = {{0}}; + git_index_entry *merge_result; + git_odb *odb = NULL; + const char *name; + bool fallback = false; + int error; + + GIT_ASSERT_ARG(resolved); + GIT_ASSERT_ARG(diff_list); + GIT_ASSERT_ARG(conflict); + + *resolved = 0; + + if (!merge_conflict_can_resolve_contents(conflict)) + return 0; + + source.repo = diff_list->repo; + source.default_driver = merge_opts->default_driver; + source.file_opts = file_opts; + source.ancestor = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) ? + &conflict->ancestor_entry : NULL; + source.ours = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ? + &conflict->our_entry : NULL; + source.theirs = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ? + &conflict->their_entry : NULL; + + if (file_opts->favor != GIT_MERGE_FILE_FAVOR_NORMAL) { + /* if the user requested a particular type of resolution (via the + * favor flag) then let that override the gitattributes and use + * the builtin driver. + */ + name = "text"; + builtin.base.apply = git_merge_driver__builtin_apply; + builtin.favor = file_opts->favor; + + driver = &builtin.base; + } else { + /* find the merge driver for this file */ + if ((error = git_merge_driver_for_source(&name, &driver, &source)) < 0) + goto done; + + if (driver == NULL) + fallback = true; + } + + if (driver) { + error = merge_conflict_invoke_driver(&merge_result, name, driver, + diff_list, &source); + + if (error == GIT_PASSTHROUGH) + fallback = true; + } + + if (fallback) { + error = merge_conflict_invoke_driver(&merge_result, "text", + &git_merge_driver__text.base, diff_list, &source); + } + + if (error < 0) { + if (error == GIT_EMERGECONFLICT) + error = 0; + + goto done; + } + + git_vector_insert(&diff_list->staged, merge_result); + git_vector_insert(&diff_list->resolved, (git_merge_diff *)conflict); + + *resolved = 1; + +done: + git_merge_file_result_free(&result); + git_odb_free(odb); + + return error; +} + +static int merge_conflict_resolve( + int *out, + git_merge_diff_list *diff_list, + const git_merge_diff *conflict, + const git_merge_options *merge_opts, + const git_merge_file_options *file_opts) +{ + int resolved = 0; + int error = 0; + + *out = 0; + + if ((error = merge_conflict_resolve_trivial( + &resolved, diff_list, conflict)) < 0) + goto done; + + if (!resolved && (error = merge_conflict_resolve_one_removed( + &resolved, diff_list, conflict)) < 0) + goto done; + + if (!resolved && (error = merge_conflict_resolve_one_renamed( + &resolved, diff_list, conflict)) < 0) + goto done; + + if (!resolved && (error = merge_conflict_resolve_contents( + &resolved, diff_list, conflict, merge_opts, file_opts)) < 0) + goto done; + + *out = resolved; + +done: + return error; +} + +/* Rename detection and coalescing */ + +struct merge_diff_similarity { + unsigned char similarity; + size_t other_idx; +}; + +static int index_entry_similarity_calc( + void **out, + git_repository *repo, + git_index_entry *entry, + const git_merge_options *opts) +{ + git_blob *blob; + git_diff_file diff_file; + git_object_size_t blobsize; + int error; + + if (*out || *out == &cache_invalid_marker) + return 0; + + *out = NULL; + + git_oid_clear(&diff_file.id, repo->oid_type); + + if ((error = git_blob_lookup(&blob, repo, &entry->id)) < 0) + return error; + + git_oid_cpy(&diff_file.id, &entry->id); + diff_file.path = entry->path; + diff_file.size = entry->file_size; + diff_file.mode = entry->mode; + diff_file.flags = 0; + + blobsize = git_blob_rawsize(blob); + + /* file too big for rename processing */ + if (!git__is_sizet(blobsize)) + return 0; + + error = opts->metric->buffer_signature(out, &diff_file, + git_blob_rawcontent(blob), (size_t)blobsize, + opts->metric->payload); + if (error == GIT_EBUFS) + *out = &cache_invalid_marker; + + git_blob_free(blob); + + return error; +} + +static int index_entry_similarity_inexact( + git_repository *repo, + git_index_entry *a, + size_t a_idx, + git_index_entry *b, + size_t b_idx, + void **cache, + const git_merge_options *opts) +{ + int score = 0; + int error = 0; + + if (!GIT_MODE_ISBLOB(a->mode) || !GIT_MODE_ISBLOB(b->mode)) + return 0; + + /* update signature cache if needed */ + if ((error = index_entry_similarity_calc(&cache[a_idx], repo, a, opts)) < 0 || + (error = index_entry_similarity_calc(&cache[b_idx], repo, b, opts)) < 0) + return error; + + /* some metrics may not wish to process this file (too big / too small) */ + if (cache[a_idx] == &cache_invalid_marker || cache[b_idx] == &cache_invalid_marker) + return 0; + + /* compare signatures */ + if (opts->metric->similarity(&score, cache[a_idx], cache[b_idx], opts->metric->payload) < 0) + return -1; + + /* clip score */ + if (score < 0) + score = 0; + else if (score > 100) + score = 100; + + return score; +} + +/* Tracks deletes by oid for merge_diff_mark_similarity_exact(). This is a +* non-shrinking queue where next_pos is the next position to dequeue. +*/ +typedef struct { + git_array_t(size_t) arr; + size_t next_pos; + size_t first_entry; +} deletes_by_oid_queue; + +static void deletes_by_oid_free(git_oidmap *map) { + deletes_by_oid_queue *queue; + + if (!map) + return; + + git_oidmap_foreach_value(map, queue, { + git_array_clear(queue->arr); + }); + git_oidmap_free(map); +} + +static int deletes_by_oid_enqueue(git_oidmap *map, git_pool *pool, const git_oid *id, size_t idx) +{ + deletes_by_oid_queue *queue; + size_t *array_entry; + + if ((queue = git_oidmap_get(map, id)) == NULL) { + queue = git_pool_malloc(pool, sizeof(deletes_by_oid_queue)); + GIT_ERROR_CHECK_ALLOC(queue); + + git_array_init(queue->arr); + queue->next_pos = 0; + queue->first_entry = idx; + + if (git_oidmap_set(map, id, queue) < 0) + return -1; + } else { + array_entry = git_array_alloc(queue->arr); + GIT_ERROR_CHECK_ALLOC(array_entry); + *array_entry = idx; + } + + return 0; +} + +static int deletes_by_oid_dequeue(size_t *idx, git_oidmap *map, const git_oid *id) +{ + deletes_by_oid_queue *queue; + size_t *array_entry; + + if ((queue = git_oidmap_get(map, id)) == NULL) + return GIT_ENOTFOUND; + + if (queue->next_pos == 0) { + *idx = queue->first_entry; + } else { + array_entry = git_array_get(queue->arr, queue->next_pos - 1); + if (array_entry == NULL) + return GIT_ENOTFOUND; + + *idx = *array_entry; + } + + queue->next_pos++; + return 0; +} + +static int merge_diff_mark_similarity_exact( + git_merge_diff_list *diff_list, + struct merge_diff_similarity *similarity_ours, + struct merge_diff_similarity *similarity_theirs) +{ + size_t i, j; + git_merge_diff *conflict_src, *conflict_tgt; + git_oidmap *ours_deletes_by_oid = NULL, *theirs_deletes_by_oid = NULL; + int error = 0; + + if (git_oidmap_new(&ours_deletes_by_oid) < 0 || + git_oidmap_new(&theirs_deletes_by_oid) < 0) { + error = -1; + goto done; + } + + /* Build a map of object ids to conflicts */ + git_vector_foreach(&diff_list->conflicts, i, conflict_src) { + /* Items can be the source of a rename iff they have an item in the + * ancestor slot and lack an item in the ours or theirs slot. */ + if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->ancestor_entry)) + continue; + + /* + * Ignore empty files because it has always the same blob sha1 + * and will lead to incorrect matches between all entries. + */ + if (git_oid_equal(&conflict_src->ancestor_entry.id, &git_oid__empty_blob_sha1)) + continue; + + if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->our_entry)) { + error = deletes_by_oid_enqueue(ours_deletes_by_oid, &diff_list->pool, &conflict_src->ancestor_entry.id, i); + if (error < 0) + goto done; + } + + if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->their_entry)) { + error = deletes_by_oid_enqueue(theirs_deletes_by_oid, &diff_list->pool, &conflict_src->ancestor_entry.id, i); + if (error < 0) + goto done; + } + } + + git_vector_foreach(&diff_list->conflicts, j, conflict_tgt) { + if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->ancestor_entry)) + continue; + + if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->our_entry)) { + if (deletes_by_oid_dequeue(&i, ours_deletes_by_oid, &conflict_tgt->our_entry.id) == 0) { + similarity_ours[i].similarity = 100; + similarity_ours[i].other_idx = j; + + similarity_ours[j].similarity = 100; + similarity_ours[j].other_idx = i; + } + } + + if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->their_entry)) { + if (deletes_by_oid_dequeue(&i, theirs_deletes_by_oid, &conflict_tgt->their_entry.id) == 0) { + similarity_theirs[i].similarity = 100; + similarity_theirs[i].other_idx = j; + + similarity_theirs[j].similarity = 100; + similarity_theirs[j].other_idx = i; + } + } + } + +done: + deletes_by_oid_free(ours_deletes_by_oid); + deletes_by_oid_free(theirs_deletes_by_oid); + + return error; +} + +static int merge_diff_mark_similarity_inexact( + git_repository *repo, + git_merge_diff_list *diff_list, + struct merge_diff_similarity *similarity_ours, + struct merge_diff_similarity *similarity_theirs, + void **cache, + const git_merge_options *opts) +{ + size_t i, j; + git_merge_diff *conflict_src, *conflict_tgt; + int similarity; + + git_vector_foreach(&diff_list->conflicts, i, conflict_src) { + /* Items can be the source of a rename iff they have an item in the + * ancestor slot and lack an item in the ours or theirs slot. */ + if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->ancestor_entry) || + (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->our_entry) && + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->their_entry))) + continue; + + git_vector_foreach(&diff_list->conflicts, j, conflict_tgt) { + size_t our_idx = diff_list->conflicts.length + j; + size_t their_idx = (diff_list->conflicts.length * 2) + j; + + if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->ancestor_entry)) + continue; + + if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->our_entry) && + !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->our_entry)) { + similarity = index_entry_similarity_inexact(repo, &conflict_src->ancestor_entry, i, &conflict_tgt->our_entry, our_idx, cache, opts); + + if (similarity == GIT_EBUFS) + continue; + else if (similarity < 0) + return similarity; + + if (similarity > similarity_ours[i].similarity && + similarity > similarity_ours[j].similarity) { + /* Clear previous best similarity */ + if (similarity_ours[i].similarity > 0) + similarity_ours[similarity_ours[i].other_idx].similarity = 0; + + if (similarity_ours[j].similarity > 0) + similarity_ours[similarity_ours[j].other_idx].similarity = 0; + + similarity_ours[i].similarity = similarity; + similarity_ours[i].other_idx = j; + + similarity_ours[j].similarity = similarity; + similarity_ours[j].other_idx = i; + } + } + + if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->their_entry) && + !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->their_entry)) { + similarity = index_entry_similarity_inexact(repo, &conflict_src->ancestor_entry, i, &conflict_tgt->their_entry, their_idx, cache, opts); + + if (similarity > similarity_theirs[i].similarity && + similarity > similarity_theirs[j].similarity) { + /* Clear previous best similarity */ + if (similarity_theirs[i].similarity > 0) + similarity_theirs[similarity_theirs[i].other_idx].similarity = 0; + + if (similarity_theirs[j].similarity > 0) + similarity_theirs[similarity_theirs[j].other_idx].similarity = 0; + + similarity_theirs[i].similarity = similarity; + similarity_theirs[i].other_idx = j; + + similarity_theirs[j].similarity = similarity; + similarity_theirs[j].other_idx = i; + } + } + } + } + + return 0; +} + +/* + * Rename conflicts: + * + * Ancestor Ours Theirs + * + * 0a A A A No rename + * b A A* A No rename (ours was rewritten) + * c A A A* No rename (theirs rewritten) + * 1a A A B[A] Rename or rename/edit + * b A B[A] A (automergeable) + * 2 A B[A] B[A] Both renamed (automergeable) + * 3a A B[A] Rename/delete + * b A B[A] (same) + * 4a A B[A] B Rename/add [B~ours B~theirs] + * b A B B[A] (same) + * 5 A B[A] C[A] Both renamed ("1 -> 2") + * 6 A C[A] Both renamed ("2 -> 1") + * B C[B] [C~ours C~theirs] (automergeable) + */ +static void merge_diff_mark_rename_conflict( + git_merge_diff_list *diff_list, + struct merge_diff_similarity *similarity_ours, + bool ours_renamed, + size_t ours_source_idx, + struct merge_diff_similarity *similarity_theirs, + bool theirs_renamed, + size_t theirs_source_idx, + git_merge_diff *target, + const git_merge_options *opts) +{ + git_merge_diff *ours_source = NULL, *theirs_source = NULL; + + if (ours_renamed) + ours_source = diff_list->conflicts.contents[ours_source_idx]; + + if (theirs_renamed) + theirs_source = diff_list->conflicts.contents[theirs_source_idx]; + + /* Detect 2->1 conflicts */ + if (ours_renamed && theirs_renamed) { + /* Both renamed to the same target name. */ + if (ours_source_idx == theirs_source_idx) + ours_source->type = GIT_MERGE_DIFF_BOTH_RENAMED; + else { + ours_source->type = GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1; + theirs_source->type = GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1; + } + } else if (ours_renamed) { + /* If our source was also renamed in theirs, this is a 1->2 */ + if (similarity_theirs[ours_source_idx].similarity >= opts->rename_threshold) + ours_source->type = GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2; + + else if (GIT_MERGE_INDEX_ENTRY_EXISTS(target->their_entry)) { + ours_source->type = GIT_MERGE_DIFF_RENAMED_ADDED; + target->type = GIT_MERGE_DIFF_RENAMED_ADDED; + } + + else if (!GIT_MERGE_INDEX_ENTRY_EXISTS(ours_source->their_entry)) + ours_source->type = GIT_MERGE_DIFF_RENAMED_DELETED; + + else if (ours_source->type == GIT_MERGE_DIFF_MODIFIED_DELETED) + ours_source->type = GIT_MERGE_DIFF_RENAMED_MODIFIED; + } else if (theirs_renamed) { + /* If their source was also renamed in ours, this is a 1->2 */ + if (similarity_ours[theirs_source_idx].similarity >= opts->rename_threshold) + theirs_source->type = GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2; + + else if (GIT_MERGE_INDEX_ENTRY_EXISTS(target->our_entry)) { + theirs_source->type = GIT_MERGE_DIFF_RENAMED_ADDED; + target->type = GIT_MERGE_DIFF_RENAMED_ADDED; + } + + else if (!GIT_MERGE_INDEX_ENTRY_EXISTS(theirs_source->our_entry)) + theirs_source->type = GIT_MERGE_DIFF_RENAMED_DELETED; + + else if (theirs_source->type == GIT_MERGE_DIFF_MODIFIED_DELETED) + theirs_source->type = GIT_MERGE_DIFF_RENAMED_MODIFIED; + } +} + +GIT_INLINE(void) merge_diff_coalesce_rename( + git_index_entry *source_entry, + git_delta_t *source_status, + git_index_entry *target_entry, + git_delta_t *target_status) +{ + /* Coalesce the rename target into the rename source. */ + memcpy(source_entry, target_entry, sizeof(git_index_entry)); + *source_status = GIT_DELTA_RENAMED; + + memset(target_entry, 0x0, sizeof(git_index_entry)); + *target_status = GIT_DELTA_UNMODIFIED; +} + +static void merge_diff_list_coalesce_renames( + git_merge_diff_list *diff_list, + struct merge_diff_similarity *similarity_ours, + struct merge_diff_similarity *similarity_theirs, + const git_merge_options *opts) +{ + size_t i; + bool ours_renamed = 0, theirs_renamed = 0; + size_t ours_source_idx = 0, theirs_source_idx = 0; + git_merge_diff *ours_source, *theirs_source, *target; + + for (i = 0; i < diff_list->conflicts.length; i++) { + target = diff_list->conflicts.contents[i]; + + ours_renamed = 0; + theirs_renamed = 0; + + if (GIT_MERGE_INDEX_ENTRY_EXISTS(target->our_entry) && + similarity_ours[i].similarity >= opts->rename_threshold) { + ours_source_idx = similarity_ours[i].other_idx; + + ours_source = diff_list->conflicts.contents[ours_source_idx]; + + merge_diff_coalesce_rename( + &ours_source->our_entry, + &ours_source->our_status, + &target->our_entry, + &target->our_status); + + similarity_ours[ours_source_idx].similarity = 0; + similarity_ours[i].similarity = 0; + + ours_renamed = 1; + } + + /* insufficient to determine direction */ + if (GIT_MERGE_INDEX_ENTRY_EXISTS(target->their_entry) && + similarity_theirs[i].similarity >= opts->rename_threshold) { + theirs_source_idx = similarity_theirs[i].other_idx; + + theirs_source = diff_list->conflicts.contents[theirs_source_idx]; + + merge_diff_coalesce_rename( + &theirs_source->their_entry, + &theirs_source->their_status, + &target->their_entry, + &target->their_status); + + similarity_theirs[theirs_source_idx].similarity = 0; + similarity_theirs[i].similarity = 0; + + theirs_renamed = 1; + } + + merge_diff_mark_rename_conflict(diff_list, + similarity_ours, ours_renamed, ours_source_idx, + similarity_theirs, theirs_renamed, theirs_source_idx, + target, opts); + } +} + +static int merge_diff_empty(const git_vector *conflicts, size_t idx, void *p) +{ + git_merge_diff *conflict = conflicts->contents[idx]; + + GIT_UNUSED(p); + + return (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) && + !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) && + !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry)); +} + +static void merge_diff_list_count_candidates( + git_merge_diff_list *diff_list, + size_t *src_count, + size_t *tgt_count) +{ + git_merge_diff *entry; + size_t i; + + *src_count = 0; + *tgt_count = 0; + + git_vector_foreach(&diff_list->conflicts, i, entry) { + if (GIT_MERGE_INDEX_ENTRY_EXISTS(entry->ancestor_entry) && + (!GIT_MERGE_INDEX_ENTRY_EXISTS(entry->our_entry) || + !GIT_MERGE_INDEX_ENTRY_EXISTS(entry->their_entry))) + (*src_count)++; + else if (!GIT_MERGE_INDEX_ENTRY_EXISTS(entry->ancestor_entry)) + (*tgt_count)++; + } +} + +int git_merge_diff_list__find_renames( + git_repository *repo, + git_merge_diff_list *diff_list, + const git_merge_options *opts) +{ + struct merge_diff_similarity *similarity_ours, *similarity_theirs; + void **cache = NULL; + size_t cache_size = 0; + size_t src_count, tgt_count, i; + int error = 0; + + GIT_ASSERT_ARG(diff_list); + GIT_ASSERT_ARG(opts); + + if ((opts->flags & GIT_MERGE_FIND_RENAMES) == 0 || + !diff_list->conflicts.length) + return 0; + + similarity_ours = git__calloc(diff_list->conflicts.length, + sizeof(struct merge_diff_similarity)); + GIT_ERROR_CHECK_ALLOC(similarity_ours); + + similarity_theirs = git__calloc(diff_list->conflicts.length, + sizeof(struct merge_diff_similarity)); + GIT_ERROR_CHECK_ALLOC(similarity_theirs); + + /* Calculate similarity between items that were deleted from the ancestor + * and added in the other branch. + */ + if ((error = merge_diff_mark_similarity_exact(diff_list, similarity_ours, similarity_theirs)) < 0) + goto done; + + if (opts->rename_threshold < 100 && diff_list->conflicts.length <= opts->target_limit) { + GIT_ERROR_CHECK_ALLOC_MULTIPLY(&cache_size, diff_list->conflicts.length, 3); + cache = git__calloc(cache_size, sizeof(void *)); + GIT_ERROR_CHECK_ALLOC(cache); + + merge_diff_list_count_candidates(diff_list, &src_count, &tgt_count); + + if (src_count > opts->target_limit || tgt_count > opts->target_limit) { + /* TODO: report! */ + } else { + if ((error = merge_diff_mark_similarity_inexact( + repo, diff_list, similarity_ours, similarity_theirs, cache, opts)) < 0) + goto done; + } + } + + /* For entries that are appropriately similar, merge the new name's entry + * into the old name. + */ + merge_diff_list_coalesce_renames(diff_list, similarity_ours, similarity_theirs, opts); + + /* And remove any entries that were merged and are now empty. */ + git_vector_remove_matching(&diff_list->conflicts, merge_diff_empty, NULL); + +done: + if (cache != NULL) { + for (i = 0; i < cache_size; ++i) { + if (cache[i] != NULL && cache[i] != &cache_invalid_marker) + opts->metric->free_signature(cache[i], opts->metric->payload); + } + + git__free(cache); + } + + git__free(similarity_ours); + git__free(similarity_theirs); + + return error; +} + +/* Directory/file conflict handling */ + +GIT_INLINE(const char *) merge_diff_path( + const git_merge_diff *conflict) +{ + if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry)) + return conflict->ancestor_entry.path; + else if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry)) + return conflict->our_entry.path; + else if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry)) + return conflict->their_entry.path; + + return NULL; +} + +GIT_INLINE(bool) merge_diff_any_side_added_or_modified( + const git_merge_diff *conflict) +{ + if (conflict->our_status == GIT_DELTA_ADDED || + conflict->our_status == GIT_DELTA_MODIFIED || + conflict->their_status == GIT_DELTA_ADDED || + conflict->their_status == GIT_DELTA_MODIFIED) + return true; + + return false; +} + +GIT_INLINE(bool) path_is_prefixed(const char *parent, const char *child) +{ + size_t child_len = strlen(child); + size_t parent_len = strlen(parent); + + if (child_len < parent_len || + strncmp(parent, child, parent_len) != 0) + return 0; + + return (child[parent_len] == '/'); +} + +GIT_INLINE(int) merge_diff_detect_df_conflict( + struct merge_diff_df_data *df_data, + git_merge_diff *conflict) +{ + const char *cur_path = merge_diff_path(conflict); + + /* Determine if this is a D/F conflict or the child of one */ + if (df_data->df_path && + path_is_prefixed(df_data->df_path, cur_path)) + conflict->type = GIT_MERGE_DIFF_DF_CHILD; + else if(df_data->df_path) + df_data->df_path = NULL; + else if (df_data->prev_path && + merge_diff_any_side_added_or_modified(df_data->prev_conflict) && + merge_diff_any_side_added_or_modified(conflict) && + path_is_prefixed(df_data->prev_path, cur_path)) { + conflict->type = GIT_MERGE_DIFF_DF_CHILD; + + df_data->prev_conflict->type = GIT_MERGE_DIFF_DIRECTORY_FILE; + df_data->df_path = df_data->prev_path; + } + + df_data->prev_path = cur_path; + df_data->prev_conflict = conflict; + + return 0; +} + +/* Conflict handling */ + +GIT_INLINE(int) merge_diff_detect_type( + git_merge_diff *conflict) +{ + if (conflict->our_status == GIT_DELTA_ADDED && + conflict->their_status == GIT_DELTA_ADDED) + conflict->type = GIT_MERGE_DIFF_BOTH_ADDED; + else if (conflict->our_status == GIT_DELTA_MODIFIED && + conflict->their_status == GIT_DELTA_MODIFIED) + conflict->type = GIT_MERGE_DIFF_BOTH_MODIFIED; + else if (conflict->our_status == GIT_DELTA_DELETED && + conflict->their_status == GIT_DELTA_DELETED) + conflict->type = GIT_MERGE_DIFF_BOTH_DELETED; + else if (conflict->our_status == GIT_DELTA_MODIFIED && + conflict->their_status == GIT_DELTA_DELETED) + conflict->type = GIT_MERGE_DIFF_MODIFIED_DELETED; + else if (conflict->our_status == GIT_DELTA_DELETED && + conflict->their_status == GIT_DELTA_MODIFIED) + conflict->type = GIT_MERGE_DIFF_MODIFIED_DELETED; + else + conflict->type = GIT_MERGE_DIFF_NONE; + + return 0; +} + +GIT_INLINE(int) index_entry_dup_pool( + git_index_entry *out, + git_pool *pool, + const git_index_entry *src) +{ + if (src != NULL) { + memcpy(out, src, sizeof(git_index_entry)); + if ((out->path = git_pool_strdup(pool, src->path)) == NULL) + return -1; + } + + return 0; +} + +GIT_INLINE(int) merge_delta_type_from_index_entries( + const git_index_entry *ancestor, + const git_index_entry *other) +{ + if (ancestor == NULL && other == NULL) + return GIT_DELTA_UNMODIFIED; + else if (ancestor == NULL && other != NULL) + return GIT_DELTA_ADDED; + else if (ancestor != NULL && other == NULL) + return GIT_DELTA_DELETED; + else if (S_ISDIR(ancestor->mode) ^ S_ISDIR(other->mode)) + return GIT_DELTA_TYPECHANGE; + else if(S_ISLNK(ancestor->mode) ^ S_ISLNK(other->mode)) + return GIT_DELTA_TYPECHANGE; + else if (git_oid__cmp(&ancestor->id, &other->id) || + ancestor->mode != other->mode) + return GIT_DELTA_MODIFIED; + + return GIT_DELTA_UNMODIFIED; +} + +static git_merge_diff *merge_diff_from_index_entries( + git_merge_diff_list *diff_list, + const git_index_entry **entries) +{ + git_merge_diff *conflict; + git_pool *pool = &diff_list->pool; + + if ((conflict = git_pool_mallocz(pool, sizeof(git_merge_diff))) == NULL) + return NULL; + + if (index_entry_dup_pool(&conflict->ancestor_entry, pool, entries[TREE_IDX_ANCESTOR]) < 0 || + index_entry_dup_pool(&conflict->our_entry, pool, entries[TREE_IDX_OURS]) < 0 || + index_entry_dup_pool(&conflict->their_entry, pool, entries[TREE_IDX_THEIRS]) < 0) + return NULL; + + conflict->our_status = merge_delta_type_from_index_entries( + entries[TREE_IDX_ANCESTOR], entries[TREE_IDX_OURS]); + conflict->their_status = merge_delta_type_from_index_entries( + entries[TREE_IDX_ANCESTOR], entries[TREE_IDX_THEIRS]); + + return conflict; +} + +/* Merge trees */ + +static int merge_diff_list_insert_conflict( + git_merge_diff_list *diff_list, + struct merge_diff_df_data *merge_df_data, + const git_index_entry *tree_items[3]) +{ + git_merge_diff *conflict; + + if ((conflict = merge_diff_from_index_entries(diff_list, tree_items)) == NULL || + merge_diff_detect_type(conflict) < 0 || + merge_diff_detect_df_conflict(merge_df_data, conflict) < 0 || + git_vector_insert(&diff_list->conflicts, conflict) < 0) + return -1; + + return 0; +} + +static int merge_diff_list_insert_unmodified( + git_merge_diff_list *diff_list, + const git_index_entry *tree_items[3]) +{ + int error = 0; + git_index_entry *entry; + + entry = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry)); + GIT_ERROR_CHECK_ALLOC(entry); + + if ((error = index_entry_dup_pool(entry, &diff_list->pool, tree_items[0])) >= 0) + error = git_vector_insert(&diff_list->staged, entry); + + return error; +} + +struct merge_diff_find_data { + git_merge_diff_list *diff_list; + struct merge_diff_df_data df_data; +}; + +static int queue_difference(const git_index_entry **entries, void *data) +{ + struct merge_diff_find_data *find_data = data; + bool item_modified = false; + size_t i; + + if (!entries[0] || !entries[1] || !entries[2]) { + item_modified = true; + } else { + for (i = 1; i < 3; i++) { + if (index_entry_cmp(entries[0], entries[i]) != 0) { + item_modified = true; + break; + } + } + } + + return item_modified ? + merge_diff_list_insert_conflict( + find_data->diff_list, &find_data->df_data, entries) : + merge_diff_list_insert_unmodified(find_data->diff_list, entries); +} + +int git_merge_diff_list__find_differences( + git_merge_diff_list *diff_list, + git_iterator *ancestor_iter, + git_iterator *our_iter, + git_iterator *their_iter) +{ + git_iterator *iterators[3] = { ancestor_iter, our_iter, their_iter }; + struct merge_diff_find_data find_data = { diff_list }; + + return git_iterator_walk(iterators, 3, queue_difference, &find_data); +} + +git_merge_diff_list *git_merge_diff_list__alloc(git_repository *repo) +{ + git_merge_diff_list *diff_list = git__calloc(1, sizeof(git_merge_diff_list)); + + if (diff_list == NULL) + return NULL; + + diff_list->repo = repo; + + + if (git_pool_init(&diff_list->pool, 1) < 0 || + git_vector_init(&diff_list->staged, 0, NULL) < 0 || + git_vector_init(&diff_list->conflicts, 0, NULL) < 0 || + git_vector_init(&diff_list->resolved, 0, NULL) < 0) { + git_merge_diff_list__free(diff_list); + return NULL; + } + + return diff_list; +} + +void git_merge_diff_list__free(git_merge_diff_list *diff_list) +{ + if (!diff_list) + return; + + git_vector_free(&diff_list->staged); + git_vector_free(&diff_list->conflicts); + git_vector_free(&diff_list->resolved); + git_pool_clear(&diff_list->pool); + git__free(diff_list); +} + +static int merge_normalize_opts( + git_repository *repo, + git_merge_options *opts, + const git_merge_options *given) +{ + git_config *cfg = NULL; + git_config_entry *entry = NULL; + int error = 0; + + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(opts); + + if ((error = git_repository_config__weakptr(&cfg, repo)) < 0) + return error; + + if (given != NULL) { + memcpy(opts, given, sizeof(git_merge_options)); + } else { + git_merge_options init = GIT_MERGE_OPTIONS_INIT; + memcpy(opts, &init, sizeof(init)); + } + + if ((opts->flags & GIT_MERGE_FIND_RENAMES) && !opts->rename_threshold) + opts->rename_threshold = GIT_MERGE_DEFAULT_RENAME_THRESHOLD; + + if (given && given->default_driver) { + opts->default_driver = git__strdup(given->default_driver); + GIT_ERROR_CHECK_ALLOC(opts->default_driver); + } else { + error = git_config_get_entry(&entry, cfg, "merge.default"); + + if (error == 0) { + opts->default_driver = git__strdup(entry->value); + GIT_ERROR_CHECK_ALLOC(opts->default_driver); + } else if (error == GIT_ENOTFOUND) { + error = 0; + } else { + goto done; + } + } + + if (!opts->target_limit) { + int limit = git_config__get_int_force(cfg, "merge.renamelimit", 0); + + if (!limit) + limit = git_config__get_int_force(cfg, "diff.renamelimit", 0); + + opts->target_limit = (limit <= 0) ? + GIT_MERGE_DEFAULT_TARGET_LIMIT : (unsigned int)limit; + } + + /* assign the internal metric with whitespace flag as payload */ + if (!opts->metric) { + opts->metric = git__malloc(sizeof(git_diff_similarity_metric)); + GIT_ERROR_CHECK_ALLOC(opts->metric); + + opts->metric->file_signature = git_diff_find_similar__hashsig_for_file; + opts->metric->buffer_signature = git_diff_find_similar__hashsig_for_buf; + opts->metric->free_signature = git_diff_find_similar__hashsig_free; + opts->metric->similarity = git_diff_find_similar__calc_similarity; + opts->metric->payload = (void *)GIT_HASHSIG_SMART_WHITESPACE; + } + +done: + git_config_entry_free(entry); + return error; +} + + +static int merge_index_insert_reuc( + git_index *index, + size_t idx, + const git_index_entry *entry) +{ + const git_index_reuc_entry *reuc; + int mode[3] = { 0, 0, 0 }; + git_oid const *oid[3] = { NULL, NULL, NULL }; + size_t i; + + if (!GIT_MERGE_INDEX_ENTRY_EXISTS(*entry)) + return 0; + + if ((reuc = git_index_reuc_get_bypath(index, entry->path)) != NULL) { + for (i = 0; i < 3; i++) { + mode[i] = reuc->mode[i]; + oid[i] = &reuc->oid[i]; + } + } + + mode[idx] = entry->mode; + oid[idx] = &entry->id; + + return git_index_reuc_add(index, entry->path, + mode[0], oid[0], mode[1], oid[1], mode[2], oid[2]); +} + +static int index_update_reuc(git_index *index, git_merge_diff_list *diff_list) +{ + int error; + size_t i; + git_merge_diff *conflict; + + /* Add each entry in the resolved conflict to the REUC independently, since + * the paths may differ due to renames. */ + git_vector_foreach(&diff_list->resolved, i, conflict) { + const git_index_entry *ancestor = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) ? + &conflict->ancestor_entry : NULL; + + const git_index_entry *ours = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ? + &conflict->our_entry : NULL; + + const git_index_entry *theirs = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ? + &conflict->their_entry : NULL; + + if (ancestor != NULL && + (error = merge_index_insert_reuc(index, TREE_IDX_ANCESTOR, ancestor)) < 0) + return error; + + if (ours != NULL && + (error = merge_index_insert_reuc(index, TREE_IDX_OURS, ours)) < 0) + return error; + + if (theirs != NULL && + (error = merge_index_insert_reuc(index, TREE_IDX_THEIRS, theirs)) < 0) + return error; + } + + return 0; +} + +static int index_from_diff_list( + git_index **out, + git_merge_diff_list *diff_list, + git_oid_t oid_type, + bool skip_reuc) +{ + git_index *index; + size_t i; + git_merge_diff *conflict; + int error = 0; + + *out = NULL; + + if ((error = git_index__new(&index, oid_type)) < 0) + return error; + + if ((error = git_index__fill(index, &diff_list->staged)) < 0) + goto on_error; + + git_vector_foreach(&diff_list->conflicts, i, conflict) { + const git_index_entry *ancestor = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) ? + &conflict->ancestor_entry : NULL; + + const git_index_entry *ours = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ? + &conflict->our_entry : NULL; + + const git_index_entry *theirs = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ? + &conflict->their_entry : NULL; + + if ((error = git_index_conflict_add(index, ancestor, ours, theirs)) < 0) + goto on_error; + } + + /* Add each rename entry to the rename portion of the index. */ + git_vector_foreach(&diff_list->conflicts, i, conflict) { + const char *ancestor_path, *our_path, *their_path; + + if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry)) + continue; + + ancestor_path = conflict->ancestor_entry.path; + + our_path = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ? + conflict->our_entry.path : NULL; + + their_path = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ? + conflict->their_entry.path : NULL; + + if ((our_path && strcmp(ancestor_path, our_path) != 0) || + (their_path && strcmp(ancestor_path, their_path) != 0)) { + if ((error = git_index_name_add(index, ancestor_path, our_path, their_path)) < 0) + goto on_error; + } + } + + if (!skip_reuc) { + if ((error = index_update_reuc(index, diff_list)) < 0) + goto on_error; + } + + *out = index; + return 0; + +on_error: + git_index_free(index); + return error; +} + +static git_iterator *iterator_given_or_empty(git_iterator **empty, git_iterator *given) +{ + git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT; + + if (given) + return given; + + opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE; + + if (git_iterator_for_nothing(empty, &opts) < 0) + return NULL; + + return *empty; +} + +int git_merge__iterators( + git_index **out, + git_repository *repo, + git_iterator *ancestor_iter, + git_iterator *our_iter, + git_iterator *theirs_iter, + const git_merge_options *given_opts) +{ + git_iterator *empty_ancestor = NULL, + *empty_ours = NULL, + *empty_theirs = NULL; + git_merge_diff_list *diff_list; + git_merge_options opts; + git_merge_file_options file_opts = GIT_MERGE_FILE_OPTIONS_INIT; + git_merge_diff *conflict; + git_vector changes; + size_t i; + int error = 0; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(repo); + + *out = NULL; + + GIT_ERROR_CHECK_VERSION( + given_opts, GIT_MERGE_OPTIONS_VERSION, "git_merge_options"); + + if ((error = merge_normalize_opts(repo, &opts, given_opts)) < 0) + return error; + + file_opts.favor = opts.file_favor; + file_opts.flags = opts.file_flags; + + /* use the git-inspired labels when virtual base building */ + if (opts.flags & GIT_MERGE_VIRTUAL_BASE) { + file_opts.ancestor_label = "merged common ancestors"; + file_opts.our_label = "Temporary merge branch 1"; + file_opts.their_label = "Temporary merge branch 2"; + file_opts.flags |= GIT_MERGE_FILE_ACCEPT_CONFLICTS; + file_opts.marker_size = GIT_MERGE_CONFLICT_MARKER_SIZE + 2; + } + + diff_list = git_merge_diff_list__alloc(repo); + GIT_ERROR_CHECK_ALLOC(diff_list); + + ancestor_iter = iterator_given_or_empty(&empty_ancestor, ancestor_iter); + our_iter = iterator_given_or_empty(&empty_ours, our_iter); + theirs_iter = iterator_given_or_empty(&empty_theirs, theirs_iter); + + if ((error = git_merge_diff_list__find_differences( + diff_list, ancestor_iter, our_iter, theirs_iter)) < 0 || + (error = git_merge_diff_list__find_renames(repo, diff_list, &opts)) < 0) + goto done; + + memcpy(&changes, &diff_list->conflicts, sizeof(git_vector)); + git_vector_clear(&diff_list->conflicts); + + git_vector_foreach(&changes, i, conflict) { + int resolved = 0; + + if ((error = merge_conflict_resolve( + &resolved, diff_list, conflict, &opts, &file_opts)) < 0) + goto done; + + if (!resolved) { + if ((opts.flags & GIT_MERGE_FAIL_ON_CONFLICT)) { + git_error_set(GIT_ERROR_MERGE, "merge conflicts exist"); + error = GIT_EMERGECONFLICT; + goto done; + } + + git_vector_insert(&diff_list->conflicts, conflict); + } + } + + error = index_from_diff_list(out, diff_list, repo->oid_type, + (opts.flags & GIT_MERGE_SKIP_REUC)); + +done: + if (!given_opts || !given_opts->metric) + git__free(opts.metric); + + git__free((char *)opts.default_driver); + + git_merge_diff_list__free(diff_list); + git_iterator_free(empty_ancestor); + git_iterator_free(empty_ours); + git_iterator_free(empty_theirs); + + return error; +} + +int git_merge_trees( + git_index **out, + git_repository *repo, + const git_tree *ancestor_tree, + const git_tree *our_tree, + const git_tree *their_tree, + const git_merge_options *merge_opts) +{ + git_iterator *ancestor_iter = NULL, *our_iter = NULL, *their_iter = NULL; + git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT; + int error; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(repo); + + /* if one side is treesame to the ancestor, take the other side */ + if (ancestor_tree && merge_opts && (merge_opts->flags & GIT_MERGE_SKIP_REUC)) { + const git_tree *result = NULL; + const git_oid *ancestor_tree_id = git_tree_id(ancestor_tree); + + if (our_tree && !git_oid_cmp(ancestor_tree_id, git_tree_id(our_tree))) + result = their_tree; + else if (their_tree && !git_oid_cmp(ancestor_tree_id, git_tree_id(their_tree))) + result = our_tree; + + if (result) { + if ((error = git_index__new(out, repo->oid_type)) == 0) + error = git_index_read_tree(*out, result); + + return error; + } + } + + iter_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE; + + if ((error = git_iterator_for_tree( + &ancestor_iter, (git_tree *)ancestor_tree, &iter_opts)) < 0 || + (error = git_iterator_for_tree( + &our_iter, (git_tree *)our_tree, &iter_opts)) < 0 || + (error = git_iterator_for_tree( + &their_iter, (git_tree *)their_tree, &iter_opts)) < 0) + goto done; + + error = git_merge__iterators( + out, repo, ancestor_iter, our_iter, their_iter, merge_opts); + +done: + git_iterator_free(ancestor_iter); + git_iterator_free(our_iter); + git_iterator_free(their_iter); + + return error; +} + +static int merge_annotated_commits( + git_index **index_out, + git_annotated_commit **base_out, + git_repository *repo, + git_annotated_commit *our_commit, + git_annotated_commit *their_commit, + size_t recursion_level, + const git_merge_options *opts); + +GIT_INLINE(int) insert_head_ids( + git_array_oid_t *ids, + const git_annotated_commit *annotated_commit) +{ + git_oid *id; + size_t i; + + if (annotated_commit->type == GIT_ANNOTATED_COMMIT_REAL) { + id = git_array_alloc(*ids); + GIT_ERROR_CHECK_ALLOC(id); + + git_oid_cpy(id, git_commit_id(annotated_commit->commit)); + } else { + for (i = 0; i < annotated_commit->parents.size; i++) { + id = git_array_alloc(*ids); + GIT_ERROR_CHECK_ALLOC(id); + + git_oid_cpy(id, &annotated_commit->parents.ptr[i]); + } + } + + return 0; +} + +static int create_virtual_base( + git_annotated_commit **out, + git_repository *repo, + git_annotated_commit *one, + git_annotated_commit *two, + const git_merge_options *opts, + size_t recursion_level) +{ + git_annotated_commit *result = NULL; + git_index *index = NULL; + git_merge_options virtual_opts = GIT_MERGE_OPTIONS_INIT; + + /* Conflicts in the merge base creation do not propagate to conflicts + * in the result; the conflicted base will act as the common ancestor. + */ + if (opts) + memcpy(&virtual_opts, opts, sizeof(git_merge_options)); + + virtual_opts.flags &= ~GIT_MERGE_FAIL_ON_CONFLICT; + virtual_opts.flags |= GIT_MERGE_VIRTUAL_BASE; + + if ((merge_annotated_commits(&index, NULL, repo, one, two, + recursion_level + 1, &virtual_opts)) < 0) + return -1; + + result = git__calloc(1, sizeof(git_annotated_commit)); + GIT_ERROR_CHECK_ALLOC(result); + result->type = GIT_ANNOTATED_COMMIT_VIRTUAL; + result->index = index; + + if (insert_head_ids(&result->parents, one) < 0 || + insert_head_ids(&result->parents, two) < 0) { + git_annotated_commit_free(result); + return -1; + } + + *out = result; + return 0; +} + +static int compute_base( + git_annotated_commit **out, + git_repository *repo, + const git_annotated_commit *one, + const git_annotated_commit *two, + const git_merge_options *given_opts, + size_t recursion_level) +{ + git_array_oid_t head_ids = GIT_ARRAY_INIT; + git_oidarray bases = {0}; + git_annotated_commit *base = NULL, *other = NULL, *new_base = NULL; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; + size_t i, base_count; + int error; + + *out = NULL; + + if (given_opts) + memcpy(&opts, given_opts, sizeof(git_merge_options)); + + /* With more than two commits, merge_bases_many finds the base of + * the first commit and a hypothetical merge of the others. Since + * "one" may itself be a virtual commit, which insert_head_ids + * substitutes multiple ancestors for, it needs to be added + * after "two" which is always a single real commit. + */ + if ((error = insert_head_ids(&head_ids, two)) < 0 || + (error = insert_head_ids(&head_ids, one)) < 0 || + (error = git_merge_bases_many(&bases, repo, + head_ids.size, head_ids.ptr)) < 0) + goto done; + + base_count = (opts.flags & GIT_MERGE_NO_RECURSIVE) ? 0 : bases.count; + + if (base_count) + git_oidarray__reverse(&bases); + + if ((error = git_annotated_commit_lookup(&base, repo, &bases.ids[0])) < 0) + goto done; + + for (i = 1; i < base_count; i++) { + recursion_level++; + + if (opts.recursion_limit && recursion_level > opts.recursion_limit) + break; + + if ((error = git_annotated_commit_lookup(&other, repo, + &bases.ids[i])) < 0 || + (error = create_virtual_base(&new_base, repo, base, other, &opts, + recursion_level)) < 0) + goto done; + + git_annotated_commit_free(base); + git_annotated_commit_free(other); + + base = new_base; + new_base = NULL; + other = NULL; + } + +done: + if (error == 0) + *out = base; + else + git_annotated_commit_free(base); + + git_annotated_commit_free(other); + git_annotated_commit_free(new_base); + git_oidarray_dispose(&bases); + git_array_clear(head_ids); + return error; +} + +static int iterator_for_annotated_commit( + git_iterator **out, + git_annotated_commit *commit) +{ + git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT; + int error; + + opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE; + + if (commit == NULL) { + error = git_iterator_for_nothing(out, &opts); + } else if (commit->type == GIT_ANNOTATED_COMMIT_VIRTUAL) { + error = git_iterator_for_index(out, git_index_owner(commit->index), commit->index, &opts); + } else { + if (!commit->tree && + (error = git_commit_tree(&commit->tree, commit->commit)) < 0) + goto done; + + error = git_iterator_for_tree(out, commit->tree, &opts); + } + +done: + return error; +} + +static int merge_annotated_commits( + git_index **index_out, + git_annotated_commit **base_out, + git_repository *repo, + git_annotated_commit *ours, + git_annotated_commit *theirs, + size_t recursion_level, + const git_merge_options *opts) +{ + git_annotated_commit *base = NULL; + git_iterator *base_iter = NULL, *our_iter = NULL, *their_iter = NULL; + int error; + + if ((error = compute_base(&base, repo, ours, theirs, opts, + recursion_level)) < 0) { + + if (error != GIT_ENOTFOUND) + goto done; + + git_error_clear(); + } + + if ((error = iterator_for_annotated_commit(&base_iter, base)) < 0 || + (error = iterator_for_annotated_commit(&our_iter, ours)) < 0 || + (error = iterator_for_annotated_commit(&their_iter, theirs)) < 0 || + (error = git_merge__iterators(index_out, repo, base_iter, our_iter, + their_iter, opts)) < 0) + goto done; + + if (base_out) { + *base_out = base; + base = NULL; + } + +done: + git_annotated_commit_free(base); + git_iterator_free(base_iter); + git_iterator_free(our_iter); + git_iterator_free(their_iter); + return error; +} + + +int git_merge_commits( + git_index **out, + git_repository *repo, + const git_commit *our_commit, + const git_commit *their_commit, + const git_merge_options *opts) +{ + git_annotated_commit *ours = NULL, *theirs = NULL, *base = NULL; + int error = 0; + + if ((error = git_annotated_commit_from_commit(&ours, (git_commit *)our_commit)) < 0 || + (error = git_annotated_commit_from_commit(&theirs, (git_commit *)their_commit)) < 0) + goto done; + + error = merge_annotated_commits(out, &base, repo, ours, theirs, 0, opts); + +done: + git_annotated_commit_free(ours); + git_annotated_commit_free(theirs); + git_annotated_commit_free(base); + return error; +} + +/* Merge setup / cleanup */ + +static int write_merge_head( + git_repository *repo, + const git_annotated_commit *heads[], + size_t heads_len) +{ + git_filebuf file = GIT_FILEBUF_INIT; + git_str file_path = GIT_STR_INIT; + size_t i; + int error = 0; + + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(heads); + + if ((error = git_str_joinpath(&file_path, repo->gitdir, GIT_MERGE_HEAD_FILE)) < 0 || + (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) < 0) + goto cleanup; + + for (i = 0; i < heads_len; i++) { + if ((error = git_filebuf_printf(&file, "%s\n", heads[i]->id_str)) < 0) + goto cleanup; + } + + error = git_filebuf_commit(&file); + +cleanup: + if (error < 0) + git_filebuf_cleanup(&file); + + git_str_dispose(&file_path); + + return error; +} + +static int write_merge_mode(git_repository *repo) +{ + git_filebuf file = GIT_FILEBUF_INIT; + git_str file_path = GIT_STR_INIT; + int error = 0; + + GIT_ASSERT_ARG(repo); + + if ((error = git_str_joinpath(&file_path, repo->gitdir, GIT_MERGE_MODE_FILE)) < 0 || + (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) < 0) + goto cleanup; + + if ((error = git_filebuf_write(&file, "no-ff", 5)) < 0) + goto cleanup; + + error = git_filebuf_commit(&file); + +cleanup: + if (error < 0) + git_filebuf_cleanup(&file); + + git_str_dispose(&file_path); + + return error; +} + +struct merge_msg_entry { + const git_annotated_commit *merge_head; + bool written; +}; + +static int msg_entry_is_branch( + const struct merge_msg_entry *entry, + git_vector *entries) +{ + GIT_UNUSED(entries); + + return (entry->written == 0 && + entry->merge_head->remote_url == NULL && + entry->merge_head->ref_name != NULL && + git__strncmp(GIT_REFS_HEADS_DIR, entry->merge_head->ref_name, strlen(GIT_REFS_HEADS_DIR)) == 0); +} + +static int msg_entry_is_tracking( + const struct merge_msg_entry *entry, + git_vector *entries) +{ + GIT_UNUSED(entries); + + return (entry->written == 0 && + entry->merge_head->remote_url == NULL && + entry->merge_head->ref_name != NULL && + git__strncmp(GIT_REFS_REMOTES_DIR, entry->merge_head->ref_name, strlen(GIT_REFS_REMOTES_DIR)) == 0); +} + +static int msg_entry_is_tag( + const struct merge_msg_entry *entry, + git_vector *entries) +{ + GIT_UNUSED(entries); + + return (entry->written == 0 && + entry->merge_head->remote_url == NULL && + entry->merge_head->ref_name != NULL && + git__strncmp(GIT_REFS_TAGS_DIR, entry->merge_head->ref_name, strlen(GIT_REFS_TAGS_DIR)) == 0); +} + +static int msg_entry_is_remote( + const struct merge_msg_entry *entry, + git_vector *entries) +{ + if (entry->written == 0 && + entry->merge_head->remote_url != NULL && + entry->merge_head->ref_name != NULL && + git__strncmp(GIT_REFS_HEADS_DIR, entry->merge_head->ref_name, strlen(GIT_REFS_HEADS_DIR)) == 0) + { + struct merge_msg_entry *existing; + + /* Match only branches from the same remote */ + if (entries->length == 0) + return 1; + + existing = git_vector_get(entries, 0); + + return (git__strcmp(existing->merge_head->remote_url, + entry->merge_head->remote_url) == 0); + } + + return 0; +} + +static int msg_entry_is_oid( + const struct merge_msg_entry *merge_msg_entry) +{ + return (merge_msg_entry->written == 0 && + merge_msg_entry->merge_head->ref_name == NULL && + merge_msg_entry->merge_head->remote_url == NULL); +} + +static int merge_msg_entry_written( + const struct merge_msg_entry *merge_msg_entry) +{ + return (merge_msg_entry->written == 1); +} + +static int merge_msg_entries( + git_vector *v, + const struct merge_msg_entry *entries, + size_t len, + int (*match)(const struct merge_msg_entry *entry, git_vector *entries)) +{ + size_t i; + int matches, total = 0; + + git_vector_clear(v); + + for (i = 0; i < len; i++) { + if ((matches = match(&entries[i], v)) < 0) + return matches; + else if (!matches) + continue; + + git_vector_insert(v, (struct merge_msg_entry *)&entries[i]); + total++; + } + + return total; +} + +static int merge_msg_write_entries( + git_filebuf *file, + git_vector *entries, + const char *item_name, + const char *item_plural_name, + size_t ref_name_skip, + const char *source, + char sep) +{ + struct merge_msg_entry *entry; + size_t i; + int error = 0; + + if (entries->length == 0) + return 0; + + if (sep && (error = git_filebuf_printf(file, "%c ", sep)) < 0) + goto done; + + if ((error = git_filebuf_printf(file, "%s ", + (entries->length == 1) ? item_name : item_plural_name)) < 0) + goto done; + + git_vector_foreach(entries, i, entry) { + if (i > 0 && + (error = git_filebuf_printf(file, "%s", (i == entries->length - 1) ? " and " : ", ")) < 0) + goto done; + + if ((error = git_filebuf_printf(file, "'%s'", entry->merge_head->ref_name + ref_name_skip)) < 0) + goto done; + + entry->written = 1; + } + + if (source) + error = git_filebuf_printf(file, " of %s", source); + +done: + return error; +} + +static int merge_msg_write_branches( + git_filebuf *file, + git_vector *entries, + char sep) +{ + return merge_msg_write_entries(file, entries, + "branch", "branches", strlen(GIT_REFS_HEADS_DIR), NULL, sep); +} + +static int merge_msg_write_tracking( + git_filebuf *file, + git_vector *entries, + char sep) +{ + return merge_msg_write_entries(file, entries, + "remote-tracking branch", "remote-tracking branches", 0, NULL, sep); +} + +static int merge_msg_write_tags( + git_filebuf *file, + git_vector *entries, + char sep) +{ + return merge_msg_write_entries(file, entries, + "tag", "tags", strlen(GIT_REFS_TAGS_DIR), NULL, sep); +} + +static int merge_msg_write_remotes( + git_filebuf *file, + git_vector *entries, + char sep) +{ + const char *source; + + if (entries->length == 0) + return 0; + + source = ((struct merge_msg_entry *)entries->contents[0])->merge_head->remote_url; + + return merge_msg_write_entries(file, entries, + "branch", "branches", strlen(GIT_REFS_HEADS_DIR), source, sep); +} + +static int write_merge_msg( + git_repository *repo, + const git_annotated_commit *heads[], + size_t heads_len) +{ + git_filebuf file = GIT_FILEBUF_INIT; + git_str file_path = GIT_STR_INIT; + struct merge_msg_entry *entries; + git_vector matching = GIT_VECTOR_INIT; + size_t i; + char sep = 0; + int error = 0; + + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(heads); + + entries = git__calloc(heads_len, sizeof(struct merge_msg_entry)); + GIT_ERROR_CHECK_ALLOC(entries); + + if (git_vector_init(&matching, heads_len, NULL) < 0) { + git__free(entries); + return -1; + } + + for (i = 0; i < heads_len; i++) + entries[i].merge_head = heads[i]; + + if ((error = git_str_joinpath(&file_path, repo->gitdir, GIT_MERGE_MSG_FILE)) < 0 || + (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) < 0 || + (error = git_filebuf_write(&file, "Merge ", 6)) < 0) + goto cleanup; + + /* + * This is to emulate the format of MERGE_MSG by core git. + * + * Core git will write all the commits specified by OID, in the order + * provided, until the first named branch or tag is reached, at which + * point all branches will be written in the order provided, then all + * tags, then all remote tracking branches and finally all commits that + * were specified by OID that were not already written. + * + * Yes. Really. + */ + for (i = 0; i < heads_len; i++) { + if (!msg_entry_is_oid(&entries[i])) + break; + + if ((error = git_filebuf_printf(&file, + "%scommit '%s'", (i > 0) ? "; " : "", + entries[i].merge_head->id_str)) < 0) + goto cleanup; + + entries[i].written = 1; + } + + if (i) + sep = ';'; + + if ((error = merge_msg_entries(&matching, entries, heads_len, msg_entry_is_branch)) < 0 || + (error = merge_msg_write_branches(&file, &matching, sep)) < 0) + goto cleanup; + + if (matching.length) + sep =','; + + if ((error = merge_msg_entries(&matching, entries, heads_len, msg_entry_is_tracking)) < 0 || + (error = merge_msg_write_tracking(&file, &matching, sep)) < 0) + goto cleanup; + + if (matching.length) + sep =','; + + if ((error = merge_msg_entries(&matching, entries, heads_len, msg_entry_is_tag)) < 0 || + (error = merge_msg_write_tags(&file, &matching, sep)) < 0) + goto cleanup; + + if (matching.length) + sep =','; + + /* We should never be called with multiple remote branches, but handle + * it in case we are... */ + while ((error = merge_msg_entries(&matching, entries, heads_len, msg_entry_is_remote)) > 0) { + if ((error = merge_msg_write_remotes(&file, &matching, sep)) < 0) + goto cleanup; + + if (matching.length) + sep =','; + } + + if (error < 0) + goto cleanup; + + for (i = 0; i < heads_len; i++) { + if (merge_msg_entry_written(&entries[i])) + continue; + + if ((error = git_filebuf_printf(&file, "; commit '%s'", + entries[i].merge_head->id_str)) < 0) + goto cleanup; + } + + if ((error = git_filebuf_printf(&file, "\n")) < 0 || + (error = git_filebuf_commit(&file)) < 0) + goto cleanup; + +cleanup: + if (error < 0) + git_filebuf_cleanup(&file); + + git_str_dispose(&file_path); + + git_vector_free(&matching); + git__free(entries); + + return error; +} + +int git_merge__setup( + git_repository *repo, + const git_annotated_commit *our_head, + const git_annotated_commit *heads[], + size_t heads_len) +{ + int error = 0; + + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(our_head); + GIT_ASSERT_ARG(heads); + + if ((error = git_repository__set_orig_head(repo, git_annotated_commit_id(our_head))) == 0 && + (error = write_merge_head(repo, heads, heads_len)) == 0 && + (error = write_merge_mode(repo)) == 0) { + error = write_merge_msg(repo, heads, heads_len); + } + + return error; +} + +/* Merge branches */ + +static int merge_ancestor_head( + git_annotated_commit **ancestor_head, + git_repository *repo, + const git_annotated_commit *our_head, + const git_annotated_commit **their_heads, + size_t their_heads_len) +{ + git_oid *oids, ancestor_oid; + size_t i, alloc_len; + int error = 0; + + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(our_head); + GIT_ASSERT_ARG(their_heads); + + GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, their_heads_len, 1); + oids = git__calloc(alloc_len, sizeof(git_oid)); + GIT_ERROR_CHECK_ALLOC(oids); + + git_oid_cpy(&oids[0], git_commit_id(our_head->commit)); + + for (i = 0; i < their_heads_len; i++) + git_oid_cpy(&oids[i + 1], git_annotated_commit_id(their_heads[i])); + + if ((error = git_merge_base_many(&ancestor_oid, repo, their_heads_len + 1, oids)) < 0) + goto on_error; + + error = git_annotated_commit_lookup(ancestor_head, repo, &ancestor_oid); + +on_error: + git__free(oids); + return error; +} + +static const char *merge_their_label(const char *branchname) +{ + const char *slash; + + if ((slash = strrchr(branchname, '/')) == NULL) + return branchname; + + if (*(slash+1) == '\0') + return "theirs"; + + return slash+1; +} + +static int merge_normalize_checkout_opts( + git_checkout_options *out, + git_repository *repo, + const git_checkout_options *given_checkout_opts, + unsigned int checkout_strategy, + git_annotated_commit *ancestor, + const git_annotated_commit *our_head, + const git_annotated_commit **their_heads, + size_t their_heads_len) +{ + git_checkout_options default_checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; + int error = 0; + + GIT_UNUSED(repo); + + if (given_checkout_opts != NULL) + memcpy(out, given_checkout_opts, sizeof(git_checkout_options)); + else + memcpy(out, &default_checkout_opts, sizeof(git_checkout_options)); + + out->checkout_strategy = checkout_strategy; + + if (!out->ancestor_label) { + if (ancestor && ancestor->type == GIT_ANNOTATED_COMMIT_REAL) + out->ancestor_label = git_commit_summary(ancestor->commit); + else if (ancestor) + out->ancestor_label = "merged common ancestors"; + else + out->ancestor_label = "empty base"; + } + + if (!out->our_label) { + if (our_head && our_head->ref_name) + out->our_label = our_head->ref_name; + else + out->our_label = "ours"; + } + + if (!out->their_label) { + if (their_heads_len == 1 && their_heads[0]->ref_name) + out->their_label = merge_their_label(their_heads[0]->ref_name); + else if (their_heads_len == 1) + out->their_label = their_heads[0]->id_str; + else + out->their_label = "theirs"; + } + + return error; +} + +static int merge_check_index(size_t *conflicts, git_repository *repo, git_index *index_new, git_vector *merged_paths) +{ + git_tree *head_tree = NULL; + git_index *index_repo = NULL; + git_iterator *iter_repo = NULL, *iter_new = NULL; + git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT; + git_diff *staged_diff_list = NULL, *index_diff_list = NULL; + git_diff_delta *delta; + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_vector staged_paths = GIT_VECTOR_INIT; + size_t i; + int error = 0; + + GIT_UNUSED(merged_paths); + + *conflicts = 0; + + /* No staged changes may exist unless the change staged is identical to + * the result of the merge. This allows one to apply to merge manually, + * then run merge. Any other staged change would be overwritten by + * a reset merge. + */ + if ((error = git_repository_head_tree(&head_tree, repo)) < 0 || + (error = git_repository_index(&index_repo, repo)) < 0 || + (error = git_diff_tree_to_index(&staged_diff_list, repo, head_tree, index_repo, &opts)) < 0) + goto done; + + if (staged_diff_list->deltas.length == 0) + goto done; + + git_vector_foreach(&staged_diff_list->deltas, i, delta) { + if ((error = git_vector_insert(&staged_paths, (char *)delta->new_file.path)) < 0) + goto done; + } + + iter_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE; + iter_opts.pathlist.strings = (char **)staged_paths.contents; + iter_opts.pathlist.count = staged_paths.length; + + if ((error = git_iterator_for_index(&iter_repo, repo, index_repo, &iter_opts)) < 0 || + (error = git_iterator_for_index(&iter_new, repo, index_new, &iter_opts)) < 0 || + (error = git_diff__from_iterators(&index_diff_list, repo, iter_repo, iter_new, &opts)) < 0) + goto done; + + *conflicts = index_diff_list->deltas.length; + +done: + git_tree_free(head_tree); + git_index_free(index_repo); + git_iterator_free(iter_repo); + git_iterator_free(iter_new); + git_diff_free(staged_diff_list); + git_diff_free(index_diff_list); + git_vector_free(&staged_paths); + + return error; +} + +static int merge_check_workdir(size_t *conflicts, git_repository *repo, git_index *index_new, git_vector *merged_paths) +{ + git_diff *wd_diff_list = NULL; + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + int error = 0; + + GIT_UNUSED(index_new); + + *conflicts = 0; + + /* We need to have merged at least 1 file for the possibility to exist to + * have conflicts with the workdir. Passing 0 as the pathspec count parameter + * will consider all files in the working directory, that is, we may detect + * a conflict if there were untracked files in the workdir prior to starting + * the merge. This typically happens when cherry-picking a commit whose + * changes have already been applied. + */ + if (merged_paths->length == 0) + return 0; + + opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED; + + /* Workdir changes may exist iff they do not conflict with changes that + * will be applied by the merge (including conflicts). Ensure that there + * are no changes in the workdir to these paths. + */ + opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH; + opts.pathspec.count = merged_paths->length; + opts.pathspec.strings = (char **)merged_paths->contents; + opts.ignore_submodules = GIT_SUBMODULE_IGNORE_ALL; + + if ((error = git_diff_index_to_workdir(&wd_diff_list, repo, NULL, &opts)) < 0) + goto done; + + *conflicts = wd_diff_list->deltas.length; + +done: + git_diff_free(wd_diff_list); + + return error; +} + +int git_merge__check_result(git_repository *repo, git_index *index_new) +{ + git_tree *head_tree = NULL; + git_iterator *iter_head = NULL, *iter_new = NULL; + git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT; + git_diff *merged_list = NULL; + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff_delta *delta; + git_vector paths = GIT_VECTOR_INIT; + size_t i, index_conflicts = 0, wd_conflicts = 0, conflicts; + const git_index_entry *e; + int error = 0; + + iter_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE; + + if ((error = git_repository_head_tree(&head_tree, repo)) < 0 || + (error = git_iterator_for_tree(&iter_head, head_tree, &iter_opts)) < 0 || + (error = git_iterator_for_index(&iter_new, repo, index_new, &iter_opts)) < 0 || + (error = git_diff__from_iterators(&merged_list, repo, iter_head, iter_new, &opts)) < 0) + goto done; + + git_vector_foreach(&merged_list->deltas, i, delta) { + if ((error = git_vector_insert(&paths, (char *)delta->new_file.path)) < 0) + goto done; + } + + for (i = 0; i < git_index_entrycount(index_new); i++) { + e = git_index_get_byindex(index_new, i); + + if (git_index_entry_is_conflict(e) && + (git_vector_last(&paths) == NULL || + strcmp(git_vector_last(&paths), e->path) != 0)) { + + if ((error = git_vector_insert(&paths, (char *)e->path)) < 0) + goto done; + } + } + + /* Make sure the index and workdir state do not prevent merging */ + if ((error = merge_check_index(&index_conflicts, repo, index_new, &paths)) < 0 || + (error = merge_check_workdir(&wd_conflicts, repo, index_new, &paths)) < 0) + goto done; + + if ((conflicts = index_conflicts + wd_conflicts) > 0) { + git_error_set(GIT_ERROR_MERGE, "%" PRIuZ " uncommitted change%s would be overwritten by merge", + conflicts, (conflicts != 1) ? "s" : ""); + error = GIT_ECONFLICT; + } + +done: + git_vector_free(&paths); + git_tree_free(head_tree); + git_iterator_free(iter_head); + git_iterator_free(iter_new); + git_diff_free(merged_list); + + return error; +} + +int git_merge__append_conflicts_to_merge_msg( + git_repository *repo, + git_index *index) +{ + git_filebuf file = GIT_FILEBUF_INIT; + git_str file_path = GIT_STR_INIT; + const char *last = NULL; + size_t i; + int error; + + if (!git_index_has_conflicts(index)) + return 0; + + if ((error = git_str_joinpath(&file_path, repo->gitdir, GIT_MERGE_MSG_FILE)) < 0 || + (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_APPEND, GIT_MERGE_FILE_MODE)) < 0) + goto cleanup; + + git_filebuf_printf(&file, "\n#Conflicts:\n"); + + for (i = 0; i < git_index_entrycount(index); i++) { + const git_index_entry *e = git_index_get_byindex(index, i); + + if (!git_index_entry_is_conflict(e)) + continue; + + if (last == NULL || strcmp(e->path, last) != 0) + git_filebuf_printf(&file, "#\t%s\n", e->path); + + last = e->path; + } + + error = git_filebuf_commit(&file); + +cleanup: + if (error < 0) + git_filebuf_cleanup(&file); + + git_str_dispose(&file_path); + + return error; +} + +static int merge_state_cleanup(git_repository *repo) +{ + const char *state_files[] = { + GIT_MERGE_HEAD_FILE, + GIT_MERGE_MODE_FILE, + GIT_MERGE_MSG_FILE, + }; + + return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files)); +} + +static int merge_heads( + git_annotated_commit **ancestor_head_out, + git_annotated_commit **our_head_out, + git_repository *repo, + git_reference *our_ref, + const git_annotated_commit **their_heads, + size_t their_heads_len) +{ + git_annotated_commit *ancestor_head = NULL, *our_head = NULL; + int error = 0; + + *ancestor_head_out = NULL; + *our_head_out = NULL; + + if ((error = git_annotated_commit_from_ref(&our_head, repo, our_ref)) < 0) + goto done; + + if ((error = merge_ancestor_head(&ancestor_head, repo, our_head, their_heads, their_heads_len)) < 0) { + if (error != GIT_ENOTFOUND) + goto done; + + git_error_clear(); + error = 0; + } + + *ancestor_head_out = ancestor_head; + *our_head_out = our_head; + +done: + if (error < 0) { + git_annotated_commit_free(ancestor_head); + git_annotated_commit_free(our_head); + } + + return error; +} + +static int merge_preference(git_merge_preference_t *out, git_repository *repo) +{ + git_config *config; + const char *value; + int bool_value, error = 0; + + *out = GIT_MERGE_PREFERENCE_NONE; + + if ((error = git_repository_config_snapshot(&config, repo)) < 0) + goto done; + + if ((error = git_config_get_string(&value, config, "merge.ff")) < 0) { + if (error == GIT_ENOTFOUND) { + git_error_clear(); + error = 0; + } + + goto done; + } + + if (git_config_parse_bool(&bool_value, value) == 0) { + if (!bool_value) + *out |= GIT_MERGE_PREFERENCE_NO_FASTFORWARD; + } else { + if (strcasecmp(value, "only") == 0) + *out |= GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY; + } + +done: + git_config_free(config); + return error; +} + +int git_merge_analysis_for_ref( + git_merge_analysis_t *analysis_out, + git_merge_preference_t *preference_out, + git_repository *repo, + git_reference *our_ref, + const git_annotated_commit **their_heads, + size_t their_heads_len) +{ + git_annotated_commit *ancestor_head = NULL, *our_head = NULL; + int error = 0; + bool unborn; + + GIT_ASSERT_ARG(analysis_out); + GIT_ASSERT_ARG(preference_out); + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(their_heads && their_heads_len > 0); + + if (their_heads_len != 1) { + git_error_set(GIT_ERROR_MERGE, "can only merge a single branch"); + error = -1; + goto done; + } + + *analysis_out = GIT_MERGE_ANALYSIS_NONE; + + if ((error = merge_preference(preference_out, repo)) < 0) + goto done; + + if ((error = git_reference__is_unborn_head(&unborn, our_ref, repo)) < 0) + goto done; + + if (unborn) { + *analysis_out |= GIT_MERGE_ANALYSIS_FASTFORWARD | GIT_MERGE_ANALYSIS_UNBORN; + error = 0; + goto done; + } + + if ((error = merge_heads(&ancestor_head, &our_head, repo, our_ref, their_heads, their_heads_len)) < 0) + goto done; + + /* We're up-to-date if we're trying to merge our own common ancestor. */ + if (ancestor_head && git_oid_equal( + git_annotated_commit_id(ancestor_head), git_annotated_commit_id(their_heads[0]))) + *analysis_out |= GIT_MERGE_ANALYSIS_UP_TO_DATE; + + /* We're fastforwardable if we're our own common ancestor. */ + else if (ancestor_head && git_oid_equal( + git_annotated_commit_id(ancestor_head), git_annotated_commit_id(our_head))) + *analysis_out |= GIT_MERGE_ANALYSIS_FASTFORWARD | GIT_MERGE_ANALYSIS_NORMAL; + + /* Otherwise, just a normal merge is possible. */ + else + *analysis_out |= GIT_MERGE_ANALYSIS_NORMAL; + +done: + git_annotated_commit_free(ancestor_head); + git_annotated_commit_free(our_head); + return error; +} + +int git_merge_analysis( + git_merge_analysis_t *analysis_out, + git_merge_preference_t *preference_out, + git_repository *repo, + const git_annotated_commit **their_heads, + size_t their_heads_len) +{ + git_reference *head_ref = NULL; + int error = 0; + + if ((error = git_reference_lookup(&head_ref, repo, GIT_HEAD_FILE)) < 0) { + git_error_set(GIT_ERROR_MERGE, "failed to lookup HEAD reference"); + return error; + } + + error = git_merge_analysis_for_ref(analysis_out, preference_out, repo, head_ref, their_heads, their_heads_len); + + git_reference_free(head_ref); + + return error; +} + +int git_merge( + git_repository *repo, + const git_annotated_commit **their_heads, + size_t their_heads_len, + const git_merge_options *merge_opts, + const git_checkout_options *given_checkout_opts) +{ + git_reference *our_ref = NULL; + git_checkout_options checkout_opts; + git_annotated_commit *our_head = NULL, *base = NULL; + git_index *repo_index = NULL, *index = NULL; + git_indexwriter indexwriter = GIT_INDEXWRITER_INIT; + unsigned int checkout_strategy; + int error = 0; + + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(their_heads && their_heads_len > 0); + + if (their_heads_len != 1) { + git_error_set(GIT_ERROR_MERGE, "can only merge a single branch"); + return -1; + } + + if ((error = git_repository__ensure_not_bare(repo, "merge")) < 0) + goto done; + + checkout_strategy = given_checkout_opts ? + given_checkout_opts->checkout_strategy : + GIT_CHECKOUT_SAFE; + + if ((error = git_indexwriter_init_for_operation(&indexwriter, repo, + &checkout_strategy)) < 0) + goto done; + + if ((error = git_repository_index(&repo_index, repo) < 0) || + (error = git_index_read(repo_index, 0) < 0)) + goto done; + + /* Write the merge setup files to the repository. */ + if ((error = git_annotated_commit_from_head(&our_head, repo)) < 0 || + (error = git_merge__setup(repo, our_head, their_heads, + their_heads_len)) < 0) + goto done; + + /* TODO: octopus */ + + if ((error = merge_annotated_commits(&index, &base, repo, our_head, + (git_annotated_commit *)their_heads[0], 0, merge_opts)) < 0 || + (error = git_merge__check_result(repo, index)) < 0 || + (error = git_merge__append_conflicts_to_merge_msg(repo, index)) < 0) + goto done; + + /* check out the merge results */ + + if ((error = merge_normalize_checkout_opts(&checkout_opts, repo, + given_checkout_opts, checkout_strategy, + base, our_head, their_heads, their_heads_len)) < 0 || + (error = git_checkout_index(repo, index, &checkout_opts)) < 0) + goto done; + + error = git_indexwriter_commit(&indexwriter); + +done: + if (error < 0) + merge_state_cleanup(repo); + + git_indexwriter_cleanup(&indexwriter); + git_index_free(index); + git_annotated_commit_free(our_head); + git_annotated_commit_free(base); + git_reference_free(our_ref); + git_index_free(repo_index); + + return error; +} + +int git_merge_options_init(git_merge_options *opts, unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE( + opts, version, git_merge_options, GIT_MERGE_OPTIONS_INIT); + return 0; +} + +#ifndef GIT_DEPRECATE_HARD +int git_merge_init_options(git_merge_options *opts, unsigned int version) +{ + return git_merge_options_init(opts, version); +} +#endif + +int git_merge_file_input_init(git_merge_file_input *input, unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE( + input, version, git_merge_file_input, GIT_MERGE_FILE_INPUT_INIT); + return 0; +} + +#ifndef GIT_DEPRECATE_HARD +int git_merge_file_init_input(git_merge_file_input *input, unsigned int version) +{ + return git_merge_file_input_init(input, version); +} +#endif + +int git_merge_file_options_init( + git_merge_file_options *opts, unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE( + opts, version, git_merge_file_options, GIT_MERGE_FILE_OPTIONS_INIT); + return 0; +} + +#ifndef GIT_DEPRECATE_HARD +int git_merge_file_init_options( + git_merge_file_options *opts, unsigned int version) +{ + return git_merge_file_options_init(opts, version); +} +#endif diff --git a/vendor/libgit2/src/merge.h b/vendor/libgit2/src/libgit2/merge.h similarity index 100% rename from vendor/libgit2/src/merge.h rename to vendor/libgit2/src/libgit2/merge.h diff --git a/vendor/libgit2/src/merge_driver.c b/vendor/libgit2/src/libgit2/merge_driver.c similarity index 100% rename from vendor/libgit2/src/merge_driver.c rename to vendor/libgit2/src/libgit2/merge_driver.c diff --git a/vendor/libgit2/src/merge_driver.h b/vendor/libgit2/src/libgit2/merge_driver.h similarity index 100% rename from vendor/libgit2/src/merge_driver.h rename to vendor/libgit2/src/libgit2/merge_driver.h diff --git a/vendor/libgit2/src/merge_file.c b/vendor/libgit2/src/libgit2/merge_file.c similarity index 99% rename from vendor/libgit2/src/merge_file.c rename to vendor/libgit2/src/libgit2/merge_file.c index 732a047b..ffe83cf2 100644 --- a/vendor/libgit2/src/merge_file.c +++ b/vendor/libgit2/src/libgit2/merge_file.c @@ -19,8 +19,6 @@ #include "git2/index.h" #include "git2/merge.h" -#include "xdiff/xdiff.h" - /* only examine the first 8000 bytes for binaryness. * https://github.com/git/git/blob/77bd3ea9f54f1584147b594abc04c26ca516d987/xdiff-interface.c#L197 */ diff --git a/vendor/libgit2/src/message.c b/vendor/libgit2/src/libgit2/message.c similarity index 100% rename from vendor/libgit2/src/message.c rename to vendor/libgit2/src/libgit2/message.c diff --git a/vendor/libgit2/src/libgit2/midx.c b/vendor/libgit2/src/libgit2/midx.c new file mode 100644 index 00000000..71bbb1d0 --- /dev/null +++ b/vendor/libgit2/src/libgit2/midx.c @@ -0,0 +1,928 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "midx.h" + +#include "array.h" +#include "buf.h" +#include "filebuf.h" +#include "futils.h" +#include "hash.h" +#include "odb.h" +#include "pack.h" +#include "fs_path.h" +#include "repository.h" +#include "str.h" + +#define MIDX_SIGNATURE 0x4d494458 /* "MIDX" */ +#define MIDX_VERSION 1 +#define MIDX_OBJECT_ID_VERSION 1 +struct git_midx_header { + uint32_t signature; + uint8_t version; + uint8_t object_id_version; + uint8_t chunks; + uint8_t base_midx_files; + uint32_t packfiles; +}; + +#define MIDX_PACKFILE_NAMES_ID 0x504e414d /* "PNAM" */ +#define MIDX_OID_FANOUT_ID 0x4f494446 /* "OIDF" */ +#define MIDX_OID_LOOKUP_ID 0x4f49444c /* "OIDL" */ +#define MIDX_OBJECT_OFFSETS_ID 0x4f4f4646 /* "OOFF" */ +#define MIDX_OBJECT_LARGE_OFFSETS_ID 0x4c4f4646 /* "LOFF" */ + +struct git_midx_chunk { + off64_t offset; + size_t length; +}; + +typedef int (*midx_write_cb)(const char *buf, size_t size, void *cb_data); + +static int midx_error(const char *message) +{ + git_error_set(GIT_ERROR_ODB, "invalid multi-pack-index file - %s", message); + return -1; +} + +static int midx_parse_packfile_names( + git_midx_file *idx, + const unsigned char *data, + uint32_t packfiles, + struct git_midx_chunk *chunk) +{ + int error; + uint32_t i; + char *packfile_name = (char *)(data + chunk->offset); + size_t chunk_size = chunk->length, len; + if (chunk->offset == 0) + return midx_error("missing Packfile Names chunk"); + if (chunk->length == 0) + return midx_error("empty Packfile Names chunk"); + if ((error = git_vector_init(&idx->packfile_names, packfiles, git__strcmp_cb)) < 0) + return error; + for (i = 0; i < packfiles; ++i) { + len = p_strnlen(packfile_name, chunk_size); + if (len == 0) + return midx_error("empty packfile name"); + if (len + 1 > chunk_size) + return midx_error("unterminated packfile name"); + git_vector_insert(&idx->packfile_names, packfile_name); + if (i && strcmp(git_vector_get(&idx->packfile_names, i - 1), packfile_name) >= 0) + return midx_error("packfile names are not sorted"); + if (strlen(packfile_name) <= strlen(".idx") || git__suffixcmp(packfile_name, ".idx") != 0) + return midx_error("non-.idx packfile name"); + if (strchr(packfile_name, '/') != NULL || strchr(packfile_name, '\\') != NULL) + return midx_error("non-local packfile"); + packfile_name += len + 1; + chunk_size -= len + 1; + } + return 0; +} + +static int midx_parse_oid_fanout( + git_midx_file *idx, + const unsigned char *data, + struct git_midx_chunk *chunk_oid_fanout) +{ + uint32_t i, nr; + if (chunk_oid_fanout->offset == 0) + return midx_error("missing OID Fanout chunk"); + if (chunk_oid_fanout->length == 0) + return midx_error("empty OID Fanout chunk"); + if (chunk_oid_fanout->length != 256 * 4) + return midx_error("OID Fanout chunk has wrong length"); + + idx->oid_fanout = (const uint32_t *)(data + chunk_oid_fanout->offset); + nr = 0; + for (i = 0; i < 256; ++i) { + uint32_t n = ntohl(idx->oid_fanout[i]); + if (n < nr) + return midx_error("index is non-monotonic"); + nr = n; + } + idx->num_objects = nr; + return 0; +} + +static int midx_parse_oid_lookup( + git_midx_file *idx, + const unsigned char *data, + struct git_midx_chunk *chunk_oid_lookup) +{ + size_t oid_size = git_oid_size(idx->oid_type); + + if (chunk_oid_lookup->offset == 0) + return midx_error("missing OID Lookup chunk"); + if (chunk_oid_lookup->length == 0) + return midx_error("empty OID Lookup chunk"); + if (chunk_oid_lookup->length != idx->num_objects * oid_size) + return midx_error("OID Lookup chunk has wrong length"); + + idx->oid_lookup = (unsigned char *)(data + chunk_oid_lookup->offset); + + return 0; +} + +static int midx_parse_object_offsets( + git_midx_file *idx, + const unsigned char *data, + struct git_midx_chunk *chunk_object_offsets) +{ + if (chunk_object_offsets->offset == 0) + return midx_error("missing Object Offsets chunk"); + if (chunk_object_offsets->length == 0) + return midx_error("empty Object Offsets chunk"); + if (chunk_object_offsets->length != idx->num_objects * 8) + return midx_error("Object Offsets chunk has wrong length"); + + idx->object_offsets = data + chunk_object_offsets->offset; + + return 0; +} + +static int midx_parse_object_large_offsets( + git_midx_file *idx, + const unsigned char *data, + struct git_midx_chunk *chunk_object_large_offsets) +{ + if (chunk_object_large_offsets->length == 0) + return 0; + if (chunk_object_large_offsets->length % 8 != 0) + return midx_error("malformed Object Large Offsets chunk"); + + idx->object_large_offsets = data + chunk_object_large_offsets->offset; + idx->num_object_large_offsets = chunk_object_large_offsets->length / 8; + + return 0; +} + +int git_midx_parse( + git_midx_file *idx, + const unsigned char *data, + size_t size) +{ + struct git_midx_header *hdr; + const unsigned char *chunk_hdr; + struct git_midx_chunk *last_chunk; + uint32_t i; + off64_t last_chunk_offset, chunk_offset, trailer_offset; + size_t checksum_size, oid_size; + int error; + struct git_midx_chunk chunk_packfile_names = {0}, + chunk_oid_fanout = {0}, + chunk_oid_lookup = {0}, + chunk_object_offsets = {0}, + chunk_object_large_offsets = {0}, + chunk_unknown = {0}; + + GIT_ASSERT_ARG(idx); + + oid_size = git_oid_size(idx->oid_type); + + if (size < sizeof(struct git_midx_header) + oid_size) + return midx_error("multi-pack index is too short"); + + hdr = ((struct git_midx_header *)data); + + if (hdr->signature != htonl(MIDX_SIGNATURE) || + hdr->version != MIDX_VERSION || + hdr->object_id_version != MIDX_OBJECT_ID_VERSION) { + return midx_error("unsupported multi-pack index version"); + } + if (hdr->chunks == 0) + return midx_error("no chunks in multi-pack index"); + + /* + * The very first chunk's offset should be after the header, all the chunk + * headers, and a special zero chunk. + */ + last_chunk_offset = + sizeof(struct git_midx_header) + + (1 + hdr->chunks) * 12; + + checksum_size = oid_size; + trailer_offset = size - checksum_size; + + if (trailer_offset < last_chunk_offset) + return midx_error("wrong index size"); + memcpy(idx->checksum, data + trailer_offset, checksum_size); + + chunk_hdr = data + sizeof(struct git_midx_header); + last_chunk = NULL; + for (i = 0; i < hdr->chunks; ++i, chunk_hdr += 12) { + uint32_t chunk_id = ntohl(*((uint32_t *)(chunk_hdr + 0))); + uint64_t high_offset = ((uint64_t)ntohl(*((uint32_t *)(chunk_hdr + 4)))) & 0xffffffffu; + uint64_t low_offset = ((uint64_t)ntohl(*((uint32_t *)(chunk_hdr + 8)))) & 0xffffffffu; + + if (high_offset >= INT32_MAX) + return midx_error("chunk offset out of range"); + chunk_offset = (off64_t)(high_offset << 32 | low_offset); + if (chunk_offset < last_chunk_offset) + return midx_error("chunks are non-monotonic"); + if (chunk_offset >= trailer_offset) + return midx_error("chunks extend beyond the trailer"); + if (last_chunk != NULL) + last_chunk->length = (size_t)(chunk_offset - last_chunk_offset); + last_chunk_offset = chunk_offset; + + switch (chunk_id) { + case MIDX_PACKFILE_NAMES_ID: + chunk_packfile_names.offset = last_chunk_offset; + last_chunk = &chunk_packfile_names; + break; + + case MIDX_OID_FANOUT_ID: + chunk_oid_fanout.offset = last_chunk_offset; + last_chunk = &chunk_oid_fanout; + break; + + case MIDX_OID_LOOKUP_ID: + chunk_oid_lookup.offset = last_chunk_offset; + last_chunk = &chunk_oid_lookup; + break; + + case MIDX_OBJECT_OFFSETS_ID: + chunk_object_offsets.offset = last_chunk_offset; + last_chunk = &chunk_object_offsets; + break; + + case MIDX_OBJECT_LARGE_OFFSETS_ID: + chunk_object_large_offsets.offset = last_chunk_offset; + last_chunk = &chunk_object_large_offsets; + break; + + default: + chunk_unknown.offset = last_chunk_offset; + last_chunk = &chunk_unknown; + break; + } + } + last_chunk->length = (size_t)(trailer_offset - last_chunk_offset); + + error = midx_parse_packfile_names( + idx, data, ntohl(hdr->packfiles), &chunk_packfile_names); + if (error < 0) + return error; + error = midx_parse_oid_fanout(idx, data, &chunk_oid_fanout); + if (error < 0) + return error; + error = midx_parse_oid_lookup(idx, data, &chunk_oid_lookup); + if (error < 0) + return error; + error = midx_parse_object_offsets(idx, data, &chunk_object_offsets); + if (error < 0) + return error; + error = midx_parse_object_large_offsets(idx, data, &chunk_object_large_offsets); + if (error < 0) + return error; + + return 0; +} + +int git_midx_open( + git_midx_file **idx_out, + const char *path, + git_oid_t oid_type) +{ + git_midx_file *idx; + git_file fd = -1; + size_t idx_size; + struct stat st; + int error; + + GIT_ASSERT_ARG(idx_out && path && oid_type); + + /* TODO: properly open the file without access time using O_NOATIME */ + fd = git_futils_open_ro(path); + if (fd < 0) + return fd; + + if (p_fstat(fd, &st) < 0) { + p_close(fd); + git_error_set(GIT_ERROR_ODB, "multi-pack-index file not found - '%s'", path); + return -1; + } + + if (!S_ISREG(st.st_mode) || !git__is_sizet(st.st_size)) { + p_close(fd); + git_error_set(GIT_ERROR_ODB, "invalid pack index '%s'", path); + return -1; + } + idx_size = (size_t)st.st_size; + + idx = git__calloc(1, sizeof(git_midx_file)); + GIT_ERROR_CHECK_ALLOC(idx); + + idx->oid_type = oid_type; + + error = git_str_sets(&idx->filename, path); + if (error < 0) + return error; + + error = git_futils_mmap_ro(&idx->index_map, fd, 0, idx_size); + p_close(fd); + if (error < 0) { + git_midx_free(idx); + return error; + } + + if ((error = git_midx_parse(idx, idx->index_map.data, idx_size)) < 0) { + git_midx_free(idx); + return error; + } + + *idx_out = idx; + return 0; +} + +bool git_midx_needs_refresh( + const git_midx_file *idx, + const char *path) +{ + git_file fd = -1; + struct stat st; + ssize_t bytes_read; + unsigned char checksum[GIT_HASH_MAX_SIZE]; + size_t checksum_size; + + /* TODO: properly open the file without access time using O_NOATIME */ + fd = git_futils_open_ro(path); + if (fd < 0) + return true; + + if (p_fstat(fd, &st) < 0) { + p_close(fd); + return true; + } + + if (!S_ISREG(st.st_mode) || + !git__is_sizet(st.st_size) || + (size_t)st.st_size != idx->index_map.len) { + p_close(fd); + return true; + } + + checksum_size = git_oid_size(idx->oid_type); + bytes_read = p_pread(fd, checksum, checksum_size, st.st_size - checksum_size); + p_close(fd); + + if (bytes_read != (ssize_t)checksum_size) + return true; + + return (memcmp(checksum, idx->checksum, checksum_size) != 0); +} + +int git_midx_entry_find( + git_midx_entry *e, + git_midx_file *idx, + const git_oid *short_oid, + size_t len) +{ + int pos, found = 0; + size_t pack_index, oid_size, oid_hexsize; + uint32_t hi, lo; + unsigned char *current = NULL; + const unsigned char *object_offset; + off64_t offset; + + GIT_ASSERT_ARG(idx); + + oid_size = git_oid_size(idx->oid_type); + oid_hexsize = git_oid_hexsize(idx->oid_type); + + hi = ntohl(idx->oid_fanout[(int)short_oid->id[0]]); + lo = ((short_oid->id[0] == 0x0) ? 0 : ntohl(idx->oid_fanout[(int)short_oid->id[0] - 1])); + + pos = git_pack__lookup_id(idx->oid_lookup, oid_size, lo, hi, short_oid->id, idx->oid_type); + + if (pos >= 0) { + /* An object matching exactly the oid was found */ + found = 1; + current = idx->oid_lookup + (pos * oid_size); + } else { + /* No object was found */ + /* pos refers to the object with the "closest" oid to short_oid */ + pos = -1 - pos; + if (pos < (int)idx->num_objects) { + current = idx->oid_lookup + (pos * oid_size); + + if (!git_oid_raw_ncmp(short_oid->id, current, len)) + found = 1; + } + } + + if (found && len != oid_hexsize && pos + 1 < (int)idx->num_objects) { + /* Check for ambiguousity */ + const unsigned char *next = current + oid_size; + + if (!git_oid_raw_ncmp(short_oid->id, next, len)) + found = 2; + } + + if (!found) + return git_odb__error_notfound("failed to find offset for multi-pack index entry", short_oid, len); + if (found > 1) + return git_odb__error_ambiguous("found multiple offsets for multi-pack index entry"); + + object_offset = idx->object_offsets + pos * 8; + offset = ntohl(*((uint32_t *)(object_offset + 4))); + if (idx->object_large_offsets && offset & 0x80000000) { + uint32_t object_large_offsets_pos = (uint32_t) (offset ^ 0x80000000); + const unsigned char *object_large_offsets_index = idx->object_large_offsets; + + /* Make sure we're not being sent out of bounds */ + if (object_large_offsets_pos >= idx->num_object_large_offsets) + return git_odb__error_notfound("invalid index into the object large offsets table", short_oid, len); + + object_large_offsets_index += 8 * object_large_offsets_pos; + + offset = (((uint64_t)ntohl(*((uint32_t *)(object_large_offsets_index + 0)))) << 32) | + ntohl(*((uint32_t *)(object_large_offsets_index + 4))); + } + pack_index = ntohl(*((uint32_t *)(object_offset + 0))); + if (pack_index >= git_vector_length(&idx->packfile_names)) + return midx_error("invalid index into the packfile names table"); + e->pack_index = pack_index; + e->offset = offset; + git_oid__fromraw(&e->sha1, current, idx->oid_type); + return 0; +} + +int git_midx_foreach_entry( + git_midx_file *idx, + git_odb_foreach_cb cb, + void *data) +{ + git_oid oid; + size_t oid_size, i; + int error; + + GIT_ASSERT_ARG(idx); + + oid_size = git_oid_size(idx->oid_type); + + for (i = 0; i < idx->num_objects; ++i) { + if ((error = git_oid__fromraw(&oid, &idx->oid_lookup[i * oid_size], idx->oid_type)) < 0) + return error; + + if ((error = cb(&oid, data)) != 0) + return git_error_set_after_callback(error); + } + + return error; +} + +int git_midx_close(git_midx_file *idx) +{ + GIT_ASSERT_ARG(idx); + + if (idx->index_map.data) + git_futils_mmap_free(&idx->index_map); + + git_vector_free(&idx->packfile_names); + + return 0; +} + +void git_midx_free(git_midx_file *idx) +{ + if (!idx) + return; + + git_str_dispose(&idx->filename); + git_midx_close(idx); + git__free(idx); +} + +static int packfile__cmp(const void *a_, const void *b_) +{ + const struct git_pack_file *a = a_; + const struct git_pack_file *b = b_; + + return strcmp(a->pack_name, b->pack_name); +} + +int git_midx_writer_new( + git_midx_writer **out, + const char *pack_dir +#ifdef GIT_EXPERIMENTAL_SHA256 + , git_oid_t oid_type +#endif + ) +{ + git_midx_writer *w; + +#ifndef GIT_EXPERIMENTAL_SHA256 + git_oid_t oid_type = GIT_OID_SHA1; +#endif + + GIT_ASSERT_ARG(out && pack_dir && oid_type); + + w = git__calloc(1, sizeof(git_midx_writer)); + GIT_ERROR_CHECK_ALLOC(w); + + if (git_str_sets(&w->pack_dir, pack_dir) < 0) { + git__free(w); + return -1; + } + git_fs_path_squash_slashes(&w->pack_dir); + + if (git_vector_init(&w->packs, 0, packfile__cmp) < 0) { + git_str_dispose(&w->pack_dir); + git__free(w); + return -1; + } + + w->oid_type = oid_type; + + *out = w; + return 0; +} + +void git_midx_writer_free(git_midx_writer *w) +{ + struct git_pack_file *p; + size_t i; + + if (!w) + return; + + git_vector_foreach (&w->packs, i, p) + git_mwindow_put_pack(p); + git_vector_free(&w->packs); + git_str_dispose(&w->pack_dir); + git__free(w); +} + +int git_midx_writer_add( + git_midx_writer *w, + const char *idx_path) +{ + git_str idx_path_buf = GIT_STR_INIT; + int error; + struct git_pack_file *p; + + error = git_fs_path_prettify(&idx_path_buf, idx_path, git_str_cstr(&w->pack_dir)); + if (error < 0) + return error; + + /* TODO: SHA256 */ + error = git_mwindow_get_pack(&p, git_str_cstr(&idx_path_buf), 0); + git_str_dispose(&idx_path_buf); + if (error < 0) + return error; + + error = git_vector_insert(&w->packs, p); + if (error < 0) { + git_mwindow_put_pack(p); + return error; + } + + return 0; +} + +typedef git_array_t(git_midx_entry) object_entry_array_t; + +struct object_entry_cb_state { + uint32_t pack_index; + object_entry_array_t *object_entries_array; +}; + +static int object_entry__cb(const git_oid *oid, off64_t offset, void *data) +{ + struct object_entry_cb_state *state = (struct object_entry_cb_state *)data; + + git_midx_entry *entry = git_array_alloc(*state->object_entries_array); + GIT_ERROR_CHECK_ALLOC(entry); + + git_oid_cpy(&entry->sha1, oid); + entry->offset = offset; + entry->pack_index = state->pack_index; + + return 0; +} + +static int object_entry__cmp(const void *a_, const void *b_) +{ + const git_midx_entry *a = (const git_midx_entry *)a_; + const git_midx_entry *b = (const git_midx_entry *)b_; + + return git_oid_cmp(&a->sha1, &b->sha1); +} + +static int write_offset(off64_t offset, midx_write_cb write_cb, void *cb_data) +{ + int error; + uint32_t word; + + word = htonl((uint32_t)((offset >> 32) & 0xffffffffu)); + error = write_cb((const char *)&word, sizeof(word), cb_data); + if (error < 0) + return error; + word = htonl((uint32_t)((offset >> 0) & 0xffffffffu)); + error = write_cb((const char *)&word, sizeof(word), cb_data); + if (error < 0) + return error; + + return 0; +} + +static int write_chunk_header(int chunk_id, off64_t offset, midx_write_cb write_cb, void *cb_data) +{ + uint32_t word = htonl(chunk_id); + int error = write_cb((const char *)&word, sizeof(word), cb_data); + if (error < 0) + return error; + return write_offset(offset, write_cb, cb_data); + + return 0; +} + +static int midx_write_buf(const char *buf, size_t size, void *data) +{ + git_str *b = (git_str *)data; + return git_str_put(b, buf, size); +} + +struct midx_write_hash_context { + midx_write_cb write_cb; + void *cb_data; + git_hash_ctx *ctx; +}; + +static int midx_write_hash(const char *buf, size_t size, void *data) +{ + struct midx_write_hash_context *ctx = (struct midx_write_hash_context *)data; + int error; + + error = git_hash_update(ctx->ctx, buf, size); + if (error < 0) + return error; + + return ctx->write_cb(buf, size, ctx->cb_data); +} + +static int midx_write( + git_midx_writer *w, + midx_write_cb write_cb, + void *cb_data) +{ + int error = 0; + size_t i; + struct git_pack_file *p; + struct git_midx_header hdr = {0}; + uint32_t oid_fanout_count; + uint32_t object_large_offsets_count; + uint32_t oid_fanout[256]; + off64_t offset; + git_str packfile_names = GIT_STR_INIT, + oid_lookup = GIT_STR_INIT, + object_offsets = GIT_STR_INIT, + object_large_offsets = GIT_STR_INIT; + unsigned char checksum[GIT_HASH_MAX_SIZE]; + size_t checksum_size, oid_size; + git_midx_entry *entry; + object_entry_array_t object_entries_array = GIT_ARRAY_INIT; + git_vector object_entries = GIT_VECTOR_INIT; + git_hash_ctx ctx; + git_hash_algorithm_t checksum_type; + struct midx_write_hash_context hash_cb_data = {0}; + + hdr.signature = htonl(MIDX_SIGNATURE); + hdr.version = MIDX_VERSION; + hdr.object_id_version = MIDX_OBJECT_ID_VERSION; + hdr.base_midx_files = 0; + + hash_cb_data.write_cb = write_cb; + hash_cb_data.cb_data = cb_data; + hash_cb_data.ctx = &ctx; + + oid_size = git_oid_size(w->oid_type); + checksum_type = git_oid_algorithm(w->oid_type); + checksum_size = git_hash_size(checksum_type); + GIT_ASSERT(oid_size && checksum_type && checksum_size); + + if ((error = git_hash_ctx_init(&ctx, checksum_type)) < 0) + return error; + + cb_data = &hash_cb_data; + write_cb = midx_write_hash; + + git_vector_sort(&w->packs); + git_vector_foreach (&w->packs, i, p) { + git_str relative_index = GIT_STR_INIT; + struct object_entry_cb_state state = {0}; + size_t path_len; + + state.pack_index = (uint32_t)i; + state.object_entries_array = &object_entries_array; + + error = git_str_sets(&relative_index, p->pack_name); + if (error < 0) + goto cleanup; + error = git_fs_path_make_relative(&relative_index, git_str_cstr(&w->pack_dir)); + if (error < 0) { + git_str_dispose(&relative_index); + goto cleanup; + } + path_len = git_str_len(&relative_index); + if (path_len <= strlen(".pack") || git__suffixcmp(git_str_cstr(&relative_index), ".pack") != 0) { + git_str_dispose(&relative_index); + git_error_set(GIT_ERROR_INVALID, "invalid packfile name: '%s'", p->pack_name); + error = -1; + goto cleanup; + } + path_len -= strlen(".pack"); + + git_str_put(&packfile_names, git_str_cstr(&relative_index), path_len); + git_str_puts(&packfile_names, ".idx"); + git_str_putc(&packfile_names, '\0'); + git_str_dispose(&relative_index); + + error = git_pack_foreach_entry_offset(p, object_entry__cb, &state); + if (error < 0) + goto cleanup; + } + + /* Sort the object entries. */ + error = git_vector_init(&object_entries, git_array_size(object_entries_array), object_entry__cmp); + if (error < 0) + goto cleanup; + git_array_foreach (object_entries_array, i, entry) { + if ((error = git_vector_set(NULL, &object_entries, i, entry)) < 0) + goto cleanup; + } + git_vector_set_sorted(&object_entries, 0); + git_vector_sort(&object_entries); + git_vector_uniq(&object_entries, NULL); + + /* Pad the packfile names so it is a multiple of four. */ + while (git_str_len(&packfile_names) & 3) + git_str_putc(&packfile_names, '\0'); + + /* Fill the OID Fanout table. */ + oid_fanout_count = 0; + for (i = 0; i < 256; i++) { + while (oid_fanout_count < git_vector_length(&object_entries) && + ((const git_midx_entry *)git_vector_get(&object_entries, oid_fanout_count))->sha1.id[0] <= i) + ++oid_fanout_count; + oid_fanout[i] = htonl(oid_fanout_count); + } + + /* Fill the OID Lookup table. */ + git_vector_foreach (&object_entries, i, entry) { + error = git_str_put(&oid_lookup, + (char *)&entry->sha1.id, oid_size); + + if (error < 0) + goto cleanup; + } + + /* Fill the Object Offsets and Object Large Offsets tables. */ + object_large_offsets_count = 0; + git_vector_foreach (&object_entries, i, entry) { + uint32_t word; + + word = htonl((uint32_t)entry->pack_index); + error = git_str_put(&object_offsets, (const char *)&word, sizeof(word)); + if (error < 0) + goto cleanup; + if (entry->offset >= 0x80000000l) { + word = htonl(0x80000000u | object_large_offsets_count++); + if ((error = write_offset(entry->offset, midx_write_buf, &object_large_offsets)) < 0) + goto cleanup; + } else { + word = htonl((uint32_t)entry->offset & 0x7fffffffu); + } + + error = git_str_put(&object_offsets, (const char *)&word, sizeof(word)); + if (error < 0) + goto cleanup; + } + + /* Write the header. */ + hdr.packfiles = htonl((uint32_t)git_vector_length(&w->packs)); + hdr.chunks = 4; + if (git_str_len(&object_large_offsets) > 0) + hdr.chunks++; + error = write_cb((const char *)&hdr, sizeof(hdr), cb_data); + if (error < 0) + goto cleanup; + + /* Write the chunk headers. */ + offset = sizeof(hdr) + (hdr.chunks + 1) * 12; + error = write_chunk_header(MIDX_PACKFILE_NAMES_ID, offset, write_cb, cb_data); + if (error < 0) + goto cleanup; + offset += git_str_len(&packfile_names); + error = write_chunk_header(MIDX_OID_FANOUT_ID, offset, write_cb, cb_data); + if (error < 0) + goto cleanup; + offset += sizeof(oid_fanout); + error = write_chunk_header(MIDX_OID_LOOKUP_ID, offset, write_cb, cb_data); + if (error < 0) + goto cleanup; + offset += git_str_len(&oid_lookup); + error = write_chunk_header(MIDX_OBJECT_OFFSETS_ID, offset, write_cb, cb_data); + if (error < 0) + goto cleanup; + offset += git_str_len(&object_offsets); + if (git_str_len(&object_large_offsets) > 0) { + error = write_chunk_header(MIDX_OBJECT_LARGE_OFFSETS_ID, offset, write_cb, cb_data); + if (error < 0) + goto cleanup; + offset += git_str_len(&object_large_offsets); + } + error = write_chunk_header(0, offset, write_cb, cb_data); + if (error < 0) + goto cleanup; + + /* Write all the chunks. */ + error = write_cb(git_str_cstr(&packfile_names), git_str_len(&packfile_names), cb_data); + if (error < 0) + goto cleanup; + error = write_cb((const char *)oid_fanout, sizeof(oid_fanout), cb_data); + if (error < 0) + goto cleanup; + error = write_cb(git_str_cstr(&oid_lookup), git_str_len(&oid_lookup), cb_data); + if (error < 0) + goto cleanup; + error = write_cb(git_str_cstr(&object_offsets), git_str_len(&object_offsets), cb_data); + if (error < 0) + goto cleanup; + error = write_cb(git_str_cstr(&object_large_offsets), git_str_len(&object_large_offsets), cb_data); + if (error < 0) + goto cleanup; + + /* Finalize the checksum and write the trailer. */ + error = git_hash_final(checksum, &ctx); + if (error < 0) + goto cleanup; + error = write_cb((char *)checksum, checksum_size, cb_data); + if (error < 0) + goto cleanup; + +cleanup: + git_array_clear(object_entries_array); + git_vector_free(&object_entries); + git_str_dispose(&packfile_names); + git_str_dispose(&oid_lookup); + git_str_dispose(&object_offsets); + git_str_dispose(&object_large_offsets); + git_hash_ctx_cleanup(&ctx); + return error; +} + +static int midx_write_filebuf(const char *buf, size_t size, void *data) +{ + git_filebuf *f = (git_filebuf *)data; + return git_filebuf_write(f, buf, size); +} + +int git_midx_writer_commit( + git_midx_writer *w) +{ + int error; + int filebuf_flags = GIT_FILEBUF_DO_NOT_BUFFER; + git_str midx_path = GIT_STR_INIT; + git_filebuf output = GIT_FILEBUF_INIT; + + error = git_str_joinpath(&midx_path, git_str_cstr(&w->pack_dir), "multi-pack-index"); + if (error < 0) + return error; + + if (git_repository__fsync_gitdir) + filebuf_flags |= GIT_FILEBUF_FSYNC; + error = git_filebuf_open(&output, git_str_cstr(&midx_path), filebuf_flags, 0644); + git_str_dispose(&midx_path); + if (error < 0) + return error; + + error = midx_write(w, midx_write_filebuf, &output); + if (error < 0) { + git_filebuf_cleanup(&output); + return error; + } + + return git_filebuf_commit(&output); +} + +int git_midx_writer_dump( + git_buf *midx, + git_midx_writer *w) +{ + git_str str = GIT_STR_INIT; + int error; + + if ((error = git_buf_tostr(&str, midx)) < 0 || + (error = midx_write(w, midx_write_buf, &str)) == 0) + error = git_buf_fromstr(midx, &str); + + git_str_dispose(&str); + return error; +} diff --git a/vendor/libgit2/src/midx.h b/vendor/libgit2/src/libgit2/midx.h similarity index 87% rename from vendor/libgit2/src/midx.h rename to vendor/libgit2/src/libgit2/midx.h index 7dd851bd..5107f69c 100644 --- a/vendor/libgit2/src/midx.h +++ b/vendor/libgit2/src/libgit2/midx.h @@ -17,6 +17,7 @@ #include "map.h" #include "mwindow.h" #include "odb.h" +#include "oid.h" /* * A multi-pack-index file. @@ -40,7 +41,7 @@ typedef struct git_midx_file { uint32_t num_objects; /* The OID Lookup table. */ - git_oid *oid_lookup; + unsigned char *oid_lookup; /* The Object Offsets table. Each entry has two 4-byte fields with the pack index and the offset. */ const unsigned char *object_offsets; @@ -50,8 +51,14 @@ typedef struct git_midx_file { /* The number of entries in the Object Large Offsets table. Each entry has an 8-byte with an offset */ size_t num_object_large_offsets; - /* The trailer of the file. Contains the SHA1-checksum of the whole file. */ - unsigned char checksum[GIT_HASH_SHA1_SIZE]; + /* + * The trailer of the file. Contains the checksum of the whole + * file, in the repository's object format hash. + */ + unsigned char checksum[GIT_HASH_MAX_SIZE]; + + /* The type of object IDs in the midx. */ + git_oid_t oid_type; /* something like ".git/objects/pack/multi-pack-index". */ git_str filename; @@ -81,11 +88,15 @@ struct git_midx_writer { /* The list of `git_pack_file`s. */ git_vector packs; + + /* The object ID type of the writer. */ + git_oid_t oid_type; }; int git_midx_open( git_midx_file **idx_out, - const char *path); + const char *path, + git_oid_t oid_type); bool git_midx_needs_refresh( const git_midx_file *idx, const char *path); diff --git a/vendor/libgit2/src/mwindow.c b/vendor/libgit2/src/libgit2/mwindow.c similarity index 94% rename from vendor/libgit2/src/mwindow.c rename to vendor/libgit2/src/libgit2/mwindow.c index d06b7a80..b8295d9d 100644 --- a/vendor/libgit2/src/mwindow.c +++ b/vendor/libgit2/src/libgit2/mwindow.c @@ -61,7 +61,10 @@ int git_mwindow_global_init(void) return git_runtime_shutdown_register(git_mwindow_global_shutdown); } -int git_mwindow_get_pack(struct git_pack_file **out, const char *path) +int git_mwindow_get_pack( + struct git_pack_file **out, + const char *path, + git_oid_t oid_type) { struct git_pack_file *pack; char *packname; @@ -86,7 +89,7 @@ int git_mwindow_get_pack(struct git_pack_file **out, const char *path) } /* If we didn't find it, we need to create it */ - if ((error = git_packfile_alloc(&pack, path)) < 0) { + if ((error = git_packfile_alloc(&pack, path, oid_type)) < 0) { git_mutex_unlock(&git__mwindow_mutex); return error; } @@ -186,13 +189,16 @@ int git_mwindow_free_all(git_mwindow_file *mwf) } /* - * Check if a window 'win' contains the address 'offset' + * Check if a window 'win' contains both the address 'offset' and 'extra'. + * + * 'extra' is the size of the hash we're using as we always want to make sure + * that it's contained. */ -int git_mwindow_contains(git_mwindow *win, off64_t offset) +int git_mwindow_contains(git_mwindow *win, off64_t offset, off64_t extra) { off64_t win_off = win->offset; return win_off <= offset - && offset <= (off64_t)(win_off + win->window_map.len); + && (offset + extra) <= (off64_t)(win_off + win->window_map.len); } #define GIT_MWINDOW__LRU -1 @@ -237,9 +243,7 @@ static bool git_mwindow_scan_recently_used( * store it in the output parameter. If lru_window is NULL, * it's the first loop, so store it as well. */ - if (!lru_window || - (comparison_sign == GIT_MWINDOW__LRU && lru_window->last_used > w->last_used) || - (comparison_sign == GIT_MWINDOW__MRU && lru_window->last_used < w->last_used)) { + if (!lru_window || (comparison_sign * w->last_used) > lru_window->last_used) { lru_window = w; lru_last = w_last; found = true; @@ -406,14 +410,13 @@ unsigned char *git_mwindow_open( return NULL; } - if (!w || !(git_mwindow_contains(w, offset) && git_mwindow_contains(w, offset + extra))) { + if (!w || !(git_mwindow_contains(w, offset, extra))) { if (w) { w->inuse_cnt--; } for (w = mwf->windows; w; w = w->next) { - if (git_mwindow_contains(w, offset) && - git_mwindow_contains(w, offset + extra)) + if (git_mwindow_contains(w, offset, extra)) break; } diff --git a/vendor/libgit2/src/mwindow.h b/vendor/libgit2/src/libgit2/mwindow.h similarity index 88% rename from vendor/libgit2/src/mwindow.h rename to vendor/libgit2/src/libgit2/mwindow.h index e3a03f01..8e6df261 100644 --- a/vendor/libgit2/src/mwindow.h +++ b/vendor/libgit2/src/libgit2/mwindow.h @@ -38,7 +38,7 @@ typedef struct git_mwindow_ctl { git_vector windowfiles; } git_mwindow_ctl; -int git_mwindow_contains(git_mwindow *win, off64_t offset); +int git_mwindow_contains(git_mwindow *win, off64_t offset, off64_t extra); int git_mwindow_free_all(git_mwindow_file *mwf); /* locks */ unsigned char *git_mwindow_open(git_mwindow_file *mwf, git_mwindow **cursor, off64_t offset, size_t extra, unsigned int *left); int git_mwindow_file_register(git_mwindow_file *mwf); @@ -48,7 +48,10 @@ void git_mwindow_close(git_mwindow **w_cursor); extern int git_mwindow_global_init(void); struct git_pack_file; /* just declaration to avoid cyclical includes */ -int git_mwindow_get_pack(struct git_pack_file **out, const char *path); +int git_mwindow_get_pack( + struct git_pack_file **out, + const char *path, + git_oid_t oid_type); int git_mwindow_put_pack(struct git_pack_file *pack); #endif diff --git a/vendor/libgit2/src/libgit2/notes.c b/vendor/libgit2/src/libgit2/notes.c new file mode 100644 index 00000000..13ca3824 --- /dev/null +++ b/vendor/libgit2/src/libgit2/notes.c @@ -0,0 +1,810 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "notes.h" + +#include "buf.h" +#include "refs.h" +#include "config.h" +#include "iterator.h" +#include "signature.h" +#include "blob.h" + +static int note_error_notfound(void) +{ + git_error_set(GIT_ERROR_INVALID, "note could not be found"); + return GIT_ENOTFOUND; +} + +static int find_subtree_in_current_level( + git_tree **out, + git_repository *repo, + git_tree *parent, + const char *annotated_object_sha, + int fanout) +{ + size_t i; + const git_tree_entry *entry; + + *out = NULL; + + if (parent == NULL) + return note_error_notfound(); + + for (i = 0; i < git_tree_entrycount(parent); i++) { + entry = git_tree_entry_byindex(parent, i); + + if (!git__ishex(git_tree_entry_name(entry))) + continue; + + if (S_ISDIR(git_tree_entry_filemode(entry)) + && strlen(git_tree_entry_name(entry)) == 2 + && !strncmp(git_tree_entry_name(entry), annotated_object_sha + fanout, 2)) + return git_tree_lookup(out, repo, git_tree_entry_id(entry)); + + /* Not a DIR, so do we have an already existing blob? */ + if (!strcmp(git_tree_entry_name(entry), annotated_object_sha + fanout)) + return GIT_EEXISTS; + } + + return note_error_notfound(); +} + +static int find_subtree_r(git_tree **out, git_tree *root, + git_repository *repo, const char *target, int *fanout) +{ + int error; + git_tree *subtree = NULL; + + *out = NULL; + + error = find_subtree_in_current_level(&subtree, repo, root, target, *fanout); + if (error == GIT_EEXISTS) + return git_tree_lookup(out, repo, git_tree_id(root)); + + if (error < 0) + return error; + + *fanout += 2; + error = find_subtree_r(out, subtree, repo, target, fanout); + git_tree_free(subtree); + + return error; +} + +static int find_blob(git_oid *blob, git_tree *tree, const char *target) +{ + size_t i; + const git_tree_entry *entry; + + for (i=0; iid, note_oid); + + if (git_signature_dup(¬e->author, git_commit_author(commit)) < 0 || + git_signature_dup(¬e->committer, git_commit_committer(commit)) < 0) + return -1; + + blobsize = git_blob_rawsize(blob); + GIT_ERROR_CHECK_BLOBSIZE(blobsize); + + note->message = git__strndup(git_blob_rawcontent(blob), (size_t)blobsize); + GIT_ERROR_CHECK_ALLOC(note->message); + + *out = note; + return 0; +} + +static int note_lookup( + git_note **out, + git_repository *repo, + git_commit *commit, + git_tree *tree, + const char *target) +{ + int error, fanout = 0; + git_oid oid; + git_blob *blob = NULL; + git_note *note = NULL; + git_tree *subtree = NULL; + + if ((error = find_subtree_r(&subtree, tree, repo, target, &fanout)) < 0) + goto cleanup; + + if ((error = find_blob(&oid, subtree, target + fanout)) < 0) + goto cleanup; + + if ((error = git_blob_lookup(&blob, repo, &oid)) < 0) + goto cleanup; + + if ((error = note_new(¬e, &oid, commit, blob)) < 0) + goto cleanup; + + *out = note; + +cleanup: + git_tree_free(subtree); + git_blob_free(blob); + return error; +} + +static int note_remove( + git_oid *notes_commit_out, + git_repository *repo, + const git_signature *author, const git_signature *committer, + const char *notes_ref, git_tree *tree, + const char *target, git_commit **parents) +{ + int error; + git_tree *tree_after_removal = NULL; + git_oid oid; + + if ((error = manipulate_note_in_tree_r( + &tree_after_removal, repo, tree, NULL, target, 0, + remove_note_in_tree_eexists_cb, remove_note_in_tree_enotfound_cb)) < 0) + goto cleanup; + + error = git_commit_create(&oid, repo, notes_ref, author, committer, + NULL, GIT_NOTES_DEFAULT_MSG_RM, + tree_after_removal, + *parents == NULL ? 0 : 1, + (const git_commit **) parents); + + if (error < 0) + goto cleanup; + + if (notes_commit_out) + git_oid_cpy(notes_commit_out, &oid); + +cleanup: + git_tree_free(tree_after_removal); + return error; +} + +static int note_get_default_ref(git_str *out, git_repository *repo) +{ + git_config *cfg; + int error; + + if ((error = git_repository_config__weakptr(&cfg, repo)) < 0) + return error; + + error = git_config__get_string_buf(out, cfg, "core.notesref"); + + if (error == GIT_ENOTFOUND) + error = git_str_puts(out, GIT_NOTES_DEFAULT_REF); + + return error; +} + +static int normalize_namespace(git_str *out, git_repository *repo, const char *notes_ref) +{ + if (notes_ref) + return git_str_puts(out, notes_ref); + + return note_get_default_ref(out, repo); +} + +static int retrieve_note_commit( + git_commit **commit_out, + git_str *notes_ref_out, + git_repository *repo, + const char *notes_ref) +{ + int error; + git_oid oid; + + if ((error = normalize_namespace(notes_ref_out, repo, notes_ref)) < 0) + return error; + + if ((error = git_reference_name_to_id(&oid, repo, notes_ref_out->ptr)) < 0) + return error; + + if (git_commit_lookup(commit_out, repo, &oid) < 0) + return error; + + return 0; +} + +int git_note_commit_read( + git_note **out, + git_repository *repo, + git_commit *notes_commit, + const git_oid *oid) +{ + int error; + git_tree *tree = NULL; + char target[GIT_OID_MAX_HEXSIZE + 1]; + + git_oid_tostr(target, sizeof(target), oid); + + if ((error = git_commit_tree(&tree, notes_commit)) < 0) + goto cleanup; + + error = note_lookup(out, repo, notes_commit, tree, target); + +cleanup: + git_tree_free(tree); + return error; +} + +int git_note_read(git_note **out, git_repository *repo, + const char *notes_ref_in, const git_oid *oid) +{ + int error; + git_str notes_ref = GIT_STR_INIT; + git_commit *commit = NULL; + + error = retrieve_note_commit(&commit, ¬es_ref, repo, notes_ref_in); + + if (error < 0) + goto cleanup; + + error = git_note_commit_read(out, repo, commit, oid); + +cleanup: + git_str_dispose(¬es_ref); + git_commit_free(commit); + return error; +} + +int git_note_commit_create( + git_oid *notes_commit_out, + git_oid *notes_blob_out, + git_repository *repo, + git_commit *parent, + const git_signature *author, + const git_signature *committer, + const git_oid *oid, + const char *note, + int allow_note_overwrite) +{ + int error; + git_tree *tree = NULL; + char target[GIT_OID_MAX_HEXSIZE + 1]; + + git_oid_tostr(target, sizeof(target), oid); + + if (parent != NULL && (error = git_commit_tree(&tree, parent)) < 0) + goto cleanup; + + error = note_write(notes_commit_out, notes_blob_out, repo, author, + committer, NULL, note, tree, target, &parent, allow_note_overwrite); + + if (error < 0) + goto cleanup; + +cleanup: + git_tree_free(tree); + return error; +} + +int git_note_create( + git_oid *out, + git_repository *repo, + const char *notes_ref_in, + const git_signature *author, + const git_signature *committer, + const git_oid *oid, + const char *note, + int allow_note_overwrite) +{ + int error; + git_str notes_ref = GIT_STR_INIT; + git_commit *existing_notes_commit = NULL; + git_reference *ref = NULL; + git_oid notes_blob_oid, notes_commit_oid; + + error = retrieve_note_commit(&existing_notes_commit, ¬es_ref, + repo, notes_ref_in); + + if (error < 0 && error != GIT_ENOTFOUND) + goto cleanup; + + error = git_note_commit_create(¬es_commit_oid, + ¬es_blob_oid, + repo, existing_notes_commit, author, + committer, oid, note, + allow_note_overwrite); + if (error < 0) + goto cleanup; + + error = git_reference_create(&ref, repo, notes_ref.ptr, + ¬es_commit_oid, 1, NULL); + + if (out != NULL) + git_oid_cpy(out, ¬es_blob_oid); + +cleanup: + git_str_dispose(¬es_ref); + git_commit_free(existing_notes_commit); + git_reference_free(ref); + return error; +} + +int git_note_commit_remove( + git_oid *notes_commit_out, + git_repository *repo, + git_commit *notes_commit, + const git_signature *author, + const git_signature *committer, + const git_oid *oid) +{ + int error; + git_tree *tree = NULL; + char target[GIT_OID_MAX_HEXSIZE + 1]; + + git_oid_tostr(target, sizeof(target), oid); + + if ((error = git_commit_tree(&tree, notes_commit)) < 0) + goto cleanup; + + error = note_remove(notes_commit_out, + repo, author, committer, NULL, tree, target, ¬es_commit); + +cleanup: + git_tree_free(tree); + return error; +} + +int git_note_remove(git_repository *repo, const char *notes_ref_in, + const git_signature *author, const git_signature *committer, + const git_oid *oid) +{ + int error; + git_str notes_ref_target = GIT_STR_INIT; + git_commit *existing_notes_commit = NULL; + git_oid new_notes_commit; + git_reference *notes_ref = NULL; + + error = retrieve_note_commit(&existing_notes_commit, ¬es_ref_target, + repo, notes_ref_in); + + if (error < 0) + goto cleanup; + + error = git_note_commit_remove(&new_notes_commit, repo, + existing_notes_commit, author, committer, oid); + if (error < 0) + goto cleanup; + + error = git_reference_create(¬es_ref, repo, notes_ref_target.ptr, + &new_notes_commit, 1, NULL); + +cleanup: + git_str_dispose(¬es_ref_target); + git_reference_free(notes_ref); + git_commit_free(existing_notes_commit); + return error; +} + +int git_note_default_ref(git_buf *out, git_repository *repo) +{ + GIT_BUF_WRAP_PRIVATE(out, note_get_default_ref, repo); +} + +const git_signature *git_note_committer(const git_note *note) +{ + GIT_ASSERT_ARG_WITH_RETVAL(note, NULL); + return note->committer; +} + +const git_signature *git_note_author(const git_note *note) +{ + GIT_ASSERT_ARG_WITH_RETVAL(note, NULL); + return note->author; +} + +const char *git_note_message(const git_note *note) +{ + GIT_ASSERT_ARG_WITH_RETVAL(note, NULL); + return note->message; +} + +const git_oid *git_note_id(const git_note *note) +{ + GIT_ASSERT_ARG_WITH_RETVAL(note, NULL); + return ¬e->id; +} + +void git_note_free(git_note *note) +{ + if (note == NULL) + return; + + git_signature_free(note->committer); + git_signature_free(note->author); + git__free(note->message); + git__free(note); +} + +static int process_entry_path( + git_oid *annotated_object_id, + git_note_iterator *it, + const char *entry_path) +{ + int error = 0; + size_t i = 0, j = 0, len; + git_str buf = GIT_STR_INIT; + + if ((error = git_str_puts(&buf, entry_path)) < 0) + goto cleanup; + + len = git_str_len(&buf); + + while (i < len) { + if (buf.ptr[i] == '/') { + i++; + continue; + } + + if (git__fromhex(buf.ptr[i]) < 0) { + /* This is not a note entry */ + goto cleanup; + } + + if (i != j) + buf.ptr[j] = buf.ptr[i]; + + i++; + j++; + } + + buf.ptr[j] = '\0'; + buf.size = j; + + if (j != git_oid_hexsize(it->repo->oid_type)) { + /* This is not a note entry */ + goto cleanup; + } + + error = git_oid__fromstr(annotated_object_id, buf.ptr, it->repo->oid_type); + +cleanup: + git_str_dispose(&buf); + return error; +} + +int git_note_foreach( + git_repository *repo, + const char *notes_ref, + git_note_foreach_cb note_cb, + void *payload) +{ + int error; + git_note_iterator *iter = NULL; + git_oid note_id, annotated_id; + + if ((error = git_note_iterator_new(&iter, repo, notes_ref)) < 0) + return error; + + while (!(error = git_note_next(¬e_id, &annotated_id, iter))) { + if ((error = note_cb(¬e_id, &annotated_id, payload)) != 0) { + git_error_set_after_callback(error); + break; + } + } + + if (error == GIT_ITEROVER) + error = 0; + + git_note_iterator_free(iter); + return error; +} + +void git_note_iterator_free(git_note_iterator *it) +{ + if (it == NULL) + return; + + git_iterator_free(it); +} + +int git_note_commit_iterator_new( + git_note_iterator **it, + git_commit *notes_commit) +{ + int error; + git_tree *tree; + + if ((error = git_commit_tree(&tree, notes_commit)) < 0) + goto cleanup; + + if ((error = git_iterator_for_tree(it, tree, NULL)) < 0) + git_iterator_free(*it); + +cleanup: + git_tree_free(tree); + + return error; +} + +int git_note_iterator_new( + git_note_iterator **it, + git_repository *repo, + const char *notes_ref_in) +{ + int error; + git_commit *commit = NULL; + git_str notes_ref = GIT_STR_INIT; + + error = retrieve_note_commit(&commit, ¬es_ref, repo, notes_ref_in); + if (error < 0) + goto cleanup; + + error = git_note_commit_iterator_new(it, commit); + +cleanup: + git_str_dispose(¬es_ref); + git_commit_free(commit); + + return error; +} + +int git_note_next( + git_oid *note_id, + git_oid *annotated_id, + git_note_iterator *it) +{ + int error; + const git_index_entry *item; + + if ((error = git_iterator_current(&item, it)) < 0) + return error; + + git_oid_cpy(note_id, &item->id); + + if ((error = process_entry_path(annotated_id, it, item->path)) < 0) + return error; + + if ((error = git_iterator_advance(NULL, it)) < 0 && error != GIT_ITEROVER) + return error; + + return 0; +} diff --git a/vendor/libgit2/src/notes.h b/vendor/libgit2/src/libgit2/notes.h similarity index 100% rename from vendor/libgit2/src/notes.h rename to vendor/libgit2/src/libgit2/notes.h diff --git a/vendor/libgit2/src/object.c b/vendor/libgit2/src/libgit2/object.c similarity index 80% rename from vendor/libgit2/src/object.c rename to vendor/libgit2/src/libgit2/object.c index 7bc256fc..70e28c2c 100644 --- a/vendor/libgit2/src/object.c +++ b/vendor/libgit2/src/libgit2/object.c @@ -21,15 +21,14 @@ bool git_object__strict_input_validation = true; -extern int git_odb_hash(git_oid *out, const void *data, size_t len, git_object_t type); size_t git_object__size(git_object_t type); typedef struct { const char *str; /* type name string */ size_t size; /* size in bytes of the object structure */ - int (*parse)(void *self, git_odb_object *obj); - int (*parse_raw)(void *self, const char *data, size_t size); + int (*parse)(void *self, git_odb_object *obj, git_oid_t oid_type); + int (*parse_raw)(void *self, const char *data, size_t size, git_oid_t oid_type); void (*free)(void *self); } git_object_def; @@ -61,7 +60,8 @@ int git_object__from_raw( git_object **object_out, const char *data, size_t size, - git_object_t type) + git_object_t object_type, + git_oid_t oid_type) { git_object_def *def; git_object *object; @@ -72,12 +72,15 @@ int git_object__from_raw( *object_out = NULL; /* Validate type match */ - if (type != GIT_OBJECT_BLOB && type != GIT_OBJECT_TREE && type != GIT_OBJECT_COMMIT && type != GIT_OBJECT_TAG) { + if (object_type != GIT_OBJECT_BLOB && + object_type != GIT_OBJECT_TREE && + object_type != GIT_OBJECT_COMMIT && + object_type != GIT_OBJECT_TAG) { git_error_set(GIT_ERROR_INVALID, "the requested type is invalid"); return GIT_ENOTFOUND; } - if ((object_size = git_object__size(type)) == 0) { + if ((object_size = git_object__size(object_type)) == 0) { git_error_set(GIT_ERROR_INVALID, "the requested type is invalid"); return GIT_ENOTFOUND; } @@ -86,15 +89,15 @@ int git_object__from_raw( object = git__calloc(1, object_size); GIT_ERROR_CHECK_ALLOC(object); object->cached.flags = GIT_CACHE_STORE_PARSED; - object->cached.type = type; - if ((error = git_odb_hash(&object->cached.oid, data, size, type)) < 0) + object->cached.type = object_type; + if ((error = git_odb__hash(&object->cached.oid, data, size, object_type, oid_type)) < 0) return error; /* Parse raw object data */ - def = &git_objects_table[type]; + def = &git_objects_table[object_type]; GIT_ASSERT(def->free && def->parse_raw); - if ((error = def->parse_raw(object, data, size)) < 0) { + if ((error = def->parse_raw(object, data, size, oid_type)) < 0) { def->free(object); return error; } @@ -105,15 +108,13 @@ int git_object__from_raw( return 0; } -int git_object__from_odb_object( +int git_object__init_from_odb_object( git_object **object_out, git_repository *repo, git_odb_object *odb_obj, git_object_t type) { - int error; size_t object_size; - git_object_def *def; git_object *object = NULL; GIT_ASSERT_ARG(object_out); @@ -140,11 +141,28 @@ int git_object__from_odb_object( object->cached.size = odb_obj->cached.size; object->repo = repo; + *object_out = object; + return 0; +} + +int git_object__from_odb_object( + git_object **object_out, + git_repository *repo, + git_odb_object *odb_obj, + git_object_t type) +{ + int error; + git_object_def *def; + git_object *object = NULL; + + if ((error = git_object__init_from_odb_object(&object, repo, odb_obj, type)) < 0) + return error; + /* Parse raw object data */ def = &git_objects_table[odb_obj->cached.type]; GIT_ASSERT(def->free && def->parse); - if ((error = def->parse(object, odb_obj)) < 0) { + if ((error = def->parse(object, odb_obj, repo->oid_type)) < 0) { /* * parse returns EINVALID on invalid data; downgrade * that to a normal -1 error code. @@ -178,6 +196,7 @@ int git_object_lookup_prefix( git_object *object = NULL; git_odb *odb = NULL; git_odb_object *odb_obj = NULL; + size_t oid_hexsize; int error = 0; GIT_ASSERT_ARG(repo); @@ -193,10 +212,12 @@ int git_object_lookup_prefix( if (error < 0) return error; - if (len > GIT_OID_HEXSZ) - len = GIT_OID_HEXSZ; + oid_hexsize = git_oid_hexsize(repo->oid_type); + + if (len > oid_hexsize) + len = oid_hexsize; - if (len == GIT_OID_HEXSZ) { + if (len == oid_hexsize) { git_cached_obj *cached = NULL; /* We want to match the full id : we can first look up in the cache, @@ -230,11 +251,12 @@ int git_object_lookup_prefix( error = git_odb_read(&odb_obj, odb, id); } } else { - git_oid short_oid = {{ 0 }}; + git_oid short_oid; + git_oid_clear(&short_oid, repo->oid_type); git_oid__cpy_prefix(&short_oid, id, len); - /* If len < GIT_OID_HEXSZ (a strict short oid was given), we have + /* If len < GIT_OID_SHA1_HEXSIZE (a strict short oid was given), we have * 2 options : * - We always search in the cache first. If we find that short oid is * ambiguous, we can stop. But in all the other cases, we must then @@ -250,6 +272,7 @@ int git_object_lookup_prefix( if (error < 0) return error; + GIT_ASSERT(odb_obj); error = git_object__from_odb_object(object_out, repo, odb_obj, type); git_odb_object_free(odb_obj); @@ -258,7 +281,9 @@ int git_object_lookup_prefix( } int git_object_lookup(git_object **object_out, git_repository *repo, const git_oid *id, git_object_t type) { - return git_object_lookup_prefix(object_out, repo, id, GIT_OID_HEXSZ, type); + GIT_ASSERT_ARG(repo); + return git_object_lookup_prefix(object_out, + repo, id, git_oid_hexsize(repo->oid_type), type); } void git_object_free(git_object *object) @@ -357,12 +382,11 @@ static int dereference_object(git_object **dereferenced, git_object *obj) static int peel_error(int error, const git_oid *oid, git_object_t type) { const char *type_name; - char hex_oid[GIT_OID_HEXSZ + 1]; + char hex_oid[GIT_OID_MAX_HEXSIZE + 1]; type_name = git_object_type2string(type); - git_oid_fmt(hex_oid, oid); - hex_oid[GIT_OID_HEXSZ] = '\0'; + git_oid_nfmt(hex_oid, GIT_OID_MAX_HEXSIZE + 1, oid); git_error_set(GIT_ERROR_OBJECT, "the git_object of id '%s' can not be " "successfully peeled into a %s (git_object_t=%i).", hex_oid, type_name, type); @@ -500,22 +524,31 @@ int git_object_lookup_bypath( static int git_object__short_id(git_str *out, const git_object *obj) { git_repository *repo; - int len = GIT_ABBREV_DEFAULT, error; - git_oid id = {{0}}; + git_oid id; git_odb *odb; + size_t oid_hexsize; + int len = GIT_ABBREV_DEFAULT, error; GIT_ASSERT_ARG(out); GIT_ASSERT_ARG(obj); repo = git_object_owner(obj); + git_oid_clear(&id, repo->oid_type); + oid_hexsize = git_oid_hexsize(repo->oid_type); + if ((error = git_repository__configmap_lookup(&len, repo, GIT_CONFIGMAP_ABBREV)) < 0) return error; + if (len < 0 || (size_t)len > oid_hexsize) { + git_error_set(GIT_ERROR_CONFIG, "invalid oid abbreviation setting: '%d'", len); + return -1; + } + if ((error = git_repository_odb(&odb, repo)) < 0) return error; - while (len < GIT_OID_HEXSZ) { + while ((size_t)len < oid_hexsize) { /* set up short oid */ memcpy(&id.id, &obj->cached.oid.id, (len + 1) / 2); if (len & 1) @@ -572,21 +605,29 @@ int git_object_rawcontent_is_valid( int *valid, const char *buf, size_t len, - git_object_t type) + git_object_t object_type +#ifdef GIT_EXPERIMENTAL_SHA256 + , git_oid_t oid_type +#endif + ) { git_object *obj = NULL; int error; +#ifndef GIT_EXPERIMENTAL_SHA256 + git_oid_t oid_type = GIT_OID_SHA1; +#endif + GIT_ASSERT_ARG(valid); GIT_ASSERT_ARG(buf); /* Blobs are always valid; don't bother parsing. */ - if (type == GIT_OBJECT_BLOB) { + if (object_type == GIT_OBJECT_BLOB) { *valid = 1; return 0; } - error = git_object__from_raw(&obj, buf, len, type); + error = git_object__from_raw(&obj, buf, len, object_type, oid_type); git_object_free(obj); if (error == 0) { @@ -599,3 +640,53 @@ int git_object_rawcontent_is_valid( return error; } + +int git_object__parse_oid_header( + git_oid *oid, + const char **buffer_out, + const char *buffer_end, + const char *header, + git_oid_t oid_type) +{ + const size_t sha_len = git_oid_hexsize(oid_type); + const size_t header_len = strlen(header); + + const char *buffer = *buffer_out; + + if (buffer + (header_len + sha_len + 1) > buffer_end) + return -1; + + if (memcmp(buffer, header, header_len) != 0) + return -1; + + if (buffer[header_len + sha_len] != '\n') + return -1; + + if (git_oid__fromstr(oid, buffer + header_len, oid_type) < 0) + return -1; + + *buffer_out = buffer + (header_len + sha_len + 1); + + return 0; +} + +int git_object__write_oid_header( + git_str *buf, + const char *header, + const git_oid *oid) +{ + size_t hex_size = git_oid_hexsize(git_oid_type(oid)); + char hex_oid[GIT_OID_MAX_HEXSIZE]; + + if (!hex_size) { + git_error_set(GIT_ERROR_INVALID, "unknown type"); + return -1; + } + + git_oid_fmt(hex_oid, oid); + git_str_puts(buf, header); + git_str_put(buf, hex_oid, hex_size); + git_str_putc(buf, '\n'); + + return git_str_oom(buf) ? -1 : 0; +} diff --git a/vendor/libgit2/src/object.h b/vendor/libgit2/src/libgit2/object.h similarity index 80% rename from vendor/libgit2/src/object.h rename to vendor/libgit2/src/libgit2/object.h index 66be5755..b6c604c8 100644 --- a/vendor/libgit2/src/object.h +++ b/vendor/libgit2/src/libgit2/object.h @@ -33,6 +33,13 @@ int git_object__from_raw( git_object **object_out, const char *data, size_t size, + git_object_t object_type, + git_oid_t oid_type); + +int git_object__init_from_odb_object( + git_object **object_out, + git_repository *repo, + git_odb_object *odb_obj, git_object_t type); int git_object__from_odb_object( @@ -45,9 +52,17 @@ int git_object__resolve_to_type(git_object **obj, git_object_t type); git_object_t git_object_stringn2type(const char *str, size_t len); -int git_oid__parse(git_oid *oid, const char **buffer_out, const char *buffer_end, const char *header); +int git_object__parse_oid_header( + git_oid *oid, + const char **buffer_out, + const char *buffer_end, + const char *header, + git_oid_t oid_type); -void git_oid__writebuf(git_str *buf, const char *header, const git_oid *oid); +int git_object__write_oid_header( + git_str *buf, + const char *header, + const git_oid *oid); bool git_object__is_valid( git_repository *repo, const git_oid *id, git_object_t expected_type); diff --git a/vendor/libgit2/src/object_api.c b/vendor/libgit2/src/libgit2/object_api.c similarity index 100% rename from vendor/libgit2/src/object_api.c rename to vendor/libgit2/src/libgit2/object_api.c diff --git a/vendor/libgit2/src/odb.c b/vendor/libgit2/src/libgit2/odb.c similarity index 85% rename from vendor/libgit2/src/odb.c rename to vendor/libgit2/src/libgit2/odb.c index 14eff53c..fec1e45b 100644 --- a/vendor/libgit2/src/odb.c +++ b/vendor/libgit2/src/libgit2/odb.c @@ -105,11 +105,12 @@ int git_odb__format_object_header( return 0; } -int git_odb__hashobj(git_oid *id, git_rawobj *obj) +int git_odb__hashobj(git_oid *id, git_rawobj *obj, git_oid_t oid_type) { git_str_vec vec[2]; char header[64]; size_t hdrlen; + git_hash_algorithm_t algorithm; int error; GIT_ASSERT_ARG(id); @@ -120,6 +121,11 @@ int git_odb__hashobj(git_oid *id, git_rawobj *obj) return -1; } + if (!(algorithm = git_oid_algorithm(oid_type))) { + git_error_set(GIT_ERROR_INVALID, "unknown oid type"); + return -1; + } + if (!obj->data && obj->len != 0) { git_error_set(GIT_ERROR_INVALID, "invalid object"); return -1; @@ -134,7 +140,11 @@ int git_odb__hashobj(git_oid *id, git_rawobj *obj) vec[1].data = obj->data; vec[1].len = obj->len; - return git_hash_vec(id->id, vec, 2, GIT_HASH_ALGORITHM_SHA1); +#ifdef GIT_EXPERIMENTAL_SHA256 + id->type = oid_type; +#endif + + return git_hash_vec(id->id, vec, 2, algorithm); } @@ -195,24 +205,35 @@ void git_odb_object_free(git_odb_object *object) git_cached_obj_decref(object); } -int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_object_t type) +int git_odb__hashfd( + git_oid *out, + git_file fd, + size_t size, + git_object_t object_type, + git_oid_t oid_type) { size_t hdr_len; - char hdr[64], buffer[FILEIO_BUFSIZE]; + char hdr[64], buffer[GIT_BUFSIZE_FILEIO]; git_hash_ctx ctx; + git_hash_algorithm_t algorithm; ssize_t read_len = 0; int error = 0; - if (!git_object_typeisloose(type)) { + if (!git_object_typeisloose(object_type)) { git_error_set(GIT_ERROR_INVALID, "invalid object type for hash"); return -1; } - if ((error = git_hash_ctx_init(&ctx, GIT_HASH_ALGORITHM_SHA1)) < 0) + if (!(algorithm = git_oid_algorithm(oid_type))) { + git_error_set(GIT_ERROR_INVALID, "unknown oid type"); + return -1; + } + + if ((error = git_hash_ctx_init(&ctx, algorithm)) < 0) return error; if ((error = git_odb__format_object_header(&hdr_len, hdr, - sizeof(hdr), size, type)) < 0) + sizeof(hdr), size, object_type)) < 0) goto done; if ((error = git_hash_update(&ctx, hdr, hdr_len)) < 0) @@ -237,19 +258,28 @@ int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_object_t type) error = git_hash_final(out->id, &ctx); +#ifdef GIT_EXPERIMENTAL_SHA256 + out->type = oid_type; +#endif + done: git_hash_ctx_cleanup(&ctx); return error; } int git_odb__hashfd_filtered( - git_oid *out, git_file fd, size_t size, git_object_t type, git_filter_list *fl) + git_oid *out, + git_file fd, + size_t size, + git_object_t object_type, + git_oid_t oid_type, + git_filter_list *fl) { int error; git_str raw = GIT_STR_INIT; if (!fl) - return git_odb__hashfd(out, fd, size, type); + return git_odb__hashfd(out, fd, size, object_type, oid_type); /* size of data is used in header, so we have to read the whole file * into memory to apply filters before beginning to calculate the hash @@ -261,7 +291,7 @@ int git_odb__hashfd_filtered( error = git_filter_list__convert_buf(&post, fl, &raw); if (!error) - error = git_odb_hash(out, post.ptr, post.size, type); + error = git_odb__hash(out, post.ptr, post.size, object_type, oid_type); git_str_dispose(&post); } @@ -269,7 +299,7 @@ int git_odb__hashfd_filtered( return error; } -int git_odb__hashlink(git_oid *out, const char *path) +int git_odb__hashlink(git_oid *out, const char *path, git_oid_t oid_type) { struct stat st; int size; @@ -303,20 +333,24 @@ int git_odb__hashlink(git_oid *out, const char *path) GIT_ASSERT(read_len <= size); link_data[read_len] = '\0'; - result = git_odb_hash(out, link_data, read_len, GIT_OBJECT_BLOB); + result = git_odb__hash(out, link_data, read_len, GIT_OBJECT_BLOB, oid_type); git__free(link_data); } else { int fd = git_futils_open_ro(path); if (fd < 0) return -1; - result = git_odb__hashfd(out, fd, size, GIT_OBJECT_BLOB); + result = git_odb__hashfd(out, fd, size, GIT_OBJECT_BLOB, oid_type); p_close(fd); } return result; } -int git_odb_hashfile(git_oid *out, const char *path, git_object_t type) +int git_odb__hashfile( + git_oid *out, + const char *path, + git_object_t object_type, + git_oid_t oid_type) { uint64_t size; int fd, error = 0; @@ -333,14 +367,38 @@ int git_odb_hashfile(git_oid *out, const char *path, git_object_t type) goto done; } - error = git_odb__hashfd(out, fd, (size_t)size, type); + error = git_odb__hashfd(out, fd, (size_t)size, object_type, oid_type); done: p_close(fd); return error; } -int git_odb_hash(git_oid *id, const void *data, size_t len, git_object_t type) +#ifdef GIT_EXPERIMENTAL_SHA256 +int git_odb_hashfile( + git_oid *out, + const char *path, + git_object_t object_type, + git_oid_t oid_type) +{ + return git_odb__hashfile(out, path, object_type, oid_type); +} +#else +int git_odb_hashfile( + git_oid *out, + const char *path, + git_object_t object_type) +{ + return git_odb__hashfile(out, path, object_type, GIT_OID_SHA1); +} +#endif + +int git_odb__hash( + git_oid *id, + const void *data, + size_t len, + git_object_t object_type, + git_oid_t oid_type) { git_rawobj raw; @@ -348,10 +406,31 @@ int git_odb_hash(git_oid *id, const void *data, size_t len, git_object_t type) raw.data = (void *)data; raw.len = len; - raw.type = type; + raw.type = object_type; + + return git_odb__hashobj(id, &raw, oid_type); +} - return git_odb__hashobj(id, &raw); +#ifdef GIT_EXPERIMENTAL_SHA256 +int git_odb_hash( + git_oid *out, + const void *data, + size_t len, + git_object_t object_type, + git_oid_t oid_type) +{ + return git_odb__hash(out, data, len, object_type, oid_type); +} +#else +int git_odb_hash( + git_oid *out, + const void *data, + size_t len, + git_object_t type) +{ + return git_odb__hash(out, data, len, type, GIT_OID_SHA1); } +#endif /** * FAKE WSTREAM @@ -442,11 +521,28 @@ static int backend_sort_cmp(const void *a, const void *b) return (backend_b->priority - backend_a->priority); } -int git_odb_new(git_odb **out) +static void normalize_options( + git_odb_options *opts, + const git_odb_options *given_opts) +{ + git_odb_options init = GIT_ODB_OPTIONS_INIT; + + if (given_opts) + memcpy(opts, given_opts, sizeof(git_odb_options)); + else + memcpy(opts, &init, sizeof(git_odb_options)); + + if (!opts->oid_type) + opts->oid_type = GIT_OID_DEFAULT; +} + +int git_odb__new(git_odb **out, const git_odb_options *opts) { git_odb *db = git__calloc(1, sizeof(*db)); GIT_ERROR_CHECK_ALLOC(db); + normalize_options(&db->options, opts); + if (git_mutex_init(&db->lock) < 0) { git__free(db); return -1; @@ -468,6 +564,18 @@ int git_odb_new(git_odb **out) return 0; } +#ifdef GIT_EXPERIMENTAL_SHA256 +int git_odb_new(git_odb **out, const git_odb_options *opts) +{ + return git_odb__new(out, opts); +} +#else +int git_odb_new(git_odb **out) +{ + return git_odb__new(out, NULL); +} +#endif + static int add_backend_internal( git_odb *odb, git_odb_backend *backend, int priority, bool is_alternate, ino_t disk_inode) @@ -575,6 +683,8 @@ int git_odb__add_default_backends( struct stat st; ino_t inode; git_odb_backend *loose, *packed; + git_odb_backend_loose_options loose_opts = GIT_ODB_BACKEND_LOOSE_OPTIONS_INIT; + git_odb_backend_pack_options pack_opts = GIT_ODB_BACKEND_PACK_OPTIONS_INIT; /* TODO: inodes are not really relevant on Win32, so we need to find * a cross-platform workaround for this */ @@ -609,21 +719,37 @@ int git_odb__add_default_backends( git_mutex_unlock(&db->lock); #endif + if (db->do_fsync) + loose_opts.flags |= GIT_ODB_BACKEND_LOOSE_FSYNC; + + loose_opts.oid_type = db->options.oid_type; + pack_opts.oid_type = db->options.oid_type; + /* add the loose object backend */ - if (git_odb_backend_loose(&loose, objects_dir, -1, db->do_fsync, 0, 0) < 0 || + if (git_odb__backend_loose(&loose, objects_dir, &loose_opts) < 0 || add_backend_internal(db, loose, git_odb__loose_priority, as_alternates, inode) < 0) return -1; /* add the packed file backend */ - if (git_odb_backend_pack(&packed, objects_dir) < 0 || - add_backend_internal(db, packed, git_odb__packed_priority, as_alternates, inode) < 0) +#ifdef GIT_EXPERIMENTAL_SHA256 + if (git_odb_backend_pack(&packed, objects_dir, &pack_opts) < 0) + return -1; +#else + GIT_UNUSED(pack_opts); + + if (git_odb_backend_pack(&packed, objects_dir) < 0) + return -1; +#endif + + if (add_backend_internal(db, packed, git_odb__packed_priority, as_alternates, inode) < 0) return -1; if (git_mutex_lock(&db->lock) < 0) { git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock"); return -1; } - if (!db->cgraph && git_commit_graph_new(&db->cgraph, objects_dir, false) < 0) { + if (!db->cgraph && + git_commit_graph_new(&db->cgraph, objects_dir, false, db->options.oid_type) < 0) { git_mutex_unlock(&db->lock); return -1; } @@ -707,7 +833,10 @@ int git_odb_set_commit_graph(git_odb *odb, git_commit_graph *cgraph) return error; } -int git_odb_open(git_odb **out, const char *objects_dir) +int git_odb__open( + git_odb **out, + const char *objects_dir, + const git_odb_options *opts) { git_odb *db; @@ -716,7 +845,7 @@ int git_odb_open(git_odb **out, const char *objects_dir) *out = NULL; - if (git_odb_new(&db) < 0) + if (git_odb__new(&db, opts) < 0) return -1; if (git_odb__add_default_backends(db, objects_dir, 0, 0) < 0) { @@ -728,6 +857,25 @@ int git_odb_open(git_odb **out, const char *objects_dir) return 0; } +#ifdef GIT_EXPERIMENTAL_SHA256 + +int git_odb_open( + git_odb **out, + const char *objects_dir, + const git_odb_options *opts) +{ + return git_odb__open(out, objects_dir, opts); +} + +#else + +int git_odb_open(git_odb **out, const char *objects_dir) +{ + return git_odb__open(out, objects_dir, NULL); +} + +#endif + int git_odb__set_caps(git_odb *odb, int caps) { if (caps == GIT_ODB_CAP_FROM_OWNER) { @@ -914,7 +1062,7 @@ static int odb_exists_prefix_1(git_oid *out, git_odb *db, { size_t i; int error = GIT_ENOTFOUND, num_found = 0; - git_oid last_found = {{0}}, found; + git_oid last_found = GIT_OID_NONE, found; if ((error = git_mutex_lock(&db->lock)) < 0) { git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock"); @@ -965,7 +1113,7 @@ int git_odb_exists_prefix( git_oid *out, git_odb *db, const git_oid *short_id, size_t len) { int error; - git_oid key = {{0}}; + git_oid key = GIT_OID_NONE; GIT_ASSERT_ARG(db); GIT_ASSERT_ARG(short_id); @@ -973,7 +1121,7 @@ int git_odb_exists_prefix( if (len < GIT_OID_MINPREFIXLEN) return git_odb__error_ambiguous("prefix length too short"); - if (len >= GIT_OID_HEXSZ) { + if (len >= git_oid_hexsize(db->options.oid_type)) { if (git_odb_exists(db, short_id)) { if (out) git_oid_cpy(out, short_id); @@ -1002,11 +1150,13 @@ int git_odb_expand_ids( git_odb_expand_id *ids, size_t count) { - size_t i; + size_t hex_size, i; GIT_ASSERT_ARG(db); GIT_ASSERT_ARG(ids); + hex_size = git_oid_hexsize(db->options.oid_type); + for (i = 0; i < count; i++) { git_odb_expand_id *query = &ids[i]; int error = GIT_EAMBIGUOUS; @@ -1015,13 +1165,13 @@ int git_odb_expand_ids( query->type = GIT_OBJECT_ANY; /* if we have a short OID, expand it first */ - if (query->length >= GIT_OID_MINPREFIXLEN && query->length < GIT_OID_HEXSZ) { + if (query->length >= GIT_OID_MINPREFIXLEN && query->length < hex_size) { git_oid actual_id; error = odb_exists_prefix_1(&actual_id, db, &query->id, query->length, false); if (!error) { git_oid_cpy(&query->id, &actual_id); - query->length = GIT_OID_HEXSZ; + query->length = (unsigned short)hex_size; } } @@ -1029,7 +1179,7 @@ int git_odb_expand_ids( * now we ought to have a 40-char OID, either because we've expanded it * or because the user passed a full OID. Ensure its type is right. */ - if (query->length >= GIT_OID_HEXSZ) { + if (query->length >= hex_size) { git_object_t actual_type; error = odb_otype_fast(&actual_type, db, &query->id); @@ -1049,7 +1199,7 @@ int git_odb_expand_ids( /* the object is missing or ambiguous */ case GIT_ENOTFOUND: case GIT_EAMBIGUOUS: - memset(&query->id, 0, sizeof(git_oid)); + git_oid_clear(&query->id, db->options.oid_type); query->length = 0; query->type = 0; break; @@ -1067,7 +1217,7 @@ int git_odb_expand_ids( int git_odb_read_header(size_t *len_p, git_object_t *type_p, git_odb *db, const git_oid *id) { int error; - git_odb_object *object; + git_odb_object *object = NULL; error = git_odb__read_header_or_object(&object, len_p, type_p, db, id); @@ -1157,7 +1307,7 @@ int git_odb__read_header_or_object( error = odb_read_header_1(len_p, type_p, db, id, true); if (error == GIT_ENOTFOUND) - return git_odb__error_notfound("cannot read header for", id, GIT_OID_HEXSZ); + return git_odb__error_notfound("cannot read header for", id, git_oid_hexsize(db->options.oid_type)); /* we found the header; return early */ if (!error) @@ -1179,8 +1329,11 @@ int git_odb__read_header_or_object( return error; } -static int odb_read_1(git_odb_object **out, git_odb *db, const git_oid *id, - bool only_refreshed) +static int odb_read_1( + git_odb_object **out, + git_odb *db, + const git_oid *id, + bool only_refreshed) { size_t i; git_rawobj raw; @@ -1224,7 +1377,7 @@ static int odb_read_1(git_odb_object **out, git_odb *db, const git_oid *id, return GIT_ENOTFOUND; if (git_odb__strict_hash_verification) { - if ((error = git_odb_hash(&hashed, raw.data, raw.len, raw.type)) < 0) + if ((error = git_odb__hash(&hashed, raw.data, raw.len, raw.type, db->options.oid_type)) < 0) goto out; if (!git_oid_equal(id, &hashed)) { @@ -1268,7 +1421,7 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) error = odb_read_1(out, db, id, true); if (error == GIT_ENOTFOUND) - return git_odb__error_notfound("no match for id", id, GIT_OID_HEXSZ); + return git_odb__error_notfound("no match for id", id, git_oid_hexsize(git_oid_type(id))); return error; } @@ -1305,7 +1458,7 @@ static int read_prefix_1(git_odb_object **out, git_odb *db, { size_t i; int error = 0; - git_oid found_full_oid = {{0}}; + git_oid found_full_oid = GIT_OID_NONE; git_rawobj raw = {0}; void *data = NULL; bool found = false; @@ -1341,11 +1494,16 @@ static int read_prefix_1(git_odb_object **out, git_odb *db, if (found && git_oid__cmp(&full_oid, &found_full_oid)) { git_str buf = GIT_STR_INIT; + const char *idstr; + + if ((idstr = git_oid_tostr_s(&full_oid)) == NULL) { + git_str_puts(&buf, "failed to parse object id"); + } else { + git_str_printf(&buf, "multiple matches for prefix: %s", idstr); - git_str_printf(&buf, "multiple matches for prefix: %s", - git_oid_tostr_s(&full_oid)); - git_str_printf(&buf, " %s", - git_oid_tostr_s(&found_full_oid)); + if ((idstr = git_oid_tostr_s(&found_full_oid)) != NULL) + git_str_printf(&buf, " %s", idstr); + } error = git_odb__error_ambiguous(buf.ptr); git_str_dispose(&buf); @@ -1365,7 +1523,7 @@ static int read_prefix_1(git_odb_object **out, git_odb *db, if (git_odb__strict_hash_verification) { git_oid hash; - if ((error = git_odb_hash(&hash, raw.data, raw.len, raw.type)) < 0) + if ((error = git_odb__hash(&hash, raw.data, raw.len, raw.type, db->options.oid_type)) < 0) goto out; if (!git_oid_equal(&found_full_oid, &hash)) { @@ -1391,19 +1549,22 @@ static int read_prefix_1(git_odb_object **out, git_odb *db, int git_odb_read_prefix( git_odb_object **out, git_odb *db, const git_oid *short_id, size_t len) { - git_oid key = {{0}}; + git_oid key = GIT_OID_NONE; + size_t hex_size; int error; GIT_ASSERT_ARG(out); GIT_ASSERT_ARG(db); + hex_size = git_oid_hexsize(db->options.oid_type); + if (len < GIT_OID_MINPREFIXLEN) return git_odb__error_ambiguous("prefix length too short"); - if (len > GIT_OID_HEXSZ) - len = GIT_OID_HEXSZ; + if (len > hex_size) + len = hex_size; - if (len == GIT_OID_HEXSZ) { + if (len == hex_size) { *out = git_cache_get_raw(odb_cache(db), short_id); if (*out != NULL) return 0; @@ -1463,7 +1624,7 @@ int git_odb_write( GIT_ASSERT_ARG(oid); GIT_ASSERT_ARG(db); - if ((error = git_odb_hash(oid, data, len, type)) < 0) + if ((error = git_odb__hash(oid, data, len, type, db->options.oid_type)) < 0) return error; if (git_oid_is_zero(oid)) @@ -1564,10 +1725,13 @@ int git_odb_open_wstream( ctx = git__malloc(sizeof(git_hash_ctx)); GIT_ERROR_CHECK_ALLOC(ctx); - if ((error = git_hash_ctx_init(ctx, GIT_HASH_ALGORITHM_SHA1)) < 0 || - (error = hash_header(ctx, size, type)) < 0) + if ((error = git_hash_ctx_init(ctx, git_oid_algorithm(db->options.oid_type))) < 0 || + (error = hash_header(ctx, size, type)) < 0) goto done; +#ifdef GIT_EXPERIMENTAL_SHA256 + (*stream)->oid_type = db->options.oid_type; +#endif (*stream)->hash_ctx = ctx; (*stream)->declared_size = size; (*stream)->received_bytes = 0; @@ -1612,6 +1776,10 @@ int git_odb_stream_finalize_write(git_oid *out, git_odb_stream *stream) git_hash_final(out->id, stream->hash_ctx); +#ifdef GIT_EXPERIMENTAL_SHA256 + out->type = stream->oid_type; +#endif + if (git_odb__freshen(stream->backend->odb, out)) return 0; @@ -1786,10 +1954,11 @@ int git_odb_refresh(struct git_odb *db) int git_odb__error_mismatch(const git_oid *expected, const git_oid *actual) { - char expected_oid[GIT_OID_HEXSZ + 1], actual_oid[GIT_OID_HEXSZ + 1]; + char expected_oid[GIT_OID_MAX_HEXSIZE + 1], + actual_oid[GIT_OID_MAX_HEXSIZE + 1]; - git_oid_tostr(expected_oid, sizeof(expected_oid), expected); - git_oid_tostr(actual_oid, sizeof(actual_oid), actual); + git_oid_tostr(expected_oid, git_oid_hexsize(git_oid_type(expected)) + 1, expected); + git_oid_tostr(actual_oid, git_oid_hexsize(git_oid_type(actual)) + 1, actual); git_error_set(GIT_ERROR_ODB, "object hash mismatch - expected %s but got %s", expected_oid, actual_oid); @@ -1801,7 +1970,7 @@ int git_odb__error_notfound( const char *message, const git_oid *oid, size_t oid_len) { if (oid != NULL) { - char oid_str[GIT_OID_HEXSZ + 1]; + char oid_str[GIT_OID_MAX_HEXSIZE + 1]; git_oid_tostr(oid_str, oid_len+1, oid); git_error_set(GIT_ERROR_ODB, "object not found - %s (%.*s)", message, (int) oid_len, oid_str); @@ -1819,7 +1988,7 @@ static int error_null_oid(int error, const char *message) int git_odb__error_ambiguous(const char *message) { - git_error_set(GIT_ERROR_ODB, "ambiguous SHA1 prefix - %s", message); + git_error_set(GIT_ERROR_ODB, "ambiguous OID prefix - %s", message); return GIT_EAMBIGUOUS; } diff --git a/vendor/libgit2/src/odb.h b/vendor/libgit2/src/libgit2/odb.h similarity index 79% rename from vendor/libgit2/src/odb.h rename to vendor/libgit2/src/libgit2/odb.h index 5aa4cc84..7a712e20 100644 --- a/vendor/libgit2/src/odb.h +++ b/vendor/libgit2/src/libgit2/odb.h @@ -10,6 +10,7 @@ #include "common.h" #include "git2/odb.h" +#include "git2/odb_backend.h" #include "git2/oid.h" #include "git2/types.h" #include "git2/sys/commit_graph.h" @@ -46,6 +47,7 @@ struct git_odb_object { struct git_odb { git_refcount rc; git_mutex lock; /* protects backends */ + git_odb_options options; git_vector backends; git_cache own_cache; git_commit_graph *cgraph; @@ -72,7 +74,7 @@ int git_odb__add_default_backends( * Hash a git_rawobj internally. * The `git_rawobj` is supposed to be previously initialized */ -int git_odb__hashobj(git_oid *id, git_rawobj *obj); +int git_odb__hashobj(git_oid *id, git_rawobj *obj, git_oid_t oid_type); /* * Format the object header such as it would appear in the on-disk object @@ -89,14 +91,24 @@ int git_odb__format_object_header(size_t *out_len, char *hdr, size_t hdr_size, g * The fd is never closed, not even on error. It must be opened and closed * by the caller */ -int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_object_t type); +int git_odb__hashfd( + git_oid *out, + git_file fd, + size_t size, + git_object_t object_type, + git_oid_t oid_type); /* * Hash an open file descriptor applying an array of filters * Acts just like git_odb__hashfd with the addition of filters... */ int git_odb__hashfd_filtered( - git_oid *out, git_file fd, size_t len, git_object_t type, git_filter_list *fl); + git_oid *out, + git_file fd, + size_t len, + git_object_t object_type, + git_oid_t oid_type, + git_filter_list *fl); /* * Hash a `path`, assuming it could be a POSIX symlink: if the path is a @@ -106,7 +118,7 @@ int git_odb__hashfd_filtered( * The hash type for this call is always `GIT_OBJECT_BLOB` because * symlinks may only point to blobs. */ -int git_odb__hashlink(git_oid *out, const char *path); +int git_odb__hashlink(git_oid *out, const char *path, git_oid_t oid_type); /** * Generate a GIT_EMISMATCH error for the ODB. @@ -146,4 +158,31 @@ int git_odb__freshen(git_odb *db, const git_oid *id); /* fully free the object; internal method, DO NOT EXPORT */ void git_odb_object__free(void *object); +/* SHA256 support */ + +int git_odb__new(git_odb **out, const git_odb_options *opts); + +int git_odb__open( + git_odb **out, + const char *objects_dir, + const git_odb_options *opts); + +int git_odb__hash( + git_oid *out, + const void *data, + size_t len, + git_object_t object_type, + git_oid_t oid_type); + +int git_odb__hashfile( + git_oid *out, + const char *path, + git_object_t object_type, + git_oid_t oid_type); + +GIT_EXTERN(int) git_odb__backend_loose( + git_odb_backend **out, + const char *objects_dir, + git_odb_backend_loose_options *opts); + #endif diff --git a/vendor/libgit2/src/odb_loose.c b/vendor/libgit2/src/libgit2/odb_loose.c similarity index 86% rename from vendor/libgit2/src/odb_loose.c rename to vendor/libgit2/src/libgit2/odb_loose.c index 463e24fa..51195d35 100644 --- a/vendor/libgit2/src/odb_loose.c +++ b/vendor/libgit2/src/libgit2/odb_loose.c @@ -46,10 +46,8 @@ typedef struct { typedef struct loose_backend { git_odb_backend parent; - int object_zlib_level; /** loose object zlib compression level. */ - int fsync_object_files; /** loose object file fsync flag. */ - mode_t object_file_mode; - mode_t object_dir_mode; + git_odb_backend_loose_options options; + size_t oid_hexsize; size_t objects_dirlen; char objects_dir[GIT_FLEX_ARRAY]; @@ -59,13 +57,19 @@ typedef struct loose_backend { * in order to locate objects matching a short oid. */ typedef struct { + loose_backend *backend; + size_t dir_len; - unsigned char short_oid[GIT_OID_HEXSZ]; /* hex formatted oid to match */ + + /* Hex formatted oid to match (and its length) */ + unsigned char short_oid[GIT_OID_MAX_HEXSIZE]; size_t short_oid_len; - int found; /* number of matching - * objects already found */ - unsigned char res_oid[GIT_OID_HEXSZ]; /* hex formatted oid of - * the object found */ + + /* Number of matching objects found so far */ + int found; + + /* Hex formatted oid of the object found */ + unsigned char res_oid[GIT_OID_MAX_HEXSIZE]; } loose_locate_object_state; @@ -78,20 +82,17 @@ typedef struct { static int object_file_name( git_str *name, const loose_backend *be, const git_oid *id) { - size_t alloclen; - - /* expand length for object root + 40 hex sha1 chars + 2 * '/' + '\0' */ - GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, be->objects_dirlen, GIT_OID_HEXSZ); - GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, alloclen, 3); - if (git_str_grow(name, alloclen) < 0) - return -1; + /* append loose object filename: aa/aaa... (41 bytes plus NUL) */ + size_t path_size = be->oid_hexsize + 1; git_str_set(name, be->objects_dir, be->objects_dirlen); git_fs_path_to_dir(name); - /* loose object filename: aa/aaa... (41 bytes) */ + if (git_str_grow_by(name, path_size + 1) < 0) + return -1; + git_oid_pathfmt(name->ptr + name->size, id); - name->size += GIT_OID_HEXSZ + 1; + name->size += path_size; name->ptr[name->size] = '\0'; return 0; @@ -100,7 +101,9 @@ static int object_file_name( static int object_mkdir(const git_str *name, const loose_backend *be) { return git_futils_mkdir_relative( - name->ptr + be->objects_dirlen, be->objects_dir, be->object_dir_mode, + name->ptr + be->objects_dirlen, + be->objects_dir, + be->options.dir_mode, GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST | GIT_MKDIR_VERIFY_DIR, NULL); } @@ -461,8 +464,9 @@ static int locate_object( /* Explore an entry of a directory and see if it matches a short oid */ static int fn_locate_object_short_oid(void *state, git_str *pathbuf) { loose_locate_object_state *sstate = (loose_locate_object_state *)state; + size_t hex_size = sstate->backend->oid_hexsize; - if (git_str_len(pathbuf) - sstate->dir_len != GIT_OID_HEXSZ - 2) { + if (git_str_len(pathbuf) - sstate->dir_len != hex_size - 2) { /* Entry cannot be an object. Continue to next entry */ return 0; } @@ -477,7 +481,9 @@ static int fn_locate_object_short_oid(void *state, git_str *pathbuf) { if (!sstate->found) { sstate->res_oid[0] = sstate->short_oid[0]; sstate->res_oid[1] = sstate->short_oid[1]; - memcpy(sstate->res_oid+2, pathbuf->ptr+sstate->dir_len, GIT_OID_HEXSZ-2); + memcpy(sstate->res_oid + 2, + pathbuf->ptr+sstate->dir_len, + hex_size - 2); } sstate->found++; } @@ -503,7 +509,7 @@ static int locate_object_short_oid( int error; /* prealloc memory for OBJ_DIR/xx/xx..38x..xx */ - GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, dir_len, GIT_OID_HEXSZ); + GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, dir_len, backend->oid_hexsize); GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 3); if (git_str_grow(object_location, alloc_len) < 0) return -1; @@ -527,6 +533,7 @@ static int locate_object_short_oid( return git_odb__error_notfound("no matching loose object for prefix", short_oid, len); + state.backend = backend; state.dir_len = git_str_len(object_location); state.short_oid_len = len; state.found = 0; @@ -545,12 +552,12 @@ static int locate_object_short_oid( return git_odb__error_ambiguous("multiple matches in loose objects"); /* Convert obtained hex formatted oid to raw */ - error = git_oid_fromstr(res_oid, (char *)state.res_oid); + error = git_oid__fromstr(res_oid, (char *)state.res_oid, backend->options.oid_type); if (error) return error; /* Update the location according to the oid obtained */ - GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, dir_len, GIT_OID_HEXSZ); + GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, dir_len, backend->oid_hexsize); GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 2); git_str_truncate(object_location, dir_len); @@ -559,20 +566,12 @@ static int locate_object_short_oid( git_oid_pathfmt(object_location->ptr + dir_len, res_oid); - object_location->size += GIT_OID_HEXSZ + 1; + object_location->size += backend->oid_hexsize + 1; object_location->ptr[object_location->size] = '\0'; return 0; } - - - - - - - - /*********************************************************** * * LOOSE BACKEND PUBLIC API @@ -595,7 +594,7 @@ static int loose_backend__read_header(size_t *len_p, git_object_t *type_p, git_o if (locate_object(&object_path, (loose_backend *)backend, oid) < 0) { error = git_odb__error_notfound("no matching loose object", - oid, GIT_OID_HEXSZ); + oid, ((struct loose_backend *)backend)->oid_hexsize); } else if ((error = read_header_loose(&raw, &object_path)) == 0) { *len_p = raw.len; *type_p = raw.type; @@ -617,7 +616,7 @@ static int loose_backend__read(void **buffer_p, size_t *len_p, git_object_t *typ if (locate_object(&object_path, (loose_backend *)backend, oid) < 0) { error = git_odb__error_notfound("no matching loose object", - oid, GIT_OID_HEXSZ); + oid, ((struct loose_backend *)backend)->oid_hexsize); } else if ((error = read_loose(&raw, &object_path)) == 0) { *buffer_p = raw.data; *len_p = raw.len; @@ -634,17 +633,19 @@ static int loose_backend__read_prefix( void **buffer_p, size_t *len_p, git_object_t *type_p, - git_odb_backend *backend, + git_odb_backend *_backend, const git_oid *short_oid, size_t len) { + struct loose_backend *backend = (struct loose_backend *)_backend; int error = 0; - GIT_ASSERT_ARG(len >= GIT_OID_MINPREFIXLEN && len <= GIT_OID_HEXSZ); + GIT_ASSERT_ARG(len >= GIT_OID_MINPREFIXLEN && + len <= backend->oid_hexsize); - if (len == GIT_OID_HEXSZ) { + if (len == backend->oid_hexsize) { /* We can fall back to regular read method */ - error = loose_backend__read(buffer_p, len_p, type_p, backend, short_oid); + error = loose_backend__read(buffer_p, len_p, type_p, _backend, short_oid); if (!error) git_oid_cpy(out_oid, short_oid); } else { @@ -703,15 +704,18 @@ static int loose_backend__exists_prefix( } struct foreach_state { + struct loose_backend *backend; size_t dir_len; git_odb_foreach_cb cb; void *data; }; -GIT_INLINE(int) filename_to_oid(git_oid *oid, const char *ptr) +GIT_INLINE(int) filename_to_oid(struct loose_backend *backend, git_oid *oid, const char *ptr) { - int v, i = 0; - if (strlen(ptr) != GIT_OID_HEXSZ+1) + int v; + size_t i = 0; + + if (strlen(ptr) != backend->oid_hexsize + 1) return -1; if (ptr[2] != '/') { @@ -725,7 +729,7 @@ GIT_INLINE(int) filename_to_oid(git_oid *oid, const char *ptr) oid->id[0] = (unsigned char) v; ptr += 3; - for (i = 0; i < 38; i += 2) { + for (i = 0; i < backend->oid_hexsize - 2; i += 2) { v = (git__fromhex(ptr[i]) << 4) | git__fromhex(ptr[i + 1]); if (v < 0) return -1; @@ -733,6 +737,10 @@ GIT_INLINE(int) filename_to_oid(git_oid *oid, const char *ptr) oid->id[1 + i/2] = (unsigned char) v; } +#ifdef GIT_EXPERIMENTAL_SHA256 + oid->type = backend->options.oid_type; +#endif + return 0; } @@ -741,7 +749,7 @@ static int foreach_object_dir_cb(void *_state, git_str *path) git_oid oid; struct foreach_state *state = (struct foreach_state *) _state; - if (filename_to_oid(&oid, path->ptr + state->dir_len) < 0) + if (filename_to_oid(state->backend, &oid, path->ptr + state->dir_len) < 0) return 0; return git_error_set_after_callback_function( @@ -778,6 +786,7 @@ static int loose_backend__foreach(git_odb_backend *_backend, git_odb_foreach_cb return -1; memset(&state, 0, sizeof(state)); + state.backend = backend; state.cb = cb; state.data = data; state.dir_len = git_str_len(&buf); @@ -825,9 +834,10 @@ static void loose_backend__writestream_free(git_odb_stream *_stream) static int filebuf_flags(loose_backend *backend) { int flags = GIT_FILEBUF_TEMPORARY | - (backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT); + (backend->options.compression_level << GIT_FILEBUF_DEFLATE_SHIFT); - if (backend->fsync_object_files || git_repository__fsync_gitdir) + if ((backend->options.flags & GIT_ODB_BACKEND_LOOSE_FSYNC) || + git_repository__fsync_gitdir) flags |= GIT_FILEBUF_FSYNC; return flags; @@ -863,7 +873,7 @@ static int loose_backend__writestream(git_odb_stream **stream_out, git_odb_backe if (git_str_joinpath(&tmp_path, backend->objects_dir, "tmp_object") < 0 || git_filebuf_open(&stream->fbuf, tmp_path.ptr, filebuf_flags(backend), - backend->object_file_mode) < 0 || + backend->options.file_mode) < 0 || stream->stream.write((git_odb_stream *)stream, hdr, hdrlen) < 0) { git_filebuf_cleanup(&stream->fbuf); @@ -997,6 +1007,7 @@ static int loose_backend__readstream( loose_readstream *stream = NULL; git_hash_ctx *hash_ctx = NULL; git_str object_path = GIT_STR_INIT; + git_hash_algorithm_t algorithm; obj_hdr hdr; int error = 0; @@ -1013,7 +1024,7 @@ static int loose_backend__readstream( if (locate_object(&object_path, backend, oid) < 0) { error = git_odb__error_notfound("no matching loose object", - oid, GIT_OID_HEXSZ); + oid, backend->oid_hexsize); goto done; } @@ -1023,9 +1034,11 @@ static int loose_backend__readstream( hash_ctx = git__malloc(sizeof(git_hash_ctx)); GIT_ERROR_CHECK_ALLOC(hash_ctx); - if ((error = git_hash_ctx_init(hash_ctx, GIT_HASH_ALGORITHM_SHA1)) < 0 || - (error = git_futils_mmap_ro_file(&stream->map, object_path.ptr)) < 0 || - (error = git_zstream_init(&stream->zstream, GIT_ZSTREAM_INFLATE)) < 0) + algorithm = git_oid_algorithm(backend->options.oid_type); + + if ((error = git_hash_ctx_init(hash_ctx, algorithm)) < 0 || + (error = git_futils_mmap_ro_file(&stream->map, object_path.ptr)) < 0 || + (error = git_zstream_init(&stream->zstream, GIT_ZSTREAM_INFLATE)) < 0) goto done; /* check for a packlike loose object */ @@ -1081,7 +1094,7 @@ static int loose_backend__write(git_odb_backend *_backend, const git_oid *oid, c if (git_str_joinpath(&final_path, backend->objects_dir, "tmp_object") < 0 || git_filebuf_open(&fbuf, final_path.ptr, filebuf_flags(backend), - backend->object_file_mode) < 0) + backend->options.file_mode) < 0) { error = -1; goto cleanup; @@ -1124,13 +1137,34 @@ static void loose_backend__free(git_odb_backend *_backend) git__free(_backend); } -int git_odb_backend_loose( +static void normalize_options( + git_odb_backend_loose_options *opts, + const git_odb_backend_loose_options *given_opts) +{ + git_odb_backend_loose_options init = GIT_ODB_BACKEND_LOOSE_OPTIONS_INIT; + + if (given_opts) + memcpy(opts, given_opts, sizeof(git_odb_backend_loose_options)); + else + memcpy(opts, &init, sizeof(git_odb_backend_loose_options)); + + if (opts->compression_level < 0) + opts->compression_level = Z_BEST_SPEED; + + if (opts->dir_mode == 0) + opts->dir_mode = GIT_OBJECT_DIR_MODE; + + if (opts->file_mode == 0) + opts->file_mode = GIT_OBJECT_FILE_MODE; + + if (opts->oid_type == 0) + opts->oid_type = GIT_OID_DEFAULT; +} + +int git_odb__backend_loose( git_odb_backend **backend_out, const char *objects_dir, - int compression_level, - int do_fsync, - unsigned int dir_mode, - unsigned int file_mode) + git_odb_backend_loose_options *opts) { loose_backend *backend; size_t objects_dirlen, alloclen; @@ -1148,22 +1182,12 @@ int git_odb_backend_loose( backend->parent.version = GIT_ODB_BACKEND_VERSION; backend->objects_dirlen = objects_dirlen; memcpy(backend->objects_dir, objects_dir, objects_dirlen); + if (backend->objects_dir[backend->objects_dirlen - 1] != '/') backend->objects_dir[backend->objects_dirlen++] = '/'; - if (compression_level < 0) - compression_level = Z_BEST_SPEED; - - if (dir_mode == 0) - dir_mode = GIT_OBJECT_DIR_MODE; - - if (file_mode == 0) - file_mode = GIT_OBJECT_FILE_MODE; - - backend->object_zlib_level = compression_level; - backend->fsync_object_files = do_fsync; - backend->object_dir_mode = dir_mode; - backend->object_file_mode = file_mode; + normalize_options(&backend->options, opts); + backend->oid_hexsize = git_oid_hexsize(backend->options.oid_type); backend->parent.read = &loose_backend__read; backend->parent.write = &loose_backend__write; @@ -1180,3 +1204,37 @@ int git_odb_backend_loose( *backend_out = (git_odb_backend *)backend; return 0; } + + +#ifdef GIT_EXPERIMENTAL_SHA256 +int git_odb_backend_loose( + git_odb_backend **backend_out, + const char *objects_dir, + git_odb_backend_loose_options *opts) +{ + return git_odb__backend_loose(backend_out, objects_dir, opts); +} +#else +int git_odb_backend_loose( + git_odb_backend **backend_out, + const char *objects_dir, + int compression_level, + int do_fsync, + unsigned int dir_mode, + unsigned int file_mode) +{ + git_odb_backend_loose_flag_t flags = 0; + git_odb_backend_loose_options opts = GIT_ODB_BACKEND_LOOSE_OPTIONS_INIT; + + if (do_fsync) + flags |= GIT_ODB_BACKEND_LOOSE_FSYNC; + + opts.flags = flags; + opts.compression_level = compression_level; + opts.dir_mode = dir_mode; + opts.file_mode = file_mode; + opts.oid_type = GIT_OID_DEFAULT; + + return git_odb__backend_loose(backend_out, objects_dir, &opts); +} +#endif diff --git a/vendor/libgit2/src/odb_mempack.c b/vendor/libgit2/src/libgit2/odb_mempack.c similarity index 100% rename from vendor/libgit2/src/odb_mempack.c rename to vendor/libgit2/src/libgit2/odb_mempack.c diff --git a/vendor/libgit2/src/odb_pack.c b/vendor/libgit2/src/libgit2/odb_pack.c similarity index 86% rename from vendor/libgit2/src/odb_pack.c rename to vendor/libgit2/src/libgit2/odb_pack.c index 818cc612..fc533ae8 100644 --- a/vendor/libgit2/src/odb_pack.c +++ b/vendor/libgit2/src/libgit2/odb_pack.c @@ -26,6 +26,7 @@ struct pack_backend { git_odb_backend parent; + git_odb_backend_pack_options opts; git_midx_file *midx; git_vector midx_packs; git_vector packs; @@ -95,24 +96,24 @@ struct pack_writepack { * -------------------------------------------------- * * # pack_backend__exists / pack_backend__exists_prefix - * | Check if the given SHA1 oid (or a SHA1 oid prefix) exists in any of the + * | Check if the given oid (or an oid prefix) exists in any of the * | packs that have been loaded for our ODB. * | * |-# pack_entry_find / pack_entry_find_prefix - * | If there is a multi-pack-index present, search the SHA1 oid in that + * | If there is a multi-pack-index present, search the oid in that * | index first. If it is not found there, iterate through all the unindexed * | packs that have been preloaded (starting by the pack where the latest * | object was found) to try to find the OID in one of them. * | * |-# git_midx_entry_find - * | Search for the SHA1 oid in the multi-pack-index. See + * | Search for the oid in the multi-pack-index. See * | * | for specifics on the multi-pack-index format and how do we find * | entries in it. * | * |-# git_pack_entry_find - * | Check the index of an individual unindexed pack to see if the SHA1 - * | OID can be found. If we can find the offset to that SHA1 inside of the + * | Check the index of an individual unindexed pack to see if the + * | OID can be found. If we can find the offset to that inside of the * | index, that means the object is contained inside of the packfile and * | we can stop searching. Before returning, we verify that the * | packfile behind the index we are searching still exists on disk. @@ -141,13 +142,13 @@ struct pack_writepack { * -------------------------------------------------- * * # pack_backend__read / pack_backend__read_prefix - * | Check if the given SHA1 oid (or a SHA1 oid prefix) exists in any of the + * | Check if the given oid (or an oid prefix) exists in any of the * | packs that have been loaded for our ODB. If it does, open the packfile and * | read from it. * | * |-# git_packfile_unpack * Armed with a packfile and the offset within it, we can finally unpack - * the object pointed at by the SHA1 oid. This involves mmapping part of + * the object pointed at by the oid. This involves mmapping part of * the `.pack` file, and uncompressing the object within it (if it is * stored in the undelfitied representation), or finding a base object and * applying some deltas to its uncompressed representation (if it is stored @@ -177,7 +178,7 @@ static int pack_entry_find(struct git_pack_entry *e, * a prefix of an identifier. * Sets GIT_EAMBIGUOUS if short oid is ambiguous. * This method assumes that len is between - * GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ. + * GIT_OID_MINPREFIXLEN and the hexsize for the hash type. */ static int pack_entry_find_prefix( struct git_pack_entry *e, @@ -251,7 +252,7 @@ static int packfile_load__cb(void *data, git_str *path) if (git_vector_search2(NULL, &backend->packs, packfile_byname_search_cmp, &index_prefix) == 0) return 0; - error = git_mwindow_get_pack(&pack, path->ptr); + error = git_mwindow_get_pack(&pack, path->ptr, backend->opts.oid_type); /* ignore missing .pack file as git does */ if (error == GIT_ENOTFOUND) { @@ -270,33 +271,34 @@ static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backen { struct git_pack_file *last_found = backend->last_found, *p; git_midx_entry midx_entry; + size_t oid_hexsize = git_oid_hexsize(backend->opts.oid_type); size_t i; if (backend->midx && - git_midx_entry_find(&midx_entry, backend->midx, oid, GIT_OID_HEXSZ) == 0 && + git_midx_entry_find(&midx_entry, backend->midx, oid, oid_hexsize) == 0 && midx_entry.pack_index < git_vector_length(&backend->midx_packs)) { e->offset = midx_entry.offset; - git_oid_cpy(&e->sha1, &midx_entry.sha1); + git_oid_cpy(&e->id, &midx_entry.sha1); e->p = git_vector_get(&backend->midx_packs, midx_entry.pack_index); return 0; } if (last_found && - git_pack_entry_find(e, last_found, oid, GIT_OID_HEXSZ) == 0) + git_pack_entry_find(e, last_found, oid, oid_hexsize) == 0) return 0; git_vector_foreach(&backend->packs, i, p) { if (p == last_found) continue; - if (git_pack_entry_find(e, p, oid, GIT_OID_HEXSZ) == 0) { + if (git_pack_entry_find(e, p, oid, oid_hexsize) == 0) { backend->last_found = p; return 0; } } return git_odb__error_notfound( - "failed to find pack entry", oid, GIT_OID_HEXSZ); + "failed to find pack entry", oid, oid_hexsize); } static int pack_entry_find_prefix( @@ -307,20 +309,26 @@ static int pack_entry_find_prefix( { int error; size_t i; - git_oid found_full_oid = {{0}}; + git_oid found_full_oid; bool found = false; struct git_pack_file *last_found = backend->last_found, *p; git_midx_entry midx_entry; +#ifdef GIT_EXPERIMENTAL_SHA256 + git_oid_clear(&found_full_oid, short_oid->type); +#else + git_oid_clear(&found_full_oid, GIT_OID_SHA1); +#endif + if (backend->midx) { error = git_midx_entry_find(&midx_entry, backend->midx, short_oid, len); if (error == GIT_EAMBIGUOUS) return error; if (!error && midx_entry.pack_index < git_vector_length(&backend->midx_packs)) { e->offset = midx_entry.offset; - git_oid_cpy(&e->sha1, &midx_entry.sha1); + git_oid_cpy(&e->id, &midx_entry.sha1); e->p = git_vector_get(&backend->midx_packs, midx_entry.pack_index); - git_oid_cpy(&found_full_oid, &e->sha1); + git_oid_cpy(&found_full_oid, &e->id); found = true; } } @@ -330,9 +338,9 @@ static int pack_entry_find_prefix( if (error == GIT_EAMBIGUOUS) return error; if (!error) { - if (found && git_oid_cmp(&e->sha1, &found_full_oid)) + if (found && git_oid_cmp(&e->id, &found_full_oid)) return git_odb__error_ambiguous("found multiple pack entries"); - git_oid_cpy(&found_full_oid, &e->sha1); + git_oid_cpy(&found_full_oid, &e->id); found = true; } } @@ -345,9 +353,9 @@ static int pack_entry_find_prefix( if (error == GIT_EAMBIGUOUS) return error; if (!error) { - if (found && git_oid_cmp(&e->sha1, &found_full_oid)) + if (found && git_oid_cmp(&e->id, &found_full_oid)) return git_odb__error_ambiguous("found multiple pack entries"); - git_oid_cpy(&found_full_oid, &e->sha1); + git_oid_cpy(&found_full_oid, &e->id); found = true; backend->last_found = p; } @@ -425,7 +433,10 @@ static int process_multi_pack_index_pack( } /* Pack was not found. Allocate a new one. */ - error = git_mwindow_get_pack(&pack, git_str_cstr(&pack_path)); + error = git_mwindow_get_pack( + &pack, + git_str_cstr(&pack_path), + backend->opts.oid_type); git_str_dispose(&pack_path); if (error < 0) return error; @@ -468,7 +479,9 @@ static int refresh_multi_pack_index(struct pack_backend *backend) } } - error = git_midx_open(&backend->midx, git_str_cstr(&midx_path)); + error = git_midx_open(&backend->midx, git_str_cstr(&midx_path), + backend->opts.oid_type); + git_str_dispose(&midx_path); if (error < 0) return error; @@ -596,32 +609,33 @@ static int pack_backend__read_prefix( void **buffer_p, size_t *len_p, git_object_t *type_p, - git_odb_backend *backend, + git_odb_backend *_backend, const git_oid *short_oid, size_t len) { + struct pack_backend *backend = (struct pack_backend *)_backend; int error = 0; if (len < GIT_OID_MINPREFIXLEN) error = git_odb__error_ambiguous("prefix length too short"); - else if (len >= GIT_OID_HEXSZ) { + else if (len >= git_oid_hexsize(backend->opts.oid_type)) { /* We can fall back to regular read method */ - error = pack_backend__read(buffer_p, len_p, type_p, backend, short_oid); + error = pack_backend__read(buffer_p, len_p, type_p, _backend, short_oid); if (!error) git_oid_cpy(out_oid, short_oid); } else { struct git_pack_entry e; git_rawobj raw = {NULL}; - if ((error = pack_entry_find_prefix( - &e, (struct pack_backend *)backend, short_oid, len)) == 0 && - (error = git_packfile_unpack(&raw, e.p, &e.offset)) == 0) + if ((error = pack_entry_find_prefix(&e, + backend, short_oid, len)) == 0 && + (error = git_packfile_unpack(&raw, e.p, &e.offset)) == 0) { *buffer_p = raw.data; *len_p = raw.len; *type_p = raw.type; - git_oid_cpy(out_oid, &e.sha1); + git_oid_cpy(out_oid, &e.id); } } @@ -642,7 +656,7 @@ static int pack_backend__exists_prefix( struct git_pack_entry e = {0}; error = pack_entry_find_prefix(&e, pb, short_id, len); - git_oid_cpy(out, &e.sha1); + git_oid_cpy(out, &e.id); return error; } @@ -712,6 +726,7 @@ static int pack_backend__writepack(struct git_odb_writepack **out, git_indexer_options opts = GIT_INDEXER_OPTIONS_INIT; struct pack_backend *backend; struct pack_writepack *writepack; + int error; GIT_ASSERT_ARG(out); GIT_ASSERT_ARG(_backend); @@ -726,11 +741,20 @@ static int pack_backend__writepack(struct git_odb_writepack **out, writepack = git__calloc(1, sizeof(struct pack_writepack)); GIT_ERROR_CHECK_ALLOC(writepack); - if (git_indexer_new(&writepack->indexer, - backend->pack_folder, 0, odb, &opts) < 0) { - git__free(writepack); +#ifdef GIT_EXPERIMENTAL_SHA256 + opts.odb = odb; + + error = git_indexer_new(&writepack->indexer, + backend->pack_folder, + backend->opts.oid_type, + &opts); +#else + error = git_indexer_new(&writepack->indexer, + backend->pack_folder, 0, odb, &opts); +#endif + + if (error < 0) return -1; - } writepack->parent.backend = _backend; writepack->parent.append = pack_backend__writepack_append; @@ -776,7 +800,12 @@ static int pack_backend__writemidx(git_odb_backend *_backend) backend = (struct pack_backend *)_backend; - error = git_midx_writer_new(&w, backend->pack_folder); + error = git_midx_writer_new(&w, backend->pack_folder +#ifdef GIT_EXPERIMENTAL_SHA256 + , backend->opts.oid_type +#endif + ); + if (error < 0) return error; @@ -840,7 +869,10 @@ static void pack_backend__free(git_odb_backend *_backend) git__free(backend); } -static int pack_backend__alloc(struct pack_backend **out, size_t initial_size) +static int pack_backend__alloc( + struct pack_backend **out, + size_t initial_size, + const git_odb_backend_pack_options *opts) { struct pack_backend *backend = git__calloc(1, sizeof(struct pack_backend)); GIT_ERROR_CHECK_ALLOC(backend); @@ -849,12 +881,19 @@ static int pack_backend__alloc(struct pack_backend **out, size_t initial_size) git__free(backend); return -1; } + if (git_vector_init(&backend->packs, initial_size, packfile_sort__cb) < 0) { git_vector_free(&backend->midx_packs); git__free(backend); return -1; } + if (opts) + memcpy(&backend->opts, opts, sizeof(git_odb_backend_pack_options)); + + if (!backend->opts.oid_type) + backend->opts.oid_type = GIT_OID_DEFAULT; + backend->parent.version = GIT_ODB_BACKEND_VERSION; backend->parent.read = &pack_backend__read; @@ -873,17 +912,31 @@ static int pack_backend__alloc(struct pack_backend **out, size_t initial_size) return 0; } -int git_odb_backend_one_pack(git_odb_backend **backend_out, const char *idx) +#ifdef GIT_EXPERIMENTAL_SHA256 +int git_odb_backend_one_pack( + git_odb_backend **backend_out, + const char *idx, + const git_odb_backend_pack_options *opts) +#else +int git_odb_backend_one_pack( + git_odb_backend **backend_out, + const char *idx) +#endif { struct pack_backend *backend = NULL; struct git_pack_file *packfile = NULL; - if (pack_backend__alloc(&backend, 1) < 0) +#ifndef GIT_EXPERIMENTAL_SHA256 + git_odb_backend_pack_options *opts = NULL; +#endif + + git_oid_t oid_type = opts ? opts->oid_type : 0; + + if (pack_backend__alloc(&backend, 1, opts) < 0) return -1; - if (git_mwindow_get_pack(&packfile, idx) < 0 || - git_vector_insert(&backend->packs, packfile) < 0) - { + if (git_mwindow_get_pack(&packfile, idx, oid_type) < 0 || + git_vector_insert(&backend->packs, packfile) < 0) { pack_backend__free((git_odb_backend *)backend); return -1; } @@ -892,18 +945,30 @@ int git_odb_backend_one_pack(git_odb_backend **backend_out, const char *idx) return 0; } -int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) +#ifdef GIT_EXPERIMENTAL_SHA256 +int git_odb_backend_pack( + git_odb_backend **backend_out, + const char *objects_dir, + const git_odb_backend_pack_options *opts) +#else +int git_odb_backend_pack( + git_odb_backend **backend_out, + const char *objects_dir) +#endif { int error = 0; struct pack_backend *backend = NULL; git_str path = GIT_STR_INIT; - if (pack_backend__alloc(&backend, 8) < 0) +#ifndef GIT_EXPERIMENTAL_SHA256 + git_odb_backend_pack_options *opts = NULL; +#endif + + if (pack_backend__alloc(&backend, 8, opts) < 0) return -1; if (!(error = git_str_joinpath(&path, objects_dir, "pack")) && - git_fs_path_isdir(git_str_cstr(&path))) - { + git_fs_path_isdir(git_str_cstr(&path))) { backend->pack_folder = git_str_detach(&path); error = pack_backend__refresh((git_odb_backend *)backend); } diff --git a/vendor/libgit2/src/offmap.c b/vendor/libgit2/src/libgit2/offmap.c similarity index 100% rename from vendor/libgit2/src/offmap.c rename to vendor/libgit2/src/libgit2/offmap.c diff --git a/vendor/libgit2/src/offmap.h b/vendor/libgit2/src/libgit2/offmap.h similarity index 100% rename from vendor/libgit2/src/offmap.h rename to vendor/libgit2/src/libgit2/offmap.h diff --git a/vendor/libgit2/src/libgit2/oid.c b/vendor/libgit2/src/libgit2/oid.c new file mode 100644 index 00000000..2bb7a6f6 --- /dev/null +++ b/vendor/libgit2/src/libgit2/oid.c @@ -0,0 +1,535 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "oid.h" + +#include "git2/oid.h" +#include "repository.h" +#include "runtime.h" +#include +#include + +const git_oid git_oid__empty_blob_sha1 = + GIT_OID_INIT(GIT_OID_SHA1, + { 0xe6, 0x9d, 0xe2, 0x9b, 0xb2, 0xd1, 0xd6, 0x43, 0x4b, 0x8b, + 0x29, 0xae, 0x77, 0x5a, 0xd8, 0xc2, 0xe4, 0x8c, 0x53, 0x91 }); +const git_oid git_oid__empty_tree_sha1 = + GIT_OID_INIT(GIT_OID_SHA1, + { 0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60, + 0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04 }); + +static int oid_error_invalid(const char *msg) +{ + git_error_set(GIT_ERROR_INVALID, "unable to parse OID - %s", msg); + return -1; +} + +int git_oid__fromstrn( + git_oid *out, + const char *str, + size_t length, + git_oid_t type) +{ + size_t size, p; + int v; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(str); + + if (!(size = git_oid_size(type))) + return oid_error_invalid("unknown type"); + + if (!length) + return oid_error_invalid("too short"); + + if (length > git_oid_hexsize(type)) + return oid_error_invalid("too long"); + +#ifdef GIT_EXPERIMENTAL_SHA256 + out->type = type; +#endif + memset(out->id, 0, size); + + for (p = 0; p < length; p++) { + v = git__fromhex(str[p]); + if (v < 0) + return oid_error_invalid("contains invalid characters"); + + out->id[p / 2] |= (unsigned char)(v << (p % 2 ? 0 : 4)); + } + + return 0; +} + +int git_oid__fromstrp(git_oid *out, const char *str, git_oid_t type) +{ + return git_oid__fromstrn(out, str, strlen(str), type); +} + +int git_oid__fromstr(git_oid *out, const char *str, git_oid_t type) +{ + return git_oid__fromstrn(out, str, git_oid_hexsize(type), type); +} + +#ifdef GIT_EXPERIMENTAL_SHA256 +int git_oid_fromstrn( + git_oid *out, + const char *str, + size_t length, + git_oid_t type) +{ + return git_oid__fromstrn(out, str, length, type); +} + +int git_oid_fromstrp(git_oid *out, const char *str, git_oid_t type) +{ + return git_oid_fromstrn(out, str, strlen(str), type); +} + +int git_oid_fromstr(git_oid *out, const char *str, git_oid_t type) +{ + return git_oid_fromstrn(out, str, git_oid_hexsize(type), type); +} +#else +int git_oid_fromstrn( + git_oid *out, + const char *str, + size_t length) +{ + return git_oid__fromstrn(out, str, length, GIT_OID_SHA1); +} + +int git_oid_fromstrp(git_oid *out, const char *str) +{ + return git_oid__fromstrn(out, str, strlen(str), GIT_OID_SHA1); +} + +int git_oid_fromstr(git_oid *out, const char *str) +{ + return git_oid__fromstrn(out, str, GIT_OID_SHA1_HEXSIZE, GIT_OID_SHA1); +} +#endif + +int git_oid_nfmt(char *str, size_t n, const git_oid *oid) +{ + size_t hex_size; + + if (!oid) { + memset(str, 0, n); + return 0; + } + + if (!(hex_size = git_oid_hexsize(git_oid_type(oid)))) + return oid_error_invalid("unknown type"); + + if (n > hex_size) { + memset(&str[hex_size], 0, n - hex_size); + n = hex_size; + } + + git_oid_fmt_substr(str, oid, 0, n); + return 0; +} + +int git_oid_fmt(char *str, const git_oid *oid) +{ + return git_oid_nfmt(str, git_oid_hexsize(git_oid_type(oid)), oid); +} + +int git_oid_pathfmt(char *str, const git_oid *oid) +{ + size_t hex_size; + + if (!(hex_size = git_oid_hexsize(git_oid_type(oid)))) + return oid_error_invalid("unknown type"); + + git_oid_fmt_substr(str, oid, 0, 2); + str[2] = '/'; + git_oid_fmt_substr(&str[3], oid, 2, (hex_size - 2)); + return 0; +} + +static git_tlsdata_key thread_str_key; + +static void GIT_SYSTEM_CALL thread_str_free(void *s) +{ + char *str = (char *)s; + git__free(str); +} + +static void thread_str_global_shutdown(void) +{ + char *str = git_tlsdata_get(thread_str_key); + git_tlsdata_set(thread_str_key, NULL); + + git__free(str); + git_tlsdata_dispose(thread_str_key); +} + +int git_oid_global_init(void) +{ + if (git_tlsdata_init(&thread_str_key, thread_str_free) != 0) + return -1; + + return git_runtime_shutdown_register(thread_str_global_shutdown); +} + +char *git_oid_tostr_s(const git_oid *oid) +{ + char *str; + + if ((str = git_tlsdata_get(thread_str_key)) == NULL) { + if ((str = git__malloc(GIT_OID_MAX_HEXSIZE + 1)) == NULL) + return NULL; + + git_tlsdata_set(thread_str_key, str); + } + + git_oid_nfmt(str, git_oid_hexsize(git_oid_type(oid)) + 1, oid); + return str; +} + +char *git_oid_allocfmt(const git_oid *oid) +{ + size_t hex_size = git_oid_hexsize(git_oid_type(oid)); + char *str = git__malloc(hex_size + 1); + + if (!hex_size || !str) + return NULL; + + if (git_oid_nfmt(str, hex_size + 1, oid) < 0) { + git__free(str); + return NULL; + } + + return str; +} + +char *git_oid_tostr(char *out, size_t n, const git_oid *oid) +{ + size_t hex_size; + + if (!out || n == 0) + return ""; + + hex_size = oid ? git_oid_hexsize(git_oid_type(oid)) : 0; + + if (n > hex_size + 1) + n = hex_size + 1; + + git_oid_nfmt(out, n - 1, oid); /* allow room for terminating NUL */ + out[n - 1] = '\0'; + + return out; +} + +int git_oid__fromraw(git_oid *out, const unsigned char *raw, git_oid_t type) +{ + size_t size; + + if (!(size = git_oid_size(type))) + return oid_error_invalid("unknown type"); + +#ifdef GIT_EXPERIMENTAL_SHA256 + out->type = type; +#endif + memcpy(out->id, raw, size); + return 0; +} + +#ifdef GIT_EXPERIMENTAL_SHA256 +int git_oid_fromraw(git_oid *out, const unsigned char *raw, git_oid_t type) +{ + return git_oid__fromraw(out, raw, type); +} +#else +int git_oid_fromraw(git_oid *out, const unsigned char *raw) +{ + return git_oid__fromraw(out, raw, GIT_OID_SHA1); +} +#endif + +int git_oid_cpy(git_oid *out, const git_oid *src) +{ + size_t size; + + if (!(size = git_oid_size(git_oid_type(src)))) + return oid_error_invalid("unknown type"); + +#ifdef GIT_EXPERIMENTAL_SHA256 + out->type = src->type; +#endif + + return git_oid_raw_cpy(out->id, src->id, size); +} + +int git_oid_cmp(const git_oid *a, const git_oid *b) +{ + return git_oid__cmp(a, b); +} + +int git_oid_equal(const git_oid *a, const git_oid *b) +{ + return (git_oid__cmp(a, b) == 0); +} + +int git_oid_ncmp(const git_oid *oid_a, const git_oid *oid_b, size_t len) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + if (oid_a->type != oid_b->type) + return oid_a->type - oid_b->type; +#endif + + return git_oid_raw_ncmp(oid_a->id, oid_b->id, len); +} + +int git_oid_strcmp(const git_oid *oid_a, const char *str) +{ + const unsigned char *a; + unsigned char strval; + long size = (long)git_oid_size(git_oid_type(oid_a)); + int hexval; + + for (a = oid_a->id; *str && (a - oid_a->id) < size; ++a) { + if ((hexval = git__fromhex(*str++)) < 0) + return -1; + strval = (unsigned char)(hexval << 4); + if (*str) { + if ((hexval = git__fromhex(*str++)) < 0) + return -1; + strval |= hexval; + } + if (*a != strval) + return (*a - strval); + } + + return 0; +} + +int git_oid_streq(const git_oid *oid_a, const char *str) +{ + return git_oid_strcmp(oid_a, str) == 0 ? 0 : -1; +} + +int git_oid_is_zero(const git_oid *oid_a) +{ + const unsigned char *a = oid_a->id; + size_t size = git_oid_size(git_oid_type(oid_a)), i; + +#ifdef GIT_EXPERIMENTAL_SHA256 + if (!oid_a->type) + return 1; + else if (!size) + return 0; +#endif + + for (i = 0; i < size; ++i, ++a) + if (*a != 0) + return 0; + return 1; +} + +#ifndef GIT_DEPRECATE_HARD +int git_oid_iszero(const git_oid *oid_a) +{ + return git_oid_is_zero(oid_a); +} +#endif + +typedef short node_index; + +typedef union { + const char *tail; + node_index children[16]; +} trie_node; + +struct git_oid_shorten { + trie_node *nodes; + size_t node_count, size; + int min_length, full; +}; + +static int resize_trie(git_oid_shorten *self, size_t new_size) +{ + self->nodes = git__reallocarray(self->nodes, new_size, sizeof(trie_node)); + GIT_ERROR_CHECK_ALLOC(self->nodes); + + if (new_size > self->size) { + memset(&self->nodes[self->size], 0x0, (new_size - self->size) * sizeof(trie_node)); + } + + self->size = new_size; + return 0; +} + +static trie_node *push_leaf(git_oid_shorten *os, node_index idx, int push_at, const char *oid) +{ + trie_node *node, *leaf; + node_index idx_leaf; + + if (os->node_count >= os->size) { + if (resize_trie(os, os->size * 2) < 0) + return NULL; + } + + idx_leaf = (node_index)os->node_count++; + + if (os->node_count == SHRT_MAX) { + os->full = 1; + return NULL; + } + + node = &os->nodes[idx]; + node->children[push_at] = -idx_leaf; + + leaf = &os->nodes[idx_leaf]; + leaf->tail = oid; + + return node; +} + +git_oid_shorten *git_oid_shorten_new(size_t min_length) +{ + git_oid_shorten *os; + + GIT_ASSERT_ARG_WITH_RETVAL((size_t)((int)min_length) == min_length, NULL); + + os = git__calloc(1, sizeof(git_oid_shorten)); + if (os == NULL) + return NULL; + + if (resize_trie(os, 16) < 0) { + git__free(os); + return NULL; + } + + os->node_count = 1; + os->min_length = (int)min_length; + + return os; +} + +void git_oid_shorten_free(git_oid_shorten *os) +{ + if (os == NULL) + return; + + git__free(os->nodes); + git__free(os); +} + + +/* + * What wizardry is this? + * + * This is just a memory-optimized trie: basically a very fancy + * 16-ary tree, which is used to store the prefixes of the OID + * strings. + * + * Read more: http://en.wikipedia.org/wiki/Trie + * + * Magic that happens in this method: + * + * - Each node in the trie is an union, so it can work both as + * a normal node, or as a leaf. + * + * - Each normal node points to 16 children (one for each possible + * character in the oid). This is *not* stored in an array of + * pointers, because in a 64-bit arch this would be sucking + * 16*sizeof(void*) = 128 bytes of memory per node, which is + * insane. What we do is store Node Indexes, and use these indexes + * to look up each node in the om->index array. These indexes are + * signed shorts, so this limits the amount of unique OIDs that + * fit in the structure to about 20000 (assuming a more or less uniform + * distribution). + * + * - All the nodes in om->index array are stored contiguously in + * memory, and each of them is 32 bytes, so we fit 2x nodes per + * cache line. Convenient for speed. + * + * - To differentiate the leafs from the normal nodes, we store all + * the indexes towards a leaf as a negative index (indexes to normal + * nodes are positives). When we find that one of the children for + * a node has a negative value, that means it's going to be a leaf. + * This reduces the amount of indexes we have by two, but also reduces + * the size of each node by 1-4 bytes (the amount we would need to + * add a `is_leaf` field): this is good because it allows the nodes + * to fit cleanly in cache lines. + * + * - Once we reach an empty children, instead of continuing to insert + * new nodes for each remaining character of the OID, we store a pointer + * to the tail in the leaf; if the leaf is reached again, we turn it + * into a normal node and use the tail to create a new leaf. + * + * This is a pretty good balance between performance and memory usage. + */ +int git_oid_shorten_add(git_oid_shorten *os, const char *text_oid) +{ + int i; + bool is_leaf; + node_index idx; + + if (os->full) { + git_error_set(GIT_ERROR_INVALID, "unable to shorten OID - OID set full"); + return -1; + } + + if (text_oid == NULL) + return os->min_length; + + idx = 0; + is_leaf = false; + + for (i = 0; i < GIT_OID_SHA1_HEXSIZE; ++i) { + int c = git__fromhex(text_oid[i]); + trie_node *node; + + if (c == -1) { + git_error_set(GIT_ERROR_INVALID, "unable to shorten OID - invalid hex value"); + return -1; + } + + node = &os->nodes[idx]; + + if (is_leaf) { + const char *tail; + + tail = node->tail; + node->tail = NULL; + + node = push_leaf(os, idx, git__fromhex(tail[0]), &tail[1]); + if (node == NULL) { + if (os->full) + git_error_set(GIT_ERROR_INVALID, "unable to shorten OID - OID set full"); + return -1; + } + } + + if (node->children[c] == 0) { + if (push_leaf(os, idx, c, &text_oid[i + 1]) == NULL) { + if (os->full) + git_error_set(GIT_ERROR_INVALID, "unable to shorten OID - OID set full"); + return -1; + } + break; + } + + idx = node->children[c]; + is_leaf = false; + + if (idx < 0) { + node->children[c] = idx = -idx; + is_leaf = true; + } + } + + if (++i > os->min_length) + os->min_length = i; + + return os->min_length; +} + diff --git a/vendor/libgit2/src/libgit2/oid.h b/vendor/libgit2/src/libgit2/oid.h new file mode 100644 index 00000000..f25a899a --- /dev/null +++ b/vendor/libgit2/src/libgit2/oid.h @@ -0,0 +1,275 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_oid_h__ +#define INCLUDE_oid_h__ + +#include "common.h" + +#include "git2/experimental.h" +#include "git2/oid.h" +#include "hash.h" + +#ifdef GIT_EXPERIMENTAL_SHA256 +# define GIT_OID_NONE { 0, { 0 } } +# define GIT_OID_INIT(type, ...) { type, __VA_ARGS__ } +#else +# define GIT_OID_NONE { { 0 } } +# define GIT_OID_INIT(type, ...) { __VA_ARGS__ } +#endif + +extern const git_oid git_oid__empty_blob_sha1; +extern const git_oid git_oid__empty_tree_sha1; + +GIT_INLINE(git_oid_t) git_oid_type(const git_oid *oid) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + return oid->type; +#else + GIT_UNUSED(oid); + return GIT_OID_SHA1; +#endif +} + +GIT_INLINE(size_t) git_oid_size(git_oid_t type) +{ + switch (type) { + case GIT_OID_SHA1: + return GIT_OID_SHA1_SIZE; + +#ifdef GIT_EXPERIMENTAL_SHA256 + case GIT_OID_SHA256: + return GIT_OID_SHA256_SIZE; +#endif + + } + + return 0; +} + +GIT_INLINE(size_t) git_oid_hexsize(git_oid_t type) +{ + switch (type) { + case GIT_OID_SHA1: + return GIT_OID_SHA1_HEXSIZE; + +#ifdef GIT_EXPERIMENTAL_SHA256 + case GIT_OID_SHA256: + return GIT_OID_SHA256_HEXSIZE; +#endif + + } + + return 0; +} + +GIT_INLINE(const char *) git_oid_type_name(git_oid_t type) +{ + switch (type) { + case GIT_OID_SHA1: + return "sha1"; + +#ifdef GIT_EXPERIMENTAL_SHA256 + case GIT_OID_SHA256: + return "sha256"; +#endif + } + + return "unknown"; +} + +GIT_INLINE(git_oid_t) git_oid_type_fromstr(const char *name) +{ + if (strcmp(name, "sha1") == 0) + return GIT_OID_SHA1; + +#ifdef GIT_EXPERIMENTAL_SHA256 + if (strcmp(name, "sha256") == 0) + return GIT_OID_SHA256; +#endif + + return 0; +} + +GIT_INLINE(git_oid_t) git_oid_type_fromstrn(const char *name, size_t len) +{ + if (len == CONST_STRLEN("sha1") && strncmp(name, "sha1", len) == 0) + return GIT_OID_SHA1; + +#ifdef GIT_EXPERIMENTAL_SHA256 + if (len == CONST_STRLEN("sha256") && strncmp(name, "sha256", len) == 0) + return GIT_OID_SHA256; +#endif + + return 0; +} + +GIT_INLINE(git_hash_algorithm_t) git_oid_algorithm(git_oid_t type) +{ + switch (type) { + case GIT_OID_SHA1: + return GIT_HASH_ALGORITHM_SHA1; + +#ifdef GIT_EXPERIMENTAL_SHA256 + case GIT_OID_SHA256: + return GIT_HASH_ALGORITHM_SHA256; +#endif + + } + + return 0; +} + +/** + * Format a git_oid into a newly allocated c-string. + * + * The c-string is owned by the caller and needs to be manually freed. + * + * @param id the oid structure to format + * @return the c-string; NULL if memory is exhausted. Caller must + * deallocate the string with git__free(). + */ +char *git_oid_allocfmt(const git_oid *id); + +/** + * Format the requested nibbles of an object id. + * + * @param str the string to write into + * @param oid the oid structure to format + * @param start the starting number of nibbles + * @param count the number of nibbles to format + */ +GIT_INLINE(void) git_oid_fmt_substr( + char *str, + const git_oid *oid, + size_t start, + size_t count) +{ + static char hex[] = "0123456789abcdef"; + size_t i, end = start + count, min = start / 2, max = end / 2; + + if (start & 1) + *str++ = hex[oid->id[min++] & 0x0f]; + + for (i = min; i < max; i++) { + *str++ = hex[oid->id[i] >> 4]; + *str++ = hex[oid->id[i] & 0x0f]; + } + + if (end & 1) + *str++ = hex[oid->id[i] >> 4]; +} + +GIT_INLINE(int) git_oid_raw_ncmp( + const unsigned char *sha1, + const unsigned char *sha2, + size_t len) +{ + if (len > GIT_OID_MAX_HEXSIZE) + len = GIT_OID_MAX_HEXSIZE; + + while (len > 1) { + if (*sha1 != *sha2) + return 1; + sha1++; + sha2++; + len -= 2; + }; + + if (len) + if ((*sha1 ^ *sha2) & 0xf0) + return 1; + + return 0; +} + +GIT_INLINE(int) git_oid_raw_cmp( + const unsigned char *sha1, + const unsigned char *sha2, + size_t size) +{ + return memcmp(sha1, sha2, size); +} + +GIT_INLINE(int) git_oid_raw_cpy( + unsigned char *dst, + const unsigned char *src, + size_t size) +{ + memcpy(dst, src, size); + return 0; +} + +/* + * Compare two oid structures. + * + * @param a first oid structure. + * @param b second oid structure. + * @return <0, 0, >0 if a < b, a == b, a > b. + */ +GIT_INLINE(int) git_oid__cmp(const git_oid *a, const git_oid *b) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + if (a->type != b->type) + return a->type - b->type; + + return git_oid_raw_cmp(a->id, b->id, git_oid_size(a->type)); +#else + return git_oid_raw_cmp(a->id, b->id, git_oid_size(GIT_OID_SHA1)); +#endif +} + +GIT_INLINE(void) git_oid__cpy_prefix( + git_oid *out, const git_oid *id, size_t len) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + out->type = id->type; +#endif + + memcpy(&out->id, id->id, (len + 1) / 2); + + if (len & 1) + out->id[len / 2] &= 0xF0; +} + +GIT_INLINE(bool) git_oid__is_hexstr(const char *str, git_oid_t type) +{ + size_t i; + + for (i = 0; str[i] != '\0'; i++) { + if (git__fromhex(str[i]) < 0) + return false; + } + + return (i == git_oid_hexsize(type)); +} + +GIT_INLINE(void) git_oid_clear(git_oid *out, git_oid_t type) +{ + memset(out->id, 0, git_oid_size(type)); + +#ifdef GIT_EXPERIMENTAL_SHA256 + out->type = type; +#endif +} + +/* SHA256 support */ + +int git_oid__fromstr(git_oid *out, const char *str, git_oid_t type); + +int git_oid__fromstrp(git_oid *out, const char *str, git_oid_t type); + +int git_oid__fromstrn( + git_oid *out, + const char *str, + size_t length, + git_oid_t type); + +int git_oid__fromraw(git_oid *out, const unsigned char *raw, git_oid_t type); + +int git_oid_global_init(void); + +#endif diff --git a/vendor/libgit2/src/libgit2/oidarray.c b/vendor/libgit2/src/libgit2/oidarray.c new file mode 100644 index 00000000..37f67756 --- /dev/null +++ b/vendor/libgit2/src/libgit2/oidarray.c @@ -0,0 +1,89 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "oidarray.h" + +#include "git2/oidarray.h" +#include "array.h" + +void git_oidarray_dispose(git_oidarray *arr) +{ + git__free(arr->ids); +} + +void git_oidarray__from_array(git_oidarray *out, const git_array_oid_t *array) +{ + out->count = array->size; + out->ids = array->ptr; +} + +void git_oidarray__to_array(git_array_oid_t *out, const git_oidarray *array) +{ + out->ptr = array->ids; + out->size = array->count; + out->asize = array->count; +} + +void git_oidarray__reverse(git_oidarray *arr) +{ + size_t i; + git_oid tmp; + + for (i = 0; i < arr->count / 2; i++) { + git_oid_cpy(&tmp, &arr->ids[i]); + git_oid_cpy(&arr->ids[i], &arr->ids[(arr->count-1)-i]); + git_oid_cpy(&arr->ids[(arr->count-1)-i], &tmp); + } +} + +int git_oidarray__add(git_array_oid_t *arr, git_oid *id) +{ + git_oid *add, *iter; + size_t i; + + git_array_foreach(*arr, i, iter) { + if (git_oid_cmp(iter, id) == 0) + return 0; + } + + if ((add = git_array_alloc(*arr)) == NULL) + return -1; + + git_oid_cpy(add, id); + return 0; +} + +bool git_oidarray__remove(git_array_oid_t *arr, git_oid *id) +{ + bool found = false; + size_t remain, i; + git_oid *iter; + + git_array_foreach(*arr, i, iter) { + if (git_oid_cmp(iter, id) == 0) { + arr->size--; + remain = arr->size - i; + + if (remain > 0) + memmove(&arr->ptr[i], &arr->ptr[i+1], remain * sizeof(git_oid)); + + found = true; + break; + } + } + + return found; +} + +#ifndef GIT_DEPRECATE_HARD + +void git_oidarray_free(git_oidarray *arr) +{ + git_oidarray_dispose(arr); +} + +#endif diff --git a/vendor/libgit2/src/libgit2/oidarray.h b/vendor/libgit2/src/libgit2/oidarray.h new file mode 100644 index 00000000..8f1543a3 --- /dev/null +++ b/vendor/libgit2/src/libgit2/oidarray.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_oidarray_h__ +#define INCLUDE_oidarray_h__ + +#include "common.h" + +#include "git2/oidarray.h" +#include "array.h" + +typedef git_array_t(git_oid) git_array_oid_t; + +extern void git_oidarray__reverse(git_oidarray *arr); +extern void git_oidarray__from_array(git_oidarray *out, const git_array_oid_t *array); +extern void git_oidarray__to_array(git_array_oid_t *out, const git_oidarray *array); + +int git_oidarray__add(git_array_oid_t *arr, git_oid *id); +bool git_oidarray__remove(git_array_oid_t *arr, git_oid *id); + +#endif diff --git a/vendor/libgit2/src/libgit2/oidmap.c b/vendor/libgit2/src/libgit2/oidmap.c new file mode 100644 index 00000000..eaf9fa05 --- /dev/null +++ b/vendor/libgit2/src/libgit2/oidmap.c @@ -0,0 +1,107 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "oidmap.h" + +#define kmalloc git__malloc +#define kcalloc git__calloc +#define krealloc git__realloc +#define kreallocarray git__reallocarray +#define kfree git__free +#include "khash.h" + +__KHASH_TYPE(oid, const git_oid *, void *) + +GIT_INLINE(khint_t) git_oidmap_hash(const git_oid *oid) +{ + khint_t h; + memcpy(&h, oid->id, sizeof(khint_t)); + return h; +} + +__KHASH_IMPL(oid, static kh_inline, const git_oid *, void *, 1, git_oidmap_hash, git_oid_equal) + +int git_oidmap_new(git_oidmap **out) +{ + *out = kh_init(oid); + GIT_ERROR_CHECK_ALLOC(*out); + + return 0; +} + +void git_oidmap_free(git_oidmap *map) +{ + kh_destroy(oid, map); +} + +void git_oidmap_clear(git_oidmap *map) +{ + kh_clear(oid, map); +} + +size_t git_oidmap_size(git_oidmap *map) +{ + return kh_size(map); +} + +void *git_oidmap_get(git_oidmap *map, const git_oid *key) +{ + size_t idx = kh_get(oid, map, key); + if (idx == kh_end(map) || !kh_exist(map, idx)) + return NULL; + return kh_val(map, idx); +} + +int git_oidmap_set(git_oidmap *map, const git_oid *key, void *value) +{ + size_t idx; + int rval; + + idx = kh_put(oid, map, key, &rval); + if (rval < 0) + return -1; + + if (rval == 0) + kh_key(map, idx) = key; + + kh_val(map, idx) = value; + + return 0; +} + +int git_oidmap_delete(git_oidmap *map, const git_oid *key) +{ + khiter_t idx = kh_get(oid, map, key); + if (idx == kh_end(map)) + return GIT_ENOTFOUND; + kh_del(oid, map, idx); + return 0; +} + +int git_oidmap_exists(git_oidmap *map, const git_oid *key) +{ + return kh_get(oid, map, key) != kh_end(map); +} + +int git_oidmap_iterate(void **value, git_oidmap *map, size_t *iter, const git_oid **key) +{ + size_t i = *iter; + + while (i < map->n_buckets && !kh_exist(map, i)) + i++; + + if (i >= map->n_buckets) + return GIT_ITEROVER; + + if (key) + *key = kh_key(map, i); + if (value) + *value = kh_value(map, i); + *iter = ++i; + + return 0; +} diff --git a/vendor/libgit2/src/oidmap.h b/vendor/libgit2/src/libgit2/oidmap.h similarity index 100% rename from vendor/libgit2/src/oidmap.h rename to vendor/libgit2/src/libgit2/oidmap.h diff --git a/vendor/libgit2/src/pack-objects.c b/vendor/libgit2/src/libgit2/pack-objects.c similarity index 97% rename from vendor/libgit2/src/pack-objects.c rename to vendor/libgit2/src/libgit2/pack-objects.c index 1aa6731b..b2d80cba 100644 --- a/vendor/libgit2/src/pack-objects.c +++ b/vendor/libgit2/src/libgit2/pack-objects.c @@ -11,7 +11,6 @@ #include "zstream.h" #include "delta.h" #include "iterator.h" -#include "netops.h" #include "pack.h" #include "thread.h" #include "tree.h" @@ -127,6 +126,7 @@ static int packbuilder_config(git_packbuilder *pb) int git_packbuilder_new(git_packbuilder **out, git_repository *repo) { + git_hash_algorithm_t hash_algorithm; git_packbuilder *pb; *out = NULL; @@ -134,6 +134,11 @@ int git_packbuilder_new(git_packbuilder **out, git_repository *repo) pb = git__calloc(1, sizeof(*pb)); GIT_ERROR_CHECK_ALLOC(pb); + pb->oid_type = repo->oid_type; + + hash_algorithm = git_oid_algorithm(pb->oid_type); + GIT_ASSERT(hash_algorithm); + if (git_oidmap_new(&pb->object_ix) < 0 || git_oidmap_new(&pb->walk_objects) < 0 || git_pool_init(&pb->object_pool, sizeof(struct walk_object)) < 0) @@ -142,7 +147,7 @@ int git_packbuilder_new(git_packbuilder **out, git_repository *repo) pb->repo = repo; pb->nr_threads = 1; /* do not spawn any thread by default */ - if (git_hash_ctx_init(&pb->ctx, GIT_HASH_ALGORITHM_SHA1) < 0 || + if (git_hash_ctx_init(&pb->ctx, hash_algorithm) < 0 || git_zstream_init(&pb->zstream, GIT_ZSTREAM_DEFLATE) < 0 || git_repository_odb(&pb->odb, repo) < 0 || packbuilder_config(pb) < 0) @@ -249,10 +254,10 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid, pb->done = false; if (pb->progress_cb) { - double current_time = git__timer(); - double elapsed = current_time - pb->last_progress_report_time; + uint64_t current_time = git_time_monotonic(); + uint64_t elapsed = current_time - pb->last_progress_report_time; - if (elapsed < 0 || elapsed >= MIN_PROGRESS_UPDATE_INTERVAL) { + if (elapsed >= MIN_PROGRESS_UPDATE_INTERVAL) { pb->last_progress_report_time = current_time; ret = pb->progress_cb( @@ -315,9 +320,11 @@ static int write_object( git_object_t type; unsigned char hdr[10], *zbuf = NULL; void *data = NULL; - size_t hdr_len, zbuf_len = COMPRESS_BUFLEN, data_len; + size_t hdr_len, zbuf_len = COMPRESS_BUFLEN, data_len, oid_size; int error; + oid_size = git_oid_size(pb->oid_type); + /* * If we have a delta base, let's use the delta to save space. * Otherwise load the whole object. 'data' ends up pointing to @@ -347,8 +354,8 @@ static int write_object( goto done; if (type == GIT_OBJECT_REF_DELTA) { - if ((error = write_cb(po->delta->id.id, GIT_OID_RAWSZ, cb_data)) < 0 || - (error = git_hash_update(&pb->ctx, po->delta->id.id, GIT_OID_RAWSZ)) < 0) + if ((error = write_cb(po->delta->id.id, oid_size, cb_data)) < 0 || + (error = git_hash_update(&pb->ctx, po->delta->id.id, oid_size)) < 0) goto done; } @@ -668,7 +675,7 @@ static int write_pack(git_packbuilder *pb, if ((error = git_hash_final(entry_oid.id, &pb->ctx)) < 0) goto done; - error = write_cb(entry_oid.id, GIT_OID_RAWSZ, cb_data); + error = write_cb(entry_oid.id, git_oid_size(pb->oid_type), cb_data); done: /* if callback cancelled writing, we must still free delta_data */ @@ -926,10 +933,10 @@ static int report_delta_progress( int ret; if (pb->progress_cb) { - double current_time = git__timer(); - double elapsed = current_time - pb->last_progress_report_time; + uint64_t current_time = git_time_monotonic(); + uint64_t elapsed = current_time - pb->last_progress_report_time; - if (force || elapsed < 0 || elapsed >= MIN_PROGRESS_UPDATE_INTERVAL) { + if (force || elapsed >= MIN_PROGRESS_UPDATE_INTERVAL) { pb->last_progress_report_time = current_time; ret = pb->progress_cb( @@ -1407,7 +1414,18 @@ int git_packbuilder_write( opts.progress_cb = progress_cb; opts.progress_cb_payload = progress_cb_payload; - if ((error = git_indexer_new(&indexer, path, mode, pb->odb, &opts)) < 0) + /* TODO: SHA256 */ + +#ifdef GIT_EXPERIMENTAL_SHA256 + opts.mode = mode; + opts.odb = pb->odb; + + error = git_indexer_new(&indexer, path, GIT_OID_SHA1, &opts); +#else + error = git_indexer_new(&indexer, path, mode, pb->odb, &opts); +#endif + + if (error < 0) goto cleanup; if (!git_repository__configmap_lookup(&t, pb->repo, GIT_CONFIGMAP_FSYNCOBJECTFILES) && t) diff --git a/vendor/libgit2/src/pack-objects.h b/vendor/libgit2/src/libgit2/pack-objects.h similarity index 94% rename from vendor/libgit2/src/pack-objects.h rename to vendor/libgit2/src/libgit2/pack-objects.h index 2faa3ec7..bbc8b943 100644 --- a/vendor/libgit2/src/pack-objects.h +++ b/vendor/libgit2/src/libgit2/pack-objects.h @@ -13,7 +13,6 @@ #include "str.h" #include "hash.h" #include "oidmap.h" -#include "netops.h" #include "zstream.h" #include "pool.h" #include "indexer.h" @@ -56,6 +55,8 @@ struct git_packbuilder { git_repository *repo; /* associated repository */ git_odb *odb; /* associated object database */ + git_oid_t oid_type; + git_hash_ctx ctx; git_zstream zstream; @@ -94,7 +95,9 @@ struct git_packbuilder { git_packbuilder_progress progress_cb; void *progress_cb_payload; - double last_progress_report_time; /* the time progress was last reported */ + + /* the time progress was last reported, in millisecond ticks */ + uint64_t last_progress_report_time; bool done; }; diff --git a/vendor/libgit2/src/pack.c b/vendor/libgit2/src/libgit2/pack.c similarity index 88% rename from vendor/libgit2/src/pack.c rename to vendor/libgit2/src/libgit2/pack.c index 5c0cba7e..1ff0eb0c 100644 --- a/vendor/libgit2/src/pack.c +++ b/vendor/libgit2/src/libgit2/pack.c @@ -32,7 +32,7 @@ static int packfile_unpack_compressed( * Throws GIT_EAMBIGUOUSOIDPREFIX if short oid * is ambiguous within the pack. * This method assumes that len is between - * GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ. + * GIT_OID_MINPREFIXLEN and the oid type's hexsize. */ static int pack_entry_find_offset( off64_t *offset_out, @@ -186,9 +186,9 @@ static int cache_add( static void pack_index_free(struct git_pack_file *p) { - if (p->oids) { - git__free(p->oids); - p->oids = NULL; + if (p->ids) { + git__free(p->ids); + p->ids = NULL; } if (p->index_map.data) { git_futils_mmap_free(&p->index_map); @@ -200,11 +200,12 @@ static void pack_index_free(struct git_pack_file *p) static int pack_index_check_locked(const char *path, struct git_pack_file *p) { struct git_pack_idx_header *hdr; - uint32_t version, nr, i, *index; + uint32_t version, nr = 0, i, *index; void *idx_map; size_t idx_size; struct stat st; int error; + /* TODO: properly open the file without access time using O_NOATIME */ git_file fd = git_futils_open_ro(path); if (fd < 0) @@ -218,8 +219,7 @@ static int pack_index_check_locked(const char *path, struct git_pack_file *p) if (!S_ISREG(st.st_mode) || !git__is_sizet(st.st_size) || - (idx_size = (size_t)st.st_size) < 4 * 256 + 20 + 20) - { + (idx_size = (size_t)st.st_size) < (size_t)((4 * 256) + (p->oid_size * 2))) { p_close(fd); git_error_set(GIT_ERROR_ODB, "invalid pack index '%s'", path); return -1; @@ -242,10 +242,10 @@ static int pack_index_check_locked(const char *path, struct git_pack_file *p) return packfile_error("unsupported index version"); } - } else + } else { version = 1; + } - nr = 0; index = idx_map; if (version > 1) @@ -264,11 +264,11 @@ static int pack_index_check_locked(const char *path, struct git_pack_file *p) /* * Total size: * - 256 index entries 4 bytes each - * - 24-byte entries * nr (20-byte sha1 + 4-byte offset) - * - 20-byte SHA1 of the packfile - * - 20-byte SHA1 file checksum + * - 24/36-byte entries * nr (20/32 byte SHA + 4-byte offset) + * - 20/32-byte SHA of the packfile + * - 20/32-byte SHA file checksum */ - if (idx_size != 4*256 + nr * 24 + 20 + 20) { + if (idx_size != (4 * 256 + ((uint64_t) nr * (p->oid_size + 4)) + (p->oid_size * 2))) { git_futils_mmap_free(&p->index_map); return packfile_error("index is corrupted"); } @@ -277,17 +277,17 @@ static int pack_index_check_locked(const char *path, struct git_pack_file *p) * Minimum size: * - 8 bytes of header * - 256 index entries 4 bytes each - * - 20-byte sha1 entry * nr + * - 20/32-byte SHA entry * nr * - 4-byte crc entry * nr * - 4-byte offset entry * nr - * - 20-byte SHA1 of the packfile - * - 20-byte SHA1 file checksum + * - 20/32-byte SHA of the packfile + * - 20/32-byte SHA file checksum * And after the 4-byte offset table might be a * variable sized table containing 8-byte entries * for offsets larger than 2^31. */ - unsigned long min_size = 8 + 4*256 + nr*(20 + 4 + 4) + 20 + 20; - unsigned long max_size = min_size; + uint64_t min_size = 8 + (4 * 256) + ((uint64_t)nr * (p->oid_size + 4 + 4)) + (p->oid_size * 2); + uint64_t max_size = min_size; if (nr) max_size += (nr - 1)*8; @@ -365,12 +365,12 @@ static unsigned char *pack_window_open( * Don't allow a negative offset, as that means we've wrapped * around. */ - if (offset > (p->mwf.size - 20)) + if (offset > (p->mwf.size - p->oid_size)) goto cleanup; if (offset < 0) goto cleanup; - pack_data = git_mwindow_open(&p->mwf, w_cursor, offset, 20, left); + pack_data = git_mwindow_open(&p->mwf, w_cursor, offset, p->oid_size, left); cleanup: git_mutex_unlock(&p->mwf.lock); @@ -473,13 +473,13 @@ int git_packfile_unpack_header( return error; } - /* pack_window_open() assures us we have [base, base + 20) available - * as a range that we can look at at. (Its actually the hash - * size that is assured.) With our object header encoding - * the maximum deflated object size is 2^137, which is just - * insane, so we know won't exceed what we have been given. + /* pack_window_open() assures us we have [base, base + oid_size) + * available as a range that we can look at at. (It's actually + * the hash size that is assured.) With our object header + * encoding the maximum deflated object size is 2^137, which is + * just insane, so we know won't exceed what we have been given. */ - base = git_mwindow_open(&p->mwf, w_curs, *curpos, 20, &left); + base = git_mwindow_open(&p->mwf, w_curs, *curpos, p->oid_size, &left); git_mutex_unlock(&p->lock); git_mutex_unlock(&p->mwf.lock); if (base == NULL) @@ -977,11 +977,12 @@ int get_delta_base( /* Assumption: the only reason this would fail is because the file is too small */ if (base_info == NULL) return GIT_EBUFS; - /* pack_window_open() assured us we have [base_info, base_info + 20) - * as a range that we can look at without walking off the - * end of the mapped window. Its actually the hash size - * that is assured. An OFS_DELTA longer than the hash size - * is stupid, as then a REF_DELTA would be smaller to store. + /* pack_window_open() assured us we have + * [base_info, base_info + oid_size) as a range that we can look + * at without walking off the end of the mapped window. Its + * actually the hash size that is assured. An OFS_DELTA longer + * than the hash size is stupid, as then a REF_DELTA would be + * smaller to store. */ if (type == GIT_OBJECT_OFS_DELTA) { unsigned used = 0; @@ -1001,17 +1002,18 @@ int get_delta_base( base_offset = delta_obj_offset - unsigned_base_offset; *curpos += used; } else if (type == GIT_OBJECT_REF_DELTA) { + git_oid base_oid; + git_oid__fromraw(&base_oid, base_info, p->oid_type); + /* If we have the cooperative cache, search in it first */ if (p->has_cache) { struct git_pack_entry *entry; - git_oid oid; - git_oid_fromraw(&oid, base_info); - if ((entry = git_oidmap_get(p->idx_cache, &oid)) != NULL) { + if ((entry = git_oidmap_get(p->idx_cache, &base_oid)) != NULL) { if (entry->offset == 0) return packfile_error("delta offset is zero"); - *curpos += 20; + *curpos += p->oid_size; *delta_base_out = entry->offset; return 0; } else { @@ -1024,9 +1026,9 @@ int get_delta_base( } /* The base entry _must_ be in the same pack */ - if (pack_entry_find_offset(&base_offset, &unused, p, (git_oid *)base_info, GIT_OID_HEXSZ) < 0) + if (pack_entry_find_offset(&base_offset, &unused, p, &base_oid, p->oid_hexsize) < 0) return packfile_error("base entry delta is not in the same pack"); - *curpos += 20; + *curpos += p->oid_size; } else return packfile_error("unknown object type"); @@ -1069,7 +1071,7 @@ void git_packfile_free(struct git_pack_file *p, bool unlink_packfile) pack_index_free(p); - git__free(p->bad_object_sha1); + git__free(p->bad_object_ids); git_mutex_free(&p->bases.lock); git_mutex_free(&p->mwf.lock); @@ -1082,8 +1084,8 @@ static int packfile_open_locked(struct git_pack_file *p) { struct stat st; struct git_pack_header hdr; - git_oid sha1; - unsigned char *idx_sha1; + unsigned char checksum[GIT_OID_MAX_SIZE]; + unsigned char *idx_checksum; if (pack_index_open_locked(p) < 0) return git_odb__error_notfound("failed to open packfile", NULL, 0); @@ -1130,12 +1132,13 @@ static int packfile_open_locked(struct git_pack_file *p) /* Verify the pack matches its index. */ if (p->num_objects != ntohl(hdr.hdr_entries) || - p_pread(p->mwf.fd, sha1.id, GIT_OID_RAWSZ, p->mwf.size - GIT_OID_RAWSZ) < 0) + p_pread(p->mwf.fd, checksum, p->oid_size, p->mwf.size - p->oid_size) < 0) goto cleanup; - idx_sha1 = ((unsigned char *)p->index_map.data) + p->index_map.len - 40; + idx_checksum = ((unsigned char *)p->index_map.data) + + p->index_map.len - (p->oid_size * 2); - if (git_oid__cmp(&sha1, (git_oid *)idx_sha1) != 0) + if (git_oid_raw_cmp(checksum, idx_checksum, p->oid_size) != 0) goto cleanup; if (git_mwindow_file_register(&p->mwf) < 0) @@ -1170,7 +1173,10 @@ int git_packfile__name(char **out, const char *path) return 0; } -int git_packfile_alloc(struct git_pack_file **pack_out, const char *path) +int git_packfile_alloc( + struct git_pack_file **pack_out, + const char *path, + git_oid_t oid_type) { struct stat st; struct git_pack_file *p; @@ -1218,6 +1224,9 @@ int git_packfile_alloc(struct git_pack_file **pack_out, const char *path) p->pack_local = 1; p->mtime = (git_time_t)st.st_mtime; p->index_version = -1; + p->oid_type = oid_type ? oid_type : GIT_OID_DEFAULT; + p->oid_size = (unsigned int)git_oid_size(p->oid_type); + p->oid_hexsize = (unsigned int)git_oid_hexsize(p->oid_type); if (git_mutex_init(&p->lock) < 0) { git_error_set(GIT_ERROR_OS, "failed to initialize packfile mutex"); @@ -1259,20 +1268,20 @@ static off64_t nth_packed_object_offset_locked(struct git_pack_file *p, uint32_t end = index + p->index_map.len; index += 4 * 256; if (p->index_version == 1) - return ntohl(*((uint32_t *)(index + 24 * n))); + return ntohl(*((uint32_t *)(index + (p->oid_size + 4) * (size_t) n))); - index += 8 + p->num_objects * (20 + 4); + index += 8 + (size_t) p->num_objects * (p->oid_size + 4); off32 = ntohl(*((uint32_t *)(index + 4 * n))); if (!(off32 & 0x80000000)) return off32; - index += p->num_objects * 4 + (off32 & 0x7fffffff) * 8; + index += (size_t) p->num_objects * 4 + (off32 & 0x7fffffff) * 8; /* Make sure we're not being sent out of bounds */ if (index >= end - 8) return -1; return (((uint64_t)ntohl(*((uint32_t *)(index + 0)))) << 32) | - ntohl(*((uint32_t *)(index + 4))); + ntohl(*((uint32_t *)(index + 4))); } static int git__memcmp4(const void *a, const void *b) { @@ -1311,7 +1320,7 @@ int git_pack_foreach_entry( index += 4 * 256; - if (p->oids == NULL) { + if (p->ids == NULL) { git_vector offsets, oids; if ((error = git_vector_init(&oids, p->num_objects, NULL))) { @@ -1325,25 +1334,32 @@ int git_pack_foreach_entry( } if (p->index_version > 1) { - const unsigned char *off = index + 24 * p->num_objects; + const unsigned char *off = index + + (p->oid_size + 4) * p->num_objects; + for (i = 0; i < p->num_objects; i++) git_vector_insert(&offsets, (void*)&off[4 * i]); + git_vector_sort(&offsets); git_vector_foreach(&offsets, i, current) git_vector_insert(&oids, (void*)&index[5 * (current - off)]); } else { for (i = 0; i < p->num_objects; i++) - git_vector_insert(&offsets, (void*)&index[24 * i]); + git_vector_insert(&offsets, (void*)&index[(p->oid_size + 4) * i]); git_vector_sort(&offsets); git_vector_foreach(&offsets, i, current) git_vector_insert(&oids, (void*)¤t[4]); } git_vector_free(&offsets); - p->oids = (git_oid **)git_vector_detach(NULL, NULL, &oids); + p->ids = (unsigned char **)git_vector_detach(NULL, NULL, &oids); } - /* We need to copy the OIDs to another array before we relinquish the lock to avoid races. */ + /* + * We need to copy the OIDs to another array before we + * relinquish the lock to avoid races. We can also take + * this opportunity to put them into normal form. + */ git_array_init_to_size(oids, p->num_objects); if (!oids.ptr) { git_mutex_unlock(&p->lock); @@ -1357,7 +1373,7 @@ int git_pack_foreach_entry( git_array_clear(oids); GIT_ERROR_CHECK_ALLOC(oid); } - git_oid_cpy(oid, p->oids[i]); + git_oid__fromraw(oid, p->ids[i], p->oid_type); } git_mutex_unlock(&p->lock); @@ -1380,7 +1396,7 @@ int git_pack_foreach_entry_offset( { const unsigned char *index; off64_t current_offset; - const git_oid *current_oid; + git_oid current_oid; uint32_t i; int error = 0; @@ -1407,10 +1423,13 @@ int git_pack_foreach_entry_offset( /* all offsets should have been validated by pack_index_check_locked */ if (p->index_version > 1) { - const unsigned char *offsets = index + 24 * p->num_objects; + const unsigned char *offsets = index + + (p->oid_size + 4) * p->num_objects; const unsigned char *large_offset_ptr; - const unsigned char *large_offsets = index + 28 * p->num_objects; - const unsigned char *large_offsets_end = ((const unsigned char *)p->index_map.data) + p->index_map.len - 20; + const unsigned char *large_offsets = index + + (p->oid_size + 8) * p->num_objects; + const unsigned char *large_offsets_end = ((const unsigned char *)p->index_map.data) + p->index_map.len - p->oid_size; + for (i = 0; i < p->num_objects; i++) { current_offset = ntohl(*(const uint32_t *)(offsets + 4 * i)); if (current_offset & 0x80000000) { @@ -1422,17 +1441,18 @@ int git_pack_foreach_entry_offset( current_offset = (((off64_t)ntohl(*((uint32_t *)(large_offset_ptr + 0)))) << 32) | ntohl(*((uint32_t *)(large_offset_ptr + 4))); } - current_oid = (const git_oid *)(index + 20 * i); - if ((error = cb(current_oid, current_offset, data)) != 0) { + + git_oid__fromraw(¤t_oid, (index + p->oid_size * i), p->oid_type); + if ((error = cb(¤t_oid, current_offset, data)) != 0) { error = git_error_set_after_callback(error); goto cleanup; } } } else { for (i = 0; i < p->num_objects; i++) { - current_offset = ntohl(*(const uint32_t *)(index + 24 * i)); - current_oid = (const git_oid *)(index + 24 * i + 4); - if ((error = cb(current_oid, current_offset, data)) != 0) { + current_offset = ntohl(*(const uint32_t *)(index + (p->oid_size + 4) * i)); + git_oid__fromraw(¤t_oid, (index + (p->oid_size + 4) * i + 4), p->oid_type); + if ((error = cb(¤t_oid, current_offset, data)) != 0) { error = git_error_set_after_callback(error); goto cleanup; } @@ -1444,14 +1464,20 @@ int git_pack_foreach_entry_offset( return error; } -int git_pack__lookup_sha1(const void *oid_lookup_table, size_t stride, unsigned lo, - unsigned hi, const unsigned char *oid_prefix) +int git_pack__lookup_id( + const void *oid_lookup_table, + size_t stride, + unsigned lo, + unsigned hi, + const unsigned char *oid_prefix, + const git_oid_t oid_type) { const unsigned char *base = oid_lookup_table; + size_t oid_size = git_oid_size(oid_type); while (lo < hi) { unsigned mi = (lo + hi) / 2; - int cmp = git_oid__hashcmp(base + mi * stride, oid_prefix); + int cmp = git_oid_raw_cmp(base + mi * stride, oid_prefix, oid_size); if (!cmp) return mi; @@ -1473,6 +1499,7 @@ static int pack_entry_find_offset( size_t len) { const uint32_t *level1_ofs; + size_t ofs_delta = 0; const unsigned char *index; unsigned hi, lo, stride; int pos, found = 0; @@ -1498,17 +1525,23 @@ static int pack_entry_find_offset( if (p->index_version > 1) { level1_ofs += 2; + ofs_delta = 2; index += 8; } + if ((size_t)short_oid->id[0] + ofs_delta >= p->index_map.len) { + git_error_set(GIT_ERROR_INTERNAL, "internal error: p->short_oid->[0] out of bounds"); + goto cleanup; + } + index += 4 * 256; hi = ntohl(level1_ofs[(int)short_oid->id[0]]); lo = ((short_oid->id[0] == 0x0) ? 0 : ntohl(level1_ofs[(int)short_oid->id[0] - 1])); if (p->index_version > 1) { - stride = 20; + stride = p->oid_size; } else { - stride = 24; + stride = p->oid_size + 4; index += 4; } @@ -1517,7 +1550,8 @@ static int pack_entry_find_offset( short_oid->id[0], short_oid->id[1], short_oid->id[2], lo, hi, p->num_objects); #endif - pos = git_pack__lookup_sha1(index, stride, lo, hi, short_oid->id); + pos = git_pack__lookup_id(index, stride, lo, hi, + short_oid->id, p->oid_type); if (pos >= 0) { /* An object matching exactly the oid was found */ @@ -1530,16 +1564,18 @@ static int pack_entry_find_offset( if (pos < (int)p->num_objects) { current = index + pos * stride; - if (!git_oid_ncmp(short_oid, (const git_oid *)current, len)) + if (!git_oid_raw_ncmp(short_oid->id, current, len)) found = 1; } } - if (found && len != GIT_OID_HEXSZ && pos + 1 < (int)p->num_objects) { + if (found && + len != p->oid_hexsize && + pos + 1 < (int)p->num_objects) { /* Check for ambiguousity */ const unsigned char *next = current + stride; - if (!git_oid_ncmp(short_oid, (const git_oid *)next, len)) { + if (!git_oid_raw_ncmp(short_oid->id, next, len)) { found = 2; } } @@ -1560,13 +1596,13 @@ static int pack_entry_find_offset( } *offset_out = offset; - git_oid_fromraw(found_oid, current); + git_oid__fromraw(found_oid, current, p->oid_type); #ifdef INDEX_DEBUG_LOOKUP { - unsigned char hex_sha1[GIT_OID_HEXSZ + 1]; + char hex_sha1[p->oid_hexsize + 1]; git_oid_fmt(hex_sha1, found_oid); - hex_sha1[GIT_OID_HEXSZ] = '\0'; + hex_sha1[p->oid_hexsize] = '\0'; printf("found lo=%d %s\n", lo, hex_sha1); } #endif @@ -1588,10 +1624,10 @@ int git_pack_entry_find( GIT_ASSERT_ARG(p); - if (len == GIT_OID_HEXSZ && p->num_bad_objects) { + if (len == p->oid_hexsize && p->num_bad_objects) { unsigned i; for (i = 0; i < p->num_bad_objects; i++) - if (git_oid__cmp(short_oid, &p->bad_object_sha1[i]) == 0) + if (git_oid__cmp(short_oid, &p->bad_object_ids[i]) == 0) return packfile_error("bad object found in packfile"); } @@ -1624,6 +1660,6 @@ int git_pack_entry_find( e->offset = offset; e->p = p; - git_oid_cpy(&e->sha1, &found_oid); + git_oid_cpy(&e->id, &found_oid); return 0; } diff --git a/vendor/libgit2/src/pack.h b/vendor/libgit2/src/libgit2/pack.h similarity index 84% rename from vendor/libgit2/src/pack.h rename to vendor/libgit2/src/libgit2/pack.h index bf279c6b..1a9eb14b 100644 --- a/vendor/libgit2/src/pack.h +++ b/vendor/libgit2/src/libgit2/pack.h @@ -19,6 +19,7 @@ #include "offmap.h" #include "oidmap.h" #include "zstream.h" +#include "oid.h" /** * Function type for callbacks from git_pack_foreach_entry_offset. @@ -32,7 +33,7 @@ typedef int git_pack_foreach_entry_offset_cb( #define PACK_SIGNATURE 0x5041434b /* "PACK" */ #define PACK_VERSION 2 -#define pack_version_ok(v) ((v) == htonl(2) || (v) == htonl(3)) +#define pack_version_ok(v) ((v) == htonl(2)) struct git_pack_header { uint32_t hdr_signature; uint32_t hdr_version; @@ -98,13 +99,19 @@ struct git_pack_file { uint32_t num_objects; uint32_t num_bad_objects; - git_oid *bad_object_sha1; /* array of git_oid */ + git_oid *bad_object_ids; /* array of git_oid */ + + git_oid_t oid_type; + unsigned oid_hexsize:7, + oid_size:6, + pack_local:1, + pack_keep:1, + has_cache:1; int index_version; git_time_t mtime; - unsigned pack_local:1, pack_keep:1, has_cache:1; git_oidmap *idx_cache; - git_oid **oids; + unsigned char **ids; git_pack_cache bases; /* delta base cache */ @@ -115,21 +122,26 @@ struct git_pack_file { }; /** - * Return the position where an OID (or a prefix) would be inserted within the - * OID Lookup Table of an .idx file. This performs binary search between the lo - * and hi indices. + * Return the position where an OID (or a prefix) would be inserted within + * the OID Lookup Table of an .idx file. This performs binary search + * between the lo and hi indices. * - * The stride parameter is provided because .idx files version 1 store the OIDs - * interleaved with the 4-byte file offsets of the objects within the .pack - * file (stride = 24), whereas files with version 2 store them in a contiguous - * flat array (stride = 20). + * The stride parameter is provided because .idx files version 1 store the + * OIDs interleaved with the 4-byte file offsets of the objects within the + * .pack file (stride = oid_size + 4), whereas files with version 2 store + * them in a contiguous flat array (stride = oid_size). */ -int git_pack__lookup_sha1(const void *oid_lookup_table, size_t stride, unsigned lo, - unsigned hi, const unsigned char *oid_prefix); +int git_pack__lookup_id( + const void *id_lookup_table, + size_t stride, + unsigned lo, + unsigned hi, + const unsigned char *id_prefix, + const git_oid_t oid_type); struct git_pack_entry { off64_t offset; - git_oid sha1; + git_oid id; struct git_pack_file *p; }; @@ -173,12 +185,15 @@ int get_delta_base( off64_t delta_obj_offset); void git_packfile_free(struct git_pack_file *p, bool unlink_packfile); -int git_packfile_alloc(struct git_pack_file **pack_out, const char *path); +int git_packfile_alloc( + struct git_pack_file **pack_out, + const char *path, + git_oid_t oid_type); int git_pack_entry_find( struct git_pack_entry *e, struct git_pack_file *p, - const git_oid *short_oid, + const git_oid *short_id, size_t len); int git_pack_foreach_entry( struct git_pack_file *p, diff --git a/vendor/libgit2/src/libgit2/parse.c b/vendor/libgit2/src/libgit2/parse.c new file mode 100644 index 00000000..9eb86a3f --- /dev/null +++ b/vendor/libgit2/src/libgit2/parse.c @@ -0,0 +1,138 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#include "parse.h" +#include "oid.h" + +int git_parse_ctx_init(git_parse_ctx *ctx, const char *content, size_t content_len) +{ + if (content && content_len) { + ctx->content = content; + ctx->content_len = content_len; + } else { + ctx->content = ""; + ctx->content_len = 0; + } + + ctx->remain = ctx->content; + ctx->remain_len = ctx->content_len; + ctx->line = ctx->remain; + ctx->line_len = git__linenlen(ctx->line, ctx->remain_len); + ctx->line_num = 1; + + return 0; +} + +void git_parse_ctx_clear(git_parse_ctx *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + ctx->content = ""; +} + +void git_parse_advance_line(git_parse_ctx *ctx) +{ + ctx->line += ctx->line_len; + ctx->remain_len -= ctx->line_len; + ctx->line_len = git__linenlen(ctx->line, ctx->remain_len); + ctx->line_num++; +} + +void git_parse_advance_chars(git_parse_ctx *ctx, size_t char_cnt) +{ + ctx->line += char_cnt; + ctx->remain_len -= char_cnt; + ctx->line_len -= char_cnt; +} + +int git_parse_advance_expected( + git_parse_ctx *ctx, + const char *expected, + size_t expected_len) +{ + if (ctx->line_len < expected_len) + return -1; + + if (memcmp(ctx->line, expected, expected_len) != 0) + return -1; + + git_parse_advance_chars(ctx, expected_len); + return 0; +} + +int git_parse_advance_ws(git_parse_ctx *ctx) +{ + int ret = -1; + + while (ctx->line_len > 0 && + ctx->line[0] != '\n' && + git__isspace(ctx->line[0])) { + ctx->line++; + ctx->line_len--; + ctx->remain_len--; + ret = 0; + } + + return ret; +} + +int git_parse_advance_nl(git_parse_ctx *ctx) +{ + if (ctx->line_len != 1 || ctx->line[0] != '\n') + return -1; + + git_parse_advance_line(ctx); + return 0; +} + +int git_parse_advance_digit(int64_t *out, git_parse_ctx *ctx, int base) +{ + const char *end; + int ret; + + if (ctx->line_len < 1 || !git__isdigit(ctx->line[0])) + return -1; + + if ((ret = git__strntol64(out, ctx->line, ctx->line_len, &end, base)) < 0) + return -1; + + git_parse_advance_chars(ctx, (end - ctx->line)); + return 0; +} + +int git_parse_advance_oid(git_oid *out, git_parse_ctx *ctx, git_oid_t oid_type) +{ + size_t oid_hexsize = git_oid_hexsize(oid_type); + GIT_ASSERT(oid_hexsize); + + if (ctx->line_len < oid_hexsize) + return -1; + if ((git_oid__fromstrn(out, ctx->line, oid_hexsize, oid_type)) < 0) + return -1; + git_parse_advance_chars(ctx, oid_hexsize); + return 0; +} + +int git_parse_peek(char *out, git_parse_ctx *ctx, int flags) +{ + size_t remain = ctx->line_len; + const char *ptr = ctx->line; + + while (remain) { + char c = *ptr; + + if ((flags & GIT_PARSE_PEEK_SKIP_WHITESPACE) && + git__isspace(c)) { + remain--; + ptr++; + continue; + } + + *out = c; + return 0; + } + + return -1; +} diff --git a/vendor/libgit2/src/parse.h b/vendor/libgit2/src/libgit2/parse.h similarity index 95% rename from vendor/libgit2/src/parse.h rename to vendor/libgit2/src/libgit2/parse.h index 0ecb7c10..beef1de1 100644 --- a/vendor/libgit2/src/parse.h +++ b/vendor/libgit2/src/libgit2/parse.h @@ -50,7 +50,7 @@ int git_parse_advance_expected( int git_parse_advance_ws(git_parse_ctx *ctx); int git_parse_advance_nl(git_parse_ctx *ctx); int git_parse_advance_digit(int64_t *out, git_parse_ctx *ctx, int base); -int git_parse_advance_oid(git_oid *out, git_parse_ctx *ctx); +int git_parse_advance_oid(git_oid *out, git_parse_ctx *ctx, git_oid_t oid_type); enum GIT_PARSE_PEEK_FLAGS { GIT_PARSE_PEEK_SKIP_WHITESPACE = (1 << 0) diff --git a/vendor/libgit2/src/patch.c b/vendor/libgit2/src/libgit2/patch.c similarity index 100% rename from vendor/libgit2/src/patch.c rename to vendor/libgit2/src/libgit2/patch.c diff --git a/vendor/libgit2/src/patch.h b/vendor/libgit2/src/libgit2/patch.h similarity index 89% rename from vendor/libgit2/src/patch.h rename to vendor/libgit2/src/libgit2/patch.h index 1e1471ed..86328e88 100644 --- a/vendor/libgit2/src/patch.h +++ b/vendor/libgit2/src/libgit2/patch.h @@ -59,9 +59,15 @@ typedef struct { * This prefix will be removed when looking for files. The default is 1. */ uint32_t prefix_len; + + /** + * The type of object IDs in the patch file. The default is + * `GIT_OID_DEFAULT`. + */ + git_oid_t oid_type; } git_patch_options; -#define GIT_PATCH_OPTIONS_INIT { 1 } +#define GIT_PATCH_OPTIONS_INIT { 1, GIT_OID_DEFAULT } extern int git_patch__to_buf(git_str *out, git_patch *patch); extern void git_patch_free(git_patch *patch); diff --git a/vendor/libgit2/src/patch_generate.c b/vendor/libgit2/src/libgit2/patch_generate.c similarity index 96% rename from vendor/libgit2/src/patch_generate.c rename to vendor/libgit2/src/libgit2/patch_generate.c index bc598fea..079bc53a 100644 --- a/vendor/libgit2/src/patch_generate.c +++ b/vendor/libgit2/src/libgit2/patch_generate.c @@ -81,7 +81,8 @@ static void patch_generated_init_common(git_patch_generated *patch) static int patch_generated_normalize_options( git_diff_options *out, - const git_diff_options *opts) + const git_diff_options *opts, + git_repository *repo) { if (opts) { GIT_ERROR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options"); @@ -91,6 +92,23 @@ static int patch_generated_normalize_options( memcpy(out, &default_opts, sizeof(git_diff_options)); } + if (repo && opts && opts->oid_type && repo->oid_type != opts->oid_type) { + /* + * This limitation feels unnecessary - we should consider + * allowing users to generate diffs with a different object + * ID format than the repository. + */ + git_error_set(GIT_ERROR_INVALID, + "specified object ID type does not match repository object ID type"); + return -1; + } else if (repo) { + out->oid_type = repo->oid_type; + } else if (opts && opts->oid_type) { + out->oid_type = opts->oid_type; + } else { + out->oid_type = GIT_OID_DEFAULT; + } + out->old_prefix = opts && opts->old_prefix ? git__strdup(opts->old_prefix) : git__strdup(DIFF_OLD_PREFIX_DEFAULT); @@ -118,7 +136,7 @@ static int patch_generated_init( patch->delta_index = delta_index; if ((error = patch_generated_normalize_options( - &patch->base.diff_opts, &diff->opts)) < 0 || + &patch->base.diff_opts, &diff->opts, diff->repo)) < 0 || (error = git_diff_file_content__init_from_diff( &patch->ofile, diff, patch->base.delta, true)) < 0 || (error = git_diff_file_content__init_from_diff( @@ -449,7 +467,7 @@ static int patch_generated_from_sources( git_xdiff_output *xo, git_diff_file_content_src *oldsrc, git_diff_file_content_src *newsrc, - const git_diff_options *opts) + const git_diff_options *given_opts) { int error = 0; git_repository *repo = @@ -457,11 +475,12 @@ static int patch_generated_from_sources( newsrc->blob ? git_blob_owner(newsrc->blob) : NULL; git_diff_file *lfile = &pd->delta.old_file, *rfile = &pd->delta.new_file; git_diff_file_content *ldata = &pd->patch.ofile, *rdata = &pd->patch.nfile; + git_diff_options *opts = &pd->patch.base.diff_opts; - if ((error = patch_generated_normalize_options(&pd->patch.base.diff_opts, opts)) < 0) + if ((error = patch_generated_normalize_options(opts, given_opts, repo)) < 0) return error; - if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) { + if ((opts->flags & GIT_DIFF_REVERSE) != 0) { void *tmp = lfile; lfile = rfile; rfile = tmp; tmp = ldata; ldata = rdata; rdata = tmp; } diff --git a/vendor/libgit2/src/patch_generate.h b/vendor/libgit2/src/libgit2/patch_generate.h similarity index 100% rename from vendor/libgit2/src/patch_generate.h rename to vendor/libgit2/src/libgit2/patch_generate.h diff --git a/vendor/libgit2/src/patch_parse.c b/vendor/libgit2/src/libgit2/patch_parse.c similarity index 98% rename from vendor/libgit2/src/patch_parse.c rename to vendor/libgit2/src/libgit2/patch_parse.c index 78cd9625..04f2a582 100644 --- a/vendor/libgit2/src/patch_parse.c +++ b/vendor/libgit2/src/libgit2/patch_parse.c @@ -166,15 +166,19 @@ static int parse_header_oid( uint16_t *oid_len, git_patch_parse_ctx *ctx) { - size_t len; + size_t hexsize, len; + + hexsize = git_oid_hexsize(ctx->opts.oid_type); - for (len = 0; len < ctx->parse_ctx.line_len && len < GIT_OID_HEXSZ; len++) { + for (len = 0; + len < ctx->parse_ctx.line_len && len < hexsize; + len++) { if (!git__isxdigit(ctx->parse_ctx.line[len])) break; } - if (len < GIT_OID_MINPREFIXLEN || len > GIT_OID_HEXSZ || - git_oid_fromstrn(oid, ctx->parse_ctx.line, len) < 0) + if (len < GIT_OID_MINPREFIXLEN || len > hexsize || + git_oid__fromstrn(oid, ctx->parse_ctx.line, len, ctx->opts.oid_type) < 0) return git_parse_err("invalid hex formatted object id at line %"PRIuZ, ctx->parse_ctx.line_num); @@ -558,9 +562,9 @@ static int parse_hunk_header( static int eof_for_origin(int origin) { if (origin == GIT_DIFF_LINE_ADDITION) - return GIT_DIFF_LINE_ADD_EOFNL; - if (origin == GIT_DIFF_LINE_DELETION) return GIT_DIFF_LINE_DEL_EOFNL; + if (origin == GIT_DIFF_LINE_DELETION) + return GIT_DIFF_LINE_ADD_EOFNL; return GIT_DIFF_LINE_CONTEXT_EOFNL; } @@ -1065,12 +1069,14 @@ static int check_patch(git_patch_parsed *patch) return git_parse_err("patch with no hunks"); if (delta->status == GIT_DELTA_ADDED) { - memset(&delta->old_file.id, 0x0, sizeof(git_oid)); + git_oid_clear(&delta->old_file.id, + patch->base.diff_opts.oid_type); delta->old_file.id_abbrev = 0; } if (delta->status == GIT_DELTA_DELETED) { - memset(&delta->new_file.id, 0x0, sizeof(git_oid)); + git_oid_clear(&delta->new_file.id, + patch->base.diff_opts.oid_type); delta->new_file.id_abbrev = 0; } @@ -1187,11 +1193,13 @@ int git_patch_parse( patch->base.delta->status = GIT_DELTA_MODIFIED; patch->base.delta->nfiles = 2; + patch->base.diff_opts.oid_type = ctx->opts.oid_type; + start = ctx->parse_ctx.remain_len; if ((error = parse_patch_header(patch, ctx)) < 0 || - (error = parse_patch_body(patch, ctx)) < 0 || - (error = check_patch(patch)) < 0) + (error = parse_patch_body(patch, ctx)) < 0 || + (error = check_patch(patch)) < 0) goto done; used = start - ctx->parse_ctx.remain_len; diff --git a/vendor/libgit2/src/patch_parse.h b/vendor/libgit2/src/libgit2/patch_parse.h similarity index 100% rename from vendor/libgit2/src/patch_parse.h rename to vendor/libgit2/src/libgit2/patch_parse.h diff --git a/vendor/libgit2/src/libgit2/path.c b/vendor/libgit2/src/libgit2/path.c new file mode 100644 index 00000000..4b584fb8 --- /dev/null +++ b/vendor/libgit2/src/libgit2/path.c @@ -0,0 +1,375 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "path.h" + +#include "repository.h" +#include "fs_path.h" +#include "utf8.h" + +typedef struct { + git_repository *repo; + uint16_t file_mode; + unsigned int flags; +} repository_path_validate_data; + +static int32_t next_hfs_char(const char **in, size_t *len) +{ + while (*len) { + uint32_t codepoint; + int cp_len = git_utf8_iterate(&codepoint, *in, *len); + if (cp_len < 0) + return -1; + + (*in) += cp_len; + (*len) -= cp_len; + + /* these code points are ignored completely */ + switch (codepoint) { + case 0x200c: /* ZERO WIDTH NON-JOINER */ + case 0x200d: /* ZERO WIDTH JOINER */ + case 0x200e: /* LEFT-TO-RIGHT MARK */ + case 0x200f: /* RIGHT-TO-LEFT MARK */ + case 0x202a: /* LEFT-TO-RIGHT EMBEDDING */ + case 0x202b: /* RIGHT-TO-LEFT EMBEDDING */ + case 0x202c: /* POP DIRECTIONAL FORMATTING */ + case 0x202d: /* LEFT-TO-RIGHT OVERRIDE */ + case 0x202e: /* RIGHT-TO-LEFT OVERRIDE */ + case 0x206a: /* INHIBIT SYMMETRIC SWAPPING */ + case 0x206b: /* ACTIVATE SYMMETRIC SWAPPING */ + case 0x206c: /* INHIBIT ARABIC FORM SHAPING */ + case 0x206d: /* ACTIVATE ARABIC FORM SHAPING */ + case 0x206e: /* NATIONAL DIGIT SHAPES */ + case 0x206f: /* NOMINAL DIGIT SHAPES */ + case 0xfeff: /* ZERO WIDTH NO-BREAK SPACE */ + continue; + } + + /* fold into lowercase -- this will only fold characters in + * the ASCII range, which is perfectly fine, because the + * git folder name can only be composed of ascii characters + */ + return git__tolower((int)codepoint); + } + return 0; /* NULL byte -- end of string */ +} + +static bool validate_dotgit_hfs_generic( + const char *path, + size_t len, + const char *needle, + size_t needle_len) +{ + size_t i; + char c; + + if (next_hfs_char(&path, &len) != '.') + return true; + + for (i = 0; i < needle_len; i++) { + c = next_hfs_char(&path, &len); + if (c != needle[i]) + return true; + } + + if (next_hfs_char(&path, &len) != '\0') + return true; + + return false; +} + +static bool validate_dotgit_hfs(const char *path, size_t len) +{ + return validate_dotgit_hfs_generic(path, len, "git", CONST_STRLEN("git")); +} + +GIT_INLINE(bool) validate_dotgit_ntfs( + git_repository *repo, + const char *path, + size_t len) +{ + git_str *reserved = git_repository__reserved_names_win32; + size_t reserved_len = git_repository__reserved_names_win32_len; + size_t start = 0, i; + + if (repo) + git_repository__reserved_names(&reserved, &reserved_len, repo, true); + + for (i = 0; i < reserved_len; i++) { + git_str *r = &reserved[i]; + + if (len >= r->size && + strncasecmp(path, r->ptr, r->size) == 0) { + start = r->size; + break; + } + } + + if (!start) + return true; + + /* + * Reject paths that start with Windows-style directory separators + * (".git\") or NTFS alternate streams (".git:") and could be used + * to write to the ".git" directory on Windows platforms. + */ + if (path[start] == '\\' || path[start] == ':') + return false; + + /* Reject paths like '.git ' or '.git.' */ + for (i = start; i < len; i++) { + if (path[i] != ' ' && path[i] != '.') + return true; + } + + return false; +} + +/* + * Windows paths that end with spaces and/or dots are elided to the + * path without them for backward compatibility. That is to say + * that opening file "foo ", "foo." or even "foo . . ." will all + * map to a filename of "foo". This function identifies spaces and + * dots at the end of a filename, whether the proper end of the + * filename (end of string) or a colon (which would indicate a + * Windows alternate data stream.) + */ +GIT_INLINE(bool) ntfs_end_of_filename(const char *path) +{ + const char *c = path; + + for (;; c++) { + if (*c == '\0' || *c == ':') + return true; + if (*c != ' ' && *c != '.') + return false; + } + + return true; +} + +GIT_INLINE(bool) validate_dotgit_ntfs_generic( + const char *name, + size_t len, + const char *dotgit_name, + size_t dotgit_len, + const char *shortname_pfix) +{ + int i, saw_tilde; + + if (name[0] == '.' && len >= dotgit_len && + !strncasecmp(name + 1, dotgit_name, dotgit_len)) { + return !ntfs_end_of_filename(name + dotgit_len + 1); + } + + /* Detect the basic NTFS shortname with the first six chars */ + if (!strncasecmp(name, dotgit_name, 6) && name[6] == '~' && + name[7] >= '1' && name[7] <= '4') + return !ntfs_end_of_filename(name + 8); + + /* Catch fallback names */ + for (i = 0, saw_tilde = 0; i < 8; i++) { + if (name[i] == '\0') { + return true; + } else if (saw_tilde) { + if (name[i] < '0' || name[i] > '9') + return true; + } else if (name[i] == '~') { + if (name[i+1] < '1' || name[i+1] > '9') + return true; + saw_tilde = 1; + } else if (i >= 6) { + return true; + } else if ((unsigned char)name[i] > 127) { + return true; + } else if (git__tolower(name[i]) != shortname_pfix[i]) { + return true; + } + } + + return !ntfs_end_of_filename(name + i); +} + +/* + * Return the length of the common prefix between str and prefix, comparing them + * case-insensitively (must be ASCII to match). + */ +GIT_INLINE(size_t) common_prefix_icase(const char *str, size_t len, const char *prefix) +{ + size_t count = 0; + + while (len > 0 && git__tolower(*str) == git__tolower(*prefix)) { + count++; + str++; + prefix++; + len--; + } + + return count; +} + +static bool validate_repo_component( + const char *component, + size_t len, + void *payload) +{ + repository_path_validate_data *data = (repository_path_validate_data *)payload; + + if (data->flags & GIT_PATH_REJECT_DOT_GIT_HFS) { + if (!validate_dotgit_hfs(component, len)) + return false; + + if (S_ISLNK(data->file_mode) && + git_path_is_gitfile(component, len, GIT_PATH_GITFILE_GITMODULES, GIT_PATH_FS_HFS)) + return false; + } + + if (data->flags & GIT_PATH_REJECT_DOT_GIT_NTFS) { + if (!validate_dotgit_ntfs(data->repo, component, len)) + return false; + + if (S_ISLNK(data->file_mode) && + git_path_is_gitfile(component, len, GIT_PATH_GITFILE_GITMODULES, GIT_PATH_FS_NTFS)) + return false; + } + + /* don't bother rerunning the `.git` test if we ran the HFS or NTFS + * specific tests, they would have already rejected `.git`. + */ + if ((data->flags & GIT_PATH_REJECT_DOT_GIT_HFS) == 0 && + (data->flags & GIT_PATH_REJECT_DOT_GIT_NTFS) == 0 && + (data->flags & GIT_PATH_REJECT_DOT_GIT_LITERAL)) { + if (len >= 4 && + component[0] == '.' && + (component[1] == 'g' || component[1] == 'G') && + (component[2] == 'i' || component[2] == 'I') && + (component[3] == 't' || component[3] == 'T')) { + if (len == 4) + return false; + + if (S_ISLNK(data->file_mode) && + common_prefix_icase(component, len, ".gitmodules") == len) + return false; + } + } + + return true; +} + +GIT_INLINE(unsigned int) dotgit_flags( + git_repository *repo, + unsigned int flags) +{ + int protectHFS = 0, protectNTFS = 1; + int error = 0; + + flags |= GIT_PATH_REJECT_DOT_GIT_LITERAL; + +#ifdef __APPLE__ + protectHFS = 1; +#endif + + if (repo && !protectHFS) + error = git_repository__configmap_lookup(&protectHFS, repo, GIT_CONFIGMAP_PROTECTHFS); + if (!error && protectHFS) + flags |= GIT_PATH_REJECT_DOT_GIT_HFS; + + if (repo) + error = git_repository__configmap_lookup(&protectNTFS, repo, GIT_CONFIGMAP_PROTECTNTFS); + if (!error && protectNTFS) + flags |= GIT_PATH_REJECT_DOT_GIT_NTFS; + + return flags; +} + +GIT_INLINE(unsigned int) length_flags( + git_repository *repo, + unsigned int flags) +{ +#ifdef GIT_WIN32 + int allow = 0; + + if (repo && + git_repository__configmap_lookup(&allow, repo, GIT_CONFIGMAP_LONGPATHS) < 0) + allow = 0; + + if (allow) + flags &= ~GIT_FS_PATH_REJECT_LONG_PATHS; + +#else + GIT_UNUSED(repo); + flags &= ~GIT_FS_PATH_REJECT_LONG_PATHS; +#endif + + return flags; +} + +bool git_path_str_is_valid( + git_repository *repo, + const git_str *path, + uint16_t file_mode, + unsigned int flags) +{ + repository_path_validate_data data = {0}; + + /* Upgrade the ".git" checks based on platform */ + if ((flags & GIT_PATH_REJECT_DOT_GIT)) + flags = dotgit_flags(repo, flags); + + /* Update the length checks based on platform */ + if ((flags & GIT_FS_PATH_REJECT_LONG_PATHS)) + flags = length_flags(repo, flags); + + data.repo = repo; + data.file_mode = file_mode; + data.flags = flags; + + return git_fs_path_str_is_valid_ext(path, flags, NULL, validate_repo_component, NULL, &data); +} + +static const struct { + const char *file; + const char *hash; + size_t filelen; +} gitfiles[] = { + { "gitignore", "gi250a", CONST_STRLEN("gitignore") }, + { "gitmodules", "gi7eba", CONST_STRLEN("gitmodules") }, + { "gitattributes", "gi7d29", CONST_STRLEN("gitattributes") } +}; + +extern int git_path_is_gitfile( + const char *path, + size_t pathlen, + git_path_gitfile gitfile, + git_path_fs fs) +{ + const char *file, *hash; + size_t filelen; + + if (!(gitfile >= GIT_PATH_GITFILE_GITIGNORE && gitfile < ARRAY_SIZE(gitfiles))) { + git_error_set(GIT_ERROR_OS, "invalid gitfile for path validation"); + return -1; + } + + file = gitfiles[gitfile].file; + filelen = gitfiles[gitfile].filelen; + hash = gitfiles[gitfile].hash; + + switch (fs) { + case GIT_PATH_FS_GENERIC: + return !validate_dotgit_ntfs_generic(path, pathlen, file, filelen, hash) || + !validate_dotgit_hfs_generic(path, pathlen, file, filelen); + case GIT_PATH_FS_NTFS: + return !validate_dotgit_ntfs_generic(path, pathlen, file, filelen, hash); + case GIT_PATH_FS_HFS: + return !validate_dotgit_hfs_generic(path, pathlen, file, filelen); + default: + git_error_set(GIT_ERROR_OS, "invalid filesystem for path validation"); + return -1; + } +} + diff --git a/vendor/libgit2/src/path.h b/vendor/libgit2/src/libgit2/path.h similarity index 100% rename from vendor/libgit2/src/path.h rename to vendor/libgit2/src/libgit2/path.h diff --git a/vendor/libgit2/src/pathspec.c b/vendor/libgit2/src/libgit2/pathspec.c similarity index 100% rename from vendor/libgit2/src/pathspec.c rename to vendor/libgit2/src/libgit2/pathspec.c diff --git a/vendor/libgit2/src/pathspec.h b/vendor/libgit2/src/libgit2/pathspec.h similarity index 100% rename from vendor/libgit2/src/pathspec.h rename to vendor/libgit2/src/libgit2/pathspec.h diff --git a/vendor/libgit2/src/proxy.c b/vendor/libgit2/src/libgit2/proxy.c similarity index 100% rename from vendor/libgit2/src/proxy.c rename to vendor/libgit2/src/libgit2/proxy.c diff --git a/vendor/libgit2/src/proxy.h b/vendor/libgit2/src/libgit2/proxy.h similarity index 100% rename from vendor/libgit2/src/proxy.h rename to vendor/libgit2/src/libgit2/proxy.h diff --git a/vendor/libgit2/src/libgit2/push.c b/vendor/libgit2/src/libgit2/push.c new file mode 100644 index 00000000..e0658588 --- /dev/null +++ b/vendor/libgit2/src/libgit2/push.c @@ -0,0 +1,605 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "push.h" + +#include "git2.h" + +#include "pack.h" +#include "pack-objects.h" +#include "remote.h" +#include "vector.h" +#include "tree.h" + +static int push_spec_rref_cmp(const void *a, const void *b) +{ + const push_spec *push_spec_a = a, *push_spec_b = b; + + return strcmp(push_spec_a->refspec.dst, push_spec_b->refspec.dst); +} + +static int push_status_ref_cmp(const void *a, const void *b) +{ + const push_status *push_status_a = a, *push_status_b = b; + + return strcmp(push_status_a->ref, push_status_b->ref); +} + +int git_push_new(git_push **out, git_remote *remote, const git_push_options *opts) +{ + git_push *p; + + *out = NULL; + + GIT_ERROR_CHECK_VERSION(opts, GIT_PUSH_OPTIONS_VERSION, "git_push_options"); + + p = git__calloc(1, sizeof(*p)); + GIT_ERROR_CHECK_ALLOC(p); + + p->repo = remote->repo; + p->remote = remote; + p->report_status = 1; + p->pb_parallelism = opts ? opts->pb_parallelism : 1; + + if (opts) { + GIT_ERROR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks"); + memcpy(&p->callbacks, &opts->callbacks, sizeof(git_remote_callbacks)); + } + + if (git_vector_init(&p->specs, 0, push_spec_rref_cmp) < 0) { + git__free(p); + return -1; + } + + if (git_vector_init(&p->status, 0, push_status_ref_cmp) < 0) { + git_vector_free(&p->specs); + git__free(p); + return -1; + } + + if (git_vector_init(&p->updates, 0, NULL) < 0) { + git_vector_free(&p->status); + git_vector_free(&p->specs); + git__free(p); + return -1; + } + + if (git_vector_init(&p->remote_push_options, 0, git__strcmp_cb) < 0) { + git_vector_free(&p->status); + git_vector_free(&p->specs); + git_vector_free(&p->updates); + git__free(p); + return -1; + } + + *out = p; + return 0; +} + +static void free_refspec(push_spec *spec) +{ + if (spec == NULL) + return; + + git_refspec__dispose(&spec->refspec); + git__free(spec); +} + +static int check_rref(char *ref) +{ + if (git__prefixcmp(ref, "refs/")) { + git_error_set(GIT_ERROR_INVALID, "not a valid reference '%s'", ref); + return -1; + } + + return 0; +} + +static int check_lref(git_push *push, char *ref) +{ + /* lref must be resolvable to an existing object */ + git_object *obj; + int error = git_revparse_single(&obj, push->repo, ref); + git_object_free(obj); + + if (!error) + return 0; + + if (error == GIT_ENOTFOUND) + git_error_set(GIT_ERROR_REFERENCE, + "src refspec '%s' does not match any existing object", ref); + else + git_error_set(GIT_ERROR_INVALID, "not a valid reference '%s'", ref); + return -1; +} + +static int parse_refspec(git_push *push, push_spec **spec, const char *str) +{ + push_spec *s; + + *spec = NULL; + + s = git__calloc(1, sizeof(*s)); + GIT_ERROR_CHECK_ALLOC(s); + + git_oid_clear(&s->loid, push->repo->oid_type); + git_oid_clear(&s->roid, push->repo->oid_type); + + if (git_refspec__parse(&s->refspec, str, false) < 0) { + git_error_set(GIT_ERROR_INVALID, "invalid refspec %s", str); + goto on_error; + } + + if (s->refspec.src && s->refspec.src[0] != '\0' && + check_lref(push, s->refspec.src) < 0) { + goto on_error; + } + + if (check_rref(s->refspec.dst) < 0) + goto on_error; + + *spec = s; + return 0; + +on_error: + free_refspec(s); + return -1; +} + +int git_push_add_refspec(git_push *push, const char *refspec) +{ + push_spec *spec; + + if (parse_refspec(push, &spec, refspec) < 0 || + git_vector_insert(&push->specs, spec) < 0) + return -1; + + return 0; +} + +int git_push_update_tips(git_push *push, const git_remote_callbacks *callbacks) +{ + git_str remote_ref_name = GIT_STR_INIT; + size_t i, j; + git_refspec *fetch_spec; + push_spec *push_spec = NULL; + git_reference *remote_ref; + push_status *status; + int error = 0; + + git_vector_foreach(&push->status, i, status) { + int fire_callback = 1; + + /* Skip unsuccessful updates which have non-empty messages */ + if (status->msg) + continue; + + /* Find the corresponding remote ref */ + fetch_spec = git_remote__matching_refspec(push->remote, status->ref); + if (!fetch_spec) + continue; + + /* Clear the buffer which can be dirty from previous iteration */ + git_str_clear(&remote_ref_name); + + if ((error = git_refspec__transform(&remote_ref_name, fetch_spec, status->ref)) < 0) + goto on_error; + + /* Find matching push ref spec */ + git_vector_foreach(&push->specs, j, push_spec) { + if (!strcmp(push_spec->refspec.dst, status->ref)) + break; + } + + /* Could not find the corresponding push ref spec for this push update */ + if (j == push->specs.length) + continue; + + /* Update the remote ref */ + if (git_oid_is_zero(&push_spec->loid)) { + error = git_reference_lookup(&remote_ref, push->remote->repo, git_str_cstr(&remote_ref_name)); + + if (error >= 0) { + error = git_reference_delete(remote_ref); + git_reference_free(remote_ref); + } + } else { + error = git_reference_create(NULL, push->remote->repo, + git_str_cstr(&remote_ref_name), &push_spec->loid, 1, + "update by push"); + } + + if (error < 0) { + if (error != GIT_ENOTFOUND) + goto on_error; + + git_error_clear(); + fire_callback = 0; + } + + if (fire_callback && callbacks && callbacks->update_tips) { + error = callbacks->update_tips(git_str_cstr(&remote_ref_name), + &push_spec->roid, &push_spec->loid, callbacks->payload); + + if (error < 0) + goto on_error; + } + } + + error = 0; + +on_error: + git_str_dispose(&remote_ref_name); + return error; +} + +/** + * Insert all tags until we find a non-tag object, which is returned + * in `out`. + */ +static int enqueue_tag(git_object **out, git_push *push, git_oid *id) +{ + git_object *obj = NULL, *target = NULL; + int error; + + if ((error = git_object_lookup(&obj, push->repo, id, GIT_OBJECT_TAG)) < 0) + return error; + + while (git_object_type(obj) == GIT_OBJECT_TAG) { + if ((error = git_packbuilder_insert(push->pb, git_object_id(obj), NULL)) < 0) + break; + + if ((error = git_tag_target(&target, (git_tag *) obj)) < 0) + break; + + git_object_free(obj); + obj = target; + } + + if (error < 0) + git_object_free(obj); + else + *out = obj; + + return error; +} + +static int queue_objects(git_push *push) +{ + git_remote_head *head; + push_spec *spec; + git_revwalk *rw; + unsigned int i; + int error = -1; + + if (git_revwalk_new(&rw, push->repo) < 0) + return -1; + + git_revwalk_sorting(rw, GIT_SORT_TIME); + + git_vector_foreach(&push->specs, i, spec) { + git_object_t type; + size_t size; + + if (git_oid_is_zero(&spec->loid)) + /* + * Delete reference on remote side; + * nothing to do here. + */ + continue; + + if (git_oid_equal(&spec->loid, &spec->roid)) + continue; /* up-to-date */ + + if ((error = git_odb_read_header(&size, &type, push->repo->_odb, &spec->loid)) < 0) + goto on_error; + + if (type == GIT_OBJECT_TAG) { + git_object *target; + + if ((error = enqueue_tag(&target, push, &spec->loid)) < 0) + goto on_error; + + if (git_object_type(target) == GIT_OBJECT_COMMIT) { + if ((error = git_revwalk_push(rw, git_object_id(target))) < 0) { + git_object_free(target); + goto on_error; + } + } else { + if ((error = git_packbuilder_insert( + push->pb, git_object_id(target), NULL)) < 0) { + git_object_free(target); + goto on_error; + } + } + git_object_free(target); + } else if ((error = git_revwalk_push(rw, &spec->loid)) < 0) + goto on_error; + + if (!spec->refspec.force) { + git_oid base; + + if (git_oid_is_zero(&spec->roid)) + continue; + + if (!git_odb_exists(push->repo->_odb, &spec->roid)) { + git_error_set(GIT_ERROR_REFERENCE, + "cannot push because a reference that you are trying to update on the remote contains commits that are not present locally."); + error = GIT_ENONFASTFORWARD; + goto on_error; + } + + error = git_merge_base(&base, push->repo, + &spec->loid, &spec->roid); + + if (error == GIT_ENOTFOUND || + (!error && !git_oid_equal(&base, &spec->roid))) { + git_error_set(GIT_ERROR_REFERENCE, + "cannot push non-fastforwardable reference"); + error = GIT_ENONFASTFORWARD; + goto on_error; + } + + if (error < 0) + goto on_error; + } + } + + git_vector_foreach(&push->remote->refs, i, head) { + if (git_oid_is_zero(&head->oid)) + continue; + + if ((error = git_revwalk_hide(rw, &head->oid)) < 0 && + error != GIT_ENOTFOUND && error != GIT_EINVALIDSPEC && error != GIT_EPEEL) + goto on_error; + } + + error = git_packbuilder_insert_walk(push->pb, rw); + +on_error: + git_revwalk_free(rw); + return error; +} + +static int add_update(git_push *push, push_spec *spec) +{ + git_push_update *u = git__calloc(1, sizeof(git_push_update)); + GIT_ERROR_CHECK_ALLOC(u); + + u->src_refname = git__strdup(spec->refspec.src); + GIT_ERROR_CHECK_ALLOC(u->src_refname); + + u->dst_refname = git__strdup(spec->refspec.dst); + GIT_ERROR_CHECK_ALLOC(u->dst_refname); + + git_oid_cpy(&u->src, &spec->roid); + git_oid_cpy(&u->dst, &spec->loid); + + return git_vector_insert(&push->updates, u); +} + +static int calculate_work(git_push *push) +{ + git_remote_head *head; + push_spec *spec; + unsigned int i, j; + + /* Update local and remote oids*/ + + git_vector_foreach(&push->specs, i, spec) { + if (spec->refspec.src && spec->refspec.src[0]!= '\0') { + /* This is a create or update. Local ref must exist. */ + + git_object *obj; + int error = git_revparse_single(&obj, push->repo, spec->refspec.src); + + if (error < 0) { + git_object_free(obj); + git_error_set(GIT_ERROR_REFERENCE, "src refspec %s does not match any", spec->refspec.src); + return -1; + } + + git_oid_cpy(&spec->loid, git_object_id(obj)); + git_object_free(obj); + } + + /* Remote ref may or may not (e.g. during create) already exist. */ + git_vector_foreach(&push->remote->refs, j, head) { + if (!strcmp(spec->refspec.dst, head->name)) { + git_oid_cpy(&spec->roid, &head->oid); + break; + } + } + + if (add_update(push, spec) < 0) + return -1; + } + + return 0; +} + +static int do_push(git_push *push) +{ + int error = 0; + git_transport *transport = push->remote->transport; + git_remote_callbacks *callbacks = &push->callbacks; + + if (!transport->push) { + git_error_set(GIT_ERROR_NET, "remote transport doesn't support push"); + error = -1; + goto on_error; + } + + /* + * A pack-file MUST be sent if either create or update command + * is used, even if the server already has all the necessary + * objects. In this case the client MUST send an empty pack-file. + */ + + if ((error = git_packbuilder_new(&push->pb, push->repo)) < 0) + goto on_error; + + git_packbuilder_set_threads(push->pb, push->pb_parallelism); + + if (callbacks && callbacks->pack_progress) + if ((error = git_packbuilder_set_callbacks(push->pb, callbacks->pack_progress, callbacks->payload)) < 0) + goto on_error; + + if ((error = calculate_work(push)) < 0) + goto on_error; + + if (callbacks && callbacks->push_negotiation) { + git_error_clear(); + + error = callbacks->push_negotiation( + (const git_push_update **) push->updates.contents, + push->updates.length, callbacks->payload); + + if (error < 0) { + git_error_set_after_callback_function(error, + "push_negotiation"); + goto on_error; + } + + error = 0; + } + + if ((error = queue_objects(push)) < 0 || + (error = transport->push(transport, push)) < 0) + goto on_error; + +on_error: + git_packbuilder_free(push->pb); + return error; +} + +static int filter_refs(git_remote *remote) +{ + const git_remote_head **heads; + size_t heads_len, i; + + git_vector_clear(&remote->refs); + + if (git_remote_ls(&heads, &heads_len, remote) < 0) + return -1; + + for (i = 0; i < heads_len; i++) { + if (git_vector_insert(&remote->refs, (void *)heads[i]) < 0) + return -1; + } + + return 0; +} + +int git_push_finish(git_push *push) +{ + int error; + unsigned int remote_caps; + + if (!git_remote_connected(push->remote)) { + git_error_set(GIT_ERROR_NET, "remote is disconnected"); + return -1; + } + + if ((error = git_remote_capabilities(&remote_caps, push->remote)) < 0) { + git_error_set(GIT_ERROR_INVALID, "remote capabilities not available"); + return -1; + } + + if (git_vector_length(&push->remote_push_options) > 0 && + !(remote_caps & GIT_REMOTE_CAPABILITY_PUSH_OPTIONS)) { + git_error_set(GIT_ERROR_INVALID, "push-options not supported by remote"); + return -1; + } + + if ((error = filter_refs(push->remote)) < 0 || + (error = do_push(push)) < 0) + return error; + + if (!push->unpack_ok) { + error = -1; + git_error_set(GIT_ERROR_NET, "unpacking the sent packfile failed on the remote"); + } + + return error; +} + +int git_push_status_foreach(git_push *push, + int (*cb)(const char *ref, const char *msg, void *data), + void *data) +{ + push_status *status; + unsigned int i; + + git_vector_foreach(&push->status, i, status) { + int error = cb(status->ref, status->msg, data); + if (error) + return git_error_set_after_callback(error); + } + + return 0; +} + +void git_push_status_free(push_status *status) +{ + if (status == NULL) + return; + + git__free(status->msg); + git__free(status->ref); + git__free(status); +} + +void git_push_free(git_push *push) +{ + push_spec *spec; + push_status *status; + git_push_update *update; + char *option; + unsigned int i; + + if (push == NULL) + return; + + git_vector_foreach(&push->specs, i, spec) { + free_refspec(spec); + } + git_vector_free(&push->specs); + + git_vector_foreach(&push->status, i, status) { + git_push_status_free(status); + } + git_vector_free(&push->status); + + git_vector_foreach(&push->updates, i, update) { + git__free(update->src_refname); + git__free(update->dst_refname); + git__free(update); + } + git_vector_free(&push->updates); + + git_vector_foreach(&push->remote_push_options, i, option) { + git__free(option); + } + git_vector_free(&push->remote_push_options); + + git__free(push); +} + +int git_push_options_init(git_push_options *opts, unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE( + opts, version, git_push_options, GIT_PUSH_OPTIONS_INIT); + return 0; +} + +#ifndef GIT_DEPRECATE_HARD +int git_push_init_options(git_push_options *opts, unsigned int version) +{ + return git_push_options_init(opts, version); +} +#endif diff --git a/vendor/libgit2/src/push.h b/vendor/libgit2/src/libgit2/push.h similarity index 98% rename from vendor/libgit2/src/push.h rename to vendor/libgit2/src/libgit2/push.h index fc72e845..40a1823e 100644 --- a/vendor/libgit2/src/push.h +++ b/vendor/libgit2/src/libgit2/push.h @@ -34,6 +34,7 @@ struct git_push { git_vector specs; git_vector updates; bool report_status; + git_vector remote_push_options; /* report-status */ bool unpack_ok; diff --git a/vendor/libgit2/src/reader.c b/vendor/libgit2/src/libgit2/reader.c similarity index 98% rename from vendor/libgit2/src/reader.c rename to vendor/libgit2/src/libgit2/reader.c index ba977524..df2b2807 100644 --- a/vendor/libgit2/src/reader.c +++ b/vendor/libgit2/src/libgit2/reader.c @@ -125,7 +125,7 @@ static int workdir_reader_read( goto done; if (out_id || reader->index) { - if ((error = git_odb_hash(&id, out->ptr, out->size, GIT_OBJECT_BLOB)) < 0) + if ((error = git_odb__hash(&id, out->ptr, out->size, GIT_OBJECT_BLOB, reader->repo->oid_type)) < 0) goto done; } diff --git a/vendor/libgit2/src/reader.h b/vendor/libgit2/src/libgit2/reader.h similarity index 100% rename from vendor/libgit2/src/reader.h rename to vendor/libgit2/src/libgit2/reader.h diff --git a/vendor/libgit2/src/rebase.c b/vendor/libgit2/src/libgit2/rebase.c similarity index 88% rename from vendor/libgit2/src/rebase.c rename to vendor/libgit2/src/libgit2/rebase.c index 6f01d399..77e442e9 100644 --- a/vendor/libgit2/src/rebase.c +++ b/vendor/libgit2/src/libgit2/rebase.c @@ -35,6 +35,7 @@ #define ONTO_FILE "onto" #define ONTO_NAME_FILE "onto_name" #define QUIET_FILE "quiet" +#define INTERACTIVE_FILE "interactive" #define MSGNUM_FILE "msgnum" #define END_FILE "end" @@ -64,6 +65,9 @@ struct git_rebase { git_rebase_t type; char *state_path; + /* Temporary buffer for paths within the state path. */ + git_str state_filename; + unsigned int head_detached:1, inmemory:1, quiet:1, @@ -92,6 +96,7 @@ static int rebase_state_type( git_repository *repo) { git_str path = GIT_STR_INIT; + git_str interactive_path = GIT_STR_INIT; git_rebase_t type = GIT_REBASE_NONE; if (git_str_joinpath(&path, repo->gitdir, REBASE_APPLY_DIR) < 0) @@ -107,7 +112,14 @@ static int rebase_state_type( return -1; if (git_fs_path_isdir(git_str_cstr(&path))) { - type = GIT_REBASE_MERGE; + if (git_str_joinpath(&interactive_path, path.ptr, INTERACTIVE_FILE) < 0) + return -1; + + if (git_fs_path_isfile(interactive_path.ptr)) + type = GIT_REBASE_INTERACTIVE; + else + type = GIT_REBASE_MERGE; + goto done; } @@ -118,39 +130,49 @@ static int rebase_state_type( *path_out = git_str_detach(&path); git_str_dispose(&path); + git_str_dispose(&interactive_path); return 0; } GIT_INLINE(int) rebase_readfile( git_str *out, - git_str *state_path, + git_rebase *rebase, const char *filename) { - size_t state_path_len = state_path->size; + /* + * `rebase->state_filename` is a temporary buffer to avoid + * unnecessary allocations and copies of `rebase->state_path`. + * At the start and end of this function it always contains the + * contents of `rebase->state_path` itself. + */ + size_t state_path_len = rebase->state_filename.size; int error; git_str_clear(out); - if ((error = git_str_joinpath(state_path, state_path->ptr, filename)) < 0 || - (error = git_futils_readbuffer(out, state_path->ptr)) < 0) + if ((error = git_str_joinpath(&rebase->state_filename, rebase->state_filename.ptr, filename)) < 0 || + (error = git_futils_readbuffer(out, rebase->state_filename.ptr)) < 0) goto done; git_str_rtrim(out); done: - git_str_truncate(state_path, state_path_len); + git_str_truncate(&rebase->state_filename, state_path_len); return error; } GIT_INLINE(int) rebase_readint( - size_t *out, git_str *asc_out, git_str *state_path, const char *filename) + size_t *out, + git_str *asc_out, + git_rebase *rebase, + const char *filename) { int32_t num; const char *eol; int error = 0; - if ((error = rebase_readfile(asc_out, state_path, filename)) < 0) + if ((error = rebase_readfile(asc_out, rebase, filename)) < 0) return error; if (git__strntol32(&num, asc_out->ptr, asc_out->size, &eol, 10) < 0 || num < 0 || *eol) { @@ -164,14 +186,18 @@ GIT_INLINE(int) rebase_readint( } GIT_INLINE(int) rebase_readoid( - git_oid *out, git_str *str_out, git_str *state_path, const char *filename) + git_oid *out, + git_str *str_out, + git_rebase *rebase, + const char *filename) { int error; - if ((error = rebase_readfile(str_out, state_path, filename)) < 0) + if ((error = rebase_readfile(str_out, rebase, filename)) < 0) return error; - if (str_out->size != GIT_OID_HEXSZ || git_oid_fromstr(out, str_out->ptr) < 0) { + if (str_out->size != git_oid_hexsize(rebase->repo->oid_type) || + git_oid__fromstr(out, str_out->ptr, rebase->repo->oid_type) < 0) { git_error_set(GIT_ERROR_REBASE, "the file '%s' contains an invalid object ID", filename); return -1; } @@ -202,17 +228,14 @@ static git_rebase_operation *rebase_operation_alloc( static int rebase_open_merge(git_rebase *rebase) { - git_str state_path = GIT_STR_INIT, buf = GIT_STR_INIT, cmt = GIT_STR_INIT; + git_str buf = GIT_STR_INIT, cmt = GIT_STR_INIT; git_oid id; git_rebase_operation *operation; size_t i, msgnum = 0, end; int error; - if ((error = git_str_puts(&state_path, rebase->state_path)) < 0) - goto done; - /* Read 'msgnum' if it exists (otherwise, let msgnum = 0) */ - if ((error = rebase_readint(&msgnum, &buf, &state_path, MSGNUM_FILE)) < 0 && + if ((error = rebase_readint(&msgnum, &buf, rebase, MSGNUM_FILE)) < 0 && error != GIT_ENOTFOUND) goto done; @@ -222,11 +245,11 @@ static int rebase_open_merge(git_rebase *rebase) } /* Read 'end' */ - if ((error = rebase_readint(&end, &buf, &state_path, END_FILE)) < 0) + if ((error = rebase_readint(&end, &buf, rebase, END_FILE)) < 0) goto done; /* Read 'current' if it exists */ - if ((error = rebase_readoid(&id, &buf, &state_path, CURRENT_FILE)) < 0 && + if ((error = rebase_readoid(&id, &buf, rebase, CURRENT_FILE)) < 0 && error != GIT_ENOTFOUND) goto done; @@ -238,7 +261,7 @@ static int rebase_open_merge(git_rebase *rebase) git_str_clear(&cmt); if ((error = git_str_printf(&cmt, "cmt.%" PRIuZ, (i+1))) < 0 || - (error = rebase_readoid(&id, &buf, &state_path, cmt.ptr)) < 0) + (error = rebase_readoid(&id, &buf, rebase, cmt.ptr)) < 0) goto done; operation = rebase_operation_alloc(rebase, GIT_REBASE_OPERATION_PICK, &id, NULL); @@ -246,14 +269,13 @@ static int rebase_open_merge(git_rebase *rebase) } /* Read 'onto_name' */ - if ((error = rebase_readfile(&buf, &state_path, ONTO_NAME_FILE)) < 0) + if ((error = rebase_readfile(&buf, rebase, ONTO_NAME_FILE)) < 0) goto done; rebase->onto_name = git_str_detach(&buf); done: git_str_dispose(&cmt); - git_str_dispose(&state_path); git_str_dispose(&buf); return error; @@ -297,9 +319,9 @@ int git_rebase_open( const git_rebase_options *given_opts) { git_rebase *rebase; - git_str path = GIT_STR_INIT, orig_head_name = GIT_STR_INIT, - orig_head_id = GIT_STR_INIT, onto_id = GIT_STR_INIT; - size_t state_path_len; + git_str orig_head_name = GIT_STR_INIT, + orig_head_id = GIT_STR_INIT, + onto_id = GIT_STR_INIT; int error; GIT_ASSERT_ARG(repo); @@ -321,13 +343,10 @@ int git_rebase_open( goto done; } - if ((error = git_str_puts(&path, rebase->state_path)) < 0) + if ((error = git_str_puts(&rebase->state_filename, rebase->state_path)) < 0) goto done; - state_path_len = git_str_len(&path); - - if ((error = git_str_joinpath(&path, path.ptr, HEAD_NAME_FILE)) < 0 || - (error = git_futils_readbuffer(&orig_head_name, path.ptr)) < 0) + if ((error = rebase_readfile(&orig_head_name, rebase, HEAD_NAME_FILE)) < 0) goto done; git_str_rtrim(&orig_head_name); @@ -335,36 +354,16 @@ int git_rebase_open( if (strcmp(ORIG_DETACHED_HEAD, orig_head_name.ptr) == 0) rebase->head_detached = 1; - git_str_truncate(&path, state_path_len); - - if ((error = git_str_joinpath(&path, path.ptr, ORIG_HEAD_FILE)) < 0) - goto done; - - if (!git_fs_path_isfile(path.ptr)) { + if ((error = rebase_readoid(&rebase->orig_head_id, &orig_head_id, rebase, ORIG_HEAD_FILE)) < 0) { /* Previous versions of git.git used 'head' here; support that. */ - git_str_truncate(&path, state_path_len); + if (error == GIT_ENOTFOUND) + error = rebase_readoid(&rebase->orig_head_id, &orig_head_id, rebase, HEAD_FILE); - if ((error = git_str_joinpath(&path, path.ptr, HEAD_FILE)) < 0) + if (error < 0) goto done; } - if ((error = git_futils_readbuffer(&orig_head_id, path.ptr)) < 0) - goto done; - - git_str_rtrim(&orig_head_id); - - if ((error = git_oid_fromstr(&rebase->orig_head_id, orig_head_id.ptr)) < 0) - goto done; - - git_str_truncate(&path, state_path_len); - - if ((error = git_str_joinpath(&path, path.ptr, ONTO_FILE)) < 0 || - (error = git_futils_readbuffer(&onto_id, path.ptr)) < 0) - goto done; - - git_str_rtrim(&onto_id); - - if ((error = git_oid_fromstr(&rebase->onto_id, onto_id.ptr)) < 0) + if ((error = rebase_readoid(&rebase->onto_id, &onto_id, rebase, ONTO_FILE)) < 0) goto done; if (!rebase->head_detached) @@ -392,7 +391,6 @@ int git_rebase_open( else git_rebase_free(rebase); - git_str_dispose(&path); git_str_dispose(&orig_head_name); git_str_dispose(&orig_head_id); git_str_dispose(&onto_id); @@ -442,13 +440,13 @@ static const char *rebase_onto_name(const git_annotated_commit *onto) static int rebase_setupfiles_merge(git_rebase *rebase) { git_str commit_filename = GIT_STR_INIT; - char id_str[GIT_OID_HEXSZ]; + char id_str[GIT_OID_MAX_HEXSIZE + 1]; git_rebase_operation *operation; size_t i; int error = 0; if ((error = rebase_setupfile(rebase, END_FILE, 0, "%" PRIuZ "\n", git_array_size(rebase->operations))) < 0 || - (error = rebase_setupfile(rebase, ONTO_NAME_FILE, 0, "%s\n", rebase->onto_name)) < 0) + (error = rebase_setupfile(rebase, ONTO_NAME_FILE, 0, "%s\n", rebase->onto_name)) < 0) goto done; for (i = 0; i < git_array_size(rebase->operations); i++) { @@ -457,10 +455,9 @@ static int rebase_setupfiles_merge(git_rebase *rebase) git_str_clear(&commit_filename); git_str_printf(&commit_filename, CMT_FILE_FMT, i+1); - git_oid_fmt(id_str, &operation->id); + git_oid_tostr(id_str, GIT_OID_MAX_HEXSIZE + 1, &operation->id); - if ((error = rebase_setupfile(rebase, commit_filename.ptr, 0, - "%.*s\n", GIT_OID_HEXSZ, id_str)) < 0) + if ((error = rebase_setupfile(rebase, commit_filename.ptr, 0, "%s\n", id_str)) < 0) goto done; } @@ -471,11 +468,11 @@ static int rebase_setupfiles_merge(git_rebase *rebase) static int rebase_setupfiles(git_rebase *rebase) { - char onto[GIT_OID_HEXSZ], orig_head[GIT_OID_HEXSZ]; + char onto[GIT_OID_MAX_HEXSIZE + 1], orig_head[GIT_OID_MAX_HEXSIZE + 1]; const char *orig_head_name; - git_oid_fmt(onto, &rebase->onto_id); - git_oid_fmt(orig_head, &rebase->orig_head_id); + git_oid_tostr(onto, GIT_OID_MAX_HEXSIZE + 1, &rebase->onto_id); + git_oid_tostr(orig_head, GIT_OID_MAX_HEXSIZE + 1, &rebase->orig_head_id); if (p_mkdir(rebase->state_path, REBASE_DIR_MODE) < 0) { git_error_set(GIT_ERROR_OS, "failed to create rebase directory '%s'", rebase->state_path); @@ -487,8 +484,8 @@ static int rebase_setupfiles(git_rebase *rebase) if (git_repository__set_orig_head(rebase->repo, &rebase->orig_head_id) < 0 || rebase_setupfile(rebase, HEAD_NAME_FILE, 0, "%s\n", orig_head_name) < 0 || - rebase_setupfile(rebase, ONTO_FILE, 0, "%.*s\n", GIT_OID_HEXSZ, onto) < 0 || - rebase_setupfile(rebase, ORIG_HEAD_FILE, 0, "%.*s\n", GIT_OID_HEXSZ, orig_head) < 0 || + rebase_setupfile(rebase, ONTO_FILE, 0, "%s\n", onto) < 0 || + rebase_setupfile(rebase, ORIG_HEAD_FILE, 0, "%s\n", orig_head) < 0 || rebase_setupfile(rebase, QUIET_FILE, 0, rebase->quiet ? "t\n" : "\n") < 0) return -1; @@ -633,7 +630,8 @@ static int rebase_init_merge( GIT_UNUSED(upstream); - if ((error = git_str_joinpath(&state_path, repo->gitdir, REBASE_MERGE_DIR)) < 0) + if ((error = git_str_joinpath(&state_path, repo->gitdir, REBASE_MERGE_DIR)) < 0 || + (error = git_str_put(&rebase->state_filename, state_path.ptr, state_path.size)) < 0) goto done; rebase->state_path = git_str_detach(&state_path); @@ -803,7 +801,7 @@ static int rebase_next_merge( git_indexwriter indexwriter = GIT_INDEXWRITER_INIT; git_rebase_operation *operation; git_checkout_options checkout_opts; - char current_idstr[GIT_OID_HEXSZ]; + char current_idstr[GIT_OID_MAX_HEXSIZE + 1]; unsigned int parent_count; int error; @@ -826,13 +824,13 @@ static int rebase_next_merge( goto done; } - git_oid_fmt(current_idstr, &operation->id); + git_oid_tostr(current_idstr, GIT_OID_MAX_HEXSIZE + 1, &operation->id); normalize_checkout_options_for_apply(&checkout_opts, rebase, current_commit); if ((error = git_indexwriter_init_for_operation(&indexwriter, rebase->repo, &checkout_opts.checkout_strategy)) < 0 || (error = rebase_setupfile(rebase, MSGNUM_FILE, 0, "%" PRIuZ "\n", rebase->current+1)) < 0 || - (error = rebase_setupfile(rebase, CURRENT_FILE, 0, "%.*s\n", GIT_OID_HEXSZ, current_idstr)) < 0 || + (error = rebase_setupfile(rebase, CURRENT_FILE, 0, "%s\n", current_idstr)) < 0 || (error = git_merge_trees(&index, rebase->repo, parent_tree, head_tree, current_tree, &rebase->options.merge_options)) < 0 || (error = git_merge__check_result(rebase->repo, index)) < 0 || (error = git_checkout_index(rebase->repo, index, &checkout_opts)) < 0 || @@ -1092,7 +1090,7 @@ static int rebase_commit_merge( git_reference *head = NULL; git_commit *head_commit = NULL, *commit = NULL; git_index *index = NULL; - char old_idstr[GIT_OID_HEXSZ], new_idstr[GIT_OID_HEXSZ]; + char old_idstr[GIT_OID_MAX_HEXSIZE + 1], new_idstr[GIT_OID_MAX_HEXSIZE + 1]; int error; operation = git_array_get(rebase->operations, rebase->current); @@ -1108,11 +1106,11 @@ static int rebase_commit_merge( rebase->repo, NULL, "HEAD", git_commit_id(commit), "rebase")) < 0) goto done; - git_oid_fmt(old_idstr, &operation->id); - git_oid_fmt(new_idstr, git_commit_id(commit)); + git_oid_tostr(old_idstr, GIT_OID_MAX_HEXSIZE + 1, &operation->id); + git_oid_tostr(new_idstr, GIT_OID_MAX_HEXSIZE + 1, git_commit_id(commit)); if ((error = rebase_setupfile(rebase, REWRITTEN_FILE, O_CREAT|O_WRONLY|O_APPEND, - "%.*s %.*s\n", GIT_OID_HEXSZ, old_idstr, GIT_OID_HEXSZ, new_idstr)) < 0) + "%s %s\n", old_idstr, new_idstr)) < 0) goto done; git_oid_cpy(commit_id, git_commit_id(commit)); @@ -1295,7 +1293,9 @@ static int rebase_copy_notes( git_rebase *rebase, const git_signature *committer) { - git_str path = GIT_STR_INIT, rewritten = GIT_STR_INIT, notes_ref = GIT_STR_INIT; + git_str path = GIT_STR_INIT, + rewritten = GIT_STR_INIT, + notes_ref = GIT_STR_INIT; char *pair_list, *fromstr, *tostr, *end; git_oid from, to; unsigned int linenum = 1; @@ -1331,10 +1331,10 @@ static int rebase_copy_notes( tostr = end+1; *end = '\0'; - if (strlen(fromstr) != GIT_OID_HEXSZ || - strlen(tostr) != GIT_OID_HEXSZ || - git_oid_fromstr(&from, fromstr) < 0 || - git_oid_fromstr(&to, tostr) < 0) + if (strlen(fromstr) != git_oid_hexsize(rebase->repo->oid_type) || + strlen(tostr) != git_oid_hexsize(rebase->repo->oid_type) || + git_oid__fromstr(&from, fromstr, rebase->repo->oid_type) < 0 || + git_oid__fromstr(&to, tostr, rebase->repo->oid_type) < 0) goto on_error; if ((error = rebase_copy_note(rebase, notes_ref.ptr, &from, &to, committer)) < 0) @@ -1362,17 +1362,15 @@ static int return_to_orig_head(git_rebase *rebase) git_reference *terminal_ref = NULL, *branch_ref = NULL, *head_ref = NULL; git_commit *terminal_commit = NULL; git_str branch_msg = GIT_STR_INIT, head_msg = GIT_STR_INIT; - char onto[GIT_OID_HEXSZ]; + char onto[GIT_OID_MAX_HEXSIZE + 1]; int error = 0; - git_oid_fmt(onto, &rebase->onto_id); + git_oid_tostr(onto, GIT_OID_MAX_HEXSIZE + 1, &rebase->onto_id); if ((error = git_str_printf(&branch_msg, - "rebase finished: %s onto %.*s", - rebase->orig_head_name, GIT_OID_HEXSZ, onto)) == 0 && + "rebase finished: %s onto %s", rebase->orig_head_name, onto)) == 0 && (error = git_str_printf(&head_msg, - "rebase finished: returning to %s", - rebase->orig_head_name)) == 0 && + "rebase finished: returning to %s", rebase->orig_head_name)) == 0 && (error = git_repository_head(&terminal_ref, rebase->repo)) == 0 && (error = git_reference_peel((git_object **)&terminal_commit, terminal_ref, GIT_OBJECT_COMMIT)) == 0 && @@ -1464,6 +1462,7 @@ void git_rebase_free(git_rebase *rebase) git__free(rebase->onto_name); git__free(rebase->orig_head_name); git__free(rebase->state_path); + git_str_dispose(&rebase->state_filename); git_array_clear(rebase->operations); git__free((char *)rebase->options.rewrite_notes_ref); git__free(rebase); diff --git a/vendor/libgit2/src/refdb.c b/vendor/libgit2/src/libgit2/refdb.c similarity index 100% rename from vendor/libgit2/src/refdb.c rename to vendor/libgit2/src/libgit2/refdb.c diff --git a/vendor/libgit2/src/refdb.h b/vendor/libgit2/src/libgit2/refdb.h similarity index 100% rename from vendor/libgit2/src/refdb.h rename to vendor/libgit2/src/libgit2/refdb.h diff --git a/vendor/libgit2/src/refdb_fs.c b/vendor/libgit2/src/libgit2/refdb_fs.c similarity index 90% rename from vendor/libgit2/src/refdb_fs.c rename to vendor/libgit2/src/libgit2/refdb_fs.c index 95bda940..9a5c38ed 100644 --- a/vendor/libgit2/src/refdb_fs.c +++ b/vendor/libgit2/src/libgit2/refdb_fs.c @@ -60,15 +60,17 @@ typedef struct refdb_fs_backend { /* path to common objects' directory */ char *commonpath; - git_sortedcache *refcache; + git_oid_t oid_type; + + unsigned int fsync : 1, + sorted : 1; int peeling_mode; git_iterator_flag_t iterator_flags; uint32_t direach_flags; - int fsync; + git_sortedcache *refcache; git_map packed_refs_map; git_mutex prlock; /* protect packed_refs_map */ git_futils_filestamp packed_refs_stamp; - bool sorted; } refdb_fs_backend; static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name); @@ -113,6 +115,7 @@ static int packed_reload(refdb_fs_backend *backend) { int error; git_str packedrefs = GIT_STR_INIT; + size_t oid_hexsize = git_oid_hexsize(backend->oid_type); char *scan, *eof, *eol; if (!backend->gitpath) @@ -158,9 +161,9 @@ static int packed_reload(refdb_fs_backend *backend) /* parse " \n" */ - if (git_oid_fromstr(&oid, scan) < 0) + if (git_oid__fromstr(&oid, scan, backend->oid_type) < 0) goto parse_failed; - scan += GIT_OID_HEXSZ; + scan += oid_hexsize; if (*scan++ != ' ') goto parse_failed; @@ -179,9 +182,9 @@ static int packed_reload(refdb_fs_backend *backend) /* look for optional "^\n" */ if (*scan == '^') { - if (git_oid_fromstr(&oid, scan + 1) < 0) + if (git_oid__fromstr(&oid, scan + 1, backend->oid_type) < 0) goto parse_failed; - scan += GIT_OID_HEXSZ + 1; + scan += oid_hexsize + 1; if (scan < eof) { if (!(eol = strchr(scan, '\n'))) @@ -214,19 +217,23 @@ static int packed_reload(refdb_fs_backend *backend) } static int loose_parse_oid( - git_oid *oid, const char *filename, git_str *file_content) + git_oid *oid, + const char *filename, + git_str *file_content, + git_oid_t oid_type) { const char *str = git_str_cstr(file_content); + size_t oid_hexsize = git_oid_hexsize(oid_type); - if (git_str_len(file_content) < GIT_OID_HEXSZ) + if (git_str_len(file_content) < oid_hexsize) goto corrupted; /* we need to get 40 OID characters from the file */ - if (git_oid_fromstr(oid, str) < 0) + if (git_oid__fromstr(oid, str, oid_type) < 0) goto corrupted; /* If the file is longer than 40 chars, the 41st must be a space */ - str += GIT_OID_HEXSZ; + str += oid_hexsize; if (*str == '\0' || git__isspace(*str)) return 0; @@ -266,7 +273,7 @@ static int loose_lookup_to_packfile(refdb_fs_backend *backend, const char *name) goto done; /* parse OID from file */ - if ((error = loose_parse_oid(&oid, name, &ref_file)) < 0) + if ((error = loose_parse_oid(&oid, name, &ref_file, backend->oid_type)) < 0) goto done; if ((error = git_sortedcache_wlock(backend->refcache)) < 0) @@ -403,7 +410,9 @@ static const char *loose_parse_symbolic(git_str *file_content) static bool is_per_worktree_ref(const char *ref_name) { return git__prefixcmp(ref_name, "refs/") != 0 || - git__prefixcmp(ref_name, "refs/bisect/") == 0; + git__prefixcmp(ref_name, "refs/bisect/") == 0 || + git__prefixcmp(ref_name, "refs/worktree/") == 0 || + git__prefixcmp(ref_name, "refs/rewritten/") == 0; } static int loose_lookup( @@ -437,7 +446,7 @@ static int loose_lookup( } else { git_oid oid; - if (!(error = loose_parse_oid(&oid, ref_name, &ref_file)) && + if (!(error = loose_parse_oid(&oid, ref_name, &ref_file, backend->oid_type)) && out != NULL) *out = git_reference__alloc(ref_name, &oid, NULL); } @@ -615,19 +624,24 @@ static const char *end_of_record(const char *p, const char *end) return p; } -static int -cmp_record_to_refname(const char *rec, size_t data_end, const char *ref_name) +static int cmp_record_to_refname( + const char *rec, + size_t data_end, + const char *ref_name, + git_oid_t oid_type) { const size_t ref_len = strlen(ref_name); int cmp_val; const char *end; + size_t oid_hexsize = git_oid_hexsize(oid_type); + + rec += oid_hexsize + 1; /* + space */ - rec += GIT_OID_HEXSZ + 1; /* + space */ - if (data_end < GIT_OID_HEXSZ + 3) { - /* an incomplete (corrupt) record is treated as less than ref_name */ + /* an incomplete (corrupt) record is treated as less than ref_name */ + if (data_end < oid_hexsize + 3) return -1; - } - data_end -= GIT_OID_HEXSZ + 1; + + data_end -= oid_hexsize + 1; end = memchr(rec, '\n', data_end); if (end) @@ -675,6 +689,7 @@ static int packed_lookup( { int error = 0; const char *left, *right, *data_end; + size_t oid_hexsize = git_oid_hexsize(backend->oid_type); if ((error = packed_map_check(backend)) < 0) return error; @@ -698,7 +713,7 @@ static int packed_lookup( mid = left + (right - left) / 2; rec = start_of_record(left, mid); - compare = cmp_record_to_refname(rec, data_end - rec, ref_name); + compare = cmp_record_to_refname(rec, data_end - rec, ref_name, backend->oid_type); if (compare < 0) { left = end_of_record(mid, right); @@ -708,11 +723,11 @@ static int packed_lookup( const char *eol; git_oid oid, peel, *peel_ptr = NULL; - if (data_end - rec < GIT_OID_HEXSZ || - git_oid_fromstr(&oid, rec) < 0) { + if (data_end - rec < (long)oid_hexsize || + git_oid__fromstr(&oid, rec, backend->oid_type) < 0) { goto parse_failed; } - rec += GIT_OID_HEXSZ + 1; + rec += oid_hexsize + 1; if (!(eol = memchr(rec, '\n', data_end - rec))) { goto parse_failed; } @@ -724,8 +739,8 @@ static int packed_lookup( if (*rec == '^') { rec++; - if (data_end - rec < GIT_OID_HEXSZ || - git_oid_fromstr(&peel, rec) < 0) { + if (data_end - rec < (long)oid_hexsize || + git_oid__fromstr(&peel, rec, backend->oid_type) < 0) { goto parse_failed; } peel_ptr = &peel; @@ -740,7 +755,7 @@ static int packed_lookup( return 0; } } - return GIT_ENOTFOUND; + return ref_error_notfound(ref_name); parse_failed: git_error_set(GIT_ERROR_REFERENCE, "corrupted packed references file"); @@ -792,80 +807,149 @@ static void refdb_fs_backend__iterator_free(git_reference_iterator *_iter) git__free(iter); } -static int iter_load_loose_paths(refdb_fs_backend *backend, refdb_fs_iter *iter) +struct iter_load_context { + refdb_fs_backend *backend; + refdb_fs_iter *iter; + + /* + * If we have a glob with a prefix (eg `refs/heads/ *`) then we can + * optimize our prefix to avoid walking refs that we know won't + * match. This is that prefix. + */ + const char *ref_prefix; + size_t ref_prefix_len; + + /* Temporary variables to avoid unnecessary allocations */ + git_str ref_name; + git_str path; +}; + +static void iter_load_optimize_prefix(struct iter_load_context *ctx) { - int error = 0; - git_str path = GIT_STR_INIT; - git_iterator *fsit = NULL; - git_iterator_options fsit_opts = GIT_ITERATOR_OPTIONS_INIT; - const git_index_entry *entry = NULL; - const char *ref_prefix = GIT_REFS_DIR; - size_t ref_prefix_len = strlen(ref_prefix); + const char *pos, *last_sep = NULL; - if (!backend->commonpath) /* do nothing if no commonpath for loose refs */ - return 0; + if (!ctx->iter->glob) + return; - fsit_opts.flags = backend->iterator_flags; - - if (iter->glob) { - const char *last_sep = NULL; - const char *pos; - for (pos = iter->glob; *pos; ++pos) { - switch (*pos) { - case '?': - case '*': - case '[': - case '\\': - break; - case '/': - last_sep = pos; - /* FALLTHROUGH */ - default: - continue; - } + for (pos = ctx->iter->glob; *pos; pos++) { + switch (*pos) { + case '?': + case '*': + case '[': + case '\\': break; + case '/': + last_sep = pos; + /* FALLTHROUGH */ + default: + continue; } - if (last_sep) { - ref_prefix = iter->glob; - ref_prefix_len = (last_sep - ref_prefix) + 1; - } + break; } - if ((error = git_str_puts(&path, backend->commonpath)) < 0 || - (error = git_str_put(&path, ref_prefix, ref_prefix_len)) < 0) { - git_str_dispose(&path); - return error; + if (last_sep) { + ctx->ref_prefix = ctx->iter->glob; + ctx->ref_prefix_len = (last_sep - ctx->ref_prefix) + 1; } +} + +static int iter_load_paths( + struct iter_load_context *ctx, + const char *root_path, + bool worktree) +{ + git_iterator *fsit = NULL; + git_iterator_options fsit_opts = GIT_ITERATOR_OPTIONS_INIT; + const git_index_entry *entry; + int error = 0; + + fsit_opts.flags = ctx->backend->iterator_flags; + + git_str_clear(&ctx->path); + git_str_puts(&ctx->path, root_path); + git_str_put(&ctx->path, ctx->ref_prefix, ctx->ref_prefix_len); + + fsit_opts.flags = ctx->backend->iterator_flags; + fsit_opts.oid_type = ctx->backend->oid_type; - if ((error = git_iterator_for_filesystem(&fsit, path.ptr, &fsit_opts)) < 0) { - git_str_dispose(&path); - return (iter->glob && error == GIT_ENOTFOUND)? 0 : error; + if ((error = git_iterator_for_filesystem(&fsit, ctx->path.ptr, &fsit_opts)) < 0) { + /* + * Subdirectories - either glob provided or per-worktree refs - need + * not exist. + */ + if ((worktree || ctx->iter->glob) && error == GIT_ENOTFOUND) + error = 0; + + goto done; } - error = git_str_sets(&path, ref_prefix); + git_str_clear(&ctx->ref_name); + git_str_put(&ctx->ref_name, ctx->ref_prefix, ctx->ref_prefix_len); - while (!error && !git_iterator_advance(&entry, fsit)) { - const char *ref_name; + while (git_iterator_advance(&entry, fsit) == 0) { char *ref_dup; - git_str_truncate(&path, ref_prefix_len); - git_str_puts(&path, entry->path); - ref_name = git_str_cstr(&path); + git_str_truncate(&ctx->ref_name, ctx->ref_prefix_len); + git_str_puts(&ctx->ref_name, entry->path); - if (git__suffixcmp(ref_name, ".lock") == 0 || - (iter->glob && wildmatch(iter->glob, ref_name, 0) != 0)) + if (worktree) { + if (!is_per_worktree_ref(ctx->ref_name.ptr)) + continue; + } else { + if (git_repository_is_worktree(ctx->backend->repo) && + is_per_worktree_ref(ctx->ref_name.ptr)) + continue; + } + + if (git__suffixcmp(ctx->ref_name.ptr, ".lock") == 0) continue; - ref_dup = git_pool_strdup(&iter->pool, ref_name); - if (!ref_dup) - error = -1; - else - error = git_vector_insert(&iter->loose, ref_dup); + if (ctx->iter->glob && wildmatch(ctx->iter->glob, ctx->ref_name.ptr, 0)) + continue; + + ref_dup = git_pool_strdup(&ctx->iter->pool, ctx->ref_name.ptr); + GIT_ERROR_CHECK_ALLOC(ref_dup); + + if ((error = git_vector_insert(&ctx->iter->loose, ref_dup)) < 0) + goto done; } +done: git_iterator_free(fsit); - git_str_dispose(&path); + return error; +} + +#define iter_load_context_init(b, i) { b, i, GIT_REFS_DIR, CONST_STRLEN(GIT_REFS_DIR) } +#define iter_load_context_dispose(ctx) do { \ + git_str_dispose(&((ctx)->path)); \ + git_str_dispose(&((ctx)->ref_name)); \ +} while(0) + +static int iter_load_loose_paths( + refdb_fs_backend *backend, + refdb_fs_iter *iter) +{ + struct iter_load_context ctx = iter_load_context_init(backend, iter); + int error = 0; + + if (!backend->commonpath) + return 0; + + iter_load_optimize_prefix(&ctx); + + if ((error = iter_load_paths(&ctx, + backend->commonpath, false)) < 0) + goto done; + + if (git_repository_is_worktree(backend->repo)) { + if ((error = iter_load_paths(&ctx, + backend->gitpath, true)) < 0) + goto done; + } + +done: + iter_load_context_dispose(&ctx); return error; } @@ -1108,7 +1192,7 @@ static int loose_commit(git_filebuf *file, const git_reference *ref) GIT_ASSERT_ARG(ref); if (ref->type == GIT_REFERENCE_DIRECT) { - char oid[GIT_OID_HEXSZ + 1]; + char oid[GIT_OID_MAX_HEXSIZE + 1]; git_oid_nfmt(oid, sizeof(oid), &ref->target.oid); git_filebuf_printf(file, "%s\n", oid); @@ -1224,7 +1308,7 @@ static int packed_find_peel(refdb_fs_backend *backend, struct packref *ref) */ static int packed_write_ref(struct packref *ref, git_filebuf *file) { - char oid[GIT_OID_HEXSZ + 1]; + char oid[GIT_OID_MAX_HEXSIZE + 1]; git_oid_nfmt(oid, sizeof(oid), &ref->oid); /* @@ -1238,7 +1322,7 @@ static int packed_write_ref(struct packref *ref, git_filebuf *file) * The required peels have already been loaded into `ref->peel_target`. */ if (ref->flags & PACKREF_HAS_PEEL) { - char peel[GIT_OID_HEXSZ + 1]; + char peel[GIT_OID_MAX_HEXSIZE + 1]; git_oid_nfmt(peel, sizeof(peel), &ref->peel); if (git_filebuf_printf(file, "%s %s\n^%s\n", oid, ref->name, peel) < 0) @@ -1302,7 +1386,7 @@ static int packed_remove_loose(refdb_fs_backend *backend) continue; /* Figure out the current id; if we find a bad ref file, skip it so we can do the rest */ - if (loose_parse_oid(¤t_id, lock.path_original, &ref_content) < 0) + if (loose_parse_oid(¤t_id, lock.path_original, &ref_content, backend->oid_type) < 0) continue; /* If the ref moved since we packed it, we must not delete it */ @@ -1361,7 +1445,11 @@ static int packed_write(refdb_fs_backend *backend) for (i = 0; i < git_sortedcache_entrycount(refcache); ++i) { struct packref *ref = git_sortedcache_entry(refcache, i); - GIT_ASSERT(ref); + + GIT_ASSERT_WITH_CLEANUP(ref, { + error = -1; + goto fail; + }); if ((error = packed_find_peel(backend, ref)) < 0) goto fail; @@ -1765,7 +1853,7 @@ static int refdb_fs_backend__rename( (error = refdb_fs_backend__lookup(&old, _backend, old_name)) < 0) return error; - if ((error = refdb_fs_backend__delete(_backend, old_name, NULL, NULL)) < 0) { + if ((error = loose_lock(&file, backend, old->name)) < 0) { git_reference_free(old); return error; } @@ -1773,32 +1861,33 @@ static int refdb_fs_backend__rename( new = git_reference__realloc(&old, new_name); if (!new) { git_reference_free(old); + git_filebuf_cleanup(&file); return -1; } - if ((error = loose_lock(&file, backend, new->name)) < 0) { + if ((error = refdb_fs_backend__delete_tail(_backend, &file, old_name, NULL, NULL)) < 0) { git_reference_free(new); + git_filebuf_cleanup(&file); return error; } - /* Try to rename the refog; it's ok if the old doesn't exist */ - error = refdb_reflog_fs__rename(_backend, old_name, new_name); - if (((error == 0) || (error == GIT_ENOTFOUND)) && - ((error = reflog_append(backend, new, git_reference_target(new), NULL, who, message)) < 0)) { + if ((error = loose_lock(&file, backend, new_name)) < 0) { git_reference_free(new); - git_filebuf_cleanup(&file); return error; } - if (error < 0) { + /* Try to rename the refog; it's ok if the old doesn't exist */ + error = refdb_reflog_fs__rename(_backend, old_name, new_name); + if (((error == 0) || (error == GIT_ENOTFOUND)) && + ((error = reflog_append(backend, new, git_reference_target(new), NULL, who, message)) < 0)) { git_reference_free(new); git_filebuf_cleanup(&file); return error; } - if ((error = loose_commit(&file, new)) < 0 || out == NULL) { git_reference_free(new); + git_filebuf_cleanup(&file); return error; } @@ -1887,7 +1976,10 @@ static char *setup_namespace(git_repository *repo, const char *in) return out; } -static int reflog_alloc(git_reflog **reflog, const char *name) +static int reflog_alloc( + git_reflog **reflog, + const char *name, + git_oid_t oid_type) { git_reflog *log; @@ -1899,6 +1991,8 @@ static int reflog_alloc(git_reflog **reflog, const char *name) log->ref_name = git__strdup(name); GIT_ERROR_CHECK_ALLOC(log->ref_name); + log->oid_type = oid_type; + if (git_vector_init(&log->entries, 0, NULL) < 0) { git__free(log->ref_name); git__free(log); @@ -1927,9 +2021,9 @@ static int reflog_parse(git_reflog *log, const char *buf, size_t buf_size) entry->committer = git__calloc(1, sizeof(*entry->committer)); GIT_ERROR_CHECK_ALLOC(entry->committer); - if (git_parse_advance_oid(&entry->oid_old, &parser) < 0 || + if (git_parse_advance_oid(&entry->oid_old, &parser, log->oid_type) < 0 || git_parse_advance_expected(&parser, " ", 1) < 0 || - git_parse_advance_oid(&entry->oid_cur, &parser) < 0) + git_parse_advance_oid(&entry->oid_cur, &parser, log->oid_type) < 0) goto next; sig = parser.line; @@ -2028,7 +2122,10 @@ static int refdb_reflog_fs__has_log(git_refdb_backend *_backend, const char *nam return has_reflog(backend->repo, name); } -static int refdb_reflog_fs__read(git_reflog **out, git_refdb_backend *_backend, const char *name) +static int refdb_reflog_fs__read( + git_reflog **out, + git_refdb_backend *_backend, + const char *name) { int error = -1; git_str log_path = GIT_STR_INIT; @@ -2044,7 +2141,7 @@ static int refdb_reflog_fs__read(git_reflog **out, git_refdb_backend *_backend, backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); repo = backend->repo; - if (reflog_alloc(&log, name) < 0) + if (reflog_alloc(&log, name, backend->oid_type) < 0) return -1; if (reflog_path(&log_path, repo, name) < 0) @@ -2082,11 +2179,11 @@ static int serialize_reflog_entry( const git_signature *committer, const char *msg) { - char raw_old[GIT_OID_HEXSZ+1]; - char raw_new[GIT_OID_HEXSZ+1]; + char raw_old[GIT_OID_MAX_HEXSIZE + 1]; + char raw_new[GIT_OID_MAX_HEXSIZE + 1]; - git_oid_tostr(raw_old, GIT_OID_HEXSZ+1, oid_old); - git_oid_tostr(raw_new, GIT_OID_HEXSZ+1, oid_new); + git_oid_tostr(raw_old, GIT_OID_MAX_HEXSIZE + 1, oid_old); + git_oid_tostr(raw_new, GIT_OID_MAX_HEXSIZE + 1, oid_new); git_str_clear(buf); @@ -2185,10 +2282,16 @@ static int refdb_reflog_fs__write(git_refdb_backend *_backend, git_reflog *reflo } /* Append to the reflog, must be called under reference lock */ -static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, const git_oid *old, const git_oid *new, const git_signature *who, const char *message) +static int reflog_append( + refdb_fs_backend *backend, + const git_reference *ref, + const git_oid *old, + const git_oid *new, + const git_signature *who, + const char *message) { int error, is_symbolic, open_flags; - git_oid old_id = {{0}}, new_id = {{0}}; + git_oid old_id, new_id; git_str buf = GIT_STR_INIT, path = GIT_STR_INIT; git_repository *repo = backend->repo; @@ -2202,6 +2305,9 @@ static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, co /* From here on is_symbolic also means that it's HEAD */ + git_oid_clear(&old_id, backend->oid_type); + git_oid_clear(&new_id, backend->oid_type); + if (old) { git_oid_cpy(&old_id, old); } else { @@ -2364,7 +2470,12 @@ static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name if ((error = reflog_path(&path, backend->repo, name)) < 0) goto out; - if (!git_fs_path_exists(path.ptr)) + /* + * If a reference was moved downwards, eg refs/heads/br2 -> refs/heads/br2/new-name, + * refs/heads/br2 does exist but it's a directory. That's a valid situation. + * Proceed only if it's a file. + */ + if (!git_fs_path_isfile(path.ptr)) goto out; if ((error = p_unlink(path.ptr)) < 0) @@ -2398,6 +2509,7 @@ int git_refdb_backend_fs( goto fail; backend->repo = repository; + backend->oid_type = repository->oid_type; if (repository->gitdir) { backend->gitpath = setup_namespace(repository, repository->gitdir); diff --git a/vendor/libgit2/src/libgit2/reflog.c b/vendor/libgit2/src/libgit2/reflog.c new file mode 100644 index 00000000..86d4355e --- /dev/null +++ b/vendor/libgit2/src/libgit2/reflog.c @@ -0,0 +1,234 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "reflog.h" + +#include "repository.h" +#include "filebuf.h" +#include "signature.h" +#include "refdb.h" + +#include "git2/sys/refdb_backend.h" +#include "git2/sys/reflog.h" + +void git_reflog_entry__free(git_reflog_entry *entry) +{ + git_signature_free(entry->committer); + + git__free(entry->msg); + git__free(entry); +} + +void git_reflog_free(git_reflog *reflog) +{ + size_t i; + git_reflog_entry *entry; + + if (reflog == NULL) + return; + + if (reflog->db) + GIT_REFCOUNT_DEC(reflog->db, git_refdb__free); + + for (i=0; i < reflog->entries.length; i++) { + entry = git_vector_get(&reflog->entries, i); + + git_reflog_entry__free(entry); + } + + git_vector_free(&reflog->entries); + git__free(reflog->ref_name); + git__free(reflog); +} + +int git_reflog_read(git_reflog **reflog, git_repository *repo, const char *name) +{ + git_refdb *refdb; + int error; + + GIT_ASSERT_ARG(reflog); + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(name); + + if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) + return error; + + return git_refdb_reflog_read(reflog, refdb, name); +} + +int git_reflog_write(git_reflog *reflog) +{ + git_refdb *db; + + GIT_ASSERT_ARG(reflog); + GIT_ASSERT_ARG(reflog->db); + + db = reflog->db; + return db->backend->reflog_write(db->backend, reflog); +} + +int git_reflog_append( + git_reflog *reflog, + const git_oid *new_oid, + const git_signature *committer, + const char *msg) +{ + const git_reflog_entry *previous; + git_reflog_entry *entry; + + GIT_ASSERT_ARG(reflog); + GIT_ASSERT_ARG(new_oid); + GIT_ASSERT_ARG(committer); + + entry = git__calloc(1, sizeof(git_reflog_entry)); + GIT_ERROR_CHECK_ALLOC(entry); + + if ((git_signature_dup(&entry->committer, committer)) < 0) + goto cleanup; + + if (msg != NULL) { + size_t i, msglen = strlen(msg); + + if ((entry->msg = git__strndup(msg, msglen)) == NULL) + goto cleanup; + + /* + * Replace all newlines with spaces, except for + * the final trailing newline. + */ + for (i = 0; i < msglen; i++) + if (entry->msg[i] == '\n') + entry->msg[i] = ' '; + } + + previous = git_reflog_entry_byindex(reflog, 0); + + if (previous == NULL) + git_oid_clear(&entry->oid_old, reflog->oid_type); + else + git_oid_cpy(&entry->oid_old, &previous->oid_cur); + + git_oid_cpy(&entry->oid_cur, new_oid); + + if (git_vector_insert(&reflog->entries, entry) < 0) + goto cleanup; + + return 0; + +cleanup: + git_reflog_entry__free(entry); + return -1; +} + +int git_reflog_rename(git_repository *repo, const char *old_name, const char *new_name) +{ + git_refdb *refdb; + int error; + + if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) + return -1; + + return refdb->backend->reflog_rename(refdb->backend, old_name, new_name); +} + +int git_reflog_delete(git_repository *repo, const char *name) +{ + git_refdb *refdb; + int error; + + if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) + return -1; + + return refdb->backend->reflog_delete(refdb->backend, name); +} + +size_t git_reflog_entrycount(git_reflog *reflog) +{ + GIT_ASSERT_ARG_WITH_RETVAL(reflog, 0); + return reflog->entries.length; +} + +const git_reflog_entry *git_reflog_entry_byindex(const git_reflog *reflog, size_t idx) +{ + GIT_ASSERT_ARG_WITH_RETVAL(reflog, NULL); + + if (idx >= reflog->entries.length) + return NULL; + + return git_vector_get( + &reflog->entries, reflog_inverse_index(idx, reflog->entries.length)); +} + +const git_oid *git_reflog_entry_id_old(const git_reflog_entry *entry) +{ + GIT_ASSERT_ARG_WITH_RETVAL(entry, NULL); + return &entry->oid_old; +} + +const git_oid *git_reflog_entry_id_new(const git_reflog_entry *entry) +{ + GIT_ASSERT_ARG_WITH_RETVAL(entry, NULL); + return &entry->oid_cur; +} + +const git_signature *git_reflog_entry_committer(const git_reflog_entry *entry) +{ + GIT_ASSERT_ARG_WITH_RETVAL(entry, NULL); + return entry->committer; +} + +const char *git_reflog_entry_message(const git_reflog_entry *entry) +{ + GIT_ASSERT_ARG_WITH_RETVAL(entry, NULL); + return entry->msg; +} + +int git_reflog_drop(git_reflog *reflog, size_t idx, int rewrite_previous_entry) +{ + size_t entrycount; + git_reflog_entry *entry, *previous; + + entrycount = git_reflog_entrycount(reflog); + + entry = (git_reflog_entry *)git_reflog_entry_byindex(reflog, idx); + + if (entry == NULL) { + git_error_set(GIT_ERROR_REFERENCE, "no reflog entry at index %"PRIuZ, idx); + return GIT_ENOTFOUND; + } + + git_reflog_entry__free(entry); + + if (git_vector_remove( + &reflog->entries, reflog_inverse_index(idx, entrycount)) < 0) + return -1; + + if (!rewrite_previous_entry) + return 0; + + /* No need to rewrite anything when removing the most recent entry */ + if (idx == 0) + return 0; + + /* Have the latest entry just been dropped? */ + if (entrycount == 1) + return 0; + + entry = (git_reflog_entry *)git_reflog_entry_byindex(reflog, idx - 1); + + /* If the oldest entry has just been removed... */ + if (idx == entrycount - 1) { + /* ...clear the oid_old member of the "new" oldest entry */ + git_oid_clear(&entry->oid_old, reflog->oid_type); + return 0; + } + + previous = (git_reflog_entry *)git_reflog_entry_byindex(reflog, idx); + git_oid_cpy(&entry->oid_old, &previous->oid_cur); + + return 0; +} diff --git a/vendor/libgit2/src/reflog.h b/vendor/libgit2/src/libgit2/reflog.h similarity index 93% rename from vendor/libgit2/src/reflog.h rename to vendor/libgit2/src/libgit2/reflog.h index 8c389595..bc987859 100644 --- a/vendor/libgit2/src/reflog.h +++ b/vendor/libgit2/src/libgit2/reflog.h @@ -16,8 +16,6 @@ #define GIT_REFLOG_DIR_MODE 0777 #define GIT_REFLOG_FILE_MODE 0666 -#define GIT_REFLOG_SIZE_MIN (2*GIT_OID_HEXSZ+2+17) - struct git_reflog_entry { git_oid oid_old; git_oid oid_cur; @@ -30,6 +28,7 @@ struct git_reflog_entry { struct git_reflog { git_refdb *db; char *ref_name; + git_oid_t oid_type; git_vector entries; }; diff --git a/vendor/libgit2/src/libgit2/refs.c b/vendor/libgit2/src/libgit2/refs.c new file mode 100644 index 00000000..c1ed04d2 --- /dev/null +++ b/vendor/libgit2/src/libgit2/refs.c @@ -0,0 +1,1410 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "refs.h" + +#include "hash.h" +#include "repository.h" +#include "futils.h" +#include "filebuf.h" +#include "pack.h" +#include "reflog.h" +#include "refdb.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +bool git_reference__enable_symbolic_ref_target_validation = true; + +enum { + GIT_PACKREF_HAS_PEEL = 1, + GIT_PACKREF_WAS_LOOSE = 2 +}; + +static git_reference *alloc_ref(const char *name) +{ + git_reference *ref = NULL; + size_t namelen = strlen(name), reflen; + + if (!GIT_ADD_SIZET_OVERFLOW(&reflen, sizeof(git_reference), namelen) && + !GIT_ADD_SIZET_OVERFLOW(&reflen, reflen, 1) && + (ref = git__calloc(1, reflen)) != NULL) + memcpy(ref->name, name, namelen + 1); + + return ref; +} + +git_reference *git_reference__alloc_symbolic( + const char *name, const char *target) +{ + git_reference *ref; + + GIT_ASSERT_ARG_WITH_RETVAL(name, NULL); + GIT_ASSERT_ARG_WITH_RETVAL(target, NULL); + + ref = alloc_ref(name); + if (!ref) + return NULL; + + ref->type = GIT_REFERENCE_SYMBOLIC; + + if ((ref->target.symbolic = git__strdup(target)) == NULL) { + git__free(ref); + return NULL; + } + + return ref; +} + +git_reference *git_reference__alloc( + const char *name, + const git_oid *oid, + const git_oid *peel) +{ + git_oid_t oid_type; + git_reference *ref; + + GIT_ASSERT_ARG_WITH_RETVAL(name, NULL); + GIT_ASSERT_ARG_WITH_RETVAL(oid, NULL); + + ref = alloc_ref(name); + if (!ref) + return NULL; + + ref->type = GIT_REFERENCE_DIRECT; + git_oid_cpy(&ref->target.oid, oid); + +#ifdef GIT_EXPERIMENTAL_SHA256 + oid_type = oid->type; +#else + oid_type = GIT_OID_SHA1; +#endif + + if (peel != NULL) + git_oid_cpy(&ref->peel, peel); + else + git_oid_clear(&ref->peel, oid_type); + + return ref; +} + +git_reference *git_reference__realloc( + git_reference **ptr_to_ref, const char *name) +{ + size_t namelen, reflen; + git_reference *rewrite = NULL; + + GIT_ASSERT_ARG_WITH_RETVAL(ptr_to_ref, NULL); + GIT_ASSERT_ARG_WITH_RETVAL(name, NULL); + + namelen = strlen(name); + + if (!GIT_ADD_SIZET_OVERFLOW(&reflen, sizeof(git_reference), namelen) && + !GIT_ADD_SIZET_OVERFLOW(&reflen, reflen, 1) && + (rewrite = git__realloc(*ptr_to_ref, reflen)) != NULL) + memcpy(rewrite->name, name, namelen + 1); + + *ptr_to_ref = NULL; + + return rewrite; +} + +int git_reference_dup(git_reference **dest, git_reference *source) +{ + if (source->type == GIT_REFERENCE_SYMBOLIC) + *dest = git_reference__alloc_symbolic(source->name, source->target.symbolic); + else + *dest = git_reference__alloc(source->name, &source->target.oid, &source->peel); + + GIT_ERROR_CHECK_ALLOC(*dest); + + (*dest)->db = source->db; + GIT_REFCOUNT_INC((*dest)->db); + + return 0; +} + +void git_reference_free(git_reference *reference) +{ + if (reference == NULL) + return; + + if (reference->type == GIT_REFERENCE_SYMBOLIC) + git__free(reference->target.symbolic); + + if (reference->db) + GIT_REFCOUNT_DEC(reference->db, git_refdb__free); + + git__free(reference); +} + +int git_reference_delete(git_reference *ref) +{ + const git_oid *old_id = NULL; + const char *old_target = NULL; + + if (!strcmp(ref->name, "HEAD")) { + git_error_set(GIT_ERROR_REFERENCE, "cannot delete HEAD"); + return GIT_ERROR; + } + + if (ref->type == GIT_REFERENCE_DIRECT) + old_id = &ref->target.oid; + else + old_target = ref->target.symbolic; + + return git_refdb_delete(ref->db, ref->name, old_id, old_target); +} + +int git_reference_remove(git_repository *repo, const char *name) +{ + git_refdb *db; + int error; + + if ((error = git_repository_refdb__weakptr(&db, repo)) < 0) + return error; + + return git_refdb_delete(db, name, NULL, NULL); +} + +int git_reference_lookup(git_reference **ref_out, + git_repository *repo, const char *name) +{ + return git_reference_lookup_resolved(ref_out, repo, name, 0); +} + +int git_reference_name_to_id( + git_oid *out, git_repository *repo, const char *name) +{ + int error; + git_reference *ref; + + if ((error = git_reference_lookup_resolved(&ref, repo, name, -1)) < 0) + return error; + + git_oid_cpy(out, git_reference_target(ref)); + git_reference_free(ref); + return 0; +} + +static int reference_normalize_for_repo( + git_refname_t out, + git_repository *repo, + const char *name, + bool validate) +{ + int precompose; + unsigned int flags = GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL; + + if (!git_repository__configmap_lookup(&precompose, repo, GIT_CONFIGMAP_PRECOMPOSE) && + precompose) + flags |= GIT_REFERENCE_FORMAT__PRECOMPOSE_UNICODE; + + if (!validate) + flags |= GIT_REFERENCE_FORMAT__VALIDATION_DISABLE; + + return git_reference_normalize_name(out, GIT_REFNAME_MAX, name, flags); +} + +int git_reference_lookup_resolved( + git_reference **ref_out, + git_repository *repo, + const char *name, + int max_nesting) +{ + git_refname_t normalized; + git_refdb *refdb; + int error = 0; + + GIT_ASSERT_ARG(ref_out); + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(name); + + if ((error = reference_normalize_for_repo(normalized, repo, name, true)) < 0 || + (error = git_repository_refdb__weakptr(&refdb, repo)) < 0 || + (error = git_refdb_resolve(ref_out, refdb, normalized, max_nesting)) < 0) + return error; + + /* + * The resolved reference may be a symbolic reference in case its + * target doesn't exist. If the user asked us to resolve (e.g. + * `max_nesting != 0`), then we need to return an error in case we got + * a symbolic reference back. + */ + if (max_nesting && git_reference_type(*ref_out) == GIT_REFERENCE_SYMBOLIC) { + git_reference_free(*ref_out); + *ref_out = NULL; + return GIT_ENOTFOUND; + } + + return 0; +} + +int git_reference_dwim(git_reference **out, git_repository *repo, const char *refname) +{ + int error = 0, i, valid; + bool fallbackmode = true, foundvalid = false; + git_reference *ref; + git_str refnamebuf = GIT_STR_INIT, name = GIT_STR_INIT; + + static const char *formatters[] = { + "%s", + GIT_REFS_DIR "%s", + GIT_REFS_TAGS_DIR "%s", + GIT_REFS_HEADS_DIR "%s", + GIT_REFS_REMOTES_DIR "%s", + GIT_REFS_REMOTES_DIR "%s/" GIT_HEAD_FILE, + NULL + }; + + if (*refname) + git_str_puts(&name, refname); + else { + git_str_puts(&name, GIT_HEAD_FILE); + fallbackmode = false; + } + + for (i = 0; formatters[i] && (fallbackmode || i == 0); i++) { + + git_str_clear(&refnamebuf); + + if ((error = git_str_printf(&refnamebuf, formatters[i], git_str_cstr(&name))) < 0 || + (error = git_reference_name_is_valid(&valid, git_str_cstr(&refnamebuf))) < 0) + goto cleanup; + + if (!valid) { + error = GIT_EINVALIDSPEC; + continue; + } + foundvalid = true; + + error = git_reference_lookup_resolved(&ref, repo, git_str_cstr(&refnamebuf), -1); + + if (!error) { + *out = ref; + error = 0; + goto cleanup; + } + + if (error != GIT_ENOTFOUND) + goto cleanup; + } + +cleanup: + if (error && !foundvalid) { + /* never found a valid reference name */ + git_error_set(GIT_ERROR_REFERENCE, + "could not use '%s' as valid reference name", git_str_cstr(&name)); + } + + if (error == GIT_ENOTFOUND) + git_error_set(GIT_ERROR_REFERENCE, "no reference found for shorthand '%s'", refname); + + git_str_dispose(&name); + git_str_dispose(&refnamebuf); + return error; +} + +/** + * Getters + */ +git_reference_t git_reference_type(const git_reference *ref) +{ + GIT_ASSERT_ARG(ref); + return ref->type; +} + +const char *git_reference_name(const git_reference *ref) +{ + GIT_ASSERT_ARG_WITH_RETVAL(ref, NULL); + return ref->name; +} + +git_repository *git_reference_owner(const git_reference *ref) +{ + GIT_ASSERT_ARG_WITH_RETVAL(ref, NULL); + return ref->db->repo; +} + +const git_oid *git_reference_target(const git_reference *ref) +{ + GIT_ASSERT_ARG_WITH_RETVAL(ref, NULL); + + if (ref->type != GIT_REFERENCE_DIRECT) + return NULL; + + return &ref->target.oid; +} + +const git_oid *git_reference_target_peel(const git_reference *ref) +{ + GIT_ASSERT_ARG_WITH_RETVAL(ref, NULL); + + if (ref->type != GIT_REFERENCE_DIRECT || git_oid_is_zero(&ref->peel)) + return NULL; + + return &ref->peel; +} + +const char *git_reference_symbolic_target(const git_reference *ref) +{ + GIT_ASSERT_ARG_WITH_RETVAL(ref, NULL); + + if (ref->type != GIT_REFERENCE_SYMBOLIC) + return NULL; + + return ref->target.symbolic; +} + +static int reference__create( + git_reference **ref_out, + git_repository *repo, + const char *name, + const git_oid *oid, + const char *symbolic, + int force, + const git_signature *signature, + const char *log_message, + const git_oid *old_id, + const char *old_target) +{ + git_refname_t normalized; + git_refdb *refdb; + git_reference *ref = NULL; + int error = 0; + + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(name); + GIT_ASSERT_ARG(symbolic || signature); + + if (ref_out) + *ref_out = NULL; + + error = reference_normalize_for_repo(normalized, repo, name, true); + if (error < 0) + return error; + + error = git_repository_refdb__weakptr(&refdb, repo); + if (error < 0) + return error; + + if (oid != NULL) { + GIT_ASSERT(symbolic == NULL); + + if (!git_object__is_valid(repo, oid, GIT_OBJECT_ANY)) { + git_error_set(GIT_ERROR_REFERENCE, + "target OID for the reference doesn't exist on the repository"); + return -1; + } + + ref = git_reference__alloc(normalized, oid, NULL); + } else { + git_refname_t normalized_target; + + error = reference_normalize_for_repo(normalized_target, repo, + symbolic, git_reference__enable_symbolic_ref_target_validation); + + if (error < 0) + return error; + + ref = git_reference__alloc_symbolic(normalized, normalized_target); + } + + GIT_ERROR_CHECK_ALLOC(ref); + + if ((error = git_refdb_write(refdb, ref, force, signature, log_message, old_id, old_target)) < 0) { + git_reference_free(ref); + return error; + } + + if (ref_out == NULL) + git_reference_free(ref); + else + *ref_out = ref; + + return 0; +} + +static int refs_configured_ident(git_signature **out, const git_repository *repo) +{ + if (repo->ident_name && repo->ident_email) + return git_signature_now(out, repo->ident_name, repo->ident_email); + + /* if not configured let us fall-through to the next method */ + return -1; +} + +int git_reference__log_signature(git_signature **out, git_repository *repo) +{ + int error; + git_signature *who; + + if(((error = refs_configured_ident(&who, repo)) < 0) && + ((error = git_signature_default(&who, repo)) < 0) && + ((error = git_signature_now(&who, "unknown", "unknown")) < 0)) + return error; + + *out = who; + return 0; +} + +int git_reference_create_matching( + git_reference **ref_out, + git_repository *repo, + const char *name, + const git_oid *id, + int force, + const git_oid *old_id, + const char *log_message) + +{ + int error; + git_signature *who = NULL; + + GIT_ASSERT_ARG(id); + + if ((error = git_reference__log_signature(&who, repo)) < 0) + return error; + + error = reference__create( + ref_out, repo, name, id, NULL, force, who, log_message, old_id, NULL); + + git_signature_free(who); + return error; +} + +int git_reference_create( + git_reference **ref_out, + git_repository *repo, + const char *name, + const git_oid *id, + int force, + const char *log_message) +{ + return git_reference_create_matching(ref_out, repo, name, id, force, NULL, log_message); +} + +int git_reference_symbolic_create_matching( + git_reference **ref_out, + git_repository *repo, + const char *name, + const char *target, + int force, + const char *old_target, + const char *log_message) +{ + int error; + git_signature *who = NULL; + + GIT_ASSERT_ARG(target); + + if ((error = git_reference__log_signature(&who, repo)) < 0) + return error; + + error = reference__create( + ref_out, repo, name, NULL, target, force, who, log_message, NULL, old_target); + + git_signature_free(who); + return error; +} + +int git_reference_symbolic_create( + git_reference **ref_out, + git_repository *repo, + const char *name, + const char *target, + int force, + const char *log_message) +{ + return git_reference_symbolic_create_matching(ref_out, repo, name, target, force, NULL, log_message); +} + +static int ensure_is_an_updatable_direct_reference(git_reference *ref) +{ + if (ref->type == GIT_REFERENCE_DIRECT) + return 0; + + git_error_set(GIT_ERROR_REFERENCE, "cannot set OID on symbolic reference"); + return -1; +} + +int git_reference_set_target( + git_reference **out, + git_reference *ref, + const git_oid *id, + const char *log_message) +{ + int error; + git_repository *repo; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(ref); + GIT_ASSERT_ARG(id); + + repo = ref->db->repo; + + if ((error = ensure_is_an_updatable_direct_reference(ref)) < 0) + return error; + + return git_reference_create_matching(out, repo, ref->name, id, 1, &ref->target.oid, log_message); +} + +static int ensure_is_an_updatable_symbolic_reference(git_reference *ref) +{ + if (ref->type == GIT_REFERENCE_SYMBOLIC) + return 0; + + git_error_set(GIT_ERROR_REFERENCE, "cannot set symbolic target on a direct reference"); + return -1; +} + +int git_reference_symbolic_set_target( + git_reference **out, + git_reference *ref, + const char *target, + const char *log_message) +{ + int error; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(ref); + GIT_ASSERT_ARG(target); + + if ((error = ensure_is_an_updatable_symbolic_reference(ref)) < 0) + return error; + + return git_reference_symbolic_create_matching( + out, ref->db->repo, ref->name, target, 1, ref->target.symbolic, log_message); +} + +typedef struct { + const char *old_name; + git_refname_t new_name; +} refs_update_head_payload; + +static int refs_update_head(git_repository *worktree, void *_payload) +{ + refs_update_head_payload *payload = (refs_update_head_payload *)_payload; + git_reference *head = NULL, *updated = NULL; + int error; + + if ((error = git_reference_lookup(&head, worktree, GIT_HEAD_FILE)) < 0) + goto out; + + if (git_reference_type(head) != GIT_REFERENCE_SYMBOLIC || + git__strcmp(git_reference_symbolic_target(head), payload->old_name) != 0) + goto out; + + /* Update HEAD if it was pointing to the reference being renamed */ + if ((error = git_reference_symbolic_set_target(&updated, head, payload->new_name, NULL)) < 0) { + git_error_set(GIT_ERROR_REFERENCE, "failed to update HEAD after renaming reference"); + goto out; + } + +out: + git_reference_free(updated); + git_reference_free(head); + return error; +} + +int git_reference_rename( + git_reference **out, + git_reference *ref, + const char *new_name, + int force, + const char *log_message) +{ + refs_update_head_payload payload; + git_signature *signature = NULL; + git_repository *repo; + int error; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(ref); + + repo = git_reference_owner(ref); + + if ((error = git_reference__log_signature(&signature, repo)) < 0 || + (error = reference_normalize_for_repo(payload.new_name, repo, new_name, true)) < 0 || + (error = git_refdb_rename(out, ref->db, ref->name, payload.new_name, force, signature, log_message)) < 0) + goto out; + + payload.old_name = ref->name; + + /* We may have to update any HEAD that was pointing to the renamed reference. */ + if ((error = git_repository_foreach_worktree(repo, refs_update_head, &payload)) < 0) + goto out; + +out: + git_signature_free(signature); + return error; +} + +int git_reference_resolve(git_reference **ref_out, const git_reference *ref) +{ + switch (git_reference_type(ref)) { + case GIT_REFERENCE_DIRECT: + return git_reference_lookup(ref_out, ref->db->repo, ref->name); + + case GIT_REFERENCE_SYMBOLIC: + return git_reference_lookup_resolved(ref_out, ref->db->repo, ref->target.symbolic, -1); + + default: + git_error_set(GIT_ERROR_REFERENCE, "invalid reference"); + return -1; + } +} + +int git_reference_foreach( + git_repository *repo, + git_reference_foreach_cb callback, + void *payload) +{ + git_reference_iterator *iter; + git_reference *ref; + int error; + + if ((error = git_reference_iterator_new(&iter, repo)) < 0) + return error; + + while (!(error = git_reference_next(&ref, iter))) { + if ((error = callback(ref, payload)) != 0) { + git_error_set_after_callback(error); + break; + } + } + + if (error == GIT_ITEROVER) + error = 0; + + git_reference_iterator_free(iter); + return error; +} + +int git_reference_foreach_name( + git_repository *repo, + git_reference_foreach_name_cb callback, + void *payload) +{ + git_reference_iterator *iter; + const char *refname; + int error; + + if ((error = git_reference_iterator_new(&iter, repo)) < 0) + return error; + + while (!(error = git_reference_next_name(&refname, iter))) { + if ((error = callback(refname, payload)) != 0) { + git_error_set_after_callback(error); + break; + } + } + + if (error == GIT_ITEROVER) + error = 0; + + git_reference_iterator_free(iter); + return error; +} + +int git_reference_foreach_glob( + git_repository *repo, + const char *glob, + git_reference_foreach_name_cb callback, + void *payload) +{ + git_reference_iterator *iter; + const char *refname; + int error; + + if ((error = git_reference_iterator_glob_new(&iter, repo, glob)) < 0) + return error; + + while (!(error = git_reference_next_name(&refname, iter))) { + if ((error = callback(refname, payload)) != 0) { + git_error_set_after_callback(error); + break; + } + } + + if (error == GIT_ITEROVER) + error = 0; + + git_reference_iterator_free(iter); + return error; +} + +int git_reference_iterator_new(git_reference_iterator **out, git_repository *repo) +{ + git_refdb *refdb; + + if (git_repository_refdb__weakptr(&refdb, repo) < 0) + return -1; + + return git_refdb_iterator(out, refdb, NULL); +} + +int git_reference_iterator_glob_new( + git_reference_iterator **out, git_repository *repo, const char *glob) +{ + git_refdb *refdb; + + if (git_repository_refdb__weakptr(&refdb, repo) < 0) + return -1; + + return git_refdb_iterator(out, refdb, glob); +} + +int git_reference_next(git_reference **out, git_reference_iterator *iter) +{ + return git_refdb_iterator_next(out, iter); +} + +int git_reference_next_name(const char **out, git_reference_iterator *iter) +{ + return git_refdb_iterator_next_name(out, iter); +} + +void git_reference_iterator_free(git_reference_iterator *iter) +{ + if (iter == NULL) + return; + + git_refdb_iterator_free(iter); +} + +static int cb__reflist_add(const char *ref, void *data) +{ + char *name = git__strdup(ref); + GIT_ERROR_CHECK_ALLOC(name); + return git_vector_insert((git_vector *)data, name); +} + +int git_reference_list( + git_strarray *array, + git_repository *repo) +{ + git_vector ref_list; + + GIT_ASSERT_ARG(array); + GIT_ASSERT_ARG(repo); + + array->strings = NULL; + array->count = 0; + + if (git_vector_init(&ref_list, 8, NULL) < 0) + return -1; + + if (git_reference_foreach_name( + repo, &cb__reflist_add, (void *)&ref_list) < 0) { + git_vector_free(&ref_list); + return -1; + } + + array->strings = (char **)git_vector_detach(&array->count, NULL, &ref_list); + + return 0; +} + +static int is_valid_ref_char(char ch) +{ + if ((unsigned) ch <= ' ') + return 0; + + switch (ch) { + case '~': + case '^': + case ':': + case '\\': + case '?': + case '[': + return 0; + default: + return 1; + } +} + +static int ensure_segment_validity(const char *name, char may_contain_glob) +{ + const char *current = name; + char prev = '\0'; + const int lock_len = (int)strlen(GIT_FILELOCK_EXTENSION); + int segment_len; + + if (*current == '.') + return -1; /* Refname starts with "." */ + + for (current = name; ; current++) { + if (*current == '\0' || *current == '/') + break; + + if (!is_valid_ref_char(*current)) + return -1; /* Illegal character in refname */ + + if (prev == '.' && *current == '.') + return -1; /* Refname contains ".." */ + + if (prev == '@' && *current == '{') + return -1; /* Refname contains "@{" */ + + if (*current == '*') { + if (!may_contain_glob) + return -1; + may_contain_glob = 0; + } + + prev = *current; + } + + segment_len = (int)(current - name); + + /* A refname component can not end with ".lock" */ + if (segment_len >= lock_len && + !memcmp(current - lock_len, GIT_FILELOCK_EXTENSION, lock_len)) + return -1; + + return segment_len; +} + +static bool is_all_caps_and_underscore(const char *name, size_t len) +{ + size_t i; + char c; + + GIT_ASSERT_ARG(name); + GIT_ASSERT_ARG(len > 0); + + for (i = 0; i < len; i++) + { + c = name[i]; + if ((c < 'A' || c > 'Z') && c != '_') + return false; + } + + if (*name == '_' || name[len - 1] == '_') + return false; + + return true; +} + +/* Inspired from https://github.com/git/git/blob/f06d47e7e0d9db709ee204ed13a8a7486149f494/refs.c#L36-100 */ +int git_reference__normalize_name( + git_str *buf, + const char *name, + unsigned int flags) +{ + const char *current; + int segment_len, segments_count = 0, error = GIT_EINVALIDSPEC; + unsigned int process_flags; + bool normalize = (buf != NULL); + bool validate = (flags & GIT_REFERENCE_FORMAT__VALIDATION_DISABLE) == 0; + +#ifdef GIT_USE_ICONV + git_fs_path_iconv_t ic = GIT_PATH_ICONV_INIT; +#endif + + GIT_ASSERT_ARG(name); + + process_flags = flags; + current = (char *)name; + + if (validate && *current == '/') + goto cleanup; + + if (normalize) + git_str_clear(buf); + +#ifdef GIT_USE_ICONV + if ((flags & GIT_REFERENCE_FORMAT__PRECOMPOSE_UNICODE) != 0) { + size_t namelen = strlen(current); + if ((error = git_fs_path_iconv_init_precompose(&ic)) < 0 || + (error = git_fs_path_iconv(&ic, ¤t, &namelen)) < 0) + goto cleanup; + error = GIT_EINVALIDSPEC; + } +#endif + + if (!validate) { + git_str_sets(buf, current); + + error = git_str_oom(buf) ? -1 : 0; + goto cleanup; + } + + while (true) { + char may_contain_glob = process_flags & GIT_REFERENCE_FORMAT_REFSPEC_PATTERN; + + segment_len = ensure_segment_validity(current, may_contain_glob); + if (segment_len < 0) + goto cleanup; + + if (segment_len > 0) { + /* + * There may only be one glob in a pattern, thus we reset + * the pattern-flag in case the current segment has one. + */ + if (memchr(current, '*', segment_len)) + process_flags &= ~GIT_REFERENCE_FORMAT_REFSPEC_PATTERN; + + if (normalize) { + size_t cur_len = git_str_len(buf); + + git_str_joinpath(buf, git_str_cstr(buf), current); + git_str_truncate(buf, + cur_len + segment_len + (segments_count ? 1 : 0)); + + if (git_str_oom(buf)) { + error = -1; + goto cleanup; + } + } + + segments_count++; + } + + /* No empty segment is allowed when not normalizing */ + if (segment_len == 0 && !normalize) + goto cleanup; + + if (current[segment_len] == '\0') + break; + + current += segment_len + 1; + } + + /* A refname can not be empty */ + if (segment_len == 0 && segments_count == 0) + goto cleanup; + + /* A refname can not end with "." */ + if (current[segment_len - 1] == '.') + goto cleanup; + + /* A refname can not end with "/" */ + if (current[segment_len - 1] == '/') + goto cleanup; + + if ((segments_count == 1 ) && !(flags & GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL)) + goto cleanup; + + if ((segments_count == 1 ) && + !(flags & GIT_REFERENCE_FORMAT_REFSPEC_SHORTHAND) && + !(is_all_caps_and_underscore(name, (size_t)segment_len) || + ((flags & GIT_REFERENCE_FORMAT_REFSPEC_PATTERN) && !strcmp("*", name)))) + goto cleanup; + + if ((segments_count > 1) + && (is_all_caps_and_underscore(name, strchr(name, '/') - name))) + goto cleanup; + + error = 0; + +cleanup: + if (error == GIT_EINVALIDSPEC) + git_error_set( + GIT_ERROR_REFERENCE, + "the given reference name '%s' is not valid", name); + + if (error && normalize) + git_str_dispose(buf); + +#ifdef GIT_USE_ICONV + git_fs_path_iconv_clear(&ic); +#endif + + return error; +} + +int git_reference_normalize_name( + char *buffer_out, + size_t buffer_size, + const char *name, + unsigned int flags) +{ + git_str buf = GIT_STR_INIT; + int error; + + if ((error = git_reference__normalize_name(&buf, name, flags)) < 0) + goto cleanup; + + if (git_str_len(&buf) > buffer_size - 1) { + git_error_set( + GIT_ERROR_REFERENCE, + "the provided buffer is too short to hold the normalization of '%s'", name); + error = GIT_EBUFS; + goto cleanup; + } + + if ((error = git_str_copy_cstr(buffer_out, buffer_size, &buf)) < 0) + goto cleanup; + + error = 0; + +cleanup: + git_str_dispose(&buf); + return error; +} + +#define GIT_REFERENCE_TYPEMASK (GIT_REFERENCE_DIRECT | GIT_REFERENCE_SYMBOLIC) + +int git_reference_cmp( + const git_reference *ref1, + const git_reference *ref2) +{ + git_reference_t type1, type2; + + GIT_ASSERT_ARG(ref1); + GIT_ASSERT_ARG(ref2); + + type1 = git_reference_type(ref1); + type2 = git_reference_type(ref2); + + /* let's put symbolic refs before OIDs */ + if (type1 != type2) + return (type1 == GIT_REFERENCE_SYMBOLIC) ? -1 : 1; + + if (type1 == GIT_REFERENCE_SYMBOLIC) + return strcmp(ref1->target.symbolic, ref2->target.symbolic); + + return git_oid__cmp(&ref1->target.oid, &ref2->target.oid); +} + +int git_reference__cmp_cb(const void *a, const void *b) +{ + return git_reference_cmp( + (const git_reference *)a, (const git_reference *)b); +} + +/* + * Starting with the reference given by `ref_name`, follows symbolic + * references until a direct reference is found and updated the OID + * on that direct reference to `oid`. + */ +int git_reference__update_terminal( + git_repository *repo, + const char *ref_name, + const git_oid *oid, + const git_signature *sig, + const char *log_message) +{ + git_reference *ref = NULL, *ref2 = NULL; + git_signature *who = NULL; + git_refdb *refdb = NULL; + const git_signature *to_use; + int error = 0; + + if (!sig && (error = git_reference__log_signature(&who, repo)) < 0) + goto out; + + to_use = sig ? sig : who; + + if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) + goto out; + + if ((error = git_refdb_resolve(&ref, refdb, ref_name, -1)) < 0) { + if (error == GIT_ENOTFOUND) { + git_error_clear(); + error = reference__create(&ref2, repo, ref_name, oid, NULL, 0, to_use, + log_message, NULL, NULL); + } + goto out; + } + + /* In case the resolved reference is symbolic, then it's a dangling symref. */ + if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) { + error = reference__create(&ref2, repo, ref->target.symbolic, oid, NULL, 0, to_use, + log_message, NULL, NULL); + } else { + error = reference__create(&ref2, repo, ref->name, oid, NULL, 1, to_use, + log_message, &ref->target.oid, NULL); + } + +out: + git_reference_free(ref2); + git_reference_free(ref); + git_signature_free(who); + return error; +} + +static const char *commit_type(const git_commit *commit) +{ + unsigned int count = git_commit_parentcount(commit); + + if (count >= 2) + return " (merge)"; + else if (count == 0) + return " (initial)"; + else + return ""; +} + +int git_reference__update_for_commit( + git_repository *repo, + git_reference *ref, + const char *ref_name, + const git_oid *id, + const char *operation) +{ + git_reference *ref_new = NULL; + git_commit *commit = NULL; + git_str reflog_msg = GIT_STR_INIT; + const git_signature *who; + int error; + + if ((error = git_commit_lookup(&commit, repo, id)) < 0 || + (error = git_str_printf(&reflog_msg, "%s%s: %s", + operation ? operation : "commit", + commit_type(commit), + git_commit_summary(commit))) < 0) + goto done; + + who = git_commit_committer(commit); + + if (ref) { + if ((error = ensure_is_an_updatable_direct_reference(ref)) < 0) + return error; + + error = reference__create(&ref_new, repo, ref->name, id, NULL, 1, who, + git_str_cstr(&reflog_msg), &ref->target.oid, NULL); + } + else + error = git_reference__update_terminal( + repo, ref_name, id, who, git_str_cstr(&reflog_msg)); + +done: + git_reference_free(ref_new); + git_str_dispose(&reflog_msg); + git_commit_free(commit); + return error; +} + +int git_reference_has_log(git_repository *repo, const char *refname) +{ + int error; + git_refdb *refdb; + + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(refname); + + if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) + return error; + + return git_refdb_has_log(refdb, refname); +} + +int git_reference_ensure_log(git_repository *repo, const char *refname) +{ + int error; + git_refdb *refdb; + + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(refname); + + if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) + return error; + + return git_refdb_ensure_log(refdb, refname); +} + +int git_reference__is_branch(const char *ref_name) +{ + return git__prefixcmp(ref_name, GIT_REFS_HEADS_DIR) == 0; +} + +int git_reference_is_branch(const git_reference *ref) +{ + GIT_ASSERT_ARG(ref); + return git_reference__is_branch(ref->name); +} + +int git_reference__is_remote(const char *ref_name) +{ + return git__prefixcmp(ref_name, GIT_REFS_REMOTES_DIR) == 0; +} + +int git_reference_is_remote(const git_reference *ref) +{ + GIT_ASSERT_ARG(ref); + return git_reference__is_remote(ref->name); +} + +int git_reference__is_tag(const char *ref_name) +{ + return git__prefixcmp(ref_name, GIT_REFS_TAGS_DIR) == 0; +} + +int git_reference_is_tag(const git_reference *ref) +{ + GIT_ASSERT_ARG(ref); + return git_reference__is_tag(ref->name); +} + +int git_reference__is_note(const char *ref_name) +{ + return git__prefixcmp(ref_name, GIT_REFS_NOTES_DIR) == 0; +} + +int git_reference_is_note(const git_reference *ref) +{ + GIT_ASSERT_ARG(ref); + return git_reference__is_note(ref->name); +} + +static int peel_error(int error, const git_reference *ref, const char *msg) +{ + git_error_set( + GIT_ERROR_INVALID, + "the reference '%s' cannot be peeled - %s", git_reference_name(ref), msg); + return error; +} + +int git_reference_peel( + git_object **peeled, + const git_reference *ref, + git_object_t target_type) +{ + const git_reference *resolved = NULL; + git_reference *allocated = NULL; + git_object *target = NULL; + int error; + + GIT_ASSERT_ARG(ref); + + if (ref->type == GIT_REFERENCE_DIRECT) { + resolved = ref; + } else { + if ((error = git_reference_resolve(&allocated, ref)) < 0) + return peel_error(error, ref, "Cannot resolve reference"); + + resolved = allocated; + } + + /* + * If we try to peel an object to a tag, we cannot use + * the fully peeled object, as that will always resolve + * to a commit. So we only want to use the peeled value + * if it is not zero and the target is not a tag. + */ + if (target_type != GIT_OBJECT_TAG && !git_oid_is_zero(&resolved->peel)) { + error = git_object_lookup(&target, + git_reference_owner(ref), &resolved->peel, GIT_OBJECT_ANY); + } else { + error = git_object_lookup(&target, + git_reference_owner(ref), &resolved->target.oid, GIT_OBJECT_ANY); + } + + if (error < 0) { + peel_error(error, ref, "Cannot retrieve reference target"); + goto cleanup; + } + + if (target_type == GIT_OBJECT_ANY && git_object_type(target) != GIT_OBJECT_TAG) + error = git_object_dup(peeled, target); + else + error = git_object_peel(peeled, target, target_type); + +cleanup: + git_object_free(target); + git_reference_free(allocated); + + return error; +} + +int git_reference__name_is_valid( + int *valid, + const char *refname, + unsigned int flags) +{ + int error; + + GIT_ASSERT(valid && refname); + + *valid = 0; + + error = git_reference__normalize_name(NULL, refname, flags); + + if (!error) + *valid = 1; + else if (error == GIT_EINVALIDSPEC) + error = 0; + + return error; +} + +int git_reference_name_is_valid(int *valid, const char *refname) +{ + return git_reference__name_is_valid(valid, refname, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL); +} + +const char *git_reference__shorthand(const char *name) +{ + if (!git__prefixcmp(name, GIT_REFS_HEADS_DIR)) + return name + strlen(GIT_REFS_HEADS_DIR); + else if (!git__prefixcmp(name, GIT_REFS_TAGS_DIR)) + return name + strlen(GIT_REFS_TAGS_DIR); + else if (!git__prefixcmp(name, GIT_REFS_REMOTES_DIR)) + return name + strlen(GIT_REFS_REMOTES_DIR); + else if (!git__prefixcmp(name, GIT_REFS_DIR)) + return name + strlen(GIT_REFS_DIR); + + /* No shorthands are available, so just return the name. */ + return name; +} + +const char *git_reference_shorthand(const git_reference *ref) +{ + return git_reference__shorthand(ref->name); +} + +int git_reference__is_unborn_head(bool *unborn, const git_reference *ref, git_repository *repo) +{ + int error; + git_reference *tmp_ref; + + GIT_ASSERT_ARG(unborn); + GIT_ASSERT_ARG(ref); + GIT_ASSERT_ARG(repo); + + if (ref->type == GIT_REFERENCE_DIRECT) { + *unborn = 0; + return 0; + } + + error = git_reference_lookup_resolved(&tmp_ref, repo, ref->name, -1); + git_reference_free(tmp_ref); + + if (error != 0 && error != GIT_ENOTFOUND) + return error; + else if (error == GIT_ENOTFOUND && git__strcmp(ref->name, GIT_HEAD_FILE) == 0) + *unborn = true; + else + *unborn = false; + + return 0; +} + +/* Deprecated functions */ + +#ifndef GIT_DEPRECATE_HARD + +int git_reference_is_valid_name(const char *refname) +{ + int valid = 0; + + git_reference__name_is_valid(&valid, refname, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL); + + return valid; +} + +#endif diff --git a/vendor/libgit2/src/refs.h b/vendor/libgit2/src/libgit2/refs.h similarity index 96% rename from vendor/libgit2/src/refs.h rename to vendor/libgit2/src/libgit2/refs.h index cb888bf8..588af82f 100644 --- a/vendor/libgit2/src/refs.h +++ b/vendor/libgit2/src/libgit2/refs.h @@ -92,6 +92,12 @@ int git_reference__is_tag(const char *ref_name); int git_reference__is_note(const char *ref_name); const char *git_reference__shorthand(const char *name); +/* + * A `git_reference_cmp` wrapper suitable for passing to generic + * comparators, like `vector_cmp` / `tsort` / etc. + */ +int git_reference__cmp_cb(const void *a, const void *b); + /** * Lookup a reference by name and try to resolve to an OID. * diff --git a/vendor/libgit2/src/refspec.c b/vendor/libgit2/src/libgit2/refspec.c similarity index 100% rename from vendor/libgit2/src/refspec.c rename to vendor/libgit2/src/libgit2/refspec.c diff --git a/vendor/libgit2/src/refspec.h b/vendor/libgit2/src/libgit2/refspec.h similarity index 100% rename from vendor/libgit2/src/refspec.h rename to vendor/libgit2/src/libgit2/refspec.h diff --git a/vendor/libgit2/src/remote.c b/vendor/libgit2/src/libgit2/remote.c similarity index 95% rename from vendor/libgit2/src/remote.c rename to vendor/libgit2/src/libgit2/remote.c index 1a79faaa..8b486ea3 100644 --- a/vendor/libgit2/src/remote.c +++ b/vendor/libgit2/src/libgit2/remote.c @@ -17,11 +17,13 @@ #include "fetchhead.h" #include "push.h" #include "proxy.h" +#include "strarray.h" #include "git2/config.h" #include "git2/types.h" #include "git2/oid.h" #include "git2/net.h" +#include "transports/smart.h" #define CONFIG_URL_FMT "remote.%s.url" #define CONFIG_PUSHURL_FMT "remote.%s.pushurl" @@ -1026,6 +1028,24 @@ int git_remote_capabilities(unsigned int *out, git_remote *remote) return remote->transport->capabilities(out, remote->transport); } +int git_remote_oid_type(git_oid_t *out, git_remote *remote) +{ + GIT_ASSERT_ARG(remote); + + if (!remote->transport) { + git_error_set(GIT_ERROR_NET, "this remote has never connected"); + *out = 0; + return -1; + } + +#ifdef GIT_EXPERIMENTAL_SHA256 + return remote->transport->oid_type(out, remote->transport); +#else + *out = GIT_OID_SHA1; + return 0; +#endif +} + static int lookup_config(char **out, git_config *cfg, const char *name) { git_config_entry *ce = NULL; @@ -1225,24 +1245,6 @@ static int ls_to_vector(git_vector *out, git_remote *remote) return 0; } -#define copy_opts(out, in) \ - if (in) { \ - (out)->callbacks = (in)->callbacks; \ - (out)->proxy_opts = (in)->proxy_opts; \ - (out)->custom_headers = (in)->custom_headers; \ - (out)->follow_redirects = (in)->follow_redirects; \ - } - -GIT_INLINE(int) connect_opts_from_fetch_opts( - git_remote_connect_options *out, - git_remote *remote, - const git_fetch_options *fetch_opts) -{ - git_remote_connect_options tmp = GIT_REMOTE_CONNECT_OPTIONS_INIT; - copy_opts(&tmp, fetch_opts); - return git_remote_connect_options_normalize(out, remote->repo, &tmp); -} - static int connect_or_reset_options( git_remote *remote, int direction, @@ -1330,13 +1332,18 @@ int git_remote_download( return -1; } - if (connect_opts_from_fetch_opts(&connect_opts, remote, opts) < 0) + if (git_remote_connect_options__from_fetch_opts(&connect_opts, + remote, opts) < 0) return -1; if ((error = connect_or_reset_options(remote, GIT_DIRECTION_FETCH, &connect_opts)) < 0) return error; - return git_remote__download(remote, refspecs, opts); + error = git_remote__download(remote, refspecs, opts); + + git_remote_connect_options_dispose(&connect_opts); + + return error; } int git_remote_fetch( @@ -1345,11 +1352,14 @@ int git_remote_fetch( const git_fetch_options *opts, const char *reflog_message) { - int error, update_fetchhead = 1; git_remote_autotag_option_t tagopt = remote->download_tags; bool prune = false; git_str reflog_msg_buf = GIT_STR_INIT; git_remote_connect_options connect_opts = GIT_REMOTE_CONNECT_OPTIONS_INIT; + unsigned int capabilities; + git_oid_t oid_type; + unsigned int update_flags = GIT_REMOTE_UPDATE_FETCHHEAD; + int error; GIT_ASSERT_ARG(remote); @@ -1358,17 +1368,22 @@ int git_remote_fetch( return -1; } - if (connect_opts_from_fetch_opts(&connect_opts, remote, opts) < 0) + if (git_remote_connect_options__from_fetch_opts(&connect_opts, + remote, opts) < 0) return -1; if ((error = connect_or_reset_options(remote, GIT_DIRECTION_FETCH, &connect_opts)) < 0) return error; if (opts) { - update_fetchhead = opts->update_fetchhead; + update_flags = opts->update_fetchhead; tagopt = opts->download_tags; } + if ((error = git_remote_capabilities(&capabilities, remote)) < 0 || + (error = git_remote_oid_type(&oid_type, remote)) < 0) + return error; + /* Connect and download everything */ error = git_remote__download(remote, refspecs, opts); @@ -1388,8 +1403,14 @@ int git_remote_fetch( } /* Create "remote/foo" branches for all remote branches */ - error = git_remote_update_tips(remote, &connect_opts.callbacks, update_fetchhead, tagopt, git_str_cstr(&reflog_msg_buf)); + error = git_remote_update_tips(remote, + &connect_opts.callbacks, + update_flags, + tagopt, + git_str_cstr(&reflog_msg_buf)); + git_str_dispose(&reflog_msg_buf); + if (error < 0) goto done; @@ -1622,7 +1643,10 @@ int git_remote_prune(git_remote *remote, const git_remote_callbacks *callbacks) const git_refspec *spec; const char *refname; int error; - git_oid zero_id = {{ 0 }}; + git_oid zero_id; + + GIT_ASSERT(remote && remote->repo); + git_oid_clear(&zero_id, remote->repo->oid_type); if (callbacks) GIT_ERROR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks"); @@ -1727,6 +1751,9 @@ static int update_ref( git_oid old_id; int error; + GIT_ASSERT(remote && remote->repo); + git_oid_clear(&old_id, remote->repo->oid_type); + error = git_reference_name_to_id(&old_id, remote->repo, ref_name); if (error < 0 && error != GIT_ENOTFOUND) @@ -1758,6 +1785,7 @@ static int update_one_tip( git_refspec *spec, git_remote_head *head, git_refspec *tagspec, + unsigned int update_flags, git_remote_autotag_option_t tagopt, const char *log_message, const git_remote_callbacks *callbacks) @@ -1765,11 +1793,13 @@ static int update_one_tip( git_odb *odb; git_str refname = GIT_STR_INIT; git_reference *ref = NULL; - bool autotag = false; + bool autotag = false, updated = false; git_oid old; int valid; int error; + GIT_ASSERT(remote && remote->repo); + if ((error = git_repository_odb__weakptr(&odb, remote->repo)) < 0) goto done; @@ -1830,28 +1860,28 @@ static int update_one_tip( } if (error == GIT_ENOTFOUND) { - memset(&old, 0, GIT_OID_RAWSZ); + git_oid_clear(&old, remote->repo->oid_type); error = 0; if (autotag && (error = git_vector_insert(update_heads, head)) < 0) goto done; } - if (!git_oid__cmp(&old, &head->oid)) - goto done; + if ((updated = !git_oid_equal(&old, &head->oid))) { + /* In autotag mode, don't overwrite any locally-existing tags */ + error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag, + log_message); - /* In autotag mode, don't overwrite any locally-existing tags */ - error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag, - log_message); + if (error < 0) { + if (error == GIT_EEXISTS) + error = 0; - if (error < 0) { - if (error == GIT_EEXISTS) - error = 0; - - goto done; + goto done; + } } if (callbacks && callbacks->update_tips != NULL && + (updated || (update_flags & GIT_REMOTE_UPDATE_REPORT_UNCHANGED)) && (error = callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload)) < 0) git_error_set_after_callback_function(error, "git_remote_fetch"); @@ -1864,7 +1894,7 @@ static int update_one_tip( static int update_tips_for_spec( git_remote *remote, const git_remote_callbacks *callbacks, - int update_fetchhead, + unsigned int update_flags, git_remote_autotag_option_t tagopt, git_refspec *spec, git_vector *refs, @@ -1876,7 +1906,7 @@ static int update_tips_for_spec( int error = 0; size_t i; - GIT_ASSERT_ARG(remote); + GIT_ASSERT_ARG(remote && remote->repo); if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0) return -1; @@ -1887,15 +1917,18 @@ static int update_tips_for_spec( /* Update tips based on the remote heads */ git_vector_foreach(refs, i, head) { - if (update_one_tip(&update_heads, remote, spec, head, &tagspec, tagopt, log_message, callbacks) < 0) + if (update_one_tip(&update_heads, + remote, spec, head, &tagspec, + update_flags, tagopt, log_message, + callbacks) < 0) goto on_error; } /* Handle specified oid sources */ - if (git_oid__is_hexstr(spec->src)) { + if (git_oid__is_hexstr(spec->src, remote->repo->oid_type)) { git_oid id; - if ((error = git_oid_fromstr(&id, spec->src)) < 0) + if ((error = git_oid__fromstr(&id, spec->src, remote->repo->oid_type)) < 0) goto on_error; if (spec->dst && @@ -1909,7 +1942,7 @@ static int update_tips_for_spec( goto on_error; } - if (update_fetchhead && + if ((update_flags & GIT_REMOTE_UPDATE_FETCHHEAD) && (error = git_remote_write_fetchhead(remote, spec, &update_heads)) < 0) goto on_error; @@ -2040,11 +2073,11 @@ static int truncate_fetch_head(const char *gitdir) } int git_remote_update_tips( - git_remote *remote, - const git_remote_callbacks *callbacks, - int update_fetchhead, - git_remote_autotag_option_t download_tags, - const char *reflog_message) + git_remote *remote, + const git_remote_callbacks *callbacks, + unsigned int update_flags, + git_remote_autotag_option_t download_tags, + const char *reflog_message) { git_refspec *spec, tagspec; git_vector refs = GIT_VECTOR_INIT; @@ -2073,7 +2106,7 @@ int git_remote_update_tips( goto out; if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_ALL) { - if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, &tagspec, &refs, reflog_message)) < 0) + if ((error = update_tips_for_spec(remote, callbacks, update_flags, tagopt, &tagspec, &refs, reflog_message)) < 0) goto out; } @@ -2081,7 +2114,7 @@ int git_remote_update_tips( if (spec->push) continue; - if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, spec, &refs, reflog_message)) < 0) + if ((error = update_tips_for_spec(remote, callbacks, update_flags, tagopt, spec, &refs, reflog_message)) < 0) goto out; } @@ -2896,16 +2929,6 @@ int git_remote__default_branch(git_str *out, git_remote *remote) return error; } -GIT_INLINE(int) connect_opts_from_push_opts( - git_remote_connect_options *out, - git_remote *remote, - const git_push_options *push_opts) -{ - git_remote_connect_options tmp = GIT_REMOTE_CONNECT_OPTIONS_INIT; - copy_opts(&tmp, push_opts); - return git_remote_connect_options_normalize(out, remote->repo, &tmp); -} - int git_remote_upload( git_remote *remote, const git_strarray *refspecs, @@ -2924,7 +2947,8 @@ int git_remote_upload( return -1; } - if ((error = connect_opts_from_push_opts(&connect_opts, remote, opts)) < 0) + if ((error = git_remote_connect_options__from_push_opts( + &connect_opts, remote, opts)) < 0) goto cleanup; if ((error = connect_or_reset_options(remote, GIT_DIRECTION_PUSH, &connect_opts)) < 0) @@ -2958,6 +2982,15 @@ int git_remote_upload( } } + if (opts && opts->remote_push_options.count > 0) + for (i = 0; i < opts->remote_push_options.count; ++i) { + char *optstr = git__strdup(opts->remote_push_options.strings[i]); + GIT_ERROR_CHECK_ALLOC(optstr); + + if ((error = git_vector_insert(&push->remote_push_options, optstr)) < 0) + goto cleanup; + } + if ((error = git_push_finish(push)) < 0) goto cleanup; @@ -2985,7 +3018,8 @@ int git_remote_push( return -1; } - if (connect_opts_from_push_opts(&connect_opts, remote, opts) < 0) + if (git_remote_connect_options__from_push_opts(&connect_opts, + remote, opts) < 0) return -1; if ((error = git_remote_upload(remote, refspecs, opts)) < 0) diff --git a/vendor/libgit2/src/libgit2/remote.h b/vendor/libgit2/src/libgit2/remote.h new file mode 100644 index 00000000..9e089be3 --- /dev/null +++ b/vendor/libgit2/src/libgit2/remote.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_remote_h__ +#define INCLUDE_remote_h__ + +#include "common.h" + +#include "git2/remote.h" +#include "git2/transport.h" +#include "git2/sys/remote.h" +#include "git2/sys/transport.h" + +#include "refspec.h" +#include "vector.h" +#include "net.h" +#include "proxy.h" + +#define GIT_REMOTE_ORIGIN "origin" + +struct git_remote { + char *name; + char *url; + char *pushurl; + git_vector refs; + git_vector refspecs; + git_vector active_refspecs; + git_vector passive_refspecs; + git_vector local_heads; + git_transport *transport; + git_repository *repo; + git_push *push; + git_indexer_progress stats; + unsigned int need_pack; + git_remote_autotag_option_t download_tags; + int prune_refs; + int passed_refspecs; + git_fetch_negotiation nego; +}; + +int git_remote__urlfordirection(git_str *url_out, struct git_remote *remote, int direction, const git_remote_callbacks *callbacks); +int git_remote__http_proxy(char **out, git_remote *remote, git_net_url *url); + +git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname); +git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname); + +int git_remote__default_branch(git_str *out, git_remote *remote); + +int git_remote_connect_options_dup( + git_remote_connect_options *dst, + const git_remote_connect_options *src); +int git_remote_connect_options_normalize( + git_remote_connect_options *dst, + git_repository *repo, + const git_remote_connect_options *src); + +int git_remote_capabilities(unsigned int *out, git_remote *remote); +int git_remote_oid_type(git_oid_t *out, git_remote *remote); + + +#define git_remote_connect_options__copy_opts(out, in) \ + if (in) { \ + (out)->callbacks = (in)->callbacks; \ + (out)->proxy_opts = (in)->proxy_opts; \ + (out)->custom_headers = (in)->custom_headers; \ + (out)->follow_redirects = (in)->follow_redirects; \ + } + +GIT_INLINE(int) git_remote_connect_options__from_fetch_opts( + git_remote_connect_options *out, + git_remote *remote, + const git_fetch_options *fetch_opts) +{ + git_remote_connect_options tmp = GIT_REMOTE_CONNECT_OPTIONS_INIT; + git_remote_connect_options__copy_opts(&tmp, fetch_opts); + return git_remote_connect_options_normalize(out, remote->repo, &tmp); +} + +GIT_INLINE(int) git_remote_connect_options__from_push_opts( + git_remote_connect_options *out, + git_remote *remote, + const git_push_options *push_opts) +{ + git_remote_connect_options tmp = GIT_REMOTE_CONNECT_OPTIONS_INIT; + git_remote_connect_options__copy_opts(&tmp, push_opts); + return git_remote_connect_options_normalize(out, remote->repo, &tmp); +} + +#undef git_remote_connect_options__copy_opts + +GIT_INLINE(void) git_remote_connect_options__dispose( + git_remote_connect_options *opts) +{ + git_proxy_options_dispose(&opts->proxy_opts); + git_strarray_dispose(&opts->custom_headers); +} + +#endif diff --git a/vendor/libgit2/src/repo_template.h b/vendor/libgit2/src/libgit2/repo_template.h similarity index 100% rename from vendor/libgit2/src/repo_template.h rename to vendor/libgit2/src/libgit2/repo_template.h diff --git a/vendor/libgit2/src/libgit2/repository.c b/vendor/libgit2/src/libgit2/repository.c new file mode 100644 index 00000000..8e449a6d --- /dev/null +++ b/vendor/libgit2/src/libgit2/repository.c @@ -0,0 +1,4011 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "repository.h" + +#include + +#include "git2/object.h" +#include "git2/sys/repository.h" + +#include "buf.h" +#include "common.h" +#include "commit.h" +#include "grafts.h" +#include "tag.h" +#include "blob.h" +#include "futils.h" +#include "sysdir.h" +#include "filebuf.h" +#include "index.h" +#include "config.h" +#include "refs.h" +#include "filter.h" +#include "odb.h" +#include "refdb.h" +#include "remote.h" +#include "merge.h" +#include "diff_driver.h" +#include "annotated_commit.h" +#include "submodule.h" +#include "worktree.h" +#include "path.h" +#include "strmap.h" + +#ifdef GIT_WIN32 +# include "win32/w32_util.h" +#endif + +bool git_repository__validate_ownership = true; +bool git_repository__fsync_gitdir = false; + +static const struct { + git_repository_item_t parent; + git_repository_item_t fallback; + const char *name; + bool directory; +} items[] = { + { GIT_REPOSITORY_ITEM_GITDIR, GIT_REPOSITORY_ITEM__LAST, NULL, true }, + { GIT_REPOSITORY_ITEM_WORKDIR, GIT_REPOSITORY_ITEM__LAST, NULL, true }, + { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM__LAST, NULL, true }, + { GIT_REPOSITORY_ITEM_GITDIR, GIT_REPOSITORY_ITEM__LAST, "index", false }, + { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "objects", true }, + { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "refs", true }, + { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "packed-refs", false }, + { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "remotes", true }, + { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "config", false }, + { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "info", true }, + { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "hooks", true }, + { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "logs", true }, + { GIT_REPOSITORY_ITEM_GITDIR, GIT_REPOSITORY_ITEM__LAST, "modules", true }, + { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "worktrees", true }, + { GIT_REPOSITORY_ITEM_GITDIR, GIT_REPOSITORY_ITEM_GITDIR, "config.worktree", false } +}; + +static int check_repositoryformatversion(int *version, git_config *config); +static int check_extensions(git_config *config, int version); +static int load_global_config(git_config **config, bool use_env); +static int load_objectformat(git_repository *repo, git_config *config); + +#define GIT_COMMONDIR_FILE "commondir" +#define GIT_GITDIR_FILE "gitdir" + +#define GIT_FILE_CONTENT_PREFIX "gitdir:" + +#define GIT_BRANCH_DEFAULT "master" + +#define GIT_REPO_VERSION_DEFAULT 0 +#define GIT_REPO_VERSION_MAX 1 + +git_str git_repository__reserved_names_win32[] = { + { DOT_GIT, 0, CONST_STRLEN(DOT_GIT) }, + { GIT_DIR_SHORTNAME, 0, CONST_STRLEN(GIT_DIR_SHORTNAME) } +}; +size_t git_repository__reserved_names_win32_len = 2; + +git_str git_repository__reserved_names_posix[] = { + { DOT_GIT, 0, CONST_STRLEN(DOT_GIT) }, +}; +size_t git_repository__reserved_names_posix_len = 1; + +static void set_odb(git_repository *repo, git_odb *odb) +{ + if (odb) { + GIT_REFCOUNT_OWN(odb, repo); + GIT_REFCOUNT_INC(odb); + } + + if ((odb = git_atomic_swap(repo->_odb, odb)) != NULL) { + GIT_REFCOUNT_OWN(odb, NULL); + git_odb_free(odb); + } +} + +static void set_refdb(git_repository *repo, git_refdb *refdb) +{ + if (refdb) { + GIT_REFCOUNT_OWN(refdb, repo); + GIT_REFCOUNT_INC(refdb); + } + + if ((refdb = git_atomic_swap(repo->_refdb, refdb)) != NULL) { + GIT_REFCOUNT_OWN(refdb, NULL); + git_refdb_free(refdb); + } +} + +static void set_config(git_repository *repo, git_config *config) +{ + if (config) { + GIT_REFCOUNT_OWN(config, repo); + GIT_REFCOUNT_INC(config); + } + + if ((config = git_atomic_swap(repo->_config, config)) != NULL) { + GIT_REFCOUNT_OWN(config, NULL); + git_config_free(config); + } + + git_repository__configmap_lookup_cache_clear(repo); +} + +static void set_index(git_repository *repo, git_index *index) +{ + if (index) { + GIT_REFCOUNT_OWN(index, repo); + GIT_REFCOUNT_INC(index); + } + + if ((index = git_atomic_swap(repo->_index, index)) != NULL) { + GIT_REFCOUNT_OWN(index, NULL); + git_index_free(index); + } +} + +int git_repository__cleanup(git_repository *repo) +{ + GIT_ASSERT_ARG(repo); + + git_repository_submodule_cache_clear(repo); + git_cache_clear(&repo->objects); + git_attr_cache_flush(repo); + git_grafts_free(repo->grafts); + repo->grafts = NULL; + git_grafts_free(repo->shallow_grafts); + repo->shallow_grafts = NULL; + + set_config(repo, NULL); + set_index(repo, NULL); + set_odb(repo, NULL); + set_refdb(repo, NULL); + + return 0; +} + +void git_repository_free(git_repository *repo) +{ + size_t i; + + if (repo == NULL) + return; + + git_repository__cleanup(repo); + + git_cache_dispose(&repo->objects); + + git_diff_driver_registry_free(repo->diff_drivers); + repo->diff_drivers = NULL; + + for (i = 0; i < repo->reserved_names.size; i++) + git_str_dispose(git_array_get(repo->reserved_names, i)); + git_array_clear(repo->reserved_names); + + git__free(repo->gitlink); + git__free(repo->gitdir); + git__free(repo->commondir); + git__free(repo->workdir); + git__free(repo->namespace); + git__free(repo->ident_name); + git__free(repo->ident_email); + + git__memzero(repo, sizeof(*repo)); + git__free(repo); +} + +/* Check if we have a separate commondir (e.g. we have a worktree) */ +static int lookup_commondir( + bool *separate, + git_str *commondir, + git_str *repository_path, + uint32_t flags) +{ + git_str common_link = GIT_STR_INIT; + int error; + + /* Environment variable overrides configuration */ + if ((flags & GIT_REPOSITORY_OPEN_FROM_ENV)) { + error = git__getenv(commondir, "GIT_COMMON_DIR"); + + if (!error || error != GIT_ENOTFOUND) + goto done; + } + + /* + * If there's no commondir file, the repository path is the + * common path, but it needs a trailing slash. + */ + if (!git_fs_path_contains_file(repository_path, GIT_COMMONDIR_FILE)) { + if ((error = git_str_set(commondir, repository_path->ptr, repository_path->size)) == 0) + error = git_fs_path_to_dir(commondir); + + *separate = false; + goto done; + } + + *separate = true; + + if ((error = git_str_joinpath(&common_link, repository_path->ptr, GIT_COMMONDIR_FILE)) < 0 || + (error = git_futils_readbuffer(&common_link, common_link.ptr)) < 0) + goto done; + + git_str_rtrim(&common_link); + if (git_fs_path_is_relative(common_link.ptr)) { + if ((error = git_str_joinpath(commondir, repository_path->ptr, common_link.ptr)) < 0) + goto done; + } else { + git_str_swap(commondir, &common_link); + } + + /* Make sure the commondir path always has a trailing slash */ + error = git_fs_path_prettify_dir(commondir, commondir->ptr, NULL); + +done: + git_str_dispose(&common_link); + return error; +} + +GIT_INLINE(int) validate_repo_path(git_str *path) +{ + /* + * The longest static path in a repository (or commondir) is the + * packed refs file. (Loose refs may be longer since they + * include the reference name, but will be validated when the + * path is constructed.) + */ + static size_t suffix_len = + CONST_STRLEN("objects/pack/pack-.pack.lock") + + GIT_OID_MAX_HEXSIZE; + + return git_fs_path_validate_str_length_with_suffix( + path, suffix_len); +} + +/* + * Git repository open methods + * + * Open a repository object from its path + */ +static int is_valid_repository_path( + bool *out, + git_str *repository_path, + git_str *common_path, + uint32_t flags) +{ + bool separate_commondir = false; + int error; + + *out = false; + + if ((error = lookup_commondir(&separate_commondir, + common_path, repository_path, flags)) < 0) + return error; + + /* Ensure HEAD file exists */ + if (git_fs_path_contains_file(repository_path, GIT_HEAD_FILE) == false) + return 0; + + /* Check files in common dir */ + if (git_fs_path_contains_dir(common_path, GIT_OBJECTS_DIR) == false) + return 0; + if (git_fs_path_contains_dir(common_path, GIT_REFS_DIR) == false) + return 0; + + /* Ensure the repo (and commondir) are valid paths */ + if ((error = validate_repo_path(common_path)) < 0 || + (separate_commondir && + (error = validate_repo_path(repository_path)) < 0)) + return error; + + *out = true; + return 0; +} + +static git_repository *repository_alloc(void) +{ + git_repository *repo = git__calloc(1, sizeof(git_repository)); + + if (repo == NULL || + git_cache_init(&repo->objects) < 0) + goto on_error; + + git_array_init_to_size(repo->reserved_names, 4); + if (!repo->reserved_names.ptr) + goto on_error; + + /* set all the entries in the configmap cache to `unset` */ + git_repository__configmap_lookup_cache_clear(repo); + + return repo; + +on_error: + if (repo) + git_cache_dispose(&repo->objects); + + git__free(repo); + return NULL; +} + +int git_repository__new(git_repository **out, git_oid_t oid_type) +{ + git_repository *repo; + + *out = repo = repository_alloc(); + GIT_ERROR_CHECK_ALLOC(repo); + + repo->is_bare = 1; + repo->is_worktree = 0; + repo->oid_type = oid_type; + + return 0; +} + +#ifdef GIT_EXPERIMENTAL_SHA256 +int git_repository_new(git_repository **out, git_oid_t oid_type) +{ + return git_repository__new(out, oid_type); +} +#else +int git_repository_new(git_repository** out) +{ + return git_repository__new(out, GIT_OID_SHA1); +} +#endif + +static int load_config_data(git_repository *repo, const git_config *config) +{ + int is_bare; + + int err = git_config_get_bool(&is_bare, config, "core.bare"); + if (err < 0 && err != GIT_ENOTFOUND) + return err; + + /* Try to figure out if it's bare, default to non-bare if it's not set */ + if (err != GIT_ENOTFOUND) + repo->is_bare = is_bare && !repo->is_worktree; + else + repo->is_bare = 0; + + return 0; +} + +static int load_workdir( + git_repository *repo, + git_config *config, + git_str *parent_path) +{ + git_config_entry *ce = NULL; + git_str worktree = GIT_STR_INIT; + git_str path = GIT_STR_INIT; + git_str workdir_env = GIT_STR_INIT; + const char *value = NULL; + int error; + + if (repo->is_bare) + return 0; + + /* Environment variables are preferred */ + if (repo->use_env) { + error = git__getenv(&workdir_env, "GIT_WORK_TREE"); + + if (error == 0) + value = workdir_env.ptr; + else if (error == GIT_ENOTFOUND) + error = 0; + else + goto cleanup; + } + + /* Examine configuration values if necessary */ + if (!value) { + if ((error = git_config__lookup_entry(&ce, config, + "core.worktree", false)) < 0) + return error; + + if (ce && ce->value) + value = ce->value; + } + + if (repo->is_worktree) { + char *gitlink = git_worktree__read_link(repo->gitdir, GIT_GITDIR_FILE); + if (!gitlink) { + error = -1; + goto cleanup; + } + + git_str_attach(&worktree, gitlink, 0); + + if ((git_fs_path_dirname_r(&worktree, worktree.ptr)) < 0 || + git_fs_path_to_dir(&worktree) < 0) { + error = -1; + goto cleanup; + } + + repo->workdir = git_str_detach(&worktree); + } else if (value) { + if (!*value) { + git_error_set(GIT_ERROR_NET, "working directory cannot be set to empty path"); + error = -1; + goto cleanup; + } + + if ((error = git_fs_path_prettify_dir(&worktree, + value, repo->gitdir)) < 0) + goto cleanup; + + repo->workdir = git_str_detach(&worktree); + } else if (parent_path && git_fs_path_isdir(parent_path->ptr)) { + repo->workdir = git_str_detach(parent_path); + } else { + if (git_fs_path_dirname_r(&worktree, repo->gitdir) < 0 || + git_fs_path_to_dir(&worktree) < 0) { + error = -1; + goto cleanup; + } + + repo->workdir = git_str_detach(&worktree); + } + + GIT_ERROR_CHECK_ALLOC(repo->workdir); + +cleanup: + git_str_dispose(&path); + git_str_dispose(&workdir_env); + git_config_entry_free(ce); + return error; +} + +/* + * This function returns furthest offset into path where a ceiling dir + * is found, so we can stop processing the path at that point. + * + * Note: converting this to use git_strs instead of GIT_PATH_MAX buffers on + * the stack could remove directories name limits, but at the cost of doing + * repeated malloc/frees inside the loop below, so let's not do it now. + */ +static size_t find_ceiling_dir_offset( + const char *path, + const char *ceiling_directories) +{ + char buf[GIT_PATH_MAX + 1]; + char buf2[GIT_PATH_MAX + 1]; + const char *ceil, *sep; + size_t len, max_len = 0, min_len; + + GIT_ASSERT_ARG(path); + + min_len = (size_t)(git_fs_path_root(path) + 1); + + if (ceiling_directories == NULL || min_len == 0) + return min_len; + + for (sep = ceil = ceiling_directories; *sep; ceil = sep + 1) { + for (sep = ceil; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++); + len = sep - ceil; + + if (len == 0 || len >= sizeof(buf) || git_fs_path_root(ceil) == -1) + continue; + + strncpy(buf, ceil, len); + buf[len] = '\0'; + + if (p_realpath(buf, buf2) == NULL) + continue; + + len = strlen(buf2); + if (len > 0 && buf2[len-1] == '/') + buf[--len] = '\0'; + + if (!strncmp(path, buf2, len) && + (path[len] == '/' || !path[len]) && + len > max_len) + { + max_len = len; + } + } + + return (max_len <= min_len ? min_len : max_len); +} + +/* + * Read the contents of `file_path` and set `path_out` to the repo dir that + * it points to. Before calling, set `path_out` to the base directory that + * should be used if the contents of `file_path` are a relative path. + */ +static int read_gitfile(git_str *path_out, const char *file_path) +{ + int error = 0; + git_str file = GIT_STR_INIT; + size_t prefix_len = strlen(GIT_FILE_CONTENT_PREFIX); + + GIT_ASSERT_ARG(path_out); + GIT_ASSERT_ARG(file_path); + + if (git_futils_readbuffer(&file, file_path) < 0) + return -1; + + git_str_rtrim(&file); + /* apparently on Windows, some people use backslashes in paths */ + git_fs_path_mkposix(file.ptr); + + if (git_str_len(&file) <= prefix_len || + memcmp(git_str_cstr(&file), GIT_FILE_CONTENT_PREFIX, prefix_len) != 0) + { + git_error_set(GIT_ERROR_REPOSITORY, + "the `.git` file at '%s' is malformed", file_path); + error = -1; + } + else if ((error = git_fs_path_dirname_r(path_out, file_path)) >= 0) { + const char *gitlink = git_str_cstr(&file) + prefix_len; + while (*gitlink && git__isspace(*gitlink)) gitlink++; + + error = git_fs_path_prettify_dir( + path_out, gitlink, git_str_cstr(path_out)); + } + + git_str_dispose(&file); + return error; +} + +typedef struct { + const char *repo_path; + git_str tmp; + bool *is_safe; +} validate_ownership_data; + +static int validate_ownership_cb(const git_config_entry *entry, void *payload) +{ + validate_ownership_data *data = payload; + const char *test_path; + + if (strcmp(entry->value, "") == 0) { + *data->is_safe = false; + } else if (strcmp(entry->value, "*") == 0) { + *data->is_safe = true; + } else { + if (git_str_sets(&data->tmp, entry->value) < 0) + return -1; + + if (!git_fs_path_is_root(data->tmp.ptr)) { + /* Input must not have trailing backslash. */ + if (!data->tmp.size || + data->tmp.ptr[data->tmp.size - 1] == '/') + return 0; + + if (git_fs_path_to_dir(&data->tmp) < 0) + return -1; + } + + test_path = data->tmp.ptr; + + /* + * Git - and especially, Git for Windows - does some + * truly bizarre things with paths that start with a + * forward slash; and expects you to escape that with + * `%(prefix)`. This syntax generally means to add the + * prefix that Git was installed to (eg `/usr/local`) + * unless it's an absolute path, in which case the + * leading `%(prefix)/` is just removed. And Git for + * Windows expects you to use this syntax for absolute + * Unix-style paths (in "Git Bash" or Windows Subsystem + * for Linux). + * + * Worse, the behavior used to be that a leading `/` was + * not absolute. It would indicate that Git for Windows + * should add the prefix. So `//` is required for absolute + * Unix-style paths. Yes, this is truly horrifying. + * + * Emulate that behavior, I guess, but only for absolute + * paths. We won't deal with the Git install prefix. Also, + * give WSL users an escape hatch where they don't have to + * think about this and can use the literal path that the + * filesystem APIs provide (`//wsl.localhost/...`). + */ + if (strncmp(test_path, "%(prefix)//", strlen("%(prefix)//")) == 0) + test_path += strlen("%(prefix)/"); + + if (strcmp(test_path, data->repo_path) == 0) + *data->is_safe = true; + } + + return 0; +} + +static int validate_ownership_config( + bool *is_safe, + const char *path, + bool use_env) +{ + validate_ownership_data ownership_data = { + path, GIT_STR_INIT, is_safe + }; + git_config *config; + int error; + + if (load_global_config(&config, use_env) != 0) + return 0; + + error = git_config_get_multivar_foreach(config, + "safe.directory", NULL, + validate_ownership_cb, + &ownership_data); + + if (error == GIT_ENOTFOUND) + error = 0; + + git_config_free(config); + git_str_dispose(&ownership_data.tmp); + + return error; +} + +static int validate_ownership_path(bool *is_safe, const char *path) +{ + git_fs_path_owner_t owner_level = + GIT_FS_PATH_OWNER_CURRENT_USER | + GIT_FS_PATH_USER_IS_ADMINISTRATOR | + GIT_FS_PATH_OWNER_RUNNING_SUDO; + int error = 0; + + if (path) + error = git_fs_path_owner_is(is_safe, path, owner_level); + + if (error == GIT_ENOTFOUND) { + *is_safe = true; + error = 0; + } else if (error == GIT_EINVALID) { + *is_safe = false; + error = 0; + } + + return error; +} + +static int validate_ownership(git_repository *repo) +{ + const char *validation_paths[3] = { NULL }, *path; + size_t validation_len = 0, i; + bool is_safe = false; + int error = 0; + + /* + * If there's a worktree, validate the permissions to it *and* + * the git directory, and use the worktree as the configuration + * key for allowlisting the directory. In a bare setup, only + * look at the gitdir and use that as the allowlist. So we + * examine all `validation_paths` but use only the first as + * the configuration lookup. + */ + + if (repo->workdir) + validation_paths[validation_len++] = repo->workdir; + + if (repo->gitlink) + validation_paths[validation_len++] = repo->gitlink; + + validation_paths[validation_len++] = repo->gitdir; + + for (i = 0; i < validation_len; i++) { + path = validation_paths[i]; + + if ((error = validate_ownership_path(&is_safe, path)) < 0) + goto done; + + if (!is_safe) + break; + } + + if (is_safe || + (error = validate_ownership_config( + &is_safe, validation_paths[0], repo->use_env)) < 0) + goto done; + + if (!is_safe) { + size_t path_len = git_fs_path_is_root(path) ? + strlen(path) : git_fs_path_dirlen(path); + + git_error_set(GIT_ERROR_CONFIG, + "repository path '%.*s' is not owned by current user", + (int)min(path_len, INT_MAX), path); + error = GIT_EOWNER; + } + +done: + return error; +} + +struct repo_paths { + git_str gitdir; + git_str workdir; + git_str gitlink; + git_str commondir; +}; + +#define REPO_PATHS_INIT { GIT_STR_INIT } + +GIT_INLINE(void) repo_paths_dispose(struct repo_paths *paths) +{ + git_str_dispose(&paths->gitdir); + git_str_dispose(&paths->workdir); + git_str_dispose(&paths->gitlink); + git_str_dispose(&paths->commondir); +} + +static int find_repo_traverse( + struct repo_paths *out, + const char *start_path, + const char *ceiling_dirs, + uint32_t flags) +{ + git_str path = GIT_STR_INIT; + git_str repo_link = GIT_STR_INIT; + git_str common_link = GIT_STR_INIT; + struct stat st; + dev_t initial_device = 0; + int min_iterations; + bool in_dot_git, is_valid; + size_t ceiling_offset = 0; + int error; + + git_str_clear(&out->gitdir); + + if ((error = git_fs_path_prettify(&path, start_path, NULL)) < 0) + return error; + + /* + * In each loop we look first for a `.git` dir within the + * directory, then to see if the directory itself is a repo. + * + * In other words: if we start in /a/b/c, then we look at: + * /a/b/c/.git, /a/b/c, /a/b/.git, /a/b, /a/.git, /a + * + * With GIT_REPOSITORY_OPEN_BARE or GIT_REPOSITORY_OPEN_NO_DOTGIT, + * we assume we started with /a/b/c.git and don't append .git the + * first time through. min_iterations indicates the number of + * iterations left before going further counts as a search. + */ + if (flags & (GIT_REPOSITORY_OPEN_BARE | GIT_REPOSITORY_OPEN_NO_DOTGIT)) { + in_dot_git = true; + min_iterations = 1; + } else { + in_dot_git = false; + min_iterations = 2; + } + + for (;;) { + if (!(flags & GIT_REPOSITORY_OPEN_NO_DOTGIT)) { + if (!in_dot_git) { + if ((error = git_str_joinpath(&path, path.ptr, DOT_GIT)) < 0) + goto out; + } + in_dot_git = !in_dot_git; + } + + if (p_stat(path.ptr, &st) == 0) { + /* check that we have not crossed device boundaries */ + if (initial_device == 0) + initial_device = st.st_dev; + else if (st.st_dev != initial_device && + !(flags & GIT_REPOSITORY_OPEN_CROSS_FS)) + break; + + if (S_ISDIR(st.st_mode)) { + if ((error = is_valid_repository_path(&is_valid, &path, &common_link, flags)) < 0) + goto out; + + if (is_valid) { + if ((error = git_fs_path_to_dir(&path)) < 0 || + (error = git_str_set(&out->gitdir, path.ptr, path.size)) < 0) + goto out; + + if ((error = git_str_attach(&out->gitlink, git_worktree__read_link(path.ptr, GIT_GITDIR_FILE), 0)) < 0) + goto out; + + git_str_swap(&common_link, &out->commondir); + + break; + } + } else if (S_ISREG(st.st_mode) && git__suffixcmp(path.ptr, "/" DOT_GIT) == 0) { + if ((error = read_gitfile(&repo_link, path.ptr)) < 0 || + (error = is_valid_repository_path(&is_valid, &repo_link, &common_link, flags)) < 0) + goto out; + + if (is_valid) { + git_str_swap(&out->gitdir, &repo_link); + + if ((error = git_str_put(&out->gitlink, path.ptr, path.size)) < 0) + goto out; + + git_str_swap(&common_link, &out->commondir); + } + break; + } + } + + /* + * Move up one directory. If we're in_dot_git, we'll + * search the parent itself next. If we're !in_dot_git, + * we'll search .git in the parent directory next (added + * at the top of the loop). + */ + if ((error = git_fs_path_dirname_r(&path, path.ptr)) < 0) + goto out; + + /* + * Once we've checked the directory (and .git if + * applicable), find the ceiling for a search. + */ + if (min_iterations && (--min_iterations == 0)) + ceiling_offset = find_ceiling_dir_offset(path.ptr, ceiling_dirs); + + /* Check if we should stop searching here. */ + if (min_iterations == 0 && + (path.ptr[ceiling_offset] == 0 || (flags & GIT_REPOSITORY_OPEN_NO_SEARCH))) + break; + } + + if (!(flags & GIT_REPOSITORY_OPEN_BARE)) { + if (!git_str_len(&out->gitdir)) + git_str_clear(&out->workdir); + else if ((error = git_fs_path_dirname_r(&out->workdir, path.ptr)) < 0 || + (error = git_fs_path_to_dir(&out->workdir)) < 0) + goto out; + } + + /* If we didn't find the repository, and we don't have any other + * error to report, report that. */ + if (!git_str_len(&out->gitdir)) { + git_error_set(GIT_ERROR_REPOSITORY, "could not find repository at '%s'", start_path); + error = GIT_ENOTFOUND; + goto out; + } + +out: + if (error) + repo_paths_dispose(out); + + git_str_dispose(&path); + git_str_dispose(&repo_link); + git_str_dispose(&common_link); + return error; +} + +static int load_grafts(git_repository *repo) +{ + git_str path = GIT_STR_INIT; + int error; + + /* refresh if they've both been opened previously */ + if (repo->grafts && repo->shallow_grafts) { + if ((error = git_grafts_refresh(repo->grafts)) < 0 || + (error = git_grafts_refresh(repo->shallow_grafts)) < 0) + return error; + } + + /* resolve info path, which may not be found for inmemory repository */ + if ((error = git_repository__item_path(&path, repo, GIT_REPOSITORY_ITEM_INFO)) < 0) { + if (error != GIT_ENOTFOUND) + return error; + + /* create empty/inmemory grafts for inmemory repository */ + if (!repo->grafts && (error = git_grafts_new(&repo->grafts, repo->oid_type)) < 0) + return error; + + if (!repo->shallow_grafts && (error = git_grafts_new(&repo->shallow_grafts, repo->oid_type)) < 0) + return error; + + return 0; + } + + /* load grafts from disk */ + if ((error = git_str_joinpath(&path, path.ptr, "grafts")) < 0 || + (error = git_grafts_open_or_refresh(&repo->grafts, path.ptr, repo->oid_type)) < 0) + goto error; + + git_str_clear(&path); + + if ((error = git_str_joinpath(&path, repo->gitdir, "shallow")) < 0 || + (error = git_grafts_open_or_refresh(&repo->shallow_grafts, path.ptr, repo->oid_type)) < 0) + goto error; + +error: + git_str_dispose(&path); + return error; +} + +static int find_repo( + struct repo_paths *out, + const char *start_path, + const char *ceiling_dirs, + uint32_t flags) +{ + bool use_env = !!(flags & GIT_REPOSITORY_OPEN_FROM_ENV); + git_str gitdir_buf = GIT_STR_INIT, + ceiling_dirs_buf = GIT_STR_INIT, + across_fs_buf = GIT_STR_INIT; + int error; + + if (use_env && !start_path) { + error = git__getenv(&gitdir_buf, "GIT_DIR"); + + if (!error) { + start_path = gitdir_buf.ptr; + flags |= GIT_REPOSITORY_OPEN_NO_SEARCH; + flags |= GIT_REPOSITORY_OPEN_NO_DOTGIT; + } else if (error == GIT_ENOTFOUND) { + start_path = "."; + } else { + goto done; + } + } + + if (use_env && !ceiling_dirs) { + error = git__getenv(&ceiling_dirs_buf, + "GIT_CEILING_DIRECTORIES"); + + if (!error) + ceiling_dirs = ceiling_dirs_buf.ptr; + else if (error != GIT_ENOTFOUND) + goto done; + } + + if (use_env) { + error = git__getenv(&across_fs_buf, + "GIT_DISCOVERY_ACROSS_FILESYSTEM"); + + if (!error) { + int across_fs = 0; + + if ((error = git_config_parse_bool(&across_fs, + git_str_cstr(&across_fs_buf))) < 0) + goto done; + + if (across_fs) + flags |= GIT_REPOSITORY_OPEN_CROSS_FS; + } else if (error != GIT_ENOTFOUND) { + goto done; + } + } + + error = find_repo_traverse(out, start_path, ceiling_dirs, flags); + +done: + git_str_dispose(&gitdir_buf); + git_str_dispose(&ceiling_dirs_buf); + git_str_dispose(&across_fs_buf); + + return error; +} + +static int obtain_config_and_set_oid_type( + git_config **config_ptr, + git_repository *repo) +{ + int error; + git_config *config = NULL; + int version = 0; + + /* + * We'd like to have the config, but git doesn't particularly + * care if it's not there, so we need to deal with that. + */ + + error = git_repository_config_snapshot(&config, repo); + if (error < 0 && error != GIT_ENOTFOUND) + goto out; + + if (config && + (error = check_repositoryformatversion(&version, config)) < 0) + goto out; + + if ((error = check_extensions(config, version)) < 0) + goto out; + + if (version > 0) { + if ((error = load_objectformat(repo, config)) < 0) + goto out; + } else { + repo->oid_type = GIT_OID_DEFAULT; + } + +out: + *config_ptr = config; + + return error; +} + +int git_repository_open_bare( + git_repository **repo_ptr, + const char *bare_path) +{ + git_str path = GIT_STR_INIT, common_path = GIT_STR_INIT; + git_repository *repo = NULL; + bool is_valid; + int error; + git_config *config; + + if ((error = git_fs_path_prettify_dir(&path, bare_path, NULL)) < 0 || + (error = is_valid_repository_path(&is_valid, &path, &common_path, 0)) < 0) + return error; + + if (!is_valid) { + git_str_dispose(&path); + git_str_dispose(&common_path); + git_error_set(GIT_ERROR_REPOSITORY, "path is not a repository: %s", bare_path); + return GIT_ENOTFOUND; + } + + repo = repository_alloc(); + GIT_ERROR_CHECK_ALLOC(repo); + + repo->gitdir = git_str_detach(&path); + GIT_ERROR_CHECK_ALLOC(repo->gitdir); + repo->commondir = git_str_detach(&common_path); + GIT_ERROR_CHECK_ALLOC(repo->commondir); + + /* of course we're bare! */ + repo->is_bare = 1; + repo->is_worktree = 0; + repo->workdir = NULL; + + if ((error = obtain_config_and_set_oid_type(&config, repo)) < 0) + goto cleanup; + + *repo_ptr = repo; + +cleanup: + git_config_free(config); + + return error; +} + +static int repo_load_namespace(git_repository *repo) +{ + git_str namespace_buf = GIT_STR_INIT; + int error; + + if (!repo->use_env) + return 0; + + error = git__getenv(&namespace_buf, "GIT_NAMESPACE"); + + if (error == 0) + repo->namespace = git_str_detach(&namespace_buf); + else if (error != GIT_ENOTFOUND) + return error; + + return 0; +} + +static int repo_is_worktree(unsigned *out, const git_repository *repo) +{ + git_str gitdir_link = GIT_STR_INIT; + int error; + + /* Worktrees cannot have the same commondir and gitdir */ + if (repo->commondir && repo->gitdir + && !strcmp(repo->commondir, repo->gitdir)) { + *out = 0; + return 0; + } + + if ((error = git_str_joinpath(&gitdir_link, repo->gitdir, "gitdir")) < 0) + return -1; + + /* A 'gitdir' file inside a git directory is currently + * only used when the repository is a working tree. */ + *out = !!git_fs_path_exists(gitdir_link.ptr); + + git_str_dispose(&gitdir_link); + return error; +} + +int git_repository_open_ext( + git_repository **repo_ptr, + const char *start_path, + unsigned int flags, + const char *ceiling_dirs) +{ + struct repo_paths paths = { GIT_STR_INIT }; + git_repository *repo = NULL; + git_config *config = NULL; + unsigned is_worktree; + int error; + + if (repo_ptr) + *repo_ptr = NULL; + + error = find_repo(&paths, start_path, ceiling_dirs, flags); + + if (error < 0 || !repo_ptr) + goto cleanup; + + repo = repository_alloc(); + GIT_ERROR_CHECK_ALLOC(repo); + + repo->use_env = !!(flags & GIT_REPOSITORY_OPEN_FROM_ENV); + + repo->gitdir = git_str_detach(&paths.gitdir); + GIT_ERROR_CHECK_ALLOC(repo->gitdir); + + if (paths.gitlink.size) { + repo->gitlink = git_str_detach(&paths.gitlink); + GIT_ERROR_CHECK_ALLOC(repo->gitlink); + } + if (paths.commondir.size) { + repo->commondir = git_str_detach(&paths.commondir); + GIT_ERROR_CHECK_ALLOC(repo->commondir); + } + + if ((error = repo_is_worktree(&is_worktree, repo)) < 0) + goto cleanup; + + repo->is_worktree = is_worktree; + + error = obtain_config_and_set_oid_type(&config, repo); + if (error < 0) + goto cleanup; + + if ((error = load_grafts(repo)) < 0) + goto cleanup; + + if ((flags & GIT_REPOSITORY_OPEN_BARE) != 0) { + repo->is_bare = 1; + } else { + if (config && + ((error = load_config_data(repo, config)) < 0 || + (error = load_workdir(repo, config, &paths.workdir)) < 0)) + goto cleanup; + } + + if ((error = repo_load_namespace(repo)) < 0) + goto cleanup; + + /* + * Ensure that the git directory and worktree are + * owned by the current user. + */ + if (git_repository__validate_ownership && + (error = validate_ownership(repo)) < 0) + goto cleanup; + +cleanup: + repo_paths_dispose(&paths); + git_config_free(config); + + if (error < 0) + git_repository_free(repo); + else if (repo_ptr) + *repo_ptr = repo; + + return error; +} + +int git_repository_open(git_repository **repo_out, const char *path) +{ + return git_repository_open_ext( + repo_out, path, GIT_REPOSITORY_OPEN_NO_SEARCH, NULL); +} + +int git_repository_open_from_worktree(git_repository **repo_out, git_worktree *wt) +{ + git_str path = GIT_STR_INIT; + git_repository *repo = NULL; + size_t len; + int err; + + GIT_ASSERT_ARG(repo_out); + GIT_ASSERT_ARG(wt); + + *repo_out = NULL; + len = strlen(wt->gitlink_path); + + if (len <= 4 || strcasecmp(wt->gitlink_path + len - 4, ".git")) { + err = -1; + goto out; + } + + if ((err = git_str_set(&path, wt->gitlink_path, len - 4)) < 0) + goto out; + + if ((err = git_repository_open(&repo, path.ptr)) < 0) + goto out; + + *repo_out = repo; + +out: + git_str_dispose(&path); + + return err; +} + +int git_repository__wrap_odb( + git_repository **out, + git_odb *odb, + git_oid_t oid_type) +{ + git_repository *repo; + + repo = repository_alloc(); + GIT_ERROR_CHECK_ALLOC(repo); + + repo->oid_type = oid_type; + + git_repository_set_odb(repo, odb); + *out = repo; + + return 0; +} + +#ifdef GIT_EXPERIMENTAL_SHA256 +int git_repository_wrap_odb( + git_repository **out, + git_odb *odb, + git_oid_t oid_type) +{ + return git_repository__wrap_odb(out, odb, oid_type); +} +#else +int git_repository_wrap_odb(git_repository **out, git_odb *odb) +{ + return git_repository__wrap_odb(out, odb, GIT_OID_DEFAULT); +} +#endif + +int git_repository_discover( + git_buf *out, + const char *start_path, + int across_fs, + const char *ceiling_dirs) +{ + struct repo_paths paths = { GIT_STR_INIT }; + uint32_t flags = across_fs ? GIT_REPOSITORY_OPEN_CROSS_FS : 0; + int error; + + GIT_ASSERT_ARG(start_path); + + if ((error = find_repo(&paths, start_path, ceiling_dirs, flags)) == 0) + error = git_buf_fromstr(out, &paths.gitdir); + + repo_paths_dispose(&paths); + return error; +} + +static int has_config_worktree(bool *out, git_config *cfg) +{ + int worktreeconfig = 0, error; + + *out = false; + + error = git_config_get_bool(&worktreeconfig, cfg, "extensions.worktreeconfig"); + + if (error == 0) + *out = worktreeconfig; + else if (error == GIT_ENOTFOUND) + *out = false; + else + return error; + + return 0; +} + +static int load_config( + git_config **out, + git_repository *repo, + const char *global_config_path, + const char *xdg_config_path, + const char *system_config_path, + const char *programdata_path) +{ + git_str config_path = GIT_STR_INIT; + git_config *cfg = NULL; + git_config_level_t write_order; + bool has_worktree; + int error; + + GIT_ASSERT_ARG(out); + + if ((error = git_config_new(&cfg)) < 0) + return error; + + if (repo) { + if ((error = git_repository__item_path(&config_path, repo, GIT_REPOSITORY_ITEM_CONFIG)) == 0) + error = git_config_add_file_ondisk(cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, repo, 0); + + if (error && error != GIT_ENOTFOUND) + goto on_error; + + if ((error = has_config_worktree(&has_worktree, cfg)) == 0 && + has_worktree && + (error = git_repository__item_path(&config_path, repo, GIT_REPOSITORY_ITEM_WORKTREE_CONFIG)) == 0) + error = git_config_add_file_ondisk(cfg, config_path.ptr, GIT_CONFIG_LEVEL_WORKTREE, repo, 0); + + if (error && error != GIT_ENOTFOUND) + goto on_error; + + git_str_dispose(&config_path); + } + + if (global_config_path != NULL && + (error = git_config_add_file_ondisk( + cfg, global_config_path, GIT_CONFIG_LEVEL_GLOBAL, repo, 0)) < 0 && + error != GIT_ENOTFOUND) + goto on_error; + + if (xdg_config_path != NULL && + (error = git_config_add_file_ondisk( + cfg, xdg_config_path, GIT_CONFIG_LEVEL_XDG, repo, 0)) < 0 && + error != GIT_ENOTFOUND) + goto on_error; + + if (system_config_path != NULL && + (error = git_config_add_file_ondisk( + cfg, system_config_path, GIT_CONFIG_LEVEL_SYSTEM, repo, 0)) < 0 && + error != GIT_ENOTFOUND) + goto on_error; + + if (programdata_path != NULL && + (error = git_config_add_file_ondisk( + cfg, programdata_path, GIT_CONFIG_LEVEL_PROGRAMDATA, repo, 0)) < 0 && + error != GIT_ENOTFOUND) + goto on_error; + + git_error_clear(); /* clear any lingering ENOTFOUND errors */ + + write_order = GIT_CONFIG_LEVEL_LOCAL; + + if ((error = git_config_set_writeorder(cfg, &write_order, 1)) < 0) + goto on_error; + + *out = cfg; + return 0; + +on_error: + git_str_dispose(&config_path); + git_config_free(cfg); + *out = NULL; + return error; +} + +static const char *path_unless_empty(git_str *buf) +{ + return git_str_len(buf) > 0 ? git_str_cstr(buf) : NULL; +} + +GIT_INLINE(int) config_path_system(git_str *out, bool use_env) +{ + if (use_env) { + git_str no_system_buf = GIT_STR_INIT; + int no_system = 0; + int error; + + error = git__getenv(&no_system_buf, "GIT_CONFIG_NOSYSTEM"); + + if (error && error != GIT_ENOTFOUND) + return error; + + error = git_config_parse_bool(&no_system, no_system_buf.ptr); + git_str_dispose(&no_system_buf); + + if (no_system) + return 0; + + error = git__getenv(out, "GIT_CONFIG_SYSTEM"); + + if (error == 0 || error != GIT_ENOTFOUND) + return 0; + } + + git_config__find_system(out); + return 0; +} + +GIT_INLINE(int) config_path_global(git_str *out, bool use_env) +{ + if (use_env) { + int error = git__getenv(out, "GIT_CONFIG_GLOBAL"); + + if (error == 0 || error != GIT_ENOTFOUND) + return 0; + } + + git_config__find_global(out); + return 0; +} + +int git_repository_config__weakptr(git_config **out, git_repository *repo) +{ + int error = 0; + + if (repo->_config == NULL) { + git_str system_buf = GIT_STR_INIT; + git_str global_buf = GIT_STR_INIT; + git_str xdg_buf = GIT_STR_INIT; + git_str programdata_buf = GIT_STR_INIT; + bool use_env = repo->use_env; + git_config *config; + + if (!(error = config_path_system(&system_buf, use_env)) && + !(error = config_path_global(&global_buf, use_env))) { + git_config__find_xdg(&xdg_buf); + git_config__find_programdata(&programdata_buf); + } + + if (!error) { + /* + * If there is no global file, open a backend + * for it anyway. + */ + if (git_str_len(&global_buf) == 0) + git_config__global_location(&global_buf); + + error = load_config( + &config, repo, + path_unless_empty(&global_buf), + path_unless_empty(&xdg_buf), + path_unless_empty(&system_buf), + path_unless_empty(&programdata_buf)); + } + + if (!error) { + GIT_REFCOUNT_OWN(config, repo); + + if (git_atomic_compare_and_swap(&repo->_config, NULL, config) != NULL) { + GIT_REFCOUNT_OWN(config, NULL); + git_config_free(config); + } + } + + git_str_dispose(&global_buf); + git_str_dispose(&xdg_buf); + git_str_dispose(&system_buf); + git_str_dispose(&programdata_buf); + } + + *out = repo->_config; + return error; +} + +int git_repository_config(git_config **out, git_repository *repo) +{ + if (git_repository_config__weakptr(out, repo) < 0) + return -1; + + GIT_REFCOUNT_INC(*out); + return 0; +} + +int git_repository_config_snapshot(git_config **out, git_repository *repo) +{ + int error; + git_config *weak; + + if ((error = git_repository_config__weakptr(&weak, repo)) < 0) + return error; + + return git_config_snapshot(out, weak); +} + +int git_repository_set_config(git_repository *repo, git_config *config) +{ + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(config); + + set_config(repo, config); + return 0; +} + +static int repository_odb_path(git_str *out, git_repository *repo) +{ + int error = GIT_ENOTFOUND; + + if (repo->use_env) + error = git__getenv(out, "GIT_OBJECT_DIRECTORY"); + + if (error == GIT_ENOTFOUND) + error = git_repository__item_path(out, repo, + GIT_REPOSITORY_ITEM_OBJECTS); + + return error; +} + +static int repository_odb_alternates( + git_odb *odb, + git_repository *repo) +{ + git_str alternates = GIT_STR_INIT; + char *sep, *alt; + int error; + + if (!repo->use_env) + return 0; + + error = git__getenv(&alternates, "GIT_ALTERNATE_OBJECT_DIRECTORIES"); + + if (error != 0) + return (error == GIT_ENOTFOUND) ? 0 : error; + + alt = alternates.ptr; + + while (*alt) { + sep = strchr(alt, GIT_PATH_LIST_SEPARATOR); + + if (sep) + *sep = '\0'; + + error = git_odb_add_disk_alternate(odb, alt); + + if (sep) + alt = sep + 1; + else + break; + } + + git_str_dispose(&alternates); + return 0; +} + +int git_repository_odb__weakptr(git_odb **out, git_repository *repo) +{ + int error = 0; + + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(out); + + *out = git_atomic_load(repo->_odb); + if (*out == NULL) { + git_str odb_path = GIT_STR_INIT; + git_odb_options odb_opts = GIT_ODB_OPTIONS_INIT; + git_odb *odb; + + odb_opts.oid_type = repo->oid_type; + + if ((error = repository_odb_path(&odb_path, repo)) < 0 || + (error = git_odb__new(&odb, &odb_opts)) < 0 || + (error = repository_odb_alternates(odb, repo)) < 0) + return error; + + GIT_REFCOUNT_OWN(odb, repo); + + if ((error = git_odb__set_caps(odb, GIT_ODB_CAP_FROM_OWNER)) < 0 || + (error = git_odb__add_default_backends(odb, odb_path.ptr, 0, 0)) < 0) { + git_odb_free(odb); + return error; + } + + if (git_atomic_compare_and_swap(&repo->_odb, NULL, odb) != NULL) { + GIT_REFCOUNT_OWN(odb, NULL); + git_odb_free(odb); + } + + git_str_dispose(&odb_path); + *out = git_atomic_load(repo->_odb); + } + + return error; +} + +int git_repository_odb(git_odb **out, git_repository *repo) +{ + if (git_repository_odb__weakptr(out, repo) < 0) + return -1; + + GIT_REFCOUNT_INC(*out); + return 0; +} + +int git_repository_set_odb(git_repository *repo, git_odb *odb) +{ + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(odb); + + set_odb(repo, odb); + return 0; +} + +int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo) +{ + int error = 0; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(repo); + + if (repo->_refdb == NULL) { + git_refdb *refdb; + + error = git_refdb_open(&refdb, repo); + if (!error) { + GIT_REFCOUNT_OWN(refdb, repo); + + if (git_atomic_compare_and_swap(&repo->_refdb, NULL, refdb) != NULL) { + GIT_REFCOUNT_OWN(refdb, NULL); + git_refdb_free(refdb); + } + } + } + + *out = repo->_refdb; + return error; +} + +int git_repository_refdb(git_refdb **out, git_repository *repo) +{ + if (git_repository_refdb__weakptr(out, repo) < 0) + return -1; + + GIT_REFCOUNT_INC(*out); + return 0; +} + +int git_repository_set_refdb(git_repository *repo, git_refdb *refdb) +{ + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(refdb); + + set_refdb(repo, refdb); + return 0; +} + +static int repository_index_path(git_str *out, git_repository *repo) +{ + int error = GIT_ENOTFOUND; + + if (repo->use_env) + error = git__getenv(out, "GIT_INDEX_FILE"); + + if (error == GIT_ENOTFOUND) + error = git_repository__item_path(out, repo, + GIT_REPOSITORY_ITEM_INDEX); + + return error; +} + +int git_repository_index__weakptr(git_index **out, git_repository *repo) +{ + int error = 0; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(repo); + + if (repo->_index == NULL) { + git_str index_path = GIT_STR_INIT; + git_index *index; + + if ((error = repository_index_path(&index_path, repo)) < 0) + return error; + + error = git_index__open(&index, index_path.ptr, repo->oid_type); + + if (!error) { + GIT_REFCOUNT_OWN(index, repo); + + if (git_atomic_compare_and_swap(&repo->_index, NULL, index) != NULL) { + GIT_REFCOUNT_OWN(index, NULL); + git_index_free(index); + } + + error = git_index_set_caps(repo->_index, + GIT_INDEX_CAPABILITY_FROM_OWNER); + } + + git_str_dispose(&index_path); + } + + *out = repo->_index; + return error; +} + +int git_repository_index(git_index **out, git_repository *repo) +{ + if (git_repository_index__weakptr(out, repo) < 0) + return -1; + + GIT_REFCOUNT_INC(*out); + return 0; +} + +int git_repository_set_index(git_repository *repo, git_index *index) +{ + GIT_ASSERT_ARG(repo); + set_index(repo, index); + return 0; +} + +int git_repository_grafts__weakptr(git_grafts **out, git_repository *repo) +{ + GIT_ASSERT_ARG(out && repo); + GIT_ASSERT(repo->grafts); + *out = repo->grafts; + return 0; +} + +int git_repository_shallow_grafts__weakptr(git_grafts **out, git_repository *repo) +{ + GIT_ASSERT_ARG(out && repo); + GIT_ASSERT(repo->shallow_grafts); + *out = repo->shallow_grafts; + return 0; +} + +int git_repository_set_namespace(git_repository *repo, const char *namespace) +{ + git__free(repo->namespace); + + if (namespace == NULL) { + repo->namespace = NULL; + return 0; + } + + return (repo->namespace = git__strdup(namespace)) ? 0 : -1; +} + +const char *git_repository_get_namespace(git_repository *repo) +{ + return repo->namespace; +} + +#ifdef GIT_WIN32 +static int reserved_names_add8dot3(git_repository *repo, const char *path) +{ + char *name = git_win32_path_8dot3_name(path); + const char *def = GIT_DIR_SHORTNAME; + const char *def_dot_git = DOT_GIT; + size_t name_len, def_len = CONST_STRLEN(GIT_DIR_SHORTNAME); + size_t def_dot_git_len = CONST_STRLEN(DOT_GIT); + git_str *buf; + + if (!name) + return 0; + + name_len = strlen(name); + + if ((name_len == def_len && memcmp(name, def, def_len) == 0) || + (name_len == def_dot_git_len && memcmp(name, def_dot_git, def_dot_git_len) == 0)) { + git__free(name); + return 0; + } + + if ((buf = git_array_alloc(repo->reserved_names)) == NULL) + return -1; + + git_str_attach(buf, name, name_len); + return true; +} + +bool git_repository__reserved_names( + git_str **out, size_t *outlen, git_repository *repo, bool include_ntfs) +{ + GIT_UNUSED(include_ntfs); + + if (repo->reserved_names.size == 0) { + git_str *buf; + size_t i; + + /* Add the static defaults */ + for (i = 0; i < git_repository__reserved_names_win32_len; i++) { + if ((buf = git_array_alloc(repo->reserved_names)) == NULL) + goto on_error; + + buf->ptr = git_repository__reserved_names_win32[i].ptr; + buf->size = git_repository__reserved_names_win32[i].size; + } + + /* Try to add any repo-specific reserved names - the gitlink file + * within a submodule or the repository (if the repository directory + * is beneath the workdir). These are typically `.git`, but should + * be protected in case they are not. Note, repo and workdir paths + * are always prettified to end in `/`, so a prefixcmp is safe. + */ + if (!repo->is_bare) { + int (*prefixcmp)(const char *, const char *); + int error, ignorecase; + + error = git_repository__configmap_lookup( + &ignorecase, repo, GIT_CONFIGMAP_IGNORECASE); + prefixcmp = (error || ignorecase) ? git__prefixcmp_icase : + git__prefixcmp; + + if (repo->gitlink && + reserved_names_add8dot3(repo, repo->gitlink) < 0) + goto on_error; + + if (repo->gitdir && + prefixcmp(repo->gitdir, repo->workdir) == 0 && + reserved_names_add8dot3(repo, repo->gitdir) < 0) + goto on_error; + } + } + + *out = repo->reserved_names.ptr; + *outlen = repo->reserved_names.size; + + return true; + + /* Always give good defaults, even on OOM */ +on_error: + *out = git_repository__reserved_names_win32; + *outlen = git_repository__reserved_names_win32_len; + + return false; +} +#else +bool git_repository__reserved_names( + git_str **out, size_t *outlen, git_repository *repo, bool include_ntfs) +{ + GIT_UNUSED(repo); + + if (include_ntfs) { + *out = git_repository__reserved_names_win32; + *outlen = git_repository__reserved_names_win32_len; + } else { + *out = git_repository__reserved_names_posix; + *outlen = git_repository__reserved_names_posix_len; + } + + return true; +} +#endif + +static int check_repositoryformatversion(int *version, git_config *config) +{ + int error; + + error = git_config_get_int32(version, config, "core.repositoryformatversion"); + + /* git ignores this if the config variable isn't there */ + if (error == GIT_ENOTFOUND) + return 0; + + if (error < 0) + return -1; + + if (*version < 0) { + git_error_set(GIT_ERROR_REPOSITORY, + "invalid repository version %d", *version); + } + + if (GIT_REPO_VERSION_MAX < *version) { + git_error_set(GIT_ERROR_REPOSITORY, + "unsupported repository version %d; only versions up to %d are supported", + *version, GIT_REPO_VERSION_MAX); + return -1; + } + + return 0; +} + +static const char *builtin_extensions[] = { + "noop", + "objectformat", + "worktreeconfig", +}; + +static git_vector user_extensions = { 0, git__strcmp_cb }; + +static int check_valid_extension(const git_config_entry *entry, void *payload) +{ + git_str cfg = GIT_STR_INIT; + bool reject; + const char *extension; + size_t i; + int error = 0; + + GIT_UNUSED(payload); + + git_vector_foreach (&user_extensions, i, extension) { + git_str_clear(&cfg); + + /* + * Users can specify that they don't want to support an + * extension with a '!' prefix. + */ + if ((reject = (extension[0] == '!')) == true) + extension = &extension[1]; + + if ((error = git_str_printf(&cfg, "extensions.%s", extension)) < 0) + goto done; + + if (strcmp(entry->name, cfg.ptr) == 0) { + if (reject) + goto fail; + + goto done; + } + } + + for (i = 0; i < ARRAY_SIZE(builtin_extensions); i++) { + git_str_clear(&cfg); + extension = builtin_extensions[i]; + + if ((error = git_str_printf(&cfg, "extensions.%s", extension)) < 0) + goto done; + + if (strcmp(entry->name, cfg.ptr) == 0) + goto done; + } + +fail: + git_error_set(GIT_ERROR_REPOSITORY, "unsupported extension name %s", entry->name); + error = -1; + +done: + git_str_dispose(&cfg); + return error; +} + +static int check_extensions(git_config *config, int version) +{ + if (version < 1) + return 0; + + return git_config_foreach_match(config, "^extensions\\.", check_valid_extension, NULL); +} + +static int load_objectformat(git_repository *repo, git_config *config) +{ + git_config_entry *entry = NULL; + int error; + + if ((error = git_config_get_entry(&entry, config, "extensions.objectformat")) < 0) { + if (error == GIT_ENOTFOUND) { + repo->oid_type = GIT_OID_DEFAULT; + git_error_clear(); + error = 0; + } + + goto done; + } + + if ((repo->oid_type = git_oid_type_fromstr(entry->value)) == 0) { + git_error_set(GIT_ERROR_REPOSITORY, + "unknown object format '%s'", entry->value); + error = GIT_EINVALID; + } + +done: + git_config_entry_free(entry); + return error; +} + +int git_repository__set_objectformat( + git_repository *repo, + git_oid_t oid_type) +{ + git_config *cfg; + + /* + * Older clients do not necessarily understand the + * `objectformat` extension, even when it's set to an + * object format that they understand (SHA1). Do not set + * the objectformat extension unless we're not using the + * default object format. + */ + if (oid_type == GIT_OID_DEFAULT) + return 0; + + if (!git_repository_is_empty(repo) && repo->oid_type != oid_type) { + git_error_set(GIT_ERROR_REPOSITORY, + "cannot change object id type of existing repository"); + return -1; + } + + if (git_repository_config__weakptr(&cfg, repo) < 0) + return -1; + + if (git_config_set_int32(cfg, + "core.repositoryformatversion", 1) < 0 || + git_config_set_string(cfg, "extensions.objectformat", + git_oid_type_name(oid_type)) < 0) + return -1; + + /* + * During repo init, we may create some backends with the + * default oid type. Clear them so that we create them with + * the proper oid type. + */ + if (repo->oid_type != oid_type) { + set_index(repo, NULL); + set_odb(repo, NULL); + set_refdb(repo, NULL); + + repo->oid_type = oid_type; + } + + return 0; +} + +int git_repository__extensions(char ***out, size_t *out_len) +{ + git_vector extensions; + const char *builtin, *user; + char *extension; + size_t i, j; + + if (git_vector_init(&extensions, 8, git__strcmp_cb) < 0) + return -1; + + for (i = 0; i < ARRAY_SIZE(builtin_extensions); i++) { + bool match = false; + + builtin = builtin_extensions[i]; + + git_vector_foreach (&user_extensions, j, user) { + if (user[0] == '!' && strcmp(builtin, &user[1]) == 0) { + match = true; + break; + } + } + + if (match) + continue; + + if ((extension = git__strdup(builtin)) == NULL || + git_vector_insert(&extensions, extension) < 0) + return -1; + } + + git_vector_foreach (&user_extensions, i, user) { + if (user[0] == '!') + continue; + + if ((extension = git__strdup(user)) == NULL || + git_vector_insert(&extensions, extension) < 0) + return -1; + } + + git_vector_sort(&extensions); + + *out = (char **)git_vector_detach(out_len, NULL, &extensions); + return 0; +} + +static int dup_ext_err(void **old, void *extension) +{ + GIT_UNUSED(old); + GIT_UNUSED(extension); + return GIT_EEXISTS; +} + +int git_repository__set_extensions(const char **extensions, size_t len) +{ + char *extension; + size_t i, j; + int error; + + git_repository__free_extensions(); + + for (i = 0; i < len; i++) { + bool is_builtin = false; + + for (j = 0; j < ARRAY_SIZE(builtin_extensions); j++) { + if (strcmp(builtin_extensions[j], extensions[i]) == 0) { + is_builtin = true; + break; + } + } + + if (is_builtin) + continue; + + if ((extension = git__strdup(extensions[i])) == NULL) + return -1; + + if ((error = git_vector_insert_sorted(&user_extensions, extension, dup_ext_err)) < 0) { + git__free(extension); + + if (error != GIT_EEXISTS) + return -1; + } + } + + return 0; +} + +void git_repository__free_extensions(void) +{ + git_vector_free_deep(&user_extensions); +} + +int git_repository_create_head(const char *git_dir, const char *ref_name) +{ + git_str ref_path = GIT_STR_INIT; + git_filebuf ref = GIT_FILEBUF_INIT; + const char *fmt; + int error; + + if ((error = git_str_joinpath(&ref_path, git_dir, GIT_HEAD_FILE)) < 0 || + (error = git_filebuf_open(&ref, ref_path.ptr, 0, GIT_REFS_FILE_MODE)) < 0) + goto out; + + if (git__prefixcmp(ref_name, GIT_REFS_DIR) == 0) + fmt = "ref: %s\n"; + else + fmt = "ref: " GIT_REFS_HEADS_DIR "%s\n"; + + if ((error = git_filebuf_printf(&ref, fmt, ref_name)) < 0 || + (error = git_filebuf_commit(&ref)) < 0) + goto out; + +out: + git_str_dispose(&ref_path); + git_filebuf_cleanup(&ref); + return error; +} + +static bool is_chmod_supported(const char *file_path) +{ + struct stat st1, st2; + + if (p_stat(file_path, &st1) < 0) + return false; + + if (p_chmod(file_path, st1.st_mode ^ S_IXUSR) < 0) + return false; + + if (p_stat(file_path, &st2) < 0) + return false; + + return (st1.st_mode != st2.st_mode); +} + +static bool is_filesystem_case_insensitive(const char *gitdir_path) +{ + git_str path = GIT_STR_INIT; + int is_insensitive = -1; + + if (!git_str_joinpath(&path, gitdir_path, "CoNfIg")) + is_insensitive = git_fs_path_exists(git_str_cstr(&path)); + + git_str_dispose(&path); + return is_insensitive; +} + +/* + * Return a configuration object with only the global and system + * configurations; no repository-level configuration. + */ +static int load_global_config(git_config **config, bool use_env) +{ + git_str global_buf = GIT_STR_INIT; + git_str xdg_buf = GIT_STR_INIT; + git_str system_buf = GIT_STR_INIT; + git_str programdata_buf = GIT_STR_INIT; + int error; + + if (!(error = config_path_system(&system_buf, use_env)) && + !(error = config_path_global(&global_buf, use_env))) { + git_config__find_xdg(&xdg_buf); + git_config__find_programdata(&programdata_buf); + + error = load_config(config, NULL, + path_unless_empty(&global_buf), + path_unless_empty(&xdg_buf), + path_unless_empty(&system_buf), + path_unless_empty(&programdata_buf)); + } + + git_str_dispose(&global_buf); + git_str_dispose(&xdg_buf); + git_str_dispose(&system_buf); + git_str_dispose(&programdata_buf); + + return error; +} + +static bool are_symlinks_supported(const char *wd_path, bool use_env) +{ + git_config *config = NULL; + int symlinks = 0; + + /* + * To emulate Git for Windows, symlinks on Windows must be explicitly + * opted-in. We examine the system configuration for a core.symlinks + * set to true. If found, we then examine the filesystem to see if + * symlinks are _actually_ supported by the current user. If that is + * _not_ set, then we do not test or enable symlink support. + */ +#ifdef GIT_WIN32 + if (load_global_config(&config, use_env) < 0 || + git_config_get_bool(&symlinks, config, "core.symlinks") < 0 || + !symlinks) + goto done; +#else + GIT_UNUSED(use_env); +#endif + + if (!(symlinks = git_fs_path_supports_symlinks(wd_path))) + goto done; + +done: + git_config_free(config); + return symlinks != 0; +} + +static int create_empty_file(const char *path, mode_t mode) +{ + int fd; + + if ((fd = p_creat(path, mode)) < 0) { + git_error_set(GIT_ERROR_OS, "error while creating '%s'", path); + return -1; + } + + if (p_close(fd) < 0) { + git_error_set(GIT_ERROR_OS, "error while closing '%s'", path); + return -1; + } + + return 0; +} + +static int repo_local_config( + git_config **out, + git_str *config_dir, + git_repository *repo, + const char *repo_dir) +{ + int error = 0; + git_config *parent; + const char *cfg_path; + + if (git_str_joinpath(config_dir, repo_dir, GIT_CONFIG_FILENAME_INREPO) < 0) + return -1; + cfg_path = git_str_cstr(config_dir); + + /* make LOCAL config if missing */ + if (!git_fs_path_isfile(cfg_path) && + (error = create_empty_file(cfg_path, GIT_CONFIG_FILE_MODE)) < 0) + return error; + + /* if no repo, just open that file directly */ + if (!repo) + return git_config_open_ondisk(out, cfg_path); + + /* otherwise, open parent config and get that level */ + if ((error = git_repository_config__weakptr(&parent, repo)) < 0) + return error; + + if (git_config_open_level(out, parent, GIT_CONFIG_LEVEL_LOCAL) < 0) { + git_error_clear(); + + if (!(error = git_config_add_file_ondisk( + parent, cfg_path, GIT_CONFIG_LEVEL_LOCAL, repo, false))) + error = git_config_open_level(out, parent, GIT_CONFIG_LEVEL_LOCAL); + } + + git_config_free(parent); + + return error; +} + +static int repo_init_fs_configs( + git_config *cfg, + const char *cfg_path, + const char *repo_dir, + const char *work_dir, + bool update_ignorecase, + bool use_env) +{ + int error = 0; + + if (!work_dir) + work_dir = repo_dir; + + if ((error = git_config_set_bool( + cfg, "core.filemode", is_chmod_supported(cfg_path))) < 0) + return error; + + if (!are_symlinks_supported(work_dir, use_env)) { + if ((error = git_config_set_bool(cfg, "core.symlinks", false)) < 0) + return error; + } else if (git_config_delete_entry(cfg, "core.symlinks") < 0) + git_error_clear(); + + if (update_ignorecase) { + if (is_filesystem_case_insensitive(repo_dir)) { + if ((error = git_config_set_bool(cfg, "core.ignorecase", true)) < 0) + return error; + } else if (git_config_delete_entry(cfg, "core.ignorecase") < 0) + git_error_clear(); + } + +#ifdef GIT_USE_ICONV + if ((error = git_config_set_bool( + cfg, "core.precomposeunicode", + git_fs_path_does_decompose_unicode(work_dir))) < 0) + return error; + /* on non-iconv platforms, don't even set core.precomposeunicode */ +#endif + + return 0; +} + +static int repo_init_config( + const char *repo_dir, + const char *work_dir, + uint32_t flags, + uint32_t mode, + git_oid_t oid_type) +{ + int error = 0; + git_str cfg_path = GIT_STR_INIT, worktree_path = GIT_STR_INIT; + git_config *config = NULL; + bool is_bare = ((flags & GIT_REPOSITORY_INIT_BARE) != 0); + bool is_reinit = ((flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0); + bool use_env = ((flags & GIT_REPOSITORY_OPEN_FROM_ENV) != 0); + int version = GIT_REPO_VERSION_DEFAULT; + + if ((error = repo_local_config(&config, &cfg_path, NULL, repo_dir)) < 0) + goto cleanup; + + if (is_reinit && + (error = check_repositoryformatversion(&version, config)) < 0) + goto cleanup; + + if ((error = check_extensions(config, version)) < 0) + goto cleanup; + +#define SET_REPO_CONFIG(TYPE, NAME, VAL) do { \ + if ((error = git_config_set_##TYPE(config, NAME, VAL)) < 0) \ + goto cleanup; } while (0) + + SET_REPO_CONFIG(bool, "core.bare", is_bare); + SET_REPO_CONFIG(int32, "core.repositoryformatversion", version); + + if ((error = repo_init_fs_configs( + config, cfg_path.ptr, repo_dir, work_dir, + !is_reinit, use_env)) < 0) + goto cleanup; + + if (!is_bare) { + SET_REPO_CONFIG(bool, "core.logallrefupdates", true); + + if (!(flags & GIT_REPOSITORY_INIT__NATURAL_WD)) { + if ((error = git_str_sets(&worktree_path, work_dir)) < 0) + goto cleanup; + + if ((flags & GIT_REPOSITORY_INIT_RELATIVE_GITLINK)) + if ((error = git_fs_path_make_relative(&worktree_path, repo_dir)) < 0) + goto cleanup; + + SET_REPO_CONFIG(string, "core.worktree", worktree_path.ptr); + } else if (is_reinit) { + if (git_config_delete_entry(config, "core.worktree") < 0) + git_error_clear(); + } + } + + if (mode == GIT_REPOSITORY_INIT_SHARED_GROUP) { + SET_REPO_CONFIG(int32, "core.sharedrepository", 1); + SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true); + } + else if (mode == GIT_REPOSITORY_INIT_SHARED_ALL) { + SET_REPO_CONFIG(int32, "core.sharedrepository", 2); + SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true); + } + + if (oid_type != GIT_OID_DEFAULT) { + SET_REPO_CONFIG(int32, "core.repositoryformatversion", 1); + SET_REPO_CONFIG(string, "extensions.objectformat", git_oid_type_name(oid_type)); + } + +cleanup: + git_str_dispose(&cfg_path); + git_str_dispose(&worktree_path); + git_config_free(config); + + return error; +} + +static int repo_reinit_submodule_fs(git_submodule *sm, const char *n, void *p) +{ + git_repository *smrepo = NULL; + GIT_UNUSED(n); GIT_UNUSED(p); + + if (git_submodule_open(&smrepo, sm) < 0 || + git_repository_reinit_filesystem(smrepo, true) < 0) + git_error_clear(); + git_repository_free(smrepo); + + return 0; +} + +int git_repository_reinit_filesystem(git_repository *repo, int recurse) +{ + int error = 0; + git_str path = GIT_STR_INIT; + git_config *config = NULL; + const char *repo_dir = git_repository_path(repo); + + if (!(error = repo_local_config(&config, &path, repo, repo_dir))) + error = repo_init_fs_configs(config, path.ptr, repo_dir, + git_repository_workdir(repo), true, repo->use_env); + + git_config_free(config); + git_str_dispose(&path); + + git_repository__configmap_lookup_cache_clear(repo); + + if (!repo->is_bare && recurse) + (void)git_submodule_foreach(repo, repo_reinit_submodule_fs, NULL); + + return error; +} + +static int repo_write_template( + const char *git_dir, + bool allow_overwrite, + const char *file, + mode_t mode, + bool hidden, + const char *content) +{ + git_str path = GIT_STR_INIT; + int fd, error = 0, flags; + + if (git_str_joinpath(&path, git_dir, file) < 0) + return -1; + + if (allow_overwrite) + flags = O_WRONLY | O_CREAT | O_TRUNC; + else + flags = O_WRONLY | O_CREAT | O_EXCL; + + fd = p_open(git_str_cstr(&path), flags, mode); + + if (fd >= 0) { + error = p_write(fd, content, strlen(content)); + + p_close(fd); + } + else if (errno != EEXIST) + error = fd; + +#ifdef GIT_WIN32 + if (!error && hidden) { + if (git_win32__set_hidden(path.ptr, true) < 0) + error = -1; + } +#else + GIT_UNUSED(hidden); +#endif + + git_str_dispose(&path); + + if (error) + git_error_set(GIT_ERROR_OS, + "failed to initialize repository with template '%s'", file); + + return error; +} + +static int repo_write_gitlink( + const char *in_dir, const char *to_repo, bool use_relative_path) +{ + int error; + git_str buf = GIT_STR_INIT; + git_str path_to_repo = GIT_STR_INIT; + struct stat st; + + git_fs_path_dirname_r(&buf, to_repo); + git_fs_path_to_dir(&buf); + if (git_str_oom(&buf)) + return -1; + + /* don't write gitlink to natural workdir */ + if (git__suffixcmp(to_repo, "/" DOT_GIT "/") == 0 && + strcmp(in_dir, buf.ptr) == 0) + { + error = GIT_PASSTHROUGH; + goto cleanup; + } + + if ((error = git_str_joinpath(&buf, in_dir, DOT_GIT)) < 0) + goto cleanup; + + if (!p_stat(buf.ptr, &st) && !S_ISREG(st.st_mode)) { + git_error_set(GIT_ERROR_REPOSITORY, + "cannot overwrite gitlink file into path '%s'", in_dir); + error = GIT_EEXISTS; + goto cleanup; + } + + git_str_clear(&buf); + + error = git_str_sets(&path_to_repo, to_repo); + + if (!error && use_relative_path) + error = git_fs_path_make_relative(&path_to_repo, in_dir); + + if (!error) + error = git_str_join(&buf, ' ', GIT_FILE_CONTENT_PREFIX, path_to_repo.ptr); + + if (!error) + error = repo_write_template(in_dir, true, DOT_GIT, 0666, true, buf.ptr); + +cleanup: + git_str_dispose(&buf); + git_str_dispose(&path_to_repo); + return error; +} + +static mode_t pick_dir_mode(git_repository_init_options *opts) +{ + if (opts->mode == GIT_REPOSITORY_INIT_SHARED_UMASK) + return 0777; + if (opts->mode == GIT_REPOSITORY_INIT_SHARED_GROUP) + return (0775 | S_ISGID); + if (opts->mode == GIT_REPOSITORY_INIT_SHARED_ALL) + return (0777 | S_ISGID); + return opts->mode; +} + +#include "repo_template.h" + +static int repo_init_structure( + const char *repo_dir, + const char *work_dir, + git_repository_init_options *opts) +{ + int error = 0; + repo_template_item *tpl; + bool external_tpl = + ((opts->flags & GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE) != 0); + mode_t dmode = pick_dir_mode(opts); + bool chmod = opts->mode != GIT_REPOSITORY_INIT_SHARED_UMASK; + + /* Hide the ".git" directory */ +#ifdef GIT_WIN32 + if ((opts->flags & GIT_REPOSITORY_INIT__HAS_DOTGIT) != 0) { + if (git_win32__set_hidden(repo_dir, true) < 0) { + git_error_set(GIT_ERROR_OS, + "failed to mark Git repository folder as hidden"); + return -1; + } + } +#endif + + /* Create the .git gitlink if appropriate */ + if ((opts->flags & GIT_REPOSITORY_INIT_BARE) == 0 && + (opts->flags & GIT_REPOSITORY_INIT__NATURAL_WD) == 0) + { + if (repo_write_gitlink(work_dir, repo_dir, opts->flags & GIT_REPOSITORY_INIT_RELATIVE_GITLINK) < 0) + return -1; + } + + /* Copy external template if requested */ + if (external_tpl) { + git_config *cfg = NULL; + const char *tdir = NULL; + bool default_template = false; + git_str template_buf = GIT_STR_INIT; + + if (opts->template_path) + tdir = opts->template_path; + else if ((error = git_config_open_default(&cfg)) >= 0) { + if (!git_config__get_path(&template_buf, cfg, "init.templatedir")) + tdir = template_buf.ptr; + git_error_clear(); + } + + if (!tdir) { + if (!(error = git_sysdir_find_template_dir(&template_buf))) + tdir = template_buf.ptr; + default_template = true; + } + + /* + * If tdir was the empty string, treat it like tdir was a path to an + * empty directory (so, don't do any copying). This is the behavior + * that git(1) exhibits, although it doesn't seem to be officially + * documented. + */ + if (tdir && git__strcmp(tdir, "") != 0) { + uint32_t cpflags = GIT_CPDIR_COPY_SYMLINKS | + GIT_CPDIR_SIMPLE_TO_MODE | + GIT_CPDIR_COPY_DOTFILES; + if (opts->mode != GIT_REPOSITORY_INIT_SHARED_UMASK) + cpflags |= GIT_CPDIR_CHMOD_DIRS; + error = git_futils_cp_r(tdir, repo_dir, cpflags, dmode); + } + + git_str_dispose(&template_buf); + git_config_free(cfg); + + /* If tdir does not exist, then do not error out. This matches the + * behaviour of git(1), which just prints a warning and continues. + * TODO: issue warning when warning API is available. + * `git` prints to stderr: 'warning: templates not found in /path/to/tdir' + */ + if (error < 0) { + if (!default_template && error != GIT_ENOTFOUND) + return error; + + /* if template was default, ignore error and use internal */ + git_error_clear(); + external_tpl = false; + error = 0; + } + } + + /* Copy internal template + * - always ensure existence of dirs + * - only create files if no external template was specified + */ + for (tpl = repo_template; !error && tpl->path; ++tpl) { + if (!tpl->content) { + uint32_t mkdir_flags = GIT_MKDIR_PATH; + if (chmod) + mkdir_flags |= GIT_MKDIR_CHMOD; + + error = git_futils_mkdir_relative( + tpl->path, repo_dir, dmode, mkdir_flags, NULL); + } + else if (!external_tpl) { + const char *content = tpl->content; + + if (opts->description && strcmp(tpl->path, GIT_DESC_FILE) == 0) + content = opts->description; + + error = repo_write_template( + repo_dir, false, tpl->path, tpl->mode, false, content); + } + } + + return error; +} + +static int mkdir_parent(git_str *buf, uint32_t mode, bool skip2) +{ + /* When making parent directories during repository initialization + * don't try to set gid or grant world write access + */ + return git_futils_mkdir( + buf->ptr, mode & ~(S_ISGID | 0002), + GIT_MKDIR_PATH | GIT_MKDIR_VERIFY_DIR | + (skip2 ? GIT_MKDIR_SKIP_LAST2 : GIT_MKDIR_SKIP_LAST)); +} + +static int repo_init_directories( + git_str *repo_path, + git_str *wd_path, + const char *given_repo, + git_repository_init_options *opts) +{ + int error = 0; + bool is_bare, add_dotgit, has_dotgit, natural_wd; + mode_t dirmode; + + /* There are three possible rules for what we are allowed to create: + * - MKPATH means anything we need + * - MKDIR means just the .git directory and its parent and the workdir + * - Neither means only the .git directory can be created + * + * There are 5 "segments" of path that we might need to deal with: + * 1. The .git directory + * 2. The parent of the .git directory + * 3. Everything above the parent of the .git directory + * 4. The working directory (often the same as #2) + * 5. Everything above the working directory (often the same as #3) + * + * For all directories created, we start with the init_mode value for + * permissions and then strip off bits in some cases: + * + * For MKPATH, we create #3 (and #5) paths without S_ISGID or S_IWOTH + * For MKPATH and MKDIR, we create #2 (and #4) without S_ISGID + * For all rules, we create #1 using the untouched init_mode + */ + + /* set up repo path */ + + is_bare = ((opts->flags & GIT_REPOSITORY_INIT_BARE) != 0); + + add_dotgit = + (opts->flags & GIT_REPOSITORY_INIT_NO_DOTGIT_DIR) == 0 && + !is_bare && + git__suffixcmp(given_repo, "/" DOT_GIT) != 0 && + git__suffixcmp(given_repo, "/" GIT_DIR) != 0; + + if (git_str_joinpath(repo_path, given_repo, add_dotgit ? GIT_DIR : "") < 0) + return -1; + + git_fs_path_mkposix(repo_path->ptr); + + has_dotgit = (git__suffixcmp(repo_path->ptr, "/" GIT_DIR) == 0); + if (has_dotgit) + opts->flags |= GIT_REPOSITORY_INIT__HAS_DOTGIT; + + /* set up workdir path */ + + if (!is_bare) { + if (opts->workdir_path) { + if (git_fs_path_join_unrooted( + wd_path, opts->workdir_path, repo_path->ptr, NULL) < 0) + return -1; + } else if (has_dotgit) { + if (git_fs_path_dirname_r(wd_path, repo_path->ptr) < 0) + return -1; + } else { + git_error_set(GIT_ERROR_REPOSITORY, "cannot pick working directory" + " for non-bare repository that isn't a '.git' directory"); + return -1; + } + + if (git_fs_path_to_dir(wd_path) < 0) + return -1; + } else { + git_str_clear(wd_path); + } + + natural_wd = + has_dotgit && + wd_path->size > 0 && + wd_path->size + strlen(GIT_DIR) == repo_path->size && + memcmp(repo_path->ptr, wd_path->ptr, wd_path->size) == 0; + if (natural_wd) + opts->flags |= GIT_REPOSITORY_INIT__NATURAL_WD; + + /* create directories as needed / requested */ + + dirmode = pick_dir_mode(opts); + + if ((opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0) { + /* create path #5 */ + if (wd_path->size > 0 && + (error = mkdir_parent(wd_path, dirmode, false)) < 0) + return error; + + /* create path #3 (if not the same as #5) */ + if (!natural_wd && + (error = mkdir_parent(repo_path, dirmode, has_dotgit)) < 0) + return error; + } + + if ((opts->flags & GIT_REPOSITORY_INIT_MKDIR) != 0 || + (opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0) + { + /* create path #4 */ + if (wd_path->size > 0 && + (error = git_futils_mkdir( + wd_path->ptr, dirmode & ~S_ISGID, + GIT_MKDIR_VERIFY_DIR)) < 0) + return error; + + /* create path #2 (if not the same as #4) */ + if (!natural_wd && + (error = git_futils_mkdir( + repo_path->ptr, dirmode & ~S_ISGID, + GIT_MKDIR_VERIFY_DIR | GIT_MKDIR_SKIP_LAST)) < 0) + return error; + } + + if ((opts->flags & GIT_REPOSITORY_INIT_MKDIR) != 0 || + (opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0 || + has_dotgit) + { + /* create path #1 */ + error = git_futils_mkdir(repo_path->ptr, dirmode, + GIT_MKDIR_VERIFY_DIR | ((dirmode & S_ISGID) ? GIT_MKDIR_CHMOD : 0)); + } + + /* prettify both directories now that they are created */ + + if (!error) { + error = git_fs_path_prettify_dir(repo_path, repo_path->ptr, NULL); + + if (!error && wd_path->size > 0) + error = git_fs_path_prettify_dir(wd_path, wd_path->ptr, NULL); + } + + return error; +} + +static int repo_init_head(const char *repo_dir, const char *given) +{ + git_config *cfg = NULL; + git_str head_path = GIT_STR_INIT, cfg_branch = GIT_STR_INIT; + const char *initial_head = NULL; + int error; + + if ((error = git_str_joinpath(&head_path, repo_dir, GIT_HEAD_FILE)) < 0) + goto out; + + /* + * A template may have set a HEAD; use that unless it's been + * overridden by the caller's given initial head setting. + */ + if (git_fs_path_exists(head_path.ptr) && !given) + goto out; + + if (given) { + initial_head = given; + } else if ((error = git_config_open_default(&cfg)) >= 0 && + (error = git_config__get_string_buf(&cfg_branch, cfg, "init.defaultbranch")) >= 0 && + *cfg_branch.ptr) { + initial_head = cfg_branch.ptr; + } + + if (!initial_head) + initial_head = GIT_BRANCH_DEFAULT; + + error = git_repository_create_head(repo_dir, initial_head); + +out: + git_config_free(cfg); + git_str_dispose(&head_path); + git_str_dispose(&cfg_branch); + + return error; +} + +static int repo_init_create_origin(git_repository *repo, const char *url) +{ + int error; + git_remote *remote; + + if (!(error = git_remote_create(&remote, repo, GIT_REMOTE_ORIGIN, url))) { + git_remote_free(remote); + } + + return error; +} + +int git_repository_init( + git_repository **repo_out, const char *path, unsigned is_bare) +{ + git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT; + + opts.flags = GIT_REPOSITORY_INIT_MKPATH; /* don't love this default */ + if (is_bare) + opts.flags |= GIT_REPOSITORY_INIT_BARE; + + return git_repository_init_ext(repo_out, path, &opts); +} + +int git_repository_init_ext( + git_repository **out, + const char *given_repo, + git_repository_init_options *opts) +{ + git_str repo_path = GIT_STR_INIT, wd_path = GIT_STR_INIT, + common_path = GIT_STR_INIT; + const char *wd; + bool is_valid; + git_oid_t oid_type = GIT_OID_DEFAULT; + int error; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(given_repo); + GIT_ASSERT_ARG(opts); + + GIT_ERROR_CHECK_VERSION(opts, GIT_REPOSITORY_INIT_OPTIONS_VERSION, "git_repository_init_options"); + +#ifdef GIT_EXPERIMENTAL_SHA256 + if (opts->oid_type) + oid_type = opts->oid_type; +#endif + + if ((error = repo_init_directories(&repo_path, &wd_path, given_repo, opts)) < 0) + goto out; + + wd = (opts->flags & GIT_REPOSITORY_INIT_BARE) ? NULL : git_str_cstr(&wd_path); + + if ((error = is_valid_repository_path(&is_valid, &repo_path, &common_path, opts->flags)) < 0) + goto out; + + if (is_valid) { + if ((opts->flags & GIT_REPOSITORY_INIT_NO_REINIT) != 0) { + git_error_set(GIT_ERROR_REPOSITORY, + "attempt to reinitialize '%s'", given_repo); + error = GIT_EEXISTS; + goto out; + } + + opts->flags |= GIT_REPOSITORY_INIT__IS_REINIT; + + if ((error = repo_init_config(repo_path.ptr, wd, opts->flags, opts->mode, oid_type)) < 0) + goto out; + + /* TODO: reinitialize the templates */ + } else { + if ((error = repo_init_structure(repo_path.ptr, wd, opts)) < 0 || + (error = repo_init_config(repo_path.ptr, wd, opts->flags, opts->mode, oid_type)) < 0 || + (error = repo_init_head(repo_path.ptr, opts->initial_head)) < 0) + goto out; + } + + if ((error = git_repository_open(out, repo_path.ptr)) < 0) + goto out; + + if (opts->origin_url && + (error = repo_init_create_origin(*out, opts->origin_url)) < 0) + goto out; + +out: + git_str_dispose(&common_path); + git_str_dispose(&repo_path); + git_str_dispose(&wd_path); + + return error; +} + +int git_repository_head_detached(git_repository *repo) +{ + git_reference *ref; + git_odb *odb = NULL; + int exists; + + if (git_repository_odb__weakptr(&odb, repo) < 0) + return -1; + + if (git_reference_lookup(&ref, repo, GIT_HEAD_FILE) < 0) + return -1; + + if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) { + git_reference_free(ref); + return 0; + } + + exists = git_odb_exists(odb, git_reference_target(ref)); + + git_reference_free(ref); + return exists; +} + +int git_repository_head_detached_for_worktree(git_repository *repo, const char *name) +{ + git_reference *ref = NULL; + int error; + + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(name); + + if ((error = git_repository_head_for_worktree(&ref, repo, name)) < 0) + goto out; + + error = (git_reference_type(ref) != GIT_REFERENCE_SYMBOLIC); +out: + git_reference_free(ref); + + return error; +} + +int git_repository_head(git_reference **head_out, git_repository *repo) +{ + git_reference *head; + int error; + + GIT_ASSERT_ARG(head_out); + + if ((error = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0) + return error; + + if (git_reference_type(head) == GIT_REFERENCE_DIRECT) { + *head_out = head; + return 0; + } + + error = git_reference_lookup_resolved(head_out, repo, git_reference_symbolic_target(head), -1); + git_reference_free(head); + + return error == GIT_ENOTFOUND ? GIT_EUNBORNBRANCH : error; +} + +int git_repository_head_for_worktree(git_reference **out, git_repository *repo, const char *name) +{ + git_repository *worktree_repo = NULL; + git_worktree *worktree = NULL; + git_reference *head = NULL; + int error; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(name); + + *out = NULL; + + if ((error = git_worktree_lookup(&worktree, repo, name)) < 0 || + (error = git_repository_open_from_worktree(&worktree_repo, worktree)) < 0 || + (error = git_reference_lookup(&head, worktree_repo, GIT_HEAD_FILE)) < 0) + goto out; + + if (git_reference_type(head) != GIT_REFERENCE_DIRECT) { + if ((error = git_reference_lookup_resolved(out, worktree_repo, git_reference_symbolic_target(head), -1)) < 0) + goto out; + } else { + *out = head; + head = NULL; + } + +out: + git_reference_free(head); + git_worktree_free(worktree); + git_repository_free(worktree_repo); + return error; +} + +int git_repository_foreach_worktree(git_repository *repo, + git_repository_foreach_worktree_cb cb, + void *payload) +{ + git_strarray worktrees = {0}; + git_repository *worktree_repo = NULL; + git_worktree *worktree = NULL; + int error; + size_t i; + + /* apply operation to repository supplied when commondir is empty, implying there's + * no linked worktrees to iterate, which can occur when using custom odb/refdb + */ + if (!repo->commondir) + return cb(repo, payload); + + if ((error = git_repository_open(&worktree_repo, repo->commondir)) < 0 || + (error = cb(worktree_repo, payload) != 0)) + goto out; + + git_repository_free(worktree_repo); + worktree_repo = NULL; + + if ((error = git_worktree_list(&worktrees, repo)) < 0) + goto out; + + for (i = 0; i < worktrees.count; i++) { + git_repository_free(worktree_repo); + worktree_repo = NULL; + git_worktree_free(worktree); + worktree = NULL; + + if ((error = git_worktree_lookup(&worktree, repo, worktrees.strings[i]) < 0) || + (error = git_repository_open_from_worktree(&worktree_repo, worktree)) < 0) { + if (error != GIT_ENOTFOUND) + goto out; + error = 0; + continue; + } + + if ((error = cb(worktree_repo, payload)) != 0) + goto out; + } + +out: + git_strarray_dispose(&worktrees); + git_repository_free(worktree_repo); + git_worktree_free(worktree); + return error; +} + +int git_repository_head_unborn(git_repository *repo) +{ + git_reference *ref = NULL; + int error; + + error = git_repository_head(&ref, repo); + git_reference_free(ref); + + if (error == GIT_EUNBORNBRANCH) { + git_error_clear(); + return 1; + } + + if (error < 0) + return -1; + + return 0; +} + +static int repo_contains_no_reference(git_repository *repo) +{ + git_reference_iterator *iter; + const char *refname; + int error; + + if ((error = git_reference_iterator_new(&iter, repo)) < 0) + return error; + + error = git_reference_next_name(&refname, iter); + git_reference_iterator_free(iter); + + if (error == GIT_ITEROVER) + return 1; + + return error; +} + +int git_repository_initialbranch(git_str *out, git_repository *repo) +{ + git_config *config; + git_config_entry *entry = NULL; + const char *branch; + int valid, error; + + if ((error = git_repository_config__weakptr(&config, repo)) < 0) + return error; + + if ((error = git_config_get_entry(&entry, config, "init.defaultbranch")) == 0 && + *entry->value) { + branch = entry->value; + } + else if (!error || error == GIT_ENOTFOUND) { + branch = GIT_BRANCH_DEFAULT; + } + else { + goto done; + } + + if ((error = git_str_puts(out, GIT_REFS_HEADS_DIR)) < 0 || + (error = git_str_puts(out, branch)) < 0 || + (error = git_reference_name_is_valid(&valid, out->ptr)) < 0) + goto done; + + if (!valid) { + git_error_set(GIT_ERROR_INVALID, "the value of init.defaultBranch is not a valid branch name"); + error = -1; + } + +done: + git_config_entry_free(entry); + return error; +} + +int git_repository_is_empty(git_repository *repo) +{ + git_reference *head = NULL; + git_str initialbranch = GIT_STR_INIT; + int result = 0; + + if ((result = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0 || + (result = git_repository_initialbranch(&initialbranch, repo)) < 0) + goto done; + + result = (git_reference_type(head) == GIT_REFERENCE_SYMBOLIC && + strcmp(git_reference_symbolic_target(head), initialbranch.ptr) == 0 && + repo_contains_no_reference(repo)); + +done: + git_reference_free(head); + git_str_dispose(&initialbranch); + + return result; +} + +static const char *resolved_parent_path(const git_repository *repo, git_repository_item_t item, git_repository_item_t fallback) +{ + const char *parent; + + switch (item) { + case GIT_REPOSITORY_ITEM_GITDIR: + parent = git_repository_path(repo); + break; + case GIT_REPOSITORY_ITEM_WORKDIR: + parent = git_repository_workdir(repo); + break; + case GIT_REPOSITORY_ITEM_COMMONDIR: + parent = git_repository_commondir(repo); + break; + default: + git_error_set(GIT_ERROR_INVALID, "invalid item directory"); + return NULL; + } + if (!parent && fallback != GIT_REPOSITORY_ITEM__LAST) + return resolved_parent_path(repo, fallback, GIT_REPOSITORY_ITEM__LAST); + + return parent; +} + +int git_repository_item_path( + git_buf *out, + const git_repository *repo, + git_repository_item_t item) +{ + GIT_BUF_WRAP_PRIVATE(out, git_repository__item_path, repo, item); +} + +int git_repository__item_path( + git_str *out, + const git_repository *repo, + git_repository_item_t item) +{ + const char *parent = resolved_parent_path(repo, items[item].parent, items[item].fallback); + if (parent == NULL) { + git_error_set(GIT_ERROR_INVALID, "path cannot exist in repository"); + return GIT_ENOTFOUND; + } + + if (git_str_sets(out, parent) < 0) + return -1; + + if (items[item].name) { + if (git_str_joinpath(out, parent, items[item].name) < 0) + return -1; + } + + if (items[item].directory) { + if (git_fs_path_to_dir(out) < 0) + return -1; + } + + return 0; +} + +const char *git_repository_path(const git_repository *repo) +{ + GIT_ASSERT_ARG_WITH_RETVAL(repo, NULL); + return repo->gitdir; +} + +const char *git_repository_workdir(const git_repository *repo) +{ + GIT_ASSERT_ARG_WITH_RETVAL(repo, NULL); + + if (repo->is_bare) + return NULL; + + return repo->workdir; +} + +int git_repository_workdir_path( + git_str *out, git_repository *repo, const char *path) +{ + int error; + + if (!repo->workdir) { + git_error_set(GIT_ERROR_REPOSITORY, "repository has no working directory"); + return GIT_EBAREREPO; + } + + if (!(error = git_str_joinpath(out, repo->workdir, path))) + error = git_path_validate_str_length(repo, out); + + return error; +} + +const char *git_repository_commondir(const git_repository *repo) +{ + GIT_ASSERT_ARG_WITH_RETVAL(repo, NULL); + return repo->commondir; +} + +int git_repository_set_workdir( + git_repository *repo, const char *workdir, int update_gitlink) +{ + int error = 0; + git_str path = GIT_STR_INIT; + + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(workdir); + + if (git_fs_path_prettify_dir(&path, workdir, NULL) < 0) + return -1; + + if (repo->workdir && strcmp(repo->workdir, path.ptr) == 0) { + git_str_dispose(&path); + return 0; + } + + if (update_gitlink) { + git_config *config; + + if (git_repository_config__weakptr(&config, repo) < 0) { + git_str_dispose(&path); + return -1; + } + + error = repo_write_gitlink(path.ptr, git_repository_path(repo), false); + + /* passthrough error means gitlink is unnecessary */ + if (error == GIT_PASSTHROUGH) + error = git_config_delete_entry(config, "core.worktree"); + else if (!error) + error = git_config_set_string(config, "core.worktree", path.ptr); + + if (!error) + error = git_config_set_bool(config, "core.bare", false); + } + + if (!error) { + char *old_workdir = repo->workdir; + + repo->workdir = git_str_detach(&path); + repo->is_bare = 0; + + git__free(old_workdir); + } + git_str_dispose(&path); + + return error; +} + +int git_repository_is_bare(const git_repository *repo) +{ + GIT_ASSERT_ARG(repo); + return repo->is_bare; +} + +int git_repository_is_worktree(const git_repository *repo) +{ + GIT_ASSERT_ARG(repo); + return repo->is_worktree; +} + +int git_repository_set_bare(git_repository *repo) +{ + int error; + git_config *config; + + GIT_ASSERT_ARG(repo); + + if (repo->is_bare) + return 0; + + if ((error = git_repository_config__weakptr(&config, repo)) < 0) + return error; + + if ((error = git_config_set_bool(config, "core.bare", true)) < 0) + return error; + + if ((error = git_config__update_entry(config, "core.worktree", NULL, true, true)) < 0) + return error; + + git__free(repo->workdir); + repo->workdir = NULL; + repo->is_bare = 1; + + return 0; +} + +int git_repository_head_commit(git_commit **commit, git_repository *repo) +{ + git_reference *head; + git_object *obj; + int error; + + if ((error = git_repository_head(&head, repo)) < 0) + return error; + + if ((error = git_reference_peel(&obj, head, GIT_OBJECT_COMMIT)) < 0) + goto cleanup; + + *commit = (git_commit *)obj; + +cleanup: + git_reference_free(head); + return error; +} + +int git_repository_head_tree(git_tree **tree, git_repository *repo) +{ + git_reference *head; + git_object *obj; + int error; + + if ((error = git_repository_head(&head, repo)) < 0) + return error; + + if ((error = git_reference_peel(&obj, head, GIT_OBJECT_TREE)) < 0) + goto cleanup; + + *tree = (git_tree *)obj; + +cleanup: + git_reference_free(head); + return error; +} + +int git_repository__set_orig_head(git_repository *repo, const git_oid *orig_head) +{ + git_filebuf file = GIT_FILEBUF_INIT; + git_str file_path = GIT_STR_INIT; + char orig_head_str[GIT_OID_MAX_HEXSIZE]; + int error = 0; + + git_oid_fmt(orig_head_str, orig_head); + + if ((error = git_str_joinpath(&file_path, repo->gitdir, GIT_ORIG_HEAD_FILE)) == 0 && + (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) == 0 && + (error = git_filebuf_printf(&file, "%.*s\n", (int)git_oid_hexsize(repo->oid_type), orig_head_str)) == 0) + error = git_filebuf_commit(&file); + + if (error < 0) + git_filebuf_cleanup(&file); + + git_str_dispose(&file_path); + + return error; +} + +static int git_repository__message(git_str *out, git_repository *repo) +{ + git_str path = GIT_STR_INIT; + struct stat st; + int error; + + if (git_str_joinpath(&path, repo->gitdir, GIT_MERGE_MSG_FILE) < 0) + return -1; + + if ((error = p_stat(git_str_cstr(&path), &st)) < 0) { + if (errno == ENOENT) + error = GIT_ENOTFOUND; + git_error_set(GIT_ERROR_OS, "could not access message file"); + } else { + error = git_futils_readbuffer(out, git_str_cstr(&path)); + } + + git_str_dispose(&path); + + return error; +} + +int git_repository_message(git_buf *out, git_repository *repo) +{ + GIT_BUF_WRAP_PRIVATE(out, git_repository__message, repo); +} + +int git_repository_message_remove(git_repository *repo) +{ + git_str path = GIT_STR_INIT; + int error; + + if (git_str_joinpath(&path, repo->gitdir, GIT_MERGE_MSG_FILE) < 0) + return -1; + + error = p_unlink(git_str_cstr(&path)); + git_str_dispose(&path); + + return error; +} + +int git_repository_hashfile( + git_oid *out, + git_repository *repo, + const char *path, + git_object_t type, + const char *as_path) +{ + int error; + git_filter_list *fl = NULL; + git_file fd = -1; + uint64_t len; + git_str full_path = GIT_STR_INIT; + const char *workdir = git_repository_workdir(repo); + + /* as_path can be NULL */ + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(path); + GIT_ASSERT_ARG(repo); + + if ((error = git_fs_path_join_unrooted(&full_path, path, workdir, NULL)) < 0 || + (error = git_path_validate_str_length(repo, &full_path)) < 0) + return error; + + /* + * NULL as_path means that we should derive it from the + * given path. + */ + if (!as_path) { + if (workdir && !git__prefixcmp(full_path.ptr, workdir)) + as_path = full_path.ptr + strlen(workdir); + else + as_path = ""; + } + + /* passing empty string for "as_path" indicated --no-filters */ + if (strlen(as_path) > 0) { + error = git_filter_list_load( + &fl, repo, NULL, as_path, + GIT_FILTER_TO_ODB, GIT_FILTER_DEFAULT); + + if (error < 0) + return error; + } + + /* at this point, error is a count of the number of loaded filters */ + + fd = git_futils_open_ro(full_path.ptr); + if (fd < 0) { + error = fd; + goto cleanup; + } + + if ((error = git_futils_filesize(&len, fd)) < 0) + goto cleanup; + + if (!git__is_sizet(len)) { + git_error_set(GIT_ERROR_OS, "file size overflow for 32-bit systems"); + error = -1; + goto cleanup; + } + + error = git_odb__hashfd_filtered(out, fd, (size_t)len, type, repo->oid_type, fl); + +cleanup: + if (fd >= 0) + p_close(fd); + git_filter_list_free(fl); + git_str_dispose(&full_path); + + return error; +} + +static int checkout_message(git_str *out, git_reference *old, const char *new) +{ + const char *idstr; + + git_str_puts(out, "checkout: moving from "); + + if (git_reference_type(old) == GIT_REFERENCE_SYMBOLIC) { + git_str_puts(out, git_reference__shorthand(git_reference_symbolic_target(old))); + } else { + if ((idstr = git_oid_tostr_s(git_reference_target(old))) == NULL) + return -1; + + git_str_puts(out, idstr); + } + + git_str_puts(out, " to "); + + if (git_reference__is_branch(new) || + git_reference__is_tag(new) || + git_reference__is_remote(new)) + git_str_puts(out, git_reference__shorthand(new)); + else + git_str_puts(out, new); + + if (git_str_oom(out)) + return -1; + + return 0; +} + +static int detach(git_repository *repo, const git_oid *id, const char *new) +{ + int error; + git_str log_message = GIT_STR_INIT; + git_object *object = NULL, *peeled = NULL; + git_reference *new_head = NULL, *current = NULL; + + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(id); + + if ((error = git_reference_lookup(¤t, repo, GIT_HEAD_FILE)) < 0) + return error; + + if ((error = git_object_lookup(&object, repo, id, GIT_OBJECT_ANY)) < 0) + goto cleanup; + + if ((error = git_object_peel(&peeled, object, GIT_OBJECT_COMMIT)) < 0) + goto cleanup; + + if (new == NULL && + (new = git_oid_tostr_s(git_object_id(peeled))) == NULL) { + error = -1; + goto cleanup; + } + + if ((error = checkout_message(&log_message, current, new)) < 0) + goto cleanup; + + error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_object_id(peeled), true, git_str_cstr(&log_message)); + +cleanup: + git_str_dispose(&log_message); + git_object_free(object); + git_object_free(peeled); + git_reference_free(current); + git_reference_free(new_head); + return error; +} + +int git_repository_set_head( + git_repository *repo, + const char *refname) +{ + git_reference *ref = NULL, *current = NULL, *new_head = NULL; + git_str log_message = GIT_STR_INIT; + int error; + + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(refname); + + if ((error = git_reference_lookup(¤t, repo, GIT_HEAD_FILE)) < 0) + return error; + + if ((error = checkout_message(&log_message, current, refname)) < 0) + goto cleanup; + + error = git_reference_lookup(&ref, repo, refname); + if (error < 0 && error != GIT_ENOTFOUND) + goto cleanup; + + if (ref && current->type == GIT_REFERENCE_SYMBOLIC && git__strcmp(current->target.symbolic, ref->name) && + git_reference_is_branch(ref) && git_branch_is_checked_out(ref)) { + git_error_set(GIT_ERROR_REPOSITORY, "cannot set HEAD to reference '%s' as it is the current HEAD " + "of a linked repository.", git_reference_name(ref)); + error = -1; + goto cleanup; + } + + if (!error) { + if (git_reference_is_branch(ref)) { + error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, + git_reference_name(ref), true, git_str_cstr(&log_message)); + } else { + error = detach(repo, git_reference_target(ref), + git_reference_is_tag(ref) || git_reference_is_remote(ref) ? refname : NULL); + } + } else if (git_reference__is_branch(refname)) { + error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, refname, + true, git_str_cstr(&log_message)); + } + +cleanup: + git_str_dispose(&log_message); + git_reference_free(current); + git_reference_free(ref); + git_reference_free(new_head); + return error; +} + +int git_repository_set_head_detached( + git_repository *repo, + const git_oid *committish) +{ + return detach(repo, committish, NULL); +} + +int git_repository_set_head_detached_from_annotated( + git_repository *repo, + const git_annotated_commit *committish) +{ + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(committish); + + return detach(repo, git_annotated_commit_id(committish), committish->description); +} + +int git_repository_detach_head(git_repository *repo) +{ + git_reference *old_head = NULL, *new_head = NULL, *current = NULL; + git_object *object = NULL; + git_str log_message = GIT_STR_INIT; + const char *idstr; + int error; + + GIT_ASSERT_ARG(repo); + + if ((error = git_reference_lookup(¤t, repo, GIT_HEAD_FILE)) < 0) + return error; + + if ((error = git_repository_head(&old_head, repo)) < 0) + goto cleanup; + + if ((error = git_object_lookup(&object, repo, git_reference_target(old_head), GIT_OBJECT_COMMIT)) < 0) + goto cleanup; + + if ((idstr = git_oid_tostr_s(git_object_id(object))) == NULL) { + error = -1; + goto cleanup; + } + + if ((error = checkout_message(&log_message, current, idstr)) < 0) + goto cleanup; + + error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_reference_target(old_head), + 1, git_str_cstr(&log_message)); + +cleanup: + git_str_dispose(&log_message); + git_object_free(object); + git_reference_free(old_head); + git_reference_free(new_head); + git_reference_free(current); + return error; +} + +/** + * Loosely ported from git.git + * https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh#L198-289 + */ +int git_repository_state(git_repository *repo) +{ + git_str repo_path = GIT_STR_INIT; + int state = GIT_REPOSITORY_STATE_NONE; + + GIT_ASSERT_ARG(repo); + + if (git_str_puts(&repo_path, repo->gitdir) < 0) + return -1; + + if (git_fs_path_contains_file(&repo_path, GIT_REBASE_MERGE_INTERACTIVE_FILE)) + state = GIT_REPOSITORY_STATE_REBASE_INTERACTIVE; + else if (git_fs_path_contains_dir(&repo_path, GIT_REBASE_MERGE_DIR)) + state = GIT_REPOSITORY_STATE_REBASE_MERGE; + else if (git_fs_path_contains_file(&repo_path, GIT_REBASE_APPLY_REBASING_FILE)) + state = GIT_REPOSITORY_STATE_REBASE; + else if (git_fs_path_contains_file(&repo_path, GIT_REBASE_APPLY_APPLYING_FILE)) + state = GIT_REPOSITORY_STATE_APPLY_MAILBOX; + else if (git_fs_path_contains_dir(&repo_path, GIT_REBASE_APPLY_DIR)) + state = GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE; + else if (git_fs_path_contains_file(&repo_path, GIT_MERGE_HEAD_FILE)) + state = GIT_REPOSITORY_STATE_MERGE; + else if (git_fs_path_contains_file(&repo_path, GIT_REVERT_HEAD_FILE)) { + state = GIT_REPOSITORY_STATE_REVERT; + if (git_fs_path_contains_file(&repo_path, GIT_SEQUENCER_TODO_FILE)) { + state = GIT_REPOSITORY_STATE_REVERT_SEQUENCE; + } + } else if (git_fs_path_contains_file(&repo_path, GIT_CHERRYPICK_HEAD_FILE)) { + state = GIT_REPOSITORY_STATE_CHERRYPICK; + if (git_fs_path_contains_file(&repo_path, GIT_SEQUENCER_TODO_FILE)) { + state = GIT_REPOSITORY_STATE_CHERRYPICK_SEQUENCE; + } + } else if (git_fs_path_contains_file(&repo_path, GIT_BISECT_LOG_FILE)) + state = GIT_REPOSITORY_STATE_BISECT; + + git_str_dispose(&repo_path); + return state; +} + +int git_repository__cleanup_files( + git_repository *repo, const char *files[], size_t files_len) +{ + git_str buf = GIT_STR_INIT; + size_t i; + int error; + + for (error = 0, i = 0; !error && i < files_len; ++i) { + const char *path; + + if (git_str_joinpath(&buf, repo->gitdir, files[i]) < 0) + return -1; + + path = git_str_cstr(&buf); + + if (git_fs_path_isfile(path)) { + error = p_unlink(path); + } else if (git_fs_path_isdir(path)) { + error = git_futils_rmdir_r(path, NULL, + GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS); + } + + git_str_clear(&buf); + } + + git_str_dispose(&buf); + return error; +} + +static const char *state_files[] = { + GIT_MERGE_HEAD_FILE, + GIT_MERGE_MODE_FILE, + GIT_MERGE_MSG_FILE, + GIT_REVERT_HEAD_FILE, + GIT_CHERRYPICK_HEAD_FILE, + GIT_BISECT_LOG_FILE, + GIT_REBASE_MERGE_DIR, + GIT_REBASE_APPLY_DIR, + GIT_SEQUENCER_DIR, +}; + +int git_repository_state_cleanup(git_repository *repo) +{ + GIT_ASSERT_ARG(repo); + + return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files)); +} + +int git_repository__shallow_roots( + git_oid **out, + size_t *out_len, + git_repository *repo) +{ + int error = 0; + + if (!repo->shallow_grafts && (error = load_grafts(repo)) < 0) + return error; + + if ((error = git_grafts_refresh(repo->shallow_grafts)) < 0) + return error; + + if ((error = git_grafts_oids(out, out_len, repo->shallow_grafts)) < 0) + return error; + + return 0; +} + +int git_repository__shallow_roots_write(git_repository *repo, git_oidarray *roots) +{ + git_filebuf file = GIT_FILEBUF_INIT; + git_str path = GIT_STR_INIT; + char oid_str[GIT_OID_MAX_HEXSIZE + 1]; + size_t i; + int filebuf_hash, error = 0; + + GIT_ASSERT_ARG(repo); + + filebuf_hash = git_filebuf_hash_flags(git_oid_algorithm(repo->oid_type)); + GIT_ASSERT(filebuf_hash); + + if ((error = git_str_joinpath(&path, repo->gitdir, "shallow")) < 0) + goto on_error; + + if ((error = git_filebuf_open(&file, git_str_cstr(&path), filebuf_hash, 0666)) < 0) + goto on_error; + + for (i = 0; i < roots->count; i++) { + git_oid_tostr(oid_str, sizeof(oid_str), &roots->ids[i]); + git_filebuf_write(&file, oid_str, git_oid_hexsize(repo->oid_type)); + git_filebuf_write(&file, "\n", 1); + } + + git_filebuf_commit(&file); + + if ((error = load_grafts(repo)) < 0) { + error = -1; + goto on_error; + } + + if (!roots->count) + remove(path.ptr); + +on_error: + git_str_dispose(&path); + + return error; +} + +int git_repository_is_shallow(git_repository *repo) +{ + git_str path = GIT_STR_INIT; + struct stat st; + int error; + + if ((error = git_str_joinpath(&path, repo->gitdir, "shallow")) < 0) + return error; + + error = git_fs_path_lstat(path.ptr, &st); + git_str_dispose(&path); + + if (error == GIT_ENOTFOUND) { + git_error_clear(); + return 0; + } + + if (error < 0) + return error; + + return st.st_size == 0 ? 0 : 1; +} + +int git_repository_init_options_init( + git_repository_init_options *opts, unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE( + opts, version, git_repository_init_options, + GIT_REPOSITORY_INIT_OPTIONS_INIT); + return 0; +} + +#ifndef GIT_DEPRECATE_HARD +int git_repository_init_init_options( + git_repository_init_options *opts, unsigned int version) +{ + return git_repository_init_options_init(opts, version); +} +#endif + +int git_repository_ident(const char **name, const char **email, const git_repository *repo) +{ + *name = repo->ident_name; + *email = repo->ident_email; + + return 0; +} + +int git_repository_set_ident(git_repository *repo, const char *name, const char *email) +{ + char *tmp_name = NULL, *tmp_email = NULL; + + if (name) { + tmp_name = git__strdup(name); + GIT_ERROR_CHECK_ALLOC(tmp_name); + } + + if (email) { + tmp_email = git__strdup(email); + GIT_ERROR_CHECK_ALLOC(tmp_email); + } + + tmp_name = git_atomic_swap(repo->ident_name, tmp_name); + tmp_email = git_atomic_swap(repo->ident_email, tmp_email); + + git__free(tmp_name); + git__free(tmp_email); + + return 0; +} + +int git_repository_submodule_cache_all(git_repository *repo) +{ + GIT_ASSERT_ARG(repo); + return git_submodule_cache_init(&repo->submodule_cache, repo); +} + +int git_repository_submodule_cache_clear(git_repository *repo) +{ + int error = 0; + GIT_ASSERT_ARG(repo); + + error = git_submodule_cache_free(repo->submodule_cache); + repo->submodule_cache = NULL; + return error; +} + +git_oid_t git_repository_oid_type(git_repository *repo) +{ + return repo ? repo->oid_type : 0; +} + +struct mergehead_data { + git_repository *repo; + git_vector *parents; +}; + +static int insert_mergehead(const git_oid *oid, void *payload) +{ + git_commit *commit; + struct mergehead_data *data = (struct mergehead_data *)payload; + + if (git_commit_lookup(&commit, data->repo, oid) < 0) + return -1; + + return git_vector_insert(data->parents, commit); +} + +int git_repository_commit_parents(git_commitarray *out, git_repository *repo) +{ + git_commit *first_parent = NULL, *commit; + git_reference *head_ref = NULL; + git_vector parents = GIT_VECTOR_INIT; + struct mergehead_data data; + size_t i; + int error; + + GIT_ASSERT_ARG(out && repo); + + out->count = 0; + out->commits = NULL; + + error = git_revparse_ext((git_object **)&first_parent, &head_ref, repo, "HEAD"); + + if (error != 0) { + if (error == GIT_ENOTFOUND) + error = 0; + + goto done; + } + + if ((error = git_vector_insert(&parents, first_parent)) < 0) + goto done; + + data.repo = repo; + data.parents = &parents; + + error = git_repository_mergehead_foreach(repo, insert_mergehead, &data); + + if (error == GIT_ENOTFOUND) + error = 0; + else if (error != 0) + goto done; + + out->commits = (git_commit **)git_vector_detach(&out->count, NULL, &parents); + +done: + git_vector_foreach(&parents, i, commit) + git__free(commit); + + git_reference_free(head_ref); + return error; +} diff --git a/vendor/libgit2/src/repository.h b/vendor/libgit2/src/libgit2/repository.h similarity index 89% rename from vendor/libgit2/src/repository.h rename to vendor/libgit2/src/libgit2/repository.h index a488f2bf..f45a3591 100644 --- a/vendor/libgit2/src/repository.h +++ b/vendor/libgit2/src/libgit2/repository.h @@ -24,6 +24,7 @@ #include "attrcache.h" #include "submodule.h" #include "diff_driver.h" +#include "grafts.h" #define DOT_GIT ".git" #define GIT_DIR DOT_GIT "/" @@ -151,11 +152,16 @@ struct git_repository { git_array_t(git_str) reserved_names; - unsigned is_bare:1; - unsigned is_worktree:1; + unsigned use_env:1, + is_bare:1, + is_worktree:1; + git_oid_t oid_type; unsigned int lru_counter; + git_grafts *grafts; + git_grafts *shallow_grafts; + git_atomic32 attr_session_key; intptr_t configmap_cache[GIT_CONFIGMAP_CACHE_MAX]; @@ -167,6 +173,7 @@ GIT_INLINE(git_attr_cache *) git_repository_attr_cache(git_repository *repo) return repo->attrcache; } +int git_repository_head_commit(git_commit **commit, git_repository *repo); int git_repository_head_tree(git_tree **tree, git_repository *repo); int git_repository_create_head(const char *git_dir, const char *ref_name); @@ -187,6 +194,13 @@ int git_repository_config__weakptr(git_config **out, git_repository *repo); int git_repository_odb__weakptr(git_odb **out, git_repository *repo); int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo); int git_repository_index__weakptr(git_index **out, git_repository *repo); +int git_repository_grafts__weakptr(git_grafts **out, git_repository *repo); +int git_repository_shallow_grafts__weakptr(git_grafts **out, git_repository *repo); + +int git_repository__wrap_odb( + git_repository **out, + git_odb *odb, + git_oid_t oid_type); /* * Configuration map cache @@ -238,6 +252,9 @@ extern size_t git_repository__reserved_names_posix_len; bool git_repository__reserved_names( git_str **out, size_t *outlen, git_repository *repo, bool include_ntfs); +int git_repository__shallow_roots(git_oid **out, size_t *out_len, git_repository *repo); +int git_repository__shallow_roots_write(git_repository *repo, git_oidarray *roots); + /* * The default branch for the repository; the `init.defaultBranch` * configuration option, if set, or `master` if it is not. @@ -256,4 +273,15 @@ int git_repository__extensions(char ***out, size_t *out_len); int git_repository__set_extensions(const char **extensions, size_t len); void git_repository__free_extensions(void); +/* + * Set the object format (OID type) for a repository; this will set + * both the configuration and the internal value for the oid type. + */ +int git_repository__set_objectformat( + git_repository *repo, + git_oid_t oid_type); + +/* SHA256-aware internal functions */ +int git_repository__new(git_repository **out, git_oid_t oid_type); + #endif diff --git a/vendor/libgit2/src/reset.c b/vendor/libgit2/src/libgit2/reset.c similarity index 98% rename from vendor/libgit2/src/reset.c rename to vendor/libgit2/src/libgit2/reset.c index e0d942e5..605c4afd 100644 --- a/vendor/libgit2/src/reset.c +++ b/vendor/libgit2/src/libgit2/reset.c @@ -188,9 +188,9 @@ int git_reset( git_reset_t reset_type, const git_checkout_options *checkout_opts) { - char to[GIT_OID_HEXSZ + 1]; + char to[GIT_OID_MAX_HEXSIZE + 1]; - git_oid_tostr(to, GIT_OID_HEXSZ + 1, git_object_id(target)); + git_oid_tostr(to, GIT_OID_MAX_HEXSIZE + 1, git_object_id(target)); return reset(repo, target, to, reset_type, checkout_opts); } diff --git a/vendor/libgit2/src/revert.c b/vendor/libgit2/src/libgit2/revert.c similarity index 92% rename from vendor/libgit2/src/revert.c rename to vendor/libgit2/src/libgit2/revert.c index d6ab6ae3..4a31ad40 100644 --- a/vendor/libgit2/src/revert.c +++ b/vendor/libgit2/src/libgit2/revert.c @@ -107,12 +107,10 @@ static int revert_state_cleanup(git_repository *repo) static int revert_seterr(git_commit *commit, const char *fmt) { - char commit_oidstr[GIT_OID_HEXSZ + 1]; + char commit_id[GIT_OID_MAX_HEXSIZE + 1]; - git_oid_fmt(commit_oidstr, git_commit_id(commit)); - commit_oidstr[GIT_OID_HEXSZ] = '\0'; - - git_error_set(GIT_ERROR_REVERT, fmt, commit_oidstr); + git_oid_tostr(commit_id, GIT_OID_MAX_HEXSIZE + 1, git_commit_id(commit)); + git_error_set(GIT_ERROR_REVERT, fmt, commit_id); return -1; } @@ -176,7 +174,7 @@ int git_revert( git_revert_options opts; git_reference *our_ref = NULL; git_commit *our_commit = NULL; - char commit_oidstr[GIT_OID_HEXSZ + 1]; + char commit_id[GIT_OID_MAX_HEXSIZE + 1]; const char *commit_msg; git_str their_label = GIT_STR_INIT; git_index *index = NULL; @@ -191,19 +189,18 @@ int git_revert( if ((error = git_repository__ensure_not_bare(repo, "revert")) < 0) return error; - git_oid_fmt(commit_oidstr, git_commit_id(commit)); - commit_oidstr[GIT_OID_HEXSZ] = '\0'; + git_oid_tostr(commit_id, GIT_OID_MAX_HEXSIZE + 1, git_commit_id(commit)); if ((commit_msg = git_commit_summary(commit)) == NULL) { error = -1; goto on_error; } - if ((error = git_str_printf(&their_label, "parent of %.7s... %s", commit_oidstr, commit_msg)) < 0 || + if ((error = git_str_printf(&their_label, "parent of %.7s... %s", commit_id, commit_msg)) < 0 || (error = revert_normalize_opts(repo, &opts, given_opts, git_str_cstr(&their_label))) < 0 || (error = git_indexwriter_init_for_operation(&indexwriter, repo, &opts.checkout_opts.checkout_strategy)) < 0 || - (error = write_revert_head(repo, commit_oidstr)) < 0 || - (error = write_merge_msg(repo, commit_oidstr, commit_msg)) < 0 || + (error = write_revert_head(repo, commit_id)) < 0 || + (error = write_merge_msg(repo, commit_id, commit_msg)) < 0 || (error = git_repository_head(&our_ref, repo)) < 0 || (error = git_reference_peel((git_object **)&our_commit, our_ref, GIT_OBJECT_COMMIT)) < 0 || (error = git_revert_commit(&index, repo, commit, our_commit, opts.mainline, &opts.merge_opts)) < 0 || diff --git a/vendor/libgit2/src/libgit2/revparse.c b/vendor/libgit2/src/libgit2/revparse.c new file mode 100644 index 00000000..9083e7a3 --- /dev/null +++ b/vendor/libgit2/src/libgit2/revparse.c @@ -0,0 +1,968 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "common.h" + +#include "str.h" +#include "tree.h" +#include "refdb.h" +#include "regexp.h" +#include "date.h" + +#include "git2.h" + +static int maybe_sha_or_abbrev( + git_object **out, + git_repository *repo, + const char *spec, + size_t speclen) +{ + git_oid oid; + + if (git_oid__fromstrn(&oid, spec, speclen, repo->oid_type) < 0) + return GIT_ENOTFOUND; + + return git_object_lookup_prefix(out, repo, &oid, speclen, GIT_OBJECT_ANY); +} + +static int maybe_sha( + git_object **out, + git_repository *repo, + const char *spec) +{ + size_t speclen = strlen(spec); + + if (speclen != git_oid_hexsize(repo->oid_type)) + return GIT_ENOTFOUND; + + return maybe_sha_or_abbrev(out, repo, spec, speclen); +} + +static int maybe_abbrev(git_object **out, git_repository *repo, const char *spec) +{ + size_t speclen = strlen(spec); + + return maybe_sha_or_abbrev(out, repo, spec, speclen); +} + +static int build_regex(git_regexp *regex, const char *pattern) +{ + int error; + + if (*pattern == '\0') { + git_error_set(GIT_ERROR_REGEX, "empty pattern"); + return GIT_EINVALIDSPEC; + } + + error = git_regexp_compile(regex, pattern, 0); + if (!error) + return 0; + + git_regexp_dispose(regex); + + return error; +} + +static int maybe_describe(git_object**out, git_repository *repo, const char *spec) +{ + const char *substr; + int error; + git_regexp regex; + + substr = strstr(spec, "-g"); + + if (substr == NULL) + return GIT_ENOTFOUND; + + if (build_regex(®ex, ".+-[0-9]+-g[0-9a-fA-F]+") < 0) + return -1; + + error = git_regexp_match(®ex, spec); + git_regexp_dispose(®ex); + + if (error) + return GIT_ENOTFOUND; + + return maybe_abbrev(out, repo, substr+2); +} + +static int revparse_lookup_object( + git_object **object_out, + git_reference **reference_out, + git_repository *repo, + const char *spec) +{ + int error; + git_reference *ref; + + if ((error = maybe_sha(object_out, repo, spec)) != GIT_ENOTFOUND) + return error; + + error = git_reference_dwim(&ref, repo, spec); + if (!error) { + + error = git_object_lookup( + object_out, repo, git_reference_target(ref), GIT_OBJECT_ANY); + + if (!error) + *reference_out = ref; + + return error; + } + + if (error != GIT_ENOTFOUND) + return error; + + if ((strlen(spec) < git_oid_hexsize(repo->oid_type)) && + ((error = maybe_abbrev(object_out, repo, spec)) != GIT_ENOTFOUND)) + return error; + + if ((error = maybe_describe(object_out, repo, spec)) != GIT_ENOTFOUND) + return error; + + git_error_set(GIT_ERROR_REFERENCE, "revspec '%s' not found", spec); + return GIT_ENOTFOUND; +} + +static int try_parse_numeric(int *n, const char *curly_braces_content) +{ + int32_t content; + const char *end_ptr; + + if (git__strntol32(&content, curly_braces_content, strlen(curly_braces_content), + &end_ptr, 10) < 0) + return -1; + + if (*end_ptr != '\0') + return -1; + + *n = (int)content; + return 0; +} + +static int retrieve_previously_checked_out_branch_or_revision(git_object **out, git_reference **base_ref, git_repository *repo, const char *identifier, size_t position) +{ + git_reference *ref = NULL; + git_reflog *reflog = NULL; + git_regexp preg; + int error = -1; + size_t i, numentries, cur; + const git_reflog_entry *entry; + const char *msg; + git_str buf = GIT_STR_INIT; + + cur = position; + + if (*identifier != '\0' || *base_ref != NULL) + return GIT_EINVALIDSPEC; + + if (build_regex(&preg, "checkout: moving from (.*) to .*") < 0) + return -1; + + if (git_reference_lookup(&ref, repo, GIT_HEAD_FILE) < 0) + goto cleanup; + + if (git_reflog_read(&reflog, repo, GIT_HEAD_FILE) < 0) + goto cleanup; + + numentries = git_reflog_entrycount(reflog); + + for (i = 0; i < numentries; i++) { + git_regmatch regexmatches[2]; + + entry = git_reflog_entry_byindex(reflog, i); + msg = git_reflog_entry_message(entry); + if (!msg) + continue; + + if (git_regexp_search(&preg, msg, 2, regexmatches) < 0) + continue; + + cur--; + + if (cur > 0) + continue; + + if ((git_str_put(&buf, msg+regexmatches[1].start, regexmatches[1].end - regexmatches[1].start)) < 0) + goto cleanup; + + if ((error = git_reference_dwim(base_ref, repo, git_str_cstr(&buf))) == 0) + goto cleanup; + + if (error < 0 && error != GIT_ENOTFOUND) + goto cleanup; + + error = maybe_abbrev(out, repo, git_str_cstr(&buf)); + + goto cleanup; + } + + error = GIT_ENOTFOUND; + +cleanup: + git_reference_free(ref); + git_str_dispose(&buf); + git_regexp_dispose(&preg); + git_reflog_free(reflog); + return error; +} + +static int retrieve_oid_from_reflog(git_oid *oid, git_reference *ref, size_t identifier) +{ + git_reflog *reflog; + size_t numentries; + const git_reflog_entry *entry = NULL; + bool search_by_pos = (identifier <= 100000000); + + if (git_reflog_read(&reflog, git_reference_owner(ref), git_reference_name(ref)) < 0) + return -1; + + numentries = git_reflog_entrycount(reflog); + + if (search_by_pos) { + if (numentries < identifier + 1) + goto notfound; + + entry = git_reflog_entry_byindex(reflog, identifier); + git_oid_cpy(oid, git_reflog_entry_id_new(entry)); + } else { + size_t i; + git_time commit_time; + + for (i = 0; i < numentries; i++) { + entry = git_reflog_entry_byindex(reflog, i); + commit_time = git_reflog_entry_committer(entry)->when; + + if (commit_time.time > (git_time_t)identifier) + continue; + + git_oid_cpy(oid, git_reflog_entry_id_new(entry)); + break; + } + + if (i == numentries) { + if (entry == NULL) + goto notfound; + + /* + * TODO: emit a warning (log for 'branch' only goes back to ...) + */ + git_oid_cpy(oid, git_reflog_entry_id_new(entry)); + } + } + + git_reflog_free(reflog); + return 0; + +notfound: + git_error_set( + GIT_ERROR_REFERENCE, + "reflog for '%s' has only %"PRIuZ" entries, asked for %"PRIuZ, + git_reference_name(ref), numentries, identifier); + + git_reflog_free(reflog); + return GIT_ENOTFOUND; +} + +static int retrieve_revobject_from_reflog(git_object **out, git_reference **base_ref, git_repository *repo, const char *identifier, size_t position) +{ + git_reference *ref; + git_oid oid; + int error = -1; + + if (*base_ref == NULL) { + /* + * When HEAD@{n} is specified, do not use dwim, which would resolve the + * reference (to the current branch that HEAD is pointing to). + */ + if (position > 0 && strcmp(identifier, GIT_HEAD_FILE) == 0) + error = git_reference_lookup(&ref, repo, GIT_HEAD_FILE); + else + error = git_reference_dwim(&ref, repo, identifier); + + if (error < 0) + return error; + } else { + ref = *base_ref; + *base_ref = NULL; + } + + if (position == 0) { + error = git_object_lookup(out, repo, git_reference_target(ref), GIT_OBJECT_ANY); + goto cleanup; + } + + if ((error = retrieve_oid_from_reflog(&oid, ref, position)) < 0) + goto cleanup; + + error = git_object_lookup(out, repo, &oid, GIT_OBJECT_ANY); + +cleanup: + git_reference_free(ref); + return error; +} + +static int retrieve_remote_tracking_reference(git_reference **base_ref, const char *identifier, git_repository *repo) +{ + git_reference *tracking, *ref; + int error = -1; + + if (*base_ref == NULL) { + if ((error = git_reference_dwim(&ref, repo, identifier)) < 0) + return error; + } else { + ref = *base_ref; + *base_ref = NULL; + } + + if (!git_reference_is_branch(ref)) { + error = GIT_EINVALIDSPEC; + goto cleanup; + } + + if ((error = git_branch_upstream(&tracking, ref)) < 0) + goto cleanup; + + *base_ref = tracking; + +cleanup: + git_reference_free(ref); + return error; +} + +static int handle_at_syntax(git_object **out, git_reference **ref, const char *spec, size_t identifier_len, git_repository *repo, const char *curly_braces_content) +{ + bool is_numeric; + int parsed = 0, error = -1; + git_str identifier = GIT_STR_INIT; + git_time_t timestamp; + + GIT_ASSERT(*out == NULL); + + if (git_str_put(&identifier, spec, identifier_len) < 0) + return -1; + + is_numeric = !try_parse_numeric(&parsed, curly_braces_content); + + if (*curly_braces_content == '-' && (!is_numeric || parsed == 0)) { + error = GIT_EINVALIDSPEC; + goto cleanup; + } + + if (is_numeric) { + if (parsed < 0) + error = retrieve_previously_checked_out_branch_or_revision(out, ref, repo, git_str_cstr(&identifier), -parsed); + else + error = retrieve_revobject_from_reflog(out, ref, repo, git_str_cstr(&identifier), parsed); + + goto cleanup; + } + + if (!strcmp(curly_braces_content, "u") || !strcmp(curly_braces_content, "upstream")) { + error = retrieve_remote_tracking_reference(ref, git_str_cstr(&identifier), repo); + + goto cleanup; + } + + if (git_date_parse(×tamp, curly_braces_content) < 0) { + error = GIT_EINVALIDSPEC; + goto cleanup; + } + + error = retrieve_revobject_from_reflog(out, ref, repo, git_str_cstr(&identifier), (size_t)timestamp); + +cleanup: + git_str_dispose(&identifier); + return error; +} + +static git_object_t parse_obj_type(const char *str) +{ + if (!strcmp(str, "commit")) + return GIT_OBJECT_COMMIT; + + if (!strcmp(str, "tree")) + return GIT_OBJECT_TREE; + + if (!strcmp(str, "blob")) + return GIT_OBJECT_BLOB; + + if (!strcmp(str, "tag")) + return GIT_OBJECT_TAG; + + return GIT_OBJECT_INVALID; +} + +static int dereference_to_non_tag(git_object **out, git_object *obj) +{ + if (git_object_type(obj) == GIT_OBJECT_TAG) + return git_tag_peel(out, (git_tag *)obj); + + return git_object_dup(out, obj); +} + +static int handle_caret_parent_syntax(git_object **out, git_object *obj, int n) +{ + git_object *temp_commit = NULL; + int error; + + if ((error = git_object_peel(&temp_commit, obj, GIT_OBJECT_COMMIT)) < 0) + return (error == GIT_EAMBIGUOUS || error == GIT_ENOTFOUND) ? + GIT_EINVALIDSPEC : error; + + if (n == 0) { + *out = temp_commit; + return 0; + } + + error = git_commit_parent((git_commit **)out, (git_commit*)temp_commit, n - 1); + + git_object_free(temp_commit); + return error; +} + +static int handle_linear_syntax(git_object **out, git_object *obj, int n) +{ + git_object *temp_commit = NULL; + int error; + + if ((error = git_object_peel(&temp_commit, obj, GIT_OBJECT_COMMIT)) < 0) + return (error == GIT_EAMBIGUOUS || error == GIT_ENOTFOUND) ? + GIT_EINVALIDSPEC : error; + + error = git_commit_nth_gen_ancestor((git_commit **)out, (git_commit*)temp_commit, n); + + git_object_free(temp_commit); + return error; +} + +static int handle_colon_syntax( + git_object **out, + git_object *obj, + const char *path) +{ + git_object *tree; + int error = -1; + git_tree_entry *entry = NULL; + + if ((error = git_object_peel(&tree, obj, GIT_OBJECT_TREE)) < 0) + return error == GIT_ENOTFOUND ? GIT_EINVALIDSPEC : error; + + if (*path == '\0') { + *out = tree; + return 0; + } + + /* + * TODO: Handle the relative path syntax + * (:./relative/path and :../relative/path) + */ + if ((error = git_tree_entry_bypath(&entry, (git_tree *)tree, path)) < 0) + goto cleanup; + + error = git_tree_entry_to_object(out, git_object_owner(tree), entry); + +cleanup: + git_tree_entry_free(entry); + git_object_free(tree); + + return error; +} + +static int walk_and_search(git_object **out, git_revwalk *walk, git_regexp *regex) +{ + int error; + git_oid oid; + git_object *obj; + + while (!(error = git_revwalk_next(&oid, walk))) { + + error = git_object_lookup(&obj, git_revwalk_repository(walk), &oid, GIT_OBJECT_COMMIT); + if ((error < 0) && (error != GIT_ENOTFOUND)) + return -1; + + if (!git_regexp_match(regex, git_commit_message((git_commit*)obj))) { + *out = obj; + return 0; + } + + git_object_free(obj); + } + + if (error < 0 && error == GIT_ITEROVER) + error = GIT_ENOTFOUND; + + return error; +} + +static int handle_grep_syntax(git_object **out, git_repository *repo, const git_oid *spec_oid, const char *pattern) +{ + git_regexp preg; + git_revwalk *walk = NULL; + int error; + + if ((error = build_regex(&preg, pattern)) < 0) + return error; + + if ((error = git_revwalk_new(&walk, repo)) < 0) + goto cleanup; + + git_revwalk_sorting(walk, GIT_SORT_TIME); + + if (spec_oid == NULL) { + if ((error = git_revwalk_push_glob(walk, "refs/*")) < 0) + goto cleanup; + } else if ((error = git_revwalk_push(walk, spec_oid)) < 0) + goto cleanup; + + error = walk_and_search(out, walk, &preg); + +cleanup: + git_regexp_dispose(&preg); + git_revwalk_free(walk); + + return error; +} + +static int handle_caret_curly_syntax(git_object **out, git_object *obj, const char *curly_braces_content) +{ + git_object_t expected_type; + + if (*curly_braces_content == '\0') + return dereference_to_non_tag(out, obj); + + if (*curly_braces_content == '/') + return handle_grep_syntax(out, git_object_owner(obj), git_object_id(obj), curly_braces_content + 1); + + expected_type = parse_obj_type(curly_braces_content); + + if (expected_type == GIT_OBJECT_INVALID) + return GIT_EINVALIDSPEC; + + return git_object_peel(out, obj, expected_type); +} + +static int extract_curly_braces_content(git_str *buf, const char *spec, size_t *pos) +{ + git_str_clear(buf); + + GIT_ASSERT_ARG(spec[*pos] == '^' || spec[*pos] == '@'); + + (*pos)++; + + if (spec[*pos] == '\0' || spec[*pos] != '{') + return GIT_EINVALIDSPEC; + + (*pos)++; + + while (spec[*pos] != '}') { + if (spec[*pos] == '\0') + return GIT_EINVALIDSPEC; + + if (git_str_putc(buf, spec[(*pos)++]) < 0) + return -1; + } + + (*pos)++; + + return 0; +} + +static int extract_path(git_str *buf, const char *spec, size_t *pos) +{ + git_str_clear(buf); + + GIT_ASSERT_ARG(spec[*pos] == ':'); + + (*pos)++; + + if (git_str_puts(buf, spec + *pos) < 0) + return -1; + + *pos += git_str_len(buf); + + return 0; +} + +static int extract_how_many(int *n, const char *spec, size_t *pos) +{ + const char *end_ptr; + int parsed, accumulated; + char kind = spec[*pos]; + + GIT_ASSERT_ARG(spec[*pos] == '^' || spec[*pos] == '~'); + + accumulated = 0; + + do { + do { + (*pos)++; + accumulated++; + } while (spec[(*pos)] == kind && kind == '~'); + + if (git__isdigit(spec[*pos])) { + if (git__strntol32(&parsed, spec + *pos, strlen(spec + *pos), &end_ptr, 10) < 0) + return GIT_EINVALIDSPEC; + + accumulated += (parsed - 1); + *pos = end_ptr - spec; + } + + } while (spec[(*pos)] == kind && kind == '~'); + + *n = accumulated; + + return 0; +} + +static int object_from_reference(git_object **object, git_reference *reference) +{ + git_reference *resolved = NULL; + int error; + + if (git_reference_resolve(&resolved, reference) < 0) + return -1; + + error = git_object_lookup(object, reference->db->repo, git_reference_target(resolved), GIT_OBJECT_ANY); + git_reference_free(resolved); + + return error; +} + +static int ensure_base_rev_loaded(git_object **object, git_reference **reference, const char *spec, size_t identifier_len, git_repository *repo, bool allow_empty_identifier) +{ + int error; + git_str identifier = GIT_STR_INIT; + + if (*object != NULL) + return 0; + + if (*reference != NULL) + return object_from_reference(object, *reference); + + if (!allow_empty_identifier && identifier_len == 0) + return GIT_EINVALIDSPEC; + + if (git_str_put(&identifier, spec, identifier_len) < 0) + return -1; + + error = revparse_lookup_object(object, reference, repo, git_str_cstr(&identifier)); + git_str_dispose(&identifier); + + return error; +} + +static int ensure_base_rev_is_not_known_yet(git_object *object) +{ + if (object == NULL) + return 0; + + return GIT_EINVALIDSPEC; +} + +static bool any_left_hand_identifier(git_object *object, git_reference *reference, size_t identifier_len) +{ + if (object != NULL) + return true; + + if (reference != NULL) + return true; + + if (identifier_len > 0) + return true; + + return false; +} + +static int ensure_left_hand_identifier_is_not_known_yet(git_object *object, git_reference *reference) +{ + if (!ensure_base_rev_is_not_known_yet(object) && reference == NULL) + return 0; + + return GIT_EINVALIDSPEC; +} + +static int revparse( + git_object **object_out, + git_reference **reference_out, + size_t *identifier_len_out, + git_repository *repo, + const char *spec) +{ + size_t pos = 0, identifier_len = 0; + int error = -1, n; + git_str buf = GIT_STR_INIT; + + git_reference *reference = NULL; + git_object *base_rev = NULL; + + bool should_return_reference = true; + bool parsed = false; + + GIT_ASSERT_ARG(object_out); + GIT_ASSERT_ARG(reference_out); + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(spec); + + *object_out = NULL; + *reference_out = NULL; + + while (!parsed && spec[pos]) { + switch (spec[pos]) { + case '^': + should_return_reference = false; + + if ((error = ensure_base_rev_loaded(&base_rev, &reference, spec, identifier_len, repo, false)) < 0) + goto cleanup; + + if (spec[pos+1] == '{') { + git_object *temp_object = NULL; + + if ((error = extract_curly_braces_content(&buf, spec, &pos)) < 0) + goto cleanup; + + if ((error = handle_caret_curly_syntax(&temp_object, base_rev, git_str_cstr(&buf))) < 0) + goto cleanup; + + git_object_free(base_rev); + base_rev = temp_object; + } else { + git_object *temp_object = NULL; + + if ((error = extract_how_many(&n, spec, &pos)) < 0) + goto cleanup; + + if ((error = handle_caret_parent_syntax(&temp_object, base_rev, n)) < 0) + goto cleanup; + + git_object_free(base_rev); + base_rev = temp_object; + } + break; + + case '~': + { + git_object *temp_object = NULL; + + should_return_reference = false; + + if ((error = extract_how_many(&n, spec, &pos)) < 0) + goto cleanup; + + if ((error = ensure_base_rev_loaded(&base_rev, &reference, spec, identifier_len, repo, false)) < 0) + goto cleanup; + + if ((error = handle_linear_syntax(&temp_object, base_rev, n)) < 0) + goto cleanup; + + git_object_free(base_rev); + base_rev = temp_object; + break; + } + + case ':': + { + git_object *temp_object = NULL; + + should_return_reference = false; + + if ((error = extract_path(&buf, spec, &pos)) < 0) + goto cleanup; + + if (any_left_hand_identifier(base_rev, reference, identifier_len)) { + if ((error = ensure_base_rev_loaded(&base_rev, &reference, spec, identifier_len, repo, true)) < 0) + goto cleanup; + + if ((error = handle_colon_syntax(&temp_object, base_rev, git_str_cstr(&buf))) < 0) + goto cleanup; + } else { + if (*git_str_cstr(&buf) == '/') { + if ((error = handle_grep_syntax(&temp_object, repo, NULL, git_str_cstr(&buf) + 1)) < 0) + goto cleanup; + } else { + + /* + * TODO: support merge-stage path lookup (":2:Makefile") + * and plain index blob lookup (:i-am/a/blob) + */ + git_error_set(GIT_ERROR_INVALID, "unimplemented"); + error = GIT_ERROR; + goto cleanup; + } + } + + git_object_free(base_rev); + base_rev = temp_object; + break; + } + + case '@': + if (spec[pos+1] == '{') { + git_object *temp_object = NULL; + + if ((error = extract_curly_braces_content(&buf, spec, &pos)) < 0) + goto cleanup; + + if ((error = ensure_base_rev_is_not_known_yet(base_rev)) < 0) + goto cleanup; + + if ((error = handle_at_syntax(&temp_object, &reference, spec, identifier_len, repo, git_str_cstr(&buf))) < 0) + goto cleanup; + + if (temp_object != NULL) + base_rev = temp_object; + break; + } else if (spec[pos + 1] == '\0' && !pos) { + spec = "HEAD"; + identifier_len = 4; + parsed = true; + break; + } + /* fall through */ + + default: + if ((error = ensure_left_hand_identifier_is_not_known_yet(base_rev, reference)) < 0) + goto cleanup; + + pos++; + identifier_len++; + } + } + + if ((error = ensure_base_rev_loaded(&base_rev, &reference, spec, identifier_len, repo, false)) < 0) + goto cleanup; + + if (!should_return_reference) { + git_reference_free(reference); + reference = NULL; + } + + *object_out = base_rev; + *reference_out = reference; + *identifier_len_out = identifier_len; + error = 0; + +cleanup: + if (error) { + if (error == GIT_EINVALIDSPEC) + git_error_set(GIT_ERROR_INVALID, + "failed to parse revision specifier - Invalid pattern '%s'", spec); + + git_object_free(base_rev); + git_reference_free(reference); + } + + git_str_dispose(&buf); + return error; +} + +int git_revparse_ext( + git_object **object_out, + git_reference **reference_out, + git_repository *repo, + const char *spec) +{ + int error; + size_t identifier_len; + git_object *obj = NULL; + git_reference *ref = NULL; + + if ((error = revparse(&obj, &ref, &identifier_len, repo, spec)) < 0) + goto cleanup; + + *object_out = obj; + *reference_out = ref; + GIT_UNUSED(identifier_len); + + return 0; + +cleanup: + git_object_free(obj); + git_reference_free(ref); + return error; +} + +int git_revparse_single(git_object **out, git_repository *repo, const char *spec) +{ + int error; + git_object *obj = NULL; + git_reference *ref = NULL; + + *out = NULL; + + if ((error = git_revparse_ext(&obj, &ref, repo, spec)) < 0) + goto cleanup; + + git_reference_free(ref); + + *out = obj; + + return 0; + +cleanup: + git_object_free(obj); + git_reference_free(ref); + return error; +} + +int git_revparse( + git_revspec *revspec, + git_repository *repo, + const char *spec) +{ + const char *dotdot; + int error = 0; + + GIT_ASSERT_ARG(revspec); + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(spec); + + memset(revspec, 0x0, sizeof(*revspec)); + + if ((dotdot = strstr(spec, "..")) != NULL) { + char *lstr; + const char *rstr; + revspec->flags = GIT_REVSPEC_RANGE; + + /* + * Following git.git, don't allow '..' because it makes command line + * arguments which can be either paths or revisions ambiguous when the + * path is almost certainly intended. The empty range '...' is still + * allowed. + */ + if (!git__strcmp(spec, "..")) { + git_error_set(GIT_ERROR_INVALID, "invalid pattern '..'"); + return GIT_EINVALIDSPEC; + } + + lstr = git__substrdup(spec, dotdot - spec); + rstr = dotdot + 2; + if (dotdot[2] == '.') { + revspec->flags |= GIT_REVSPEC_MERGE_BASE; + rstr++; + } + + error = git_revparse_single( + &revspec->from, + repo, + *lstr == '\0' ? "HEAD" : lstr); + + if (!error) { + error = git_revparse_single( + &revspec->to, + repo, + *rstr == '\0' ? "HEAD" : rstr); + } + + git__free((void*)lstr); + } else { + revspec->flags = GIT_REVSPEC_SINGLE; + error = git_revparse_single(&revspec->from, repo, spec); + } + + return error; +} diff --git a/vendor/libgit2/src/revwalk.c b/vendor/libgit2/src/libgit2/revwalk.c similarity index 94% rename from vendor/libgit2/src/revwalk.c rename to vendor/libgit2/src/libgit2/revwalk.c index 553e0497..4ea6fae8 100644 --- a/vendor/libgit2/src/revwalk.c +++ b/vendor/libgit2/src/libgit2/revwalk.c @@ -83,8 +83,13 @@ int git_revwalk__push_commit(git_revwalk *walk, const git_oid *oid, const git_re commit->uninteresting = opts->uninteresting; list = walk->user_input; - if ((opts->insert_by_date && - git_commit_list_insert_by_date(commit, &list) == NULL) || + + /* To insert by date, we need to parse so we know the date. */ + if (opts->insert_by_date && ((error = git_commit_list_parse(walk, commit)) < 0)) + return error; + + if ((opts->insert_by_date == 0 || + git_commit_list_insert_by_date(commit, &list) == NULL) && git_commit_list_insert(commit, &list) == NULL) { git_error_set_oom(); return -1; @@ -121,8 +126,12 @@ int git_revwalk__push_ref(git_revwalk *walk, const char *refname, const git_revw { git_oid oid; - if (git_reference_name_to_id(&oid, walk->repo, refname) < 0) + int error = git_reference_name_to_id(&oid, walk->repo, refname); + if (opts->from_glob && (error == GIT_ENOTFOUND || error == GIT_EINVALIDSPEC || error == GIT_EPEEL)) { + return 0; + } else if (error < 0) { return -1; + } return git_revwalk__push_commit(walk, &oid, opts); } @@ -605,7 +614,7 @@ static int sort_in_topological_order(git_commit_list **out, git_revwalk *walk, g static int prepare_walk(git_revwalk *walk) { int error = 0; - git_commit_list *list, *commits = NULL; + git_commit_list *list, *commits = NULL, *commits_last = NULL; git_commit_list_node *next; /* If there were no pushes, we know that the walk is already over */ @@ -614,6 +623,12 @@ static int prepare_walk(git_revwalk *walk) return GIT_ITEROVER; } + /* + * This is a bit convoluted, but necessary to maintain the order of + * the commits. This is especially important in situations where + * git_revwalk__push_glob is called with a git_revwalk__push_options + * setting insert_by_date = 1, which is critical for fetch negotiation. + */ for (list = walk->user_input; list; list = list->next) { git_commit_list_node *commit = list->item; if ((error = git_commit_list_parse(walk, commit)) < 0) @@ -623,8 +638,19 @@ static int prepare_walk(git_revwalk *walk) mark_parents_uninteresting(commit); if (!commit->seen) { + git_commit_list *new_list = NULL; + if ((new_list = git_commit_list_create(commit, NULL)) == NULL) { + git_error_set_oom(); + return -1; + } + commit->seen = 1; - git_commit_list_insert(commit, &commits); + if (commits_last == NULL) + commits = new_list; + else + commits_last->next = new_list; + + commits_last = new_list; } } diff --git a/vendor/libgit2/src/revwalk.h b/vendor/libgit2/src/libgit2/revwalk.h similarity index 100% rename from vendor/libgit2/src/revwalk.h rename to vendor/libgit2/src/libgit2/revwalk.h diff --git a/vendor/libgit2/src/libgit2/settings.c b/vendor/libgit2/src/libgit2/settings.c new file mode 100644 index 00000000..4a41830b --- /dev/null +++ b/vendor/libgit2/src/libgit2/settings.c @@ -0,0 +1,456 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "settings.h" + +#include +#include "alloc.h" +#include "buf.h" +#include "cache.h" +#include "common.h" +#include "filter.h" +#include "grafts.h" +#include "hash.h" +#include "index.h" +#include "merge_driver.h" +#include "pool.h" +#include "mwindow.h" +#include "object.h" +#include "odb.h" +#include "rand.h" +#include "refs.h" +#include "runtime.h" +#include "sysdir.h" +#include "thread.h" +#include "git2/global.h" +#include "streams/registry.h" +#include "streams/mbedtls.h" +#include "streams/openssl.h" +#include "streams/socket.h" +#include "transports/smart.h" +#include "transports/http.h" +#include "transports/ssh_libssh2.h" + +#ifdef GIT_WIN32 +# include "win32/w32_leakcheck.h" +#endif + +/* Declarations for tuneable settings */ +extern size_t git_mwindow__window_size; +extern size_t git_mwindow__mapped_limit; +extern size_t git_mwindow__file_limit; +extern size_t git_indexer__max_objects; +extern bool git_disable_pack_keep_file_checks; +extern int git_odb__packed_priority; +extern int git_odb__loose_priority; +extern int git_socket_stream__connect_timeout; +extern int git_socket_stream__timeout; + +char *git__user_agent; +char *git__user_agent_product; +char *git__ssl_ciphers; + +static void settings_global_shutdown(void) +{ + git__free(git__user_agent); + git__free(git__user_agent_product); + + git__free(git__ssl_ciphers); + git_repository__free_extensions(); +} + +int git_settings_global_init(void) +{ + return git_runtime_shutdown_register(settings_global_shutdown); +} + +static int config_level_to_sysdir(int *out, int config_level) +{ + switch (config_level) { + case GIT_CONFIG_LEVEL_SYSTEM: + *out = GIT_SYSDIR_SYSTEM; + return 0; + case GIT_CONFIG_LEVEL_XDG: + *out = GIT_SYSDIR_XDG; + return 0; + case GIT_CONFIG_LEVEL_GLOBAL: + *out = GIT_SYSDIR_GLOBAL; + return 0; + case GIT_CONFIG_LEVEL_PROGRAMDATA: + *out = GIT_SYSDIR_PROGRAMDATA; + return 0; + default: + break; + } + + git_error_set( + GIT_ERROR_INVALID, "invalid config path selector %d", config_level); + return -1; +} + +const char *git_settings__user_agent_product(void) +{ + return git__user_agent_product ? git__user_agent_product : + "git/2.0"; +} + +const char *git_settings__user_agent(void) +{ + return git__user_agent ? git__user_agent : + "libgit2 " LIBGIT2_VERSION; +} + +int git_libgit2_opts(int key, ...) +{ + int error = 0; + va_list ap; + + va_start(ap, key); + + switch (key) { + case GIT_OPT_SET_MWINDOW_SIZE: + git_mwindow__window_size = va_arg(ap, size_t); + break; + + case GIT_OPT_GET_MWINDOW_SIZE: + *(va_arg(ap, size_t *)) = git_mwindow__window_size; + break; + + case GIT_OPT_SET_MWINDOW_MAPPED_LIMIT: + git_mwindow__mapped_limit = va_arg(ap, size_t); + break; + + case GIT_OPT_GET_MWINDOW_MAPPED_LIMIT: + *(va_arg(ap, size_t *)) = git_mwindow__mapped_limit; + break; + + case GIT_OPT_SET_MWINDOW_FILE_LIMIT: + git_mwindow__file_limit = va_arg(ap, size_t); + break; + + case GIT_OPT_GET_MWINDOW_FILE_LIMIT: + *(va_arg(ap, size_t *)) = git_mwindow__file_limit; + break; + + case GIT_OPT_GET_SEARCH_PATH: + { + int sysdir = va_arg(ap, int); + git_buf *out = va_arg(ap, git_buf *); + git_str str = GIT_STR_INIT; + const git_str *tmp; + int level; + + if ((error = git_buf_tostr(&str, out)) < 0 || + (error = config_level_to_sysdir(&level, sysdir)) < 0 || + (error = git_sysdir_get(&tmp, level)) < 0 || + (error = git_str_put(&str, tmp->ptr, tmp->size)) < 0) + break; + + error = git_buf_fromstr(out, &str); + } + break; + + case GIT_OPT_SET_SEARCH_PATH: + { + int level; + + if ((error = config_level_to_sysdir(&level, va_arg(ap, int))) >= 0) + error = git_sysdir_set(level, va_arg(ap, const char *)); + } + break; + + case GIT_OPT_SET_CACHE_OBJECT_LIMIT: + { + git_object_t type = (git_object_t)va_arg(ap, int); + size_t size = va_arg(ap, size_t); + error = git_cache_set_max_object_size(type, size); + break; + } + + case GIT_OPT_SET_CACHE_MAX_SIZE: + git_cache__max_storage = va_arg(ap, ssize_t); + break; + + case GIT_OPT_ENABLE_CACHING: + git_cache__enabled = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_GET_CACHED_MEMORY: + *(va_arg(ap, ssize_t *)) = git_cache__current_storage.val; + *(va_arg(ap, ssize_t *)) = git_cache__max_storage; + break; + + case GIT_OPT_GET_TEMPLATE_PATH: + { + git_buf *out = va_arg(ap, git_buf *); + git_str str = GIT_STR_INIT; + const git_str *tmp; + + if ((error = git_buf_tostr(&str, out)) < 0 || + (error = git_sysdir_get(&tmp, GIT_SYSDIR_TEMPLATE)) < 0 || + (error = git_str_put(&str, tmp->ptr, tmp->size)) < 0) + break; + + error = git_buf_fromstr(out, &str); + } + break; + + case GIT_OPT_SET_TEMPLATE_PATH: + error = git_sysdir_set(GIT_SYSDIR_TEMPLATE, va_arg(ap, const char *)); + break; + + case GIT_OPT_SET_SSL_CERT_LOCATIONS: +#ifdef GIT_OPENSSL + { + const char *file = va_arg(ap, const char *); + const char *path = va_arg(ap, const char *); + error = git_openssl__set_cert_location(file, path); + } +#elif defined(GIT_MBEDTLS) + { + const char *file = va_arg(ap, const char *); + const char *path = va_arg(ap, const char *); + error = git_mbedtls__set_cert_location(file, path); + } +#else + git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support certificate locations"); + error = -1; +#endif + break; + + case GIT_OPT_SET_USER_AGENT: + { + const char *new_agent = va_arg(ap, const char *); + + git__free(git__user_agent); + + if (new_agent) { + git__user_agent= git__strdup(new_agent); + + if (!git__user_agent) + error = -1; + } else { + git__user_agent = NULL; + } + } + break; + + case GIT_OPT_GET_USER_AGENT: + { + git_buf *out = va_arg(ap, git_buf *); + git_str str = GIT_STR_INIT; + + if ((error = git_buf_tostr(&str, out)) < 0 || + (error = git_str_puts(&str, git_settings__user_agent())) < 0) + break; + + error = git_buf_fromstr(out, &str); + } + break; + + case GIT_OPT_SET_USER_AGENT_PRODUCT: + { + const char *new_agent = va_arg(ap, const char *); + + git__free(git__user_agent_product); + + if (new_agent) { + git__user_agent_product = git__strdup(new_agent); + + if (!git__user_agent_product) + error = -1; + } else { + git__user_agent_product = NULL; + } + } + break; + + case GIT_OPT_GET_USER_AGENT_PRODUCT: + { + git_buf *out = va_arg(ap, git_buf *); + git_str str = GIT_STR_INIT; + + if ((error = git_buf_tostr(&str, out)) < 0 || + (error = git_str_puts(&str, git_settings__user_agent_product())) < 0) + break; + + error = git_buf_fromstr(out, &str); + } + break; + + case GIT_OPT_ENABLE_STRICT_OBJECT_CREATION: + git_object__strict_input_validation = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION: + git_reference__enable_symbolic_ref_target_validation = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_SET_SSL_CIPHERS: +#if (GIT_OPENSSL || GIT_MBEDTLS) + { + git__free(git__ssl_ciphers); + git__ssl_ciphers = git__strdup(va_arg(ap, const char *)); + if (!git__ssl_ciphers) { + git_error_set_oom(); + error = -1; + } + } +#else + git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support custom ciphers"); + error = -1; +#endif + break; + + case GIT_OPT_ENABLE_OFS_DELTA: + git_smart__ofs_delta_enabled = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_ENABLE_FSYNC_GITDIR: + git_repository__fsync_gitdir = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_GET_WINDOWS_SHAREMODE: +#ifdef GIT_WIN32 + *(va_arg(ap, unsigned long *)) = git_win32__createfile_sharemode; +#endif + break; + + case GIT_OPT_SET_WINDOWS_SHAREMODE: +#ifdef GIT_WIN32 + git_win32__createfile_sharemode = va_arg(ap, unsigned long); +#endif + break; + + case GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION: + git_odb__strict_hash_verification = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_SET_ALLOCATOR: + error = git_allocator_setup(va_arg(ap, git_allocator *)); + break; + + case GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY: + git_index__enforce_unsaved_safety = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_SET_PACK_MAX_OBJECTS: + git_indexer__max_objects = va_arg(ap, size_t); + break; + + case GIT_OPT_GET_PACK_MAX_OBJECTS: + *(va_arg(ap, size_t *)) = git_indexer__max_objects; + break; + + case GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS: + git_disable_pack_keep_file_checks = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE: + git_http__expect_continue = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_SET_ODB_PACKED_PRIORITY: + git_odb__packed_priority = va_arg(ap, int); + break; + + case GIT_OPT_SET_ODB_LOOSE_PRIORITY: + git_odb__loose_priority = va_arg(ap, int); + break; + + case GIT_OPT_SET_EXTENSIONS: + { + const char **extensions = va_arg(ap, const char **); + size_t len = va_arg(ap, size_t); + error = git_repository__set_extensions(extensions, len); + } + break; + + case GIT_OPT_GET_EXTENSIONS: + { + git_strarray *out = va_arg(ap, git_strarray *); + char **extensions; + size_t len; + + if ((error = git_repository__extensions(&extensions, &len)) < 0) + break; + + out->strings = extensions; + out->count = len; + } + break; + + case GIT_OPT_GET_OWNER_VALIDATION: + *(va_arg(ap, int *)) = git_repository__validate_ownership; + break; + + case GIT_OPT_SET_OWNER_VALIDATION: + git_repository__validate_ownership = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_GET_HOMEDIR: + { + git_buf *out = va_arg(ap, git_buf *); + git_str str = GIT_STR_INIT; + const git_str *tmp; + + if ((error = git_buf_tostr(&str, out)) < 0 || + (error = git_sysdir_get(&tmp, GIT_SYSDIR_HOME)) < 0 || + (error = git_str_put(&str, tmp->ptr, tmp->size)) < 0) + break; + + error = git_buf_fromstr(out, &str); + } + break; + + case GIT_OPT_SET_HOMEDIR: + error = git_sysdir_set(GIT_SYSDIR_HOME, va_arg(ap, const char *)); + break; + + case GIT_OPT_GET_SERVER_CONNECT_TIMEOUT: + *(va_arg(ap, int *)) = git_socket_stream__connect_timeout; + break; + + case GIT_OPT_SET_SERVER_CONNECT_TIMEOUT: + { + int timeout = va_arg(ap, int); + + if (timeout < 0) { + git_error_set(GIT_ERROR_INVALID, "invalid connect timeout"); + error = -1; + } else { + git_socket_stream__connect_timeout = timeout; + } + } + break; + + case GIT_OPT_GET_SERVER_TIMEOUT: + *(va_arg(ap, int *)) = git_socket_stream__timeout; + break; + + case GIT_OPT_SET_SERVER_TIMEOUT: + { + int timeout = va_arg(ap, int); + + if (timeout < 0) { + git_error_set(GIT_ERROR_INVALID, "invalid timeout"); + error = -1; + } else { + git_socket_stream__timeout = timeout; + } + } + break; + + default: + git_error_set(GIT_ERROR_INVALID, "invalid option key"); + error = -1; + } + + va_end(ap); + + return error; +} diff --git a/vendor/libgit2/src/libgit2/settings.h b/vendor/libgit2/src/libgit2/settings.h new file mode 100644 index 00000000..29293667 --- /dev/null +++ b/vendor/libgit2/src/libgit2/settings.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_settings_h__ +#define INCLUDE_settings_h__ + +extern int git_settings_global_init(void); + +extern const char *git_settings__user_agent(void); +extern const char *git_settings__user_agent_product(void); + +#endif diff --git a/vendor/libgit2/src/libgit2/signature.c b/vendor/libgit2/src/libgit2/signature.c new file mode 100644 index 00000000..12d2b5f8 --- /dev/null +++ b/vendor/libgit2/src/libgit2/signature.c @@ -0,0 +1,338 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "signature.h" + +#include "repository.h" +#include "git2/common.h" +#include "posix.h" + +void git_signature_free(git_signature *sig) +{ + if (sig == NULL) + return; + + git__free(sig->name); + sig->name = NULL; + git__free(sig->email); + sig->email = NULL; + git__free(sig); +} + +static int signature_parse_error(const char *msg) +{ + git_error_set(GIT_ERROR_INVALID, "failed to parse signature - %s", msg); + return GIT_EINVALID; +} + +static int signature_error(const char *msg) +{ + git_error_set(GIT_ERROR_INVALID, "failed to parse signature - %s", msg); + return -1; +} + +static bool contains_angle_brackets(const char *input) +{ + return strchr(input, '<') != NULL || strchr(input, '>') != NULL; +} + +static bool is_crud(unsigned char c) +{ + return c <= 32 || + c == ',' || + c == ':' || + c == ';' || + c == '<' || + c == '>' || + c == '"' || + c == '\\' || + c == '\''; +} + +static char *extract_trimmed(const char *ptr, size_t len) +{ + while (len && is_crud((unsigned char)ptr[0])) { + ptr++; len--; + } + + while (len && is_crud((unsigned char)ptr[len - 1])) { + len--; + } + + return git__substrdup(ptr, len); +} + +int git_signature_new(git_signature **sig_out, const char *name, const char *email, git_time_t time, int offset) +{ + git_signature *p = NULL; + + GIT_ASSERT_ARG(name); + GIT_ASSERT_ARG(email); + + *sig_out = NULL; + + if (contains_angle_brackets(name) || + contains_angle_brackets(email)) { + return signature_error( + "Neither `name` nor `email` should contain angle brackets chars."); + } + + p = git__calloc(1, sizeof(git_signature)); + GIT_ERROR_CHECK_ALLOC(p); + + p->name = extract_trimmed(name, strlen(name)); + GIT_ERROR_CHECK_ALLOC(p->name); + p->email = extract_trimmed(email, strlen(email)); + GIT_ERROR_CHECK_ALLOC(p->email); + + if (p->name[0] == '\0' || p->email[0] == '\0') { + git_signature_free(p); + return signature_error("Signature cannot have an empty name or email"); + } + + p->when.time = time; + p->when.offset = offset; + p->when.sign = (offset < 0) ? '-' : '+'; + + *sig_out = p; + return 0; +} + +int git_signature_dup(git_signature **dest, const git_signature *source) +{ + git_signature *signature; + + if (source == NULL) + return 0; + + signature = git__calloc(1, sizeof(git_signature)); + GIT_ERROR_CHECK_ALLOC(signature); + + signature->name = git__strdup(source->name); + GIT_ERROR_CHECK_ALLOC(signature->name); + + signature->email = git__strdup(source->email); + GIT_ERROR_CHECK_ALLOC(signature->email); + + signature->when.time = source->when.time; + signature->when.offset = source->when.offset; + signature->when.sign = source->when.sign; + + *dest = signature; + + return 0; +} + +int git_signature__pdup(git_signature **dest, const git_signature *source, git_pool *pool) +{ + git_signature *signature; + + if (source == NULL) + return 0; + + signature = git_pool_mallocz(pool, sizeof(git_signature)); + GIT_ERROR_CHECK_ALLOC(signature); + + signature->name = git_pool_strdup(pool, source->name); + GIT_ERROR_CHECK_ALLOC(signature->name); + + signature->email = git_pool_strdup(pool, source->email); + GIT_ERROR_CHECK_ALLOC(signature->email); + + signature->when.time = source->when.time; + signature->when.offset = source->when.offset; + signature->when.sign = source->when.sign; + + *dest = signature; + + return 0; +} + +int git_signature_now(git_signature **sig_out, const char *name, const char *email) +{ + time_t now; + time_t offset; + struct tm *utc_tm; + git_signature *sig; + struct tm _utc; + + *sig_out = NULL; + + /* + * Get the current time as seconds since the epoch and + * transform that into a tm struct containing the time at + * UTC. Give that to mktime which considers it a local time + * (tm_isdst = -1 asks it to take DST into account) and gives + * us that time as seconds since the epoch. The difference + * between its return value and 'now' is our offset to UTC. + */ + time(&now); + utc_tm = p_gmtime_r(&now, &_utc); + utc_tm->tm_isdst = -1; + offset = (time_t)difftime(now, mktime(utc_tm)); + offset /= 60; + + if (git_signature_new(&sig, name, email, now, (int)offset) < 0) + return -1; + + *sig_out = sig; + + return 0; +} + +int git_signature_default(git_signature **out, git_repository *repo) +{ + int error; + git_config *cfg; + const char *user_name, *user_email; + + if ((error = git_repository_config_snapshot(&cfg, repo)) < 0) + return error; + + if (!(error = git_config_get_string(&user_name, cfg, "user.name")) && + !(error = git_config_get_string(&user_email, cfg, "user.email"))) + error = git_signature_now(out, user_name, user_email); + + git_config_free(cfg); + return error; +} + +int git_signature__parse(git_signature *sig, const char **buffer_out, + const char *buffer_end, const char *header, char ender) +{ + const char *buffer = *buffer_out; + const char *email_start, *email_end; + + memset(sig, 0, sizeof(git_signature)); + + if (ender && + (buffer_end = memchr(buffer, ender, buffer_end - buffer)) == NULL) + return signature_parse_error("no newline given"); + + if (header) { + const size_t header_len = strlen(header); + + if (buffer + header_len >= buffer_end || memcmp(buffer, header, header_len) != 0) + return signature_parse_error("expected prefix doesn't match actual"); + + buffer += header_len; + } + + email_start = git__memrchr(buffer, '<', buffer_end - buffer); + email_end = git__memrchr(buffer, '>', buffer_end - buffer); + + if (!email_start || !email_end || email_end <= email_start) + return signature_parse_error("malformed e-mail"); + + email_start += 1; + sig->name = extract_trimmed(buffer, email_start - buffer - 1); + sig->email = extract_trimmed(email_start, email_end - email_start); + + /* Do we even have a time at the end of the signature? */ + if (email_end + 2 < buffer_end) { + const char *time_start = email_end + 2; + const char *time_end; + + if (git__strntol64(&sig->when.time, time_start, + buffer_end - time_start, &time_end, 10) < 0) { + git__free(sig->name); + git__free(sig->email); + sig->name = sig->email = NULL; + return signature_parse_error("invalid Unix timestamp"); + } + + /* do we have a timezone? */ + if (time_end + 1 < buffer_end) { + int offset, hours, mins; + const char *tz_start, *tz_end; + + tz_start = time_end + 1; + + if ((tz_start[0] != '-' && tz_start[0] != '+') || + git__strntol32(&offset, tz_start + 1, + buffer_end - tz_start - 1, &tz_end, 10) < 0) { + /* malformed timezone, just assume it's zero */ + offset = 0; + } + + hours = offset / 100; + mins = offset % 100; + + /* + * only store timezone if it's not overflowing; + * see http://www.worldtimezone.com/faq.html + */ + if (hours <= 14 && mins <= 59) { + sig->when.offset = (hours * 60) + mins; + sig->when.sign = tz_start[0]; + if (tz_start[0] == '-') + sig->when.offset = -sig->when.offset; + } + } + } + + *buffer_out = buffer_end + 1; + return 0; +} + +int git_signature_from_buffer(git_signature **out, const char *buf) +{ + git_signature *sig; + const char *buf_end; + int error; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(buf); + + *out = NULL; + + sig = git__calloc(1, sizeof(git_signature)); + GIT_ERROR_CHECK_ALLOC(sig); + + buf_end = buf + strlen(buf); + error = git_signature__parse(sig, &buf, buf_end, NULL, '\0'); + + if (error) + git__free(sig); + else + *out = sig; + + return error; +} + +void git_signature__writebuf(git_str *buf, const char *header, const git_signature *sig) +{ + int offset, hours, mins; + char sign; + + offset = sig->when.offset; + sign = (sig->when.offset < 0 || sig->when.sign == '-') ? '-' : '+'; + + if (offset < 0) + offset = -offset; + + hours = offset / 60; + mins = offset % 60; + + git_str_printf(buf, "%s%s <%s> %u %c%02d%02d\n", + header ? header : "", sig->name, sig->email, + (unsigned)sig->when.time, sign, hours, mins); +} + +bool git_signature__equal(const git_signature *one, const git_signature *two) +{ + GIT_ASSERT_ARG(one); + GIT_ASSERT_ARG(two); + + return + git__strcmp(one->name, two->name) == 0 && + git__strcmp(one->email, two->email) == 0 && + one->when.time == two->when.time && + one->when.offset == two->when.offset && + one->when.sign == two->when.sign; +} + diff --git a/vendor/libgit2/src/signature.h b/vendor/libgit2/src/libgit2/signature.h similarity index 100% rename from vendor/libgit2/src/signature.h rename to vendor/libgit2/src/libgit2/signature.h diff --git a/vendor/libgit2/src/stash.c b/vendor/libgit2/src/libgit2/stash.c similarity index 83% rename from vendor/libgit2/src/stash.c rename to vendor/libgit2/src/libgit2/stash.c index 5fc01ac3..b49e95cd 100644 --- a/vendor/libgit2/src/stash.c +++ b/vendor/libgit2/src/libgit2/stash.c @@ -25,6 +25,7 @@ #include "merge.h" #include "diff.h" #include "diff_generate.h" +#include "strarray.h" static int create_error(int error, const char *msg) { @@ -193,6 +194,30 @@ static int stash_to_index( return git_index_add(index, &entry); } +static int stash_update_index_from_paths( + git_repository *repo, + git_index *index, + const git_strarray *paths) +{ + unsigned int status_flags; + size_t i; + int error = 0; + + for (i = 0; i < paths->count; i++) { + git_status_file(&status_flags, repo, paths->strings[i]); + + if (status_flags & (GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_DELETED)) { + if ((error = git_index_remove(index, paths->strings[i], 0)) < 0) + return error; + } else { + if ((error = stash_to_index(repo, index, paths->strings[i])) < 0) + return error; + } + } + + return error; +} + static int stash_update_index_from_diff( git_repository *repo, git_index *index, @@ -259,7 +284,7 @@ static int build_untracked_tree( struct stash_update_rules data = {0}; int error; - if ((error = git_index_new(&i_index)) < 0) + if ((error = git_index__new(&i_index, repo->oid_type)) < 0) goto cleanup; if (flags & GIT_STASH_INCLUDE_UNTRACKED) { @@ -388,26 +413,81 @@ static int build_workdir_tree( return error; } -static int commit_worktree( +static int build_stash_commit_from_tree( git_oid *w_commit_oid, git_repository *repo, const git_signature *stasher, const char *message, git_commit *i_commit, git_commit *b_commit, - git_commit *u_commit) + git_commit *u_commit, + const git_tree *tree) { const git_commit *parents[] = { NULL, NULL, NULL }; - git_index *i_index = NULL, *r_index = NULL; - git_tree *w_tree = NULL; - int error = 0, ignorecase; parents[0] = b_commit; parents[1] = i_commit; parents[2] = u_commit; + return git_commit_create( + w_commit_oid, + repo, + NULL, + stasher, + stasher, + NULL, + message, + tree, + u_commit ? 3 : 2, + parents); +} + +static int build_stash_commit_from_index( + git_oid *w_commit_oid, + git_repository *repo, + const git_signature *stasher, + const char *message, + git_commit *i_commit, + git_commit *b_commit, + git_commit *u_commit, + git_index *index) +{ + git_tree *tree; + int error; + + if ((error = build_tree_from_index(&tree, repo, index)) < 0) + goto cleanup; + + error = build_stash_commit_from_tree( + w_commit_oid, + repo, + stasher, + message, + i_commit, + b_commit, + u_commit, + tree); + +cleanup: + git_tree_free(tree); + return error; +} + +static int commit_worktree( + git_oid *w_commit_oid, + git_repository *repo, + const git_signature *stasher, + const char *message, + git_commit *i_commit, + git_commit *b_commit, + git_commit *u_commit) +{ + git_index *i_index = NULL, *r_index = NULL; + git_tree *w_tree = NULL; + int error = 0, ignorecase; + if ((error = git_repository_index(&r_index, repo) < 0) || - (error = git_index_new(&i_index)) < 0 || + (error = git_index__new(&i_index, repo->oid_type)) < 0 || (error = git_index__fill(i_index, &r_index->entries) < 0) || (error = git_repository__configmap_lookup(&ignorecase, repo, GIT_CONFIGMAP_IGNORECASE)) < 0) goto cleanup; @@ -417,17 +497,16 @@ static int commit_worktree( if ((error = build_workdir_tree(&w_tree, repo, i_index, b_commit)) < 0) goto cleanup; - error = git_commit_create( + error = build_stash_commit_from_tree( w_commit_oid, repo, - NULL, - stasher, stasher, - NULL, message, - w_tree, - u_commit ? 3 : 2, - parents); + i_commit, + b_commit, + u_commit, + w_tree + ); cleanup: git_tree_free(w_tree); @@ -520,6 +599,54 @@ static int ensure_there_are_changes_to_stash(git_repository *repo, uint32_t flag return error; } +static int has_changes_cb( + const char *path, + unsigned int status, + void *payload) +{ + GIT_UNUSED(path); + GIT_UNUSED(status); + GIT_UNUSED(payload); + + if (status == GIT_STATUS_CURRENT) + return GIT_ENOTFOUND; + + return 0; +} + +static int ensure_there_are_changes_to_stash_paths( + git_repository *repo, + uint32_t flags, + const git_strarray *paths) +{ + int error; + git_status_options opts = GIT_STATUS_OPTIONS_INIT; + + opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR; + opts.flags = GIT_STATUS_OPT_EXCLUDE_SUBMODULES | + GIT_STATUS_OPT_INCLUDE_UNMODIFIED | + GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH; + + if (flags & GIT_STASH_INCLUDE_UNTRACKED) + opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED | + GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS; + + if (flags & GIT_STASH_INCLUDE_IGNORED) + opts.flags |= GIT_STATUS_OPT_INCLUDE_IGNORED | + GIT_STATUS_OPT_RECURSE_IGNORED_DIRS; + + git_strarray_copy(&opts.pathspec, paths); + + error = git_status_foreach_ext(repo, &opts, has_changes_cb, NULL); + + git_strarray_dispose(&opts.pathspec); + + if (error == GIT_ENOTFOUND) + return create_error(GIT_ENOTFOUND, "one of the files does not have any changes to stash."); + + return error; +} + static int reset_index_and_workdir(git_repository *repo, git_commit *commit, uint32_t flags) { git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; @@ -540,14 +667,36 @@ int git_stash_save( const char *message, uint32_t flags) { - git_index *index = NULL; + git_stash_save_options opts = GIT_STASH_SAVE_OPTIONS_INIT; + + GIT_ASSERT_ARG(stasher); + + opts.stasher = stasher; + opts.message = message; + opts.flags = flags; + + return git_stash_save_with_opts(out, repo, &opts); +} + +int git_stash_save_with_opts( + git_oid *out, + git_repository *repo, + const git_stash_save_options *opts) +{ + git_index *index = NULL, *paths_index = NULL; git_commit *b_commit = NULL, *i_commit = NULL, *u_commit = NULL; git_str msg = GIT_STR_INIT; + git_tree *tree = NULL; + git_reference *head = NULL; + bool has_paths = false; + int error; GIT_ASSERT_ARG(out); GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(stasher); + GIT_ASSERT_ARG(opts && opts->stasher); + + has_paths = opts->paths.count > 0; if ((error = git_repository__ensure_not_bare(repo, "stash save")) < 0) return error; @@ -555,44 +704,63 @@ int git_stash_save( if ((error = retrieve_base_commit_and_message(&b_commit, &msg, repo)) < 0) goto cleanup; - if ((error = ensure_there_are_changes_to_stash(repo, flags)) < 0) + if (!has_paths && + (error = ensure_there_are_changes_to_stash(repo, opts->flags)) < 0) + goto cleanup; + else if (has_paths && + (error = ensure_there_are_changes_to_stash_paths( + repo, opts->flags, &opts->paths)) < 0) goto cleanup; if ((error = git_repository_index(&index, repo)) < 0) goto cleanup; - if ((error = commit_index(&i_commit, repo, index, stasher, + if ((error = commit_index(&i_commit, repo, index, opts->stasher, git_str_cstr(&msg), b_commit)) < 0) goto cleanup; - if ((flags & (GIT_STASH_INCLUDE_UNTRACKED | GIT_STASH_INCLUDE_IGNORED)) && - (error = commit_untracked(&u_commit, repo, stasher, - git_str_cstr(&msg), i_commit, flags)) < 0) + if ((opts->flags & (GIT_STASH_INCLUDE_UNTRACKED | GIT_STASH_INCLUDE_IGNORED)) && + (error = commit_untracked(&u_commit, repo, opts->stasher, + git_str_cstr(&msg), i_commit, opts->flags)) < 0) goto cleanup; - if ((error = prepare_worktree_commit_message(&msg, message)) < 0) + if ((error = prepare_worktree_commit_message(&msg, opts->message)) < 0) goto cleanup; - if ((error = commit_worktree(out, repo, stasher, git_str_cstr(&msg), - i_commit, b_commit, u_commit)) < 0) - goto cleanup; + if (!has_paths) { + if ((error = commit_worktree(out, repo, opts->stasher, git_str_cstr(&msg), + i_commit, b_commit, u_commit)) < 0) + goto cleanup; + } else { + if ((error = git_index__new(&paths_index, repo->oid_type)) < 0 || + (error = retrieve_head(&head, repo)) < 0 || + (error = git_reference_peel((git_object**)&tree, head, GIT_OBJECT_TREE)) < 0 || + (error = git_index_read_tree(paths_index, tree)) < 0 || + (error = stash_update_index_from_paths(repo, paths_index, &opts->paths)) < 0 || + (error = build_stash_commit_from_index(out, repo, opts->stasher, git_str_cstr(&msg), + i_commit, b_commit, u_commit, paths_index)) < 0) + goto cleanup; + } git_str_rtrim(&msg); if ((error = update_reflog(out, repo, git_str_cstr(&msg))) < 0) goto cleanup; - if ((error = reset_index_and_workdir(repo, (flags & GIT_STASH_KEEP_INDEX) ? i_commit : b_commit, - flags)) < 0) + if (!(opts->flags & GIT_STASH_KEEP_ALL) && + (error = reset_index_and_workdir(repo, + (opts->flags & GIT_STASH_KEEP_INDEX) ? i_commit : b_commit,opts->flags)) < 0) goto cleanup; cleanup: - git_str_dispose(&msg); git_commit_free(i_commit); git_commit_free(b_commit); git_commit_free(u_commit); + git_tree_free(tree); + git_reference_free(head); git_index_free(index); + git_index_free(paths_index); return error; } @@ -777,6 +945,13 @@ int git_stash_apply_options_init(git_stash_apply_options *opts, unsigned int ver return 0; } +int git_stash_save_options_init(git_stash_save_options *opts, unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE( + opts, version, git_stash_save_options, GIT_STASH_SAVE_OPTIONS_INIT); + return 0; +} + #ifndef GIT_DEPRECATE_HARD int git_stash_apply_init_options(git_stash_apply_options *opts, unsigned int version) { @@ -828,6 +1003,7 @@ static int stage_new_file(const git_index_entry **entries, void *data) static int stage_new_files( git_index **out, + git_repository *repo, git_tree *parent_tree, git_tree *tree) { @@ -836,7 +1012,7 @@ static int stage_new_files( git_index *index = NULL; int error; - if ((error = git_index_new(&index)) < 0 || + if ((error = git_index__new(&index, repo->oid_type)) < 0 || (error = git_iterator_for_tree( &iterators[0], parent_tree, &iterator_options)) < 0 || (error = git_iterator_for_tree( @@ -920,10 +1096,10 @@ int git_stash_apply( * previously unstaged contents are staged, not the previously staged.) */ } else if ((opts.flags & GIT_STASH_APPLY_REINSTATE_INDEX) == 0) { - if ((error = stage_new_files( - &stash_adds, stash_parent_tree, stash_tree)) < 0 || - (error = merge_indexes( - &unstashed_index, repo, stash_parent_tree, repo_index, stash_adds)) < 0) + if ((error = stage_new_files(&stash_adds, repo, + stash_parent_tree, stash_tree)) < 0 || + (error = merge_indexes(&unstashed_index, repo, + stash_parent_tree, repo_index, stash_adds)) < 0) goto cleanup; } diff --git a/vendor/libgit2/src/status.c b/vendor/libgit2/src/libgit2/status.c similarity index 100% rename from vendor/libgit2/src/status.c rename to vendor/libgit2/src/libgit2/status.c diff --git a/vendor/libgit2/src/status.h b/vendor/libgit2/src/libgit2/status.h similarity index 100% rename from vendor/libgit2/src/status.h rename to vendor/libgit2/src/libgit2/status.h diff --git a/vendor/libgit2/src/strarray.c b/vendor/libgit2/src/libgit2/strarray.c similarity index 98% rename from vendor/libgit2/src/strarray.c rename to vendor/libgit2/src/libgit2/strarray.c index 2f9b77cc..25e75f02 100644 --- a/vendor/libgit2/src/strarray.c +++ b/vendor/libgit2/src/libgit2/strarray.c @@ -8,6 +8,7 @@ #include "util.h" #include "common.h" +#include "strarray.h" int git_strarray_copy(git_strarray *tgt, const git_strarray *src) { diff --git a/vendor/libgit2/src/libgit2/strarray.h b/vendor/libgit2/src/libgit2/strarray.h new file mode 100644 index 00000000..19848053 --- /dev/null +++ b/vendor/libgit2/src/libgit2/strarray.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_strarray_h__ +#define INCLUDE_strarray_h__ + +#include "common.h" +#include "git2/strarray.h" + +/** + * Copy a string array object from source to target. + * + * Note: target is overwritten and hence should be empty, otherwise its + * contents are leaked. Call git_strarray_free() if necessary. + * + * @param tgt target + * @param src source + * @return 0 on success, < 0 on allocation failure + */ +extern int git_strarray_copy(git_strarray *tgt, const git_strarray *src); + +#endif diff --git a/vendor/libgit2/src/stream.h b/vendor/libgit2/src/libgit2/stream.h similarity index 100% rename from vendor/libgit2/src/stream.h rename to vendor/libgit2/src/libgit2/stream.h diff --git a/vendor/libgit2/src/libgit2/streams/mbedtls.c b/vendor/libgit2/src/libgit2/streams/mbedtls.c new file mode 100644 index 00000000..1b278070 --- /dev/null +++ b/vendor/libgit2/src/libgit2/streams/mbedtls.c @@ -0,0 +1,475 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "streams/mbedtls.h" + +#ifdef GIT_MBEDTLS + +#include + +#include "runtime.h" +#include "stream.h" +#include "streams/socket.h" +#include "git2/transport.h" +#include "util.h" + +#ifndef GIT_DEFAULT_CERT_LOCATION +#define GIT_DEFAULT_CERT_LOCATION NULL +#endif + +/* Work around C90-conformance issues */ +#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) +# if defined(_MSC_VER) +# define inline __inline +# elif defined(__GNUC__) +# define inline __inline__ +# else +# define inline +# endif +#endif + +#include +#include +#include +#include + +#undef inline + +#define GIT_SSL_DEFAULT_CIPHERS "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-DSS-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-DSS-WITH-AES-256-GCM-SHA384:TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256:TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA:TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA:TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384:TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384:TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA:TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-DSS-WITH-AES-128-CBC-SHA256:TLS-DHE-DSS-WITH-AES-256-CBC-SHA256:TLS-DHE-DSS-WITH-AES-128-CBC-SHA:TLS-DHE-DSS-WITH-AES-256-CBC-SHA:TLS-RSA-WITH-AES-128-GCM-SHA256:TLS-RSA-WITH-AES-256-GCM-SHA384:TLS-RSA-WITH-AES-128-CBC-SHA256:TLS-RSA-WITH-AES-256-CBC-SHA256:TLS-RSA-WITH-AES-128-CBC-SHA:TLS-RSA-WITH-AES-256-CBC-SHA" +#define GIT_SSL_DEFAULT_CIPHERS_COUNT 30 + +static int ciphers_list[GIT_SSL_DEFAULT_CIPHERS_COUNT]; + +static bool initialized = false; +static mbedtls_ssl_config mbedtls_config; +static mbedtls_ctr_drbg_context mbedtls_rng; +static mbedtls_entropy_context mbedtls_entropy; + +static bool has_ca_chain = false; +static mbedtls_x509_crt mbedtls_ca_chain; + +/** + * This function aims to clean-up the SSL context which + * we allocated. + */ +static void shutdown_ssl(void) +{ + if (has_ca_chain) { + mbedtls_x509_crt_free(&mbedtls_ca_chain); + has_ca_chain = false; + } + + if (initialized) { + mbedtls_ctr_drbg_free(&mbedtls_rng); + mbedtls_ssl_config_free(&mbedtls_config); + mbedtls_entropy_free(&mbedtls_entropy); + initialized = false; + } +} + +int git_mbedtls_stream_global_init(void) +{ + int loaded = 0; + char *crtpath = GIT_DEFAULT_CERT_LOCATION; + struct stat statbuf; + + size_t ciphers_known = 0; + char *cipher_name = NULL; + char *cipher_string = NULL; + char *cipher_string_tmp = NULL; + + mbedtls_ssl_config_init(&mbedtls_config); + mbedtls_entropy_init(&mbedtls_entropy); + mbedtls_ctr_drbg_init(&mbedtls_rng); + + if (mbedtls_ssl_config_defaults(&mbedtls_config, + MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT) != 0) { + git_error_set(GIT_ERROR_SSL, "failed to initialize mbedTLS"); + goto cleanup; + } + + /* configure TLSv1.1 */ +#ifdef MBEDTLS_SSL_MINOR_VERSION_2 + mbedtls_ssl_conf_min_version(&mbedtls_config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_2); +#endif + + /* verify_server_cert is responsible for making the check. + * OPTIONAL because REQUIRED drops the certificate as soon as the check + * is made, so we can never see the certificate and override it. */ + mbedtls_ssl_conf_authmode(&mbedtls_config, MBEDTLS_SSL_VERIFY_OPTIONAL); + + /* set the list of allowed ciphersuites */ + ciphers_known = 0; + cipher_string = cipher_string_tmp = git__strdup(GIT_SSL_DEFAULT_CIPHERS); + GIT_ERROR_CHECK_ALLOC(cipher_string); + + while ((cipher_name = git__strtok(&cipher_string_tmp, ":")) != NULL) { + int cipherid = mbedtls_ssl_get_ciphersuite_id(cipher_name); + if (cipherid == 0) continue; + + if (ciphers_known >= ARRAY_SIZE(ciphers_list)) { + git_error_set(GIT_ERROR_SSL, "out of cipher list space"); + goto cleanup; + } + + ciphers_list[ciphers_known++] = cipherid; + } + git__free(cipher_string); + + if (!ciphers_known) { + git_error_set(GIT_ERROR_SSL, "no cipher could be enabled"); + goto cleanup; + } + mbedtls_ssl_conf_ciphersuites(&mbedtls_config, ciphers_list); + + /* Seeding the random number generator */ + + if (mbedtls_ctr_drbg_seed(&mbedtls_rng, mbedtls_entropy_func, + &mbedtls_entropy, NULL, 0) != 0) { + git_error_set(GIT_ERROR_SSL, "failed to initialize mbedTLS entropy pool"); + goto cleanup; + } + + mbedtls_ssl_conf_rng(&mbedtls_config, mbedtls_ctr_drbg_random, &mbedtls_rng); + + /* load default certificates */ + if (crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISREG(statbuf.st_mode)) + loaded = (git_mbedtls__set_cert_location(crtpath, NULL) == 0); + + if (!loaded && crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) + loaded = (git_mbedtls__set_cert_location(NULL, crtpath) == 0); + + initialized = true; + + return git_runtime_shutdown_register(shutdown_ssl); + +cleanup: + mbedtls_ctr_drbg_free(&mbedtls_rng); + mbedtls_ssl_config_free(&mbedtls_config); + mbedtls_entropy_free(&mbedtls_entropy); + + return -1; +} + +static int bio_read(void *b, unsigned char *buf, size_t len) +{ + git_stream *io = (git_stream *) b; + return (int) git_stream_read(io, buf, min(len, INT_MAX)); +} + +static int bio_write(void *b, const unsigned char *buf, size_t len) +{ + git_stream *io = (git_stream *) b; + return (int) git_stream_write(io, (const char *)buf, min(len, INT_MAX), 0); +} + +static int ssl_set_error(mbedtls_ssl_context *ssl, int error) +{ + char errbuf[512]; + int ret = -1; + + GIT_ASSERT(error != MBEDTLS_ERR_SSL_WANT_READ); + GIT_ASSERT(error != MBEDTLS_ERR_SSL_WANT_WRITE); + + if (error != 0) + mbedtls_strerror( error, errbuf, 512 ); + + switch(error) { + case 0: + git_error_set(GIT_ERROR_SSL, "SSL error: unknown error"); + break; + + case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: + git_error_set(GIT_ERROR_SSL, "SSL error: %#04x [%x] - %s", error, mbedtls_ssl_get_verify_result(ssl), errbuf); + ret = GIT_ECERTIFICATE; + break; + + default: + git_error_set(GIT_ERROR_SSL, "SSL error: %#04x - %s", error, errbuf); + } + + return ret; +} + +static int ssl_teardown(mbedtls_ssl_context *ssl) +{ + int ret = 0; + + ret = mbedtls_ssl_close_notify(ssl); + if (ret < 0) + ret = ssl_set_error(ssl, ret); + + mbedtls_ssl_free(ssl); + return ret; +} + +static int verify_server_cert(mbedtls_ssl_context *ssl) +{ + int ret = -1; + + if ((ret = mbedtls_ssl_get_verify_result(ssl)) != 0) { + char vrfy_buf[512]; + int len = mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "", ret); + if (len >= 1) vrfy_buf[len - 1] = '\0'; /* Remove trailing \n */ + git_error_set(GIT_ERROR_SSL, "the SSL certificate is invalid: %#04x - %s", ret, vrfy_buf); + return GIT_ECERTIFICATE; + } + + return 0; +} + +typedef struct { + git_stream parent; + git_stream *io; + int owned; + bool connected; + char *host; + mbedtls_ssl_context *ssl; + git_cert_x509 cert_info; +} mbedtls_stream; + + +static int mbedtls_connect(git_stream *stream) +{ + int ret; + mbedtls_stream *st = (mbedtls_stream *) stream; + + if (st->owned && (ret = git_stream_connect(st->io)) < 0) + return ret; + + st->connected = true; + + mbedtls_ssl_set_hostname(st->ssl, st->host); + + mbedtls_ssl_set_bio(st->ssl, st->io, bio_write, bio_read, NULL); + + if ((ret = mbedtls_ssl_handshake(st->ssl)) != 0) + return ssl_set_error(st->ssl, ret); + + return verify_server_cert(st->ssl); +} + +static int mbedtls_certificate(git_cert **out, git_stream *stream) +{ + unsigned char *encoded_cert; + mbedtls_stream *st = (mbedtls_stream *) stream; + + const mbedtls_x509_crt *cert = mbedtls_ssl_get_peer_cert(st->ssl); + if (!cert) { + git_error_set(GIT_ERROR_SSL, "the server did not provide a certificate"); + return -1; + } + + /* Retrieve the length of the certificate first */ + if (cert->raw.len == 0) { + git_error_set(GIT_ERROR_NET, "failed to retrieve certificate information"); + return -1; + } + + encoded_cert = git__malloc(cert->raw.len); + GIT_ERROR_CHECK_ALLOC(encoded_cert); + memcpy(encoded_cert, cert->raw.p, cert->raw.len); + + st->cert_info.parent.cert_type = GIT_CERT_X509; + st->cert_info.data = encoded_cert; + st->cert_info.len = cert->raw.len; + + *out = &st->cert_info.parent; + + return 0; +} + +static int mbedtls_set_proxy(git_stream *stream, const git_proxy_options *proxy_options) +{ + mbedtls_stream *st = (mbedtls_stream *) stream; + + return git_stream_set_proxy(st->io, proxy_options); +} + +static ssize_t mbedtls_stream_write(git_stream *stream, const char *data, size_t len, int flags) +{ + mbedtls_stream *st = (mbedtls_stream *) stream; + int written; + + GIT_UNUSED(flags); + + /* + * `mbedtls_ssl_write` can only represent INT_MAX bytes + * written via its return value. We thus need to clamp + * the maximum number of bytes written. + */ + len = min(len, INT_MAX); + + if ((written = mbedtls_ssl_write(st->ssl, (const unsigned char *)data, len)) <= 0) + return ssl_set_error(st->ssl, written); + + return written; +} + +static ssize_t mbedtls_stream_read(git_stream *stream, void *data, size_t len) +{ + mbedtls_stream *st = (mbedtls_stream *) stream; + int ret; + + if ((ret = mbedtls_ssl_read(st->ssl, (unsigned char *)data, len)) <= 0) + ssl_set_error(st->ssl, ret); + + return ret; +} + +static int mbedtls_stream_close(git_stream *stream) +{ + mbedtls_stream *st = (mbedtls_stream *) stream; + int ret = 0; + + if (st->connected && (ret = ssl_teardown(st->ssl)) != 0) + return -1; + + st->connected = false; + + return st->owned ? git_stream_close(st->io) : 0; +} + +static void mbedtls_stream_free(git_stream *stream) +{ + mbedtls_stream *st = (mbedtls_stream *) stream; + + if (st->owned) + git_stream_free(st->io); + + git__free(st->host); + git__free(st->cert_info.data); + mbedtls_ssl_free(st->ssl); + git__free(st->ssl); + git__free(st); +} + +static int mbedtls_stream_wrap( + git_stream **out, + git_stream *in, + const char *host, + int owned) +{ + mbedtls_stream *st; + int error; + + st = git__calloc(1, sizeof(mbedtls_stream)); + GIT_ERROR_CHECK_ALLOC(st); + + st->io = in; + st->owned = owned; + + st->ssl = git__malloc(sizeof(mbedtls_ssl_context)); + GIT_ERROR_CHECK_ALLOC(st->ssl); + mbedtls_ssl_init(st->ssl); + if (mbedtls_ssl_setup(st->ssl, &mbedtls_config)) { + git_error_set(GIT_ERROR_SSL, "failed to create ssl object"); + error = -1; + goto out_err; + } + + st->host = git__strdup(host); + GIT_ERROR_CHECK_ALLOC(st->host); + + st->parent.version = GIT_STREAM_VERSION; + st->parent.encrypted = 1; + st->parent.proxy_support = git_stream_supports_proxy(st->io); + st->parent.connect = mbedtls_connect; + st->parent.certificate = mbedtls_certificate; + st->parent.set_proxy = mbedtls_set_proxy; + st->parent.read = mbedtls_stream_read; + st->parent.write = mbedtls_stream_write; + st->parent.close = mbedtls_stream_close; + st->parent.free = mbedtls_stream_free; + + *out = (git_stream *) st; + return 0; + +out_err: + mbedtls_ssl_free(st->ssl); + git_stream_close(st->io); + git_stream_free(st->io); + git__free(st); + + return error; +} + +int git_mbedtls_stream_wrap( + git_stream **out, + git_stream *in, + const char *host) +{ + return mbedtls_stream_wrap(out, in, host, 0); +} + +int git_mbedtls_stream_new( + git_stream **out, + const char *host, + const char *port) +{ + git_stream *stream; + int error; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(host); + GIT_ASSERT_ARG(port); + + if ((error = git_socket_stream_new(&stream, host, port)) < 0) + return error; + + if ((error = mbedtls_stream_wrap(out, stream, host, 1)) < 0) { + git_stream_close(stream); + git_stream_free(stream); + } + + return error; +} + +int git_mbedtls__set_cert_location(const char *file, const char *path) +{ + int ret = 0; + char errbuf[512]; + + GIT_ASSERT_ARG(file || path); + + if (has_ca_chain) + mbedtls_x509_crt_free(&mbedtls_ca_chain); + + mbedtls_x509_crt_init(&mbedtls_ca_chain); + + if (file) + ret = mbedtls_x509_crt_parse_file(&mbedtls_ca_chain, file); + + if (ret >= 0 && path) + ret = mbedtls_x509_crt_parse_path(&mbedtls_ca_chain, path); + + /* mbedtls_x509_crt_parse_path returns the number of invalid certs on success */ + if (ret < 0) { + mbedtls_x509_crt_free(&mbedtls_ca_chain); + mbedtls_strerror( ret, errbuf, 512 ); + git_error_set(GIT_ERROR_SSL, "failed to load CA certificates: %#04x - %s", ret, errbuf); + return -1; + } + + mbedtls_ssl_conf_ca_chain(&mbedtls_config, &mbedtls_ca_chain, NULL); + has_ca_chain = true; + + return 0; +} + +#else + +#include "stream.h" + +int git_mbedtls_stream_global_init(void) +{ + return 0; +} + +#endif diff --git a/vendor/libgit2/src/streams/mbedtls.h b/vendor/libgit2/src/libgit2/streams/mbedtls.h similarity index 100% rename from vendor/libgit2/src/streams/mbedtls.h rename to vendor/libgit2/src/libgit2/streams/mbedtls.h diff --git a/vendor/libgit2/src/libgit2/streams/openssl.c b/vendor/libgit2/src/libgit2/streams/openssl.c new file mode 100644 index 00000000..7cb8f7f9 --- /dev/null +++ b/vendor/libgit2/src/libgit2/streams/openssl.c @@ -0,0 +1,741 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "streams/openssl.h" +#include "streams/openssl_legacy.h" +#include "streams/openssl_dynamic.h" + +#ifdef GIT_OPENSSL + +#include + +#include "common.h" +#include "runtime.h" +#include "settings.h" +#include "posix.h" +#include "stream.h" +#include "net.h" +#include "streams/socket.h" +#include "git2/transport.h" +#include "git2/sys/openssl.h" + +#ifndef GIT_WIN32 +# include +# include +# include +#endif + +#ifndef GIT_OPENSSL_DYNAMIC +# include +# include +# include +# include +#endif + +extern char *git__ssl_ciphers; + +SSL_CTX *git__ssl_ctx; + +#define GIT_SSL_DEFAULT_CIPHERS "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES128-SHA256:DHE-DSS-AES256-SHA256:DHE-DSS-AES128-SHA:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA" + + +static BIO_METHOD *git_stream_bio_method; +static int init_bio_method(void); + +/** + * This function aims to clean-up the SSL context which + * we allocated. + */ +static void shutdown_ssl(void) +{ + if (git_stream_bio_method) { + BIO_meth_free(git_stream_bio_method); + git_stream_bio_method = NULL; + } + + if (git__ssl_ctx) { + SSL_CTX_free(git__ssl_ctx); + git__ssl_ctx = NULL; + } +} + +#ifdef VALGRIND +# if !defined(GIT_OPENSSL_LEGACY) && !defined(GIT_OPENSSL_DYNAMIC) + +static void *git_openssl_malloc(size_t bytes, const char *file, int line) +{ + GIT_UNUSED(file); + GIT_UNUSED(line); + return git__calloc(1, bytes); +} + +static void *git_openssl_realloc(void *mem, size_t size, const char *file, int line) +{ + GIT_UNUSED(file); + GIT_UNUSED(line); + return git__realloc(mem, size); +} + +static void git_openssl_free(void *mem, const char *file, int line) +{ + GIT_UNUSED(file); + GIT_UNUSED(line); + git__free(mem); +} +# else /* !GIT_OPENSSL_LEGACY && !GIT_OPENSSL_DYNAMIC */ +static void *git_openssl_malloc(size_t bytes) +{ + return git__calloc(1, bytes); +} + +static void *git_openssl_realloc(void *mem, size_t size) +{ + return git__realloc(mem, size); +} + +static void git_openssl_free(void *mem) +{ + git__free(mem); +} +# endif /* !GIT_OPENSSL_LEGACY && !GIT_OPENSSL_DYNAMIC */ +#endif /* VALGRIND */ + +static int openssl_init(void) +{ + long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; + const char *ciphers = git__ssl_ciphers; +#ifdef VALGRIND + static bool allocators_initialized = false; +#endif + + /* Older OpenSSL and MacOS OpenSSL doesn't have this */ +#ifdef SSL_OP_NO_COMPRESSION + ssl_opts |= SSL_OP_NO_COMPRESSION; +#endif + +#ifdef VALGRIND + /* + * Swap in our own allocator functions that initialize + * allocated memory to avoid spurious valgrind warnings. + * Don't error on failure; many builds of OpenSSL do not + * allow you to set these functions. + */ + if (!allocators_initialized) { + CRYPTO_set_mem_functions(git_openssl_malloc, + git_openssl_realloc, + git_openssl_free); + allocators_initialized = true; + } +#endif + + OPENSSL_init_ssl(0, NULL); + + /* + * Load SSLv{2,3} and TLSv1 so that we can talk with servers + * which use the SSL hellos, which are often used for + * compatibility. We then disable SSL so we only allow OpenSSL + * to speak TLSv1 to perform the encryption itself. + */ + if (!(git__ssl_ctx = SSL_CTX_new(SSLv23_method()))) + goto error; + + SSL_CTX_set_options(git__ssl_ctx, ssl_opts); + SSL_CTX_set_mode(git__ssl_ctx, SSL_MODE_AUTO_RETRY); + SSL_CTX_set_verify(git__ssl_ctx, SSL_VERIFY_NONE, NULL); + if (!SSL_CTX_set_default_verify_paths(git__ssl_ctx)) + goto error; + + if (!ciphers) + ciphers = GIT_SSL_DEFAULT_CIPHERS; + + if(!SSL_CTX_set_cipher_list(git__ssl_ctx, ciphers)) + goto error; + + if (init_bio_method() < 0) + goto error; + + return git_runtime_shutdown_register(shutdown_ssl); + +error: + git_error_set(GIT_ERROR_NET, "could not initialize openssl: %s", + ERR_error_string(ERR_get_error(), NULL)); + SSL_CTX_free(git__ssl_ctx); + git__ssl_ctx = NULL; + return -1; +} + +/* + * When we use dynamic loading, we defer OpenSSL initialization until + * it's first used. `openssl_ensure_initialized` will do the work + * under a mutex. + */ +git_mutex openssl_mutex; +bool openssl_initialized; + +int git_openssl_stream_global_init(void) +{ +#ifndef GIT_OPENSSL_DYNAMIC + return openssl_init(); +#else + if (git_mutex_init(&openssl_mutex) != 0) + return -1; + + return 0; +#endif +} + +static int openssl_ensure_initialized(void) +{ +#ifdef GIT_OPENSSL_DYNAMIC + int error = 0; + + if (git_mutex_lock(&openssl_mutex) != 0) + return -1; + + if (!openssl_initialized) { + if ((error = git_openssl_stream_dynamic_init()) == 0) + error = openssl_init(); + + openssl_initialized = !error; + } + + error |= git_mutex_unlock(&openssl_mutex); + return error; + +#else + return 0; +#endif +} + +#if !defined(GIT_OPENSSL_LEGACY) && !defined(GIT_OPENSSL_DYNAMIC) +int git_openssl_set_locking(void) +{ +# ifdef GIT_THREADS + return 0; +# else + git_error_set(GIT_ERROR_THREAD, "libgit2 was not built with threads"); + return -1; +# endif +} +#endif + + +static int bio_create(BIO *b) +{ + BIO_set_init(b, 1); + BIO_set_data(b, NULL); + + return 1; +} + +static int bio_destroy(BIO *b) +{ + if (!b) + return 0; + + BIO_set_data(b, NULL); + + return 1; +} + +static int bio_read(BIO *b, char *buf, int len) +{ + git_stream *io = (git_stream *) BIO_get_data(b); + + return (int) git_stream_read(io, buf, len); +} + +static int bio_write(BIO *b, const char *buf, int len) +{ + git_stream *io = (git_stream *) BIO_get_data(b); + return (int) git_stream_write(io, buf, len, 0); +} + +static long bio_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + GIT_UNUSED(b); + GIT_UNUSED(num); + GIT_UNUSED(ptr); + + if (cmd == BIO_CTRL_FLUSH) + return 1; + + return 0; +} + +static int bio_gets(BIO *b, char *buf, int len) +{ + GIT_UNUSED(b); + GIT_UNUSED(buf); + GIT_UNUSED(len); + return -1; +} + +static int bio_puts(BIO *b, const char *str) +{ + return bio_write(b, str, strlen(str)); +} + +static int init_bio_method(void) +{ + /* Set up the BIO_METHOD we use for wrapping our own stream implementations */ + git_stream_bio_method = BIO_meth_new(BIO_TYPE_SOURCE_SINK | BIO_get_new_index(), "git_stream"); + GIT_ERROR_CHECK_ALLOC(git_stream_bio_method); + + BIO_meth_set_write(git_stream_bio_method, bio_write); + BIO_meth_set_read(git_stream_bio_method, bio_read); + BIO_meth_set_puts(git_stream_bio_method, bio_puts); + BIO_meth_set_gets(git_stream_bio_method, bio_gets); + BIO_meth_set_ctrl(git_stream_bio_method, bio_ctrl); + BIO_meth_set_create(git_stream_bio_method, bio_create); + BIO_meth_set_destroy(git_stream_bio_method, bio_destroy); + + return 0; +} + +static int ssl_set_error(SSL *ssl, int error) +{ + int err; + unsigned long e; + + err = SSL_get_error(ssl, error); + + GIT_ASSERT(err != SSL_ERROR_WANT_READ); + GIT_ASSERT(err != SSL_ERROR_WANT_WRITE); + + switch (err) { + case SSL_ERROR_WANT_CONNECT: + case SSL_ERROR_WANT_ACCEPT: + git_error_set(GIT_ERROR_SSL, "SSL error: connection failure"); + break; + case SSL_ERROR_WANT_X509_LOOKUP: + git_error_set(GIT_ERROR_SSL, "SSL error: x509 error"); + break; + case SSL_ERROR_SYSCALL: + e = ERR_get_error(); + if (e > 0) { + char errmsg[256]; + ERR_error_string_n(e, errmsg, sizeof(errmsg)); + git_error_set(GIT_ERROR_NET, "SSL error: %s", errmsg); + break; + } else if (error < 0) { + git_error_set(GIT_ERROR_OS, "SSL error: syscall failure"); + break; + } + git_error_set(GIT_ERROR_SSL, "SSL error: received early EOF"); + return GIT_EEOF; + break; + case SSL_ERROR_SSL: + { + char errmsg[256]; + e = ERR_get_error(); + ERR_error_string_n(e, errmsg, sizeof(errmsg)); + git_error_set(GIT_ERROR_SSL, "SSL error: %s", errmsg); + break; + } + case SSL_ERROR_NONE: + case SSL_ERROR_ZERO_RETURN: + default: + git_error_set(GIT_ERROR_SSL, "SSL error: unknown error"); + break; + } + return -1; +} + +static int ssl_teardown(SSL *ssl) +{ + int ret; + + ret = SSL_shutdown(ssl); + if (ret < 0) + ret = ssl_set_error(ssl, ret); + else + ret = 0; + + return ret; +} + +static bool check_host_name(const char *host, const char *name) +{ + return !strcasecmp(host, name) || + git_net_hostname_matches_cert(host, name); +} + +static int verify_server_cert(SSL *ssl, const char *host) +{ + X509 *cert = NULL; + X509_NAME *peer_name; + ASN1_STRING *str; + unsigned char *peer_cn = NULL; + int matched = -1, type = GEN_DNS; + GENERAL_NAMES *alts; + struct in6_addr addr6; + struct in_addr addr4; + void *addr = NULL; + int i = -1, j, error = 0; + + if (SSL_get_verify_result(ssl) != X509_V_OK) { + git_error_set(GIT_ERROR_SSL, "the SSL certificate is invalid"); + return GIT_ECERTIFICATE; + } + + /* Try to parse the host as an IP address to see if it is */ + if (p_inet_pton(AF_INET, host, &addr4)) { + type = GEN_IPADD; + addr = &addr4; + } else { + if (p_inet_pton(AF_INET6, host, &addr6)) { + type = GEN_IPADD; + addr = &addr6; + } + } + + + cert = SSL_get_peer_certificate(ssl); + if (!cert) { + error = -1; + git_error_set(GIT_ERROR_SSL, "the server did not provide a certificate"); + goto cleanup; + } + + /* Check the alternative names */ + alts = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); + if (alts) { + int num; + + num = sk_GENERAL_NAME_num(alts); + for (i = 0; i < num && matched != 1; i++) { + const GENERAL_NAME *gn = sk_GENERAL_NAME_value(alts, i); + const char *name = (char *) ASN1_STRING_get0_data(gn->d.ia5); + size_t namelen = (size_t) ASN1_STRING_length(gn->d.ia5); + + /* Skip any names of a type we're not looking for */ + if (gn->type != type) + continue; + + if (type == GEN_DNS) { + /* If it contains embedded NULs, don't even try */ + if (memchr(name, '\0', namelen)) + continue; + + matched = !!check_host_name(host, name); + } else if (type == GEN_IPADD) { + /* Here name isn't so much a name but a binary representation of the IP */ + matched = addr && !!memcmp(name, addr, namelen); + } + } + } + GENERAL_NAMES_free(alts); + + if (matched == 0) + goto cert_fail_name; + + if (matched == 1) { + goto cleanup; + } + + /* If no alternative names are available, check the common name */ + peer_name = X509_get_subject_name(cert); + if (peer_name == NULL) + goto on_error; + + if (peer_name) { + /* Get the index of the last CN entry */ + while ((j = X509_NAME_get_index_by_NID(peer_name, NID_commonName, i)) >= 0) + i = j; + } + + if (i < 0) + goto on_error; + + str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(peer_name, i)); + if (str == NULL) + goto on_error; + + /* Work around a bug in OpenSSL whereby ASN1_STRING_to_UTF8 fails if it's already in utf-8 */ + if (ASN1_STRING_type(str) == V_ASN1_UTF8STRING) { + int size = ASN1_STRING_length(str); + + if (size > 0) { + peer_cn = OPENSSL_malloc(size + 1); + GIT_ERROR_CHECK_ALLOC(peer_cn); + memcpy(peer_cn, ASN1_STRING_get0_data(str), size); + peer_cn[size] = '\0'; + } else { + goto cert_fail_name; + } + } else { + int size = ASN1_STRING_to_UTF8(&peer_cn, str); + GIT_ERROR_CHECK_ALLOC(peer_cn); + if (memchr(peer_cn, '\0', size)) + goto cert_fail_name; + } + + if (!check_host_name(host, (char *)peer_cn)) + goto cert_fail_name; + + goto cleanup; + +cert_fail_name: + error = GIT_ECERTIFICATE; + git_error_set(GIT_ERROR_SSL, "hostname does not match certificate"); + goto cleanup; + +on_error: + error = ssl_set_error(ssl, 0); + goto cleanup; + +cleanup: + X509_free(cert); + OPENSSL_free(peer_cn); + return error; +} + +typedef struct { + git_stream parent; + git_stream *io; + int owned; + bool connected; + char *host; + SSL *ssl; + git_cert_x509 cert_info; +} openssl_stream; + +static int openssl_connect(git_stream *stream) +{ + int ret; + BIO *bio; + openssl_stream *st = (openssl_stream *) stream; + + if (st->owned && (ret = git_stream_connect(st->io)) < 0) + return ret; + + bio = BIO_new(git_stream_bio_method); + GIT_ERROR_CHECK_ALLOC(bio); + + BIO_set_data(bio, st->io); + SSL_set_bio(st->ssl, bio, bio); + + /* specify the host in case SNI is needed */ +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + SSL_set_tlsext_host_name(st->ssl, st->host); +#endif + + if ((ret = SSL_connect(st->ssl)) <= 0) + return ssl_set_error(st->ssl, ret); + + st->connected = true; + + return verify_server_cert(st->ssl, st->host); +} + +static int openssl_certificate(git_cert **out, git_stream *stream) +{ + openssl_stream *st = (openssl_stream *) stream; + X509 *cert = SSL_get_peer_certificate(st->ssl); + unsigned char *guard, *encoded_cert = NULL; + int error, len; + + /* Retrieve the length of the certificate first */ + len = i2d_X509(cert, NULL); + if (len < 0) { + git_error_set(GIT_ERROR_NET, "failed to retrieve certificate information"); + error = -1; + goto out; + } + + encoded_cert = git__malloc(len); + GIT_ERROR_CHECK_ALLOC(encoded_cert); + /* i2d_X509 makes 'guard' point to just after the data */ + guard = encoded_cert; + + len = i2d_X509(cert, &guard); + if (len < 0) { + git_error_set(GIT_ERROR_NET, "failed to retrieve certificate information"); + error = -1; + goto out; + } + + st->cert_info.parent.cert_type = GIT_CERT_X509; + st->cert_info.data = encoded_cert; + st->cert_info.len = len; + encoded_cert = NULL; + + *out = &st->cert_info.parent; + error = 0; + +out: + git__free(encoded_cert); + X509_free(cert); + return error; +} + +static int openssl_set_proxy(git_stream *stream, const git_proxy_options *proxy_opts) +{ + openssl_stream *st = (openssl_stream *) stream; + + return git_stream_set_proxy(st->io, proxy_opts); +} + +static ssize_t openssl_write(git_stream *stream, const char *data, size_t data_len, int flags) +{ + openssl_stream *st = (openssl_stream *) stream; + int ret, len = min(data_len, INT_MAX); + + GIT_UNUSED(flags); + + if ((ret = SSL_write(st->ssl, data, len)) <= 0) + return ssl_set_error(st->ssl, ret); + + return ret; +} + +static ssize_t openssl_read(git_stream *stream, void *data, size_t len) +{ + openssl_stream *st = (openssl_stream *) stream; + int ret; + + if ((ret = SSL_read(st->ssl, data, len)) <= 0) + return ssl_set_error(st->ssl, ret); + + return ret; +} + +static int openssl_close(git_stream *stream) +{ + openssl_stream *st = (openssl_stream *) stream; + int ret; + + if (st->connected && (ret = ssl_teardown(st->ssl)) < 0) + return -1; + + st->connected = false; + + return st->owned ? git_stream_close(st->io) : 0; +} + +static void openssl_free(git_stream *stream) +{ + openssl_stream *st = (openssl_stream *) stream; + + if (st->owned) + git_stream_free(st->io); + + SSL_free(st->ssl); + git__free(st->host); + git__free(st->cert_info.data); + git__free(st); +} + +static int openssl_stream_wrap( + git_stream **out, + git_stream *in, + const char *host, + int owned) +{ + openssl_stream *st; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(in); + GIT_ASSERT_ARG(host); + + st = git__calloc(1, sizeof(openssl_stream)); + GIT_ERROR_CHECK_ALLOC(st); + + st->io = in; + st->owned = owned; + + st->ssl = SSL_new(git__ssl_ctx); + if (st->ssl == NULL) { + git_error_set(GIT_ERROR_SSL, "failed to create ssl object"); + git__free(st); + return -1; + } + + st->host = git__strdup(host); + GIT_ERROR_CHECK_ALLOC(st->host); + + st->parent.version = GIT_STREAM_VERSION; + st->parent.encrypted = 1; + st->parent.proxy_support = git_stream_supports_proxy(st->io); + st->parent.connect = openssl_connect; + st->parent.certificate = openssl_certificate; + st->parent.set_proxy = openssl_set_proxy; + st->parent.read = openssl_read; + st->parent.write = openssl_write; + st->parent.close = openssl_close; + st->parent.free = openssl_free; + + *out = (git_stream *) st; + return 0; +} + +int git_openssl_stream_wrap(git_stream **out, git_stream *in, const char *host) +{ + if (openssl_ensure_initialized() < 0) + return -1; + + return openssl_stream_wrap(out, in, host, 0); +} + +int git_openssl_stream_new(git_stream **out, const char *host, const char *port) +{ + git_stream *stream = NULL; + int error; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(host); + GIT_ASSERT_ARG(port); + + if (openssl_ensure_initialized() < 0) + return -1; + + if ((error = git_socket_stream_new(&stream, host, port)) < 0) + return error; + + if ((error = openssl_stream_wrap(out, stream, host, 1)) < 0) { + git_stream_close(stream); + git_stream_free(stream); + } + + return error; +} + +int git_openssl__set_cert_location(const char *file, const char *path) +{ + if (openssl_ensure_initialized() < 0) + return -1; + + if (SSL_CTX_load_verify_locations(git__ssl_ctx, file, path) == 0) { + char errmsg[256]; + + ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg)); + git_error_set(GIT_ERROR_SSL, "OpenSSL error: failed to load certificates: %s", + errmsg); + + return -1; + } + return 0; +} + +#else + +#include "stream.h" +#include "git2/sys/openssl.h" + +int git_openssl_stream_global_init(void) +{ + return 0; +} + +int git_openssl_set_locking(void) +{ + git_error_set(GIT_ERROR_SSL, "libgit2 was not built with OpenSSL support"); + return -1; +} + +#endif diff --git a/vendor/libgit2/src/streams/openssl.h b/vendor/libgit2/src/libgit2/streams/openssl.h similarity index 100% rename from vendor/libgit2/src/streams/openssl.h rename to vendor/libgit2/src/libgit2/streams/openssl.h diff --git a/vendor/libgit2/src/streams/openssl_dynamic.c b/vendor/libgit2/src/libgit2/streams/openssl_dynamic.c similarity index 97% rename from vendor/libgit2/src/streams/openssl_dynamic.c rename to vendor/libgit2/src/libgit2/streams/openssl_dynamic.c index da16b6ed..222c1099 100644 --- a/vendor/libgit2/src/streams/openssl_dynamic.c +++ b/vendor/libgit2/src/libgit2/streams/openssl_dynamic.c @@ -91,7 +91,7 @@ int (*sk_num)(const void *sk); void *(*sk_value)(const void *sk, int i); void (*sk_free)(void *sk); -void *openssl_handle; +static void *openssl_handle; GIT_INLINE(void *) openssl_sym(int *err, const char *name, bool required) { @@ -125,7 +125,8 @@ int git_openssl_stream_dynamic_init(void) (openssl_handle = dlopen("libssl.1.1.dylib", RTLD_NOW)) == NULL && (openssl_handle = dlopen("libssl.so.1.0.0", RTLD_NOW)) == NULL && (openssl_handle = dlopen("libssl.1.0.0.dylib", RTLD_NOW)) == NULL && - (openssl_handle = dlopen("libssl.so.10", RTLD_NOW)) == NULL) { + (openssl_handle = dlopen("libssl.so.10", RTLD_NOW)) == NULL && + (openssl_handle = dlopen("libssl.so.3", RTLD_NOW)) == NULL) { git_error_set(GIT_ERROR_SSL, "could not load ssl libraries"); return -1; } @@ -175,7 +176,6 @@ int git_openssl_stream_dynamic_init(void) SSL_connect = (int (*)(SSL *))openssl_sym(&err, "SSL_connect", true); SSL_ctrl = (long (*)(SSL *, int, long, void *))openssl_sym(&err, "SSL_ctrl", true); - SSL_get_peer_certificate = (X509 *(*)(const SSL *))openssl_sym(&err, "SSL_get_peer_certificate", true); SSL_library_init = (int (*)(void))openssl_sym(&err, "SSL_library_init", false); SSL_free = (void (*)(SSL *))openssl_sym(&err, "SSL_free", true); SSL_get_error = (int (*)(SSL *, int))openssl_sym(&err, "SSL_get_error", true); @@ -187,6 +187,10 @@ int git_openssl_stream_dynamic_init(void) SSL_shutdown = (int (*)(SSL *ssl))openssl_sym(&err, "SSL_shutdown", true); SSL_write = (int (*)(SSL *, const void *, int))openssl_sym(&err, "SSL_write", true); + if (!(SSL_get_peer_certificate = (X509 *(*)(const SSL *))openssl_sym(&err, "SSL_get_peer_certificate", false))) { + SSL_get_peer_certificate = (X509 *(*)(const SSL *))openssl_sym(&err, "SSL_get1_peer_certificate", true); + } + SSL_CTX_ctrl = (long (*)(SSL_CTX *, int, long, void *))openssl_sym(&err, "SSL_CTX_ctrl", true); SSL_CTX_free = (void (*)(SSL_CTX *))openssl_sym(&err, "SSL_CTX_free", true); SSL_CTX_new = (SSL_CTX *(*)(const SSL_METHOD *))openssl_sym(&err, "SSL_CTX_new", true); diff --git a/vendor/libgit2/src/streams/openssl_dynamic.h b/vendor/libgit2/src/libgit2/streams/openssl_dynamic.h similarity index 100% rename from vendor/libgit2/src/streams/openssl_dynamic.h rename to vendor/libgit2/src/libgit2/streams/openssl_dynamic.h diff --git a/vendor/libgit2/src/streams/openssl_legacy.c b/vendor/libgit2/src/libgit2/streams/openssl_legacy.c similarity index 100% rename from vendor/libgit2/src/streams/openssl_legacy.c rename to vendor/libgit2/src/libgit2/streams/openssl_legacy.c diff --git a/vendor/libgit2/src/streams/openssl_legacy.h b/vendor/libgit2/src/libgit2/streams/openssl_legacy.h similarity index 100% rename from vendor/libgit2/src/streams/openssl_legacy.h rename to vendor/libgit2/src/libgit2/streams/openssl_legacy.h diff --git a/vendor/libgit2/src/streams/registry.c b/vendor/libgit2/src/libgit2/streams/registry.c similarity index 100% rename from vendor/libgit2/src/streams/registry.c rename to vendor/libgit2/src/libgit2/streams/registry.c diff --git a/vendor/libgit2/src/streams/registry.h b/vendor/libgit2/src/libgit2/streams/registry.h similarity index 100% rename from vendor/libgit2/src/streams/registry.h rename to vendor/libgit2/src/libgit2/streams/registry.h diff --git a/vendor/libgit2/src/libgit2/streams/schannel.c b/vendor/libgit2/src/libgit2/streams/schannel.c new file mode 100644 index 00000000..f0961581 --- /dev/null +++ b/vendor/libgit2/src/libgit2/streams/schannel.c @@ -0,0 +1,715 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "streams/schannel.h" + +#ifdef GIT_SCHANNEL + +#define SECURITY_WIN32 + +#include +#include +#include + +#include "stream.h" +#include "streams/socket.h" + +#ifndef SP_PROT_TLS1_2_CLIENT +# define SP_PROT_TLS1_2_CLIENT 2048 +#endif + +#ifndef SP_PROT_TLS1_3_CLIENT +# define SP_PROT_TLS1_3_CLIENT 8192 +#endif + +#ifndef SECBUFFER_ALERT +# define SECBUFFER_ALERT 17 +#endif + +#define READ_BLOCKSIZE (16 * 1024) + +typedef enum { + STATE_NONE = 0, + STATE_CRED = 1, + STATE_CONTEXT = 2, + STATE_CERTIFICATE = 3 +} schannel_state; + +typedef struct { + git_stream parent; + git_stream *io; + int owned; + bool connected; + wchar_t *host_w; + + schannel_state state; + + CredHandle cred; + CtxtHandle context; + SecPkgContext_StreamSizes stream_sizes; + + CERT_CONTEXT *certificate; + const CERT_CHAIN_CONTEXT *cert_chain; + git_cert_x509 x509; + + git_str plaintext_in; + git_str ciphertext_in; +} schannel_stream; + +static int connect_context(schannel_stream *st) +{ + SCHANNEL_CRED cred = { 0 }; + SECURITY_STATUS status = SEC_E_INTERNAL_ERROR; + DWORD context_flags; + static size_t MAX_RETRIES = 1024; + size_t retries; + ssize_t read_len; + int error = 0; + + if (st->owned && (error = git_stream_connect(st->io)) < 0) + return error; + + cred.dwVersion = SCHANNEL_CRED_VERSION; + cred.dwFlags = SCH_CRED_IGNORE_NO_REVOCATION_CHECK | + SCH_CRED_IGNORE_REVOCATION_OFFLINE | + SCH_CRED_MANUAL_CRED_VALIDATION | + SCH_CRED_NO_DEFAULT_CREDS | + SCH_CRED_NO_SERVERNAME_CHECK; + cred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | + SP_PROT_TLS1_3_CLIENT; + + if (AcquireCredentialsHandleW(NULL, SCHANNEL_NAME_W, + SECPKG_CRED_OUTBOUND, NULL, &cred, NULL, + NULL, &st->cred, NULL) != SEC_E_OK) { + git_error_set(GIT_ERROR_OS, "could not acquire credentials handle"); + return -1; + } + + st->state = STATE_CRED; + + context_flags = ISC_REQ_ALLOCATE_MEMORY | + ISC_REQ_CONFIDENTIALITY | + ISC_REQ_REPLAY_DETECT | + ISC_REQ_SEQUENCE_DETECT | + ISC_REQ_STREAM; + + for (retries = 0; retries < MAX_RETRIES; retries++) { + SecBuffer input_buf[] = { + { (unsigned long)st->ciphertext_in.size, + SECBUFFER_TOKEN, + st->ciphertext_in.size ? st->ciphertext_in.ptr : NULL }, + { 0, SECBUFFER_EMPTY, NULL } + }; + SecBuffer output_buf[] = { { 0, SECBUFFER_TOKEN, NULL }, + { 0, SECBUFFER_ALERT, NULL } }; + + SecBufferDesc input_buf_desc = { SECBUFFER_VERSION, 2, input_buf }; + SecBufferDesc output_buf_desc = { SECBUFFER_VERSION, 2, output_buf }; + + status = InitializeSecurityContextW(&st->cred, + retries ? &st->context : NULL, st->host_w, + context_flags, 0, 0, retries ? &input_buf_desc : NULL, 0, + retries ? NULL : &st->context, &output_buf_desc, + &context_flags, NULL); + + if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED) { + st->state = STATE_CONTEXT; + + if (output_buf[0].cbBuffer > 0) { + error = git_stream__write_full(st->io, + output_buf[0].pvBuffer, + output_buf[0].cbBuffer, 0); + + FreeContextBuffer(output_buf[0].pvBuffer); + } + + /* handle any leftover, unprocessed data */ + if (input_buf[1].BufferType == SECBUFFER_EXTRA) { + GIT_ASSERT(st->ciphertext_in.size > input_buf[1].cbBuffer); + + git_str_consume_bytes(&st->ciphertext_in, + st->ciphertext_in.size - input_buf[1].cbBuffer); + } else { + git_str_clear(&st->ciphertext_in); + } + + if (error < 0 || status == SEC_E_OK) + break; + } else if (status == SEC_E_INCOMPLETE_MESSAGE) { + /* we need additional data from the client; */ + if (git_str_grow_by(&st->ciphertext_in, READ_BLOCKSIZE) < 0) { + error = -1; + break; + } + + if ((read_len = git_stream_read(st->io, + st->ciphertext_in.ptr + st->ciphertext_in.size, + (st->ciphertext_in.asize - st->ciphertext_in.size))) < 0) { + error = -1; + break; + } + + GIT_ASSERT((size_t)read_len <= + st->ciphertext_in.asize - st->ciphertext_in.size); + st->ciphertext_in.size += read_len; + } else { + git_error_set(GIT_ERROR_OS, + "could not initialize security context"); + error = -1; + break; + } + + GIT_ASSERT(st->ciphertext_in.size < ULONG_MAX); + } + + if (retries == MAX_RETRIES) { + git_error_set(GIT_ERROR_SSL, + "could not initialize security context: too many retries"); + error = -1; + } + + if (!error) { + if (QueryContextAttributesW(&st->context, + SECPKG_ATTR_STREAM_SIZES, + &st->stream_sizes) != SEC_E_OK) { + git_error_set(GIT_ERROR_SSL, + "could not query stream sizes"); + error = -1; + } + } + + return error; +} + +static int set_certificate_lookup_error(DWORD status) +{ + switch (status) { + case CERT_TRUST_IS_NOT_TIME_VALID: + git_error_set(GIT_ERROR_SSL, + "certificate is expired or not yet valid"); + break; + case CERT_TRUST_IS_REVOKED: + git_error_set(GIT_ERROR_SSL, "certificate is revoked"); + break; + case CERT_TRUST_IS_NOT_SIGNATURE_VALID: + case CERT_TRUST_IS_NOT_VALID_FOR_USAGE: + case CERT_TRUST_INVALID_EXTENSION: + case CERT_TRUST_INVALID_POLICY_CONSTRAINTS: + case CERT_TRUST_INVALID_BASIC_CONSTRAINTS: + case CERT_TRUST_INVALID_NAME_CONSTRAINTS: + case CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT: + case CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT: + case CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT: + case CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT: + case CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY: + case CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT: + git_error_set(GIT_ERROR_SSL, "certificate is not valid"); + break; + case CERT_TRUST_IS_UNTRUSTED_ROOT: + case CERT_TRUST_IS_CYCLIC: + case CERT_TRUST_IS_EXPLICIT_DISTRUST: + git_error_set(GIT_ERROR_SSL, "certificate is not trusted"); + break; + case CERT_TRUST_REVOCATION_STATUS_UNKNOWN: + git_error_set(GIT_ERROR_SSL, + "certificate revocation status could not be verified"); + break; + case CERT_TRUST_IS_OFFLINE_REVOCATION: + git_error_set(GIT_ERROR_SSL, + "certificate revocation is offline or stale"); + break; + case CERT_TRUST_HAS_WEAK_SIGNATURE: + git_error_set(GIT_ERROR_SSL, "certificate has a weak signature"); + break; + default: + git_error_set(GIT_ERROR_SSL, + "unknown certificate lookup failure: %d", status); + return -1; + } + + return GIT_ECERTIFICATE; +} + +static int set_certificate_validation_error(DWORD status) +{ + switch (status) { + case TRUST_E_CERT_SIGNATURE: + git_error_set(GIT_ERROR_SSL, + "the certificate cannot be verified"); + break; + case CRYPT_E_REVOKED: + git_error_set(GIT_ERROR_SSL, + "the certificate or signature has been revoked"); + break; + case CERT_E_UNTRUSTEDROOT: + git_error_set(GIT_ERROR_SSL, + "the certificate root is not trusted"); + break; + case CERT_E_UNTRUSTEDTESTROOT: + git_error_set(GIT_ERROR_SSL, + "the certificate root is a test certificate"); + break; + case CERT_E_CHAINING: + git_error_set(GIT_ERROR_SSL, + "the certificate chain is invalid"); + break; + case CERT_E_WRONG_USAGE: + case CERT_E_PURPOSE: + git_error_set(GIT_ERROR_SSL, + "the certificate is not valid for this usage"); + break; + case CERT_E_EXPIRED: + git_error_set(GIT_ERROR_SSL, + "certificate is expired or not yet valid"); + break; + case CERT_E_INVALID_NAME: + case CERT_E_CN_NO_MATCH: + git_error_set(GIT_ERROR_SSL, + "certificate is not valid for this hostname"); + break; + case CERT_E_INVALID_POLICY: + case TRUST_E_BASIC_CONSTRAINTS: + case CERT_E_CRITICAL: + case CERT_E_VALIDITYPERIODNESTING: + git_error_set(GIT_ERROR_SSL, "certificate is not valid"); + break; + case CRYPT_E_NO_REVOCATION_CHECK: + git_error_set(GIT_ERROR_SSL, + "certificate revocation status could not be verified"); + break; + case CRYPT_E_REVOCATION_OFFLINE: + git_error_set(GIT_ERROR_SSL, + "certificate revocation is offline or stale"); + break; + case CERT_E_ROLE: + git_error_set(GIT_ERROR_SSL, "certificate authority is not valid"); + break; + default: + git_error_set(GIT_ERROR_SSL, + "unknown certificate policy checking failure: %d", + status); + return -1; + } + + return GIT_ECERTIFICATE; +} + +static int check_certificate(schannel_stream* st) +{ + CERT_CHAIN_PARA cert_chain_parameters; + SSL_EXTRA_CERT_CHAIN_POLICY_PARA ssl_policy_parameters; + CERT_CHAIN_POLICY_PARA cert_policy_parameters = + { sizeof(CERT_CHAIN_POLICY_PARA), 0, &ssl_policy_parameters }; + CERT_CHAIN_POLICY_STATUS cert_policy_status; + + memset(&cert_chain_parameters, 0, sizeof(CERT_CHAIN_PARA)); + cert_chain_parameters.cbSize = sizeof(CERT_CHAIN_PARA); + + if (QueryContextAttributesW(&st->context, + SECPKG_ATTR_REMOTE_CERT_CONTEXT, + &st->certificate) != SEC_E_OK) { + git_error_set(GIT_ERROR_OS, + "could not query remote certificate context"); + return -1; + } + + /* TODO: do we really want to do revokcation checking ? */ + if (!CertGetCertificateChain(NULL, st->certificate, NULL, + st->certificate->hCertStore, &cert_chain_parameters, + CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, + NULL, &st->cert_chain)) { + git_error_set(GIT_ERROR_OS, "could not query remote certificate chain"); + CertFreeCertificateContext(st->certificate); + return -1; + } + + st->state = STATE_CERTIFICATE; + + /* Set up the x509 certificate data for future callbacks */ + + st->x509.parent.cert_type = GIT_CERT_X509; + st->x509.data = st->certificate->pbCertEncoded; + st->x509.len = st->certificate->cbCertEncoded; + + /* Handle initial certificate validation */ + + if (st->cert_chain->TrustStatus.dwErrorStatus != CERT_TRUST_NO_ERROR) + return set_certificate_lookup_error(st->cert_chain->TrustStatus.dwErrorStatus); + + ssl_policy_parameters.cbSize = sizeof(SSL_EXTRA_CERT_CHAIN_POLICY_PARA); + ssl_policy_parameters.dwAuthType = AUTHTYPE_SERVER; + ssl_policy_parameters.pwszServerName = st->host_w; + + if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, + st->cert_chain, &cert_policy_parameters, + &cert_policy_status)) { + git_error_set(GIT_ERROR_OS, "could not verify certificate chain policy"); + return -1; + } + + if (cert_policy_status.dwError != SEC_E_OK) + return set_certificate_validation_error(cert_policy_status.dwError); + + return 0; +} + +static int schannel_connect(git_stream *stream) +{ + schannel_stream *st = (schannel_stream *)stream; + int error; + + GIT_ASSERT(st->state == STATE_NONE); + + if ((error = connect_context(st)) < 0 || + (error = check_certificate(st)) < 0) + return error; + + st->connected = 1; + return 0; +} + +static int schannel_certificate(git_cert **out, git_stream *stream) +{ + schannel_stream *st = (schannel_stream *)stream; + + *out = &st->x509.parent; + return 0; +} + +static int schannel_set_proxy( + git_stream *stream, + const git_proxy_options *proxy_options) +{ + schannel_stream *st = (schannel_stream *)stream; + return git_stream_set_proxy(st->io, proxy_options); +} + +static ssize_t schannel_write( + git_stream *stream, + const char *data, + size_t data_len, + int flags) +{ + schannel_stream *st = (schannel_stream *)stream; + SecBuffer encrypt_buf[3]; + SecBufferDesc encrypt_buf_desc = { SECBUFFER_VERSION, 3, encrypt_buf }; + git_str ciphertext_out = GIT_STR_INIT; + ssize_t total_len = 0; + + GIT_UNUSED(flags); + + if (data_len > SSIZE_MAX) + data_len = SSIZE_MAX; + + git_str_init(&ciphertext_out, + st->stream_sizes.cbHeader + + st->stream_sizes.cbMaximumMessage + + st->stream_sizes.cbTrailer); + + while (data_len > 0) { + size_t message_len = min(data_len, st->stream_sizes.cbMaximumMessage); + size_t ciphertext_len, ciphertext_written = 0; + + encrypt_buf[0].BufferType = SECBUFFER_STREAM_HEADER; + encrypt_buf[0].cbBuffer = st->stream_sizes.cbHeader; + encrypt_buf[0].pvBuffer = ciphertext_out.ptr; + + encrypt_buf[1].BufferType = SECBUFFER_DATA; + encrypt_buf[1].cbBuffer = (unsigned long)message_len; + encrypt_buf[1].pvBuffer = + ciphertext_out.ptr + st->stream_sizes.cbHeader; + + encrypt_buf[2].BufferType = SECBUFFER_STREAM_TRAILER; + encrypt_buf[2].cbBuffer = st->stream_sizes.cbTrailer; + encrypt_buf[2].pvBuffer = + ciphertext_out.ptr + st->stream_sizes.cbHeader + + message_len; + + memcpy(ciphertext_out.ptr + st->stream_sizes.cbHeader, data, message_len); + + if (EncryptMessage(&st->context, 0, &encrypt_buf_desc, 0) != SEC_E_OK) { + git_error_set(GIT_ERROR_OS, "could not encrypt tls message"); + total_len = -1; + goto done; + } + + ciphertext_len = encrypt_buf[0].cbBuffer + + encrypt_buf[1].cbBuffer + + encrypt_buf[2].cbBuffer; + + while (ciphertext_written < ciphertext_len) { + ssize_t chunk_len = git_stream_write(st->io, + ciphertext_out.ptr + ciphertext_written, + ciphertext_len - ciphertext_written, 0); + + if (chunk_len < 0) { + total_len = -1; + goto done; + } + + ciphertext_len -= chunk_len; + ciphertext_written += chunk_len; + } + + total_len += message_len; + + data += message_len; + data_len -= message_len; + } + +done: + git_str_dispose(&ciphertext_out); + return total_len; +} + +static ssize_t schannel_read(git_stream *stream, void *_data, size_t data_len) +{ + schannel_stream *st = (schannel_stream *)stream; + char *data = (char *)_data; + SecBuffer decrypt_buf[4]; + SecBufferDesc decrypt_buf_desc = { SECBUFFER_VERSION, 4, decrypt_buf }; + SECURITY_STATUS status; + ssize_t chunk_len, total_len = 0; + + if (data_len > SSIZE_MAX) + data_len = SSIZE_MAX; + + /* + * Loop until we have some bytes to return - we may have decrypted + * bytes queued or ciphertext from the wire that we can decrypt and + * return. Return any queued bytes if they're available to avoid a + * network read, which may block. We may return less than the + * caller requested, and they can retry for an actual network + */ + while ((size_t)total_len < data_len) { + if (st->plaintext_in.size > 0) { + size_t copy_len = min(st->plaintext_in.size, data_len); + + memcpy(data, st->plaintext_in.ptr, copy_len); + git_str_consume_bytes(&st->plaintext_in, copy_len); + + data += copy_len; + data_len -= copy_len; + + total_len += copy_len; + + continue; + } + + if (st->ciphertext_in.size > 0) { + decrypt_buf[0].BufferType = SECBUFFER_DATA; + decrypt_buf[0].cbBuffer = (unsigned long)min(st->ciphertext_in.size, ULONG_MAX); + decrypt_buf[0].pvBuffer = st->ciphertext_in.ptr; + + decrypt_buf[1].BufferType = SECBUFFER_EMPTY; + decrypt_buf[1].cbBuffer = 0; + decrypt_buf[1].pvBuffer = NULL; + + decrypt_buf[2].BufferType = SECBUFFER_EMPTY; + decrypt_buf[2].cbBuffer = 0; + decrypt_buf[2].pvBuffer = NULL; + + decrypt_buf[3].BufferType = SECBUFFER_EMPTY; + decrypt_buf[3].cbBuffer = 0; + decrypt_buf[3].pvBuffer = NULL; + + status = DecryptMessage(&st->context, &decrypt_buf_desc, 0, NULL); + + if (status == SEC_E_OK) { + GIT_ASSERT(decrypt_buf[0].BufferType == SECBUFFER_STREAM_HEADER); + GIT_ASSERT(decrypt_buf[1].BufferType == SECBUFFER_DATA); + GIT_ASSERT(decrypt_buf[2].BufferType == SECBUFFER_STREAM_TRAILER); + + if (git_str_put(&st->plaintext_in, decrypt_buf[1].pvBuffer, decrypt_buf[1].cbBuffer) < 0) { + total_len = -1; + goto done; + } + + if (decrypt_buf[3].BufferType == SECBUFFER_EXTRA) { + git_str_consume_bytes(&st->ciphertext_in, (st->ciphertext_in.size - decrypt_buf[3].cbBuffer)); + } else { + git_str_clear(&st->ciphertext_in); + } + + continue; + } else if (status == SEC_E_CONTEXT_EXPIRED) { + break; + } else if (status != SEC_E_INCOMPLETE_MESSAGE) { + git_error_set(GIT_ERROR_SSL, "could not decrypt tls message"); + total_len = -1; + goto done; + } + } + + if (total_len != 0) + break; + + if (git_str_grow_by(&st->ciphertext_in, READ_BLOCKSIZE) < 0) { + total_len = -1; + goto done; + } + + if ((chunk_len = git_stream_read(st->io, st->ciphertext_in.ptr + st->ciphertext_in.size, st->ciphertext_in.asize - st->ciphertext_in.size)) < 0) { + total_len = -1; + goto done; + } + + st->ciphertext_in.size += chunk_len; + } + +done: + return total_len; +} + +static int schannel_close(git_stream *stream) +{ + schannel_stream *st = (schannel_stream *)stream; + int error = 0; + + if (st->connected) { + SecBuffer shutdown_buf; + SecBufferDesc shutdown_buf_desc = + { SECBUFFER_VERSION, 1, &shutdown_buf }; + DWORD shutdown_message = SCHANNEL_SHUTDOWN, shutdown_flags; + + shutdown_buf.BufferType = SECBUFFER_TOKEN; + shutdown_buf.cbBuffer = sizeof(DWORD); + shutdown_buf.pvBuffer = &shutdown_message; + + if (ApplyControlToken(&st->context, &shutdown_buf_desc) != SEC_E_OK) { + git_error_set(GIT_ERROR_SSL, "could not shutdown stream"); + error = -1; + } + + shutdown_buf.BufferType = SECBUFFER_TOKEN; + shutdown_buf.cbBuffer = 0; + shutdown_buf.pvBuffer = NULL; + + shutdown_flags = ISC_REQ_ALLOCATE_MEMORY | + ISC_REQ_CONFIDENTIALITY | + ISC_REQ_REPLAY_DETECT | + ISC_REQ_SEQUENCE_DETECT | + ISC_REQ_STREAM; + + if (InitializeSecurityContext(&st->cred, &st->context, + NULL, shutdown_flags, 0, 0, + &shutdown_buf_desc, 0, NULL, + &shutdown_buf_desc, &shutdown_flags, + NULL) == SEC_E_OK) { + if (shutdown_buf.cbBuffer > 0) { + if (git_stream__write_full(st->io, + shutdown_buf.pvBuffer, + shutdown_buf.cbBuffer, 0) < 0) + error = -1; + + FreeContextBuffer(shutdown_buf.pvBuffer); + } + } + } + + st->connected = false; + + if (st->owned && git_stream_close(st->io) < 0) + error = -1; + + return error; +} + +static void schannel_free(git_stream *stream) +{ + schannel_stream *st = (schannel_stream *)stream; + + if (st->state >= STATE_CERTIFICATE) { + CertFreeCertificateContext(st->certificate); + CertFreeCertificateChain(st->cert_chain); + } + + if (st->state >= STATE_CONTEXT) + DeleteSecurityContext(&st->context); + + if (st->state >= STATE_CRED) + FreeCredentialsHandle(&st->cred); + + st->state = STATE_NONE; + + git_str_dispose(&st->ciphertext_in); + git_str_dispose(&st->plaintext_in); + + git__free(st->host_w); + + if (st->owned) + git_stream_free(st->io); + + git__free(st); +} + +static int schannel_stream_wrap( + git_stream **out, + git_stream *in, + const char *host, + int owned) +{ + schannel_stream *st; + + st = git__calloc(1, sizeof(schannel_stream)); + GIT_ERROR_CHECK_ALLOC(st); + + st->io = in; + st->owned = owned; + + if (git_utf8_to_16_alloc(&st->host_w, host) < 0) { + git__free(st); + return -1; + } + + st->parent.version = GIT_STREAM_VERSION; + st->parent.encrypted = 1; + st->parent.proxy_support = git_stream_supports_proxy(st->io); + st->parent.connect = schannel_connect; + st->parent.certificate = schannel_certificate; + st->parent.set_proxy = schannel_set_proxy; + st->parent.read = schannel_read; + st->parent.write = schannel_write; + st->parent.close = schannel_close; + st->parent.free = schannel_free; + + *out = (git_stream *)st; + return 0; +} + +extern int git_schannel_stream_new( + git_stream **out, + const char *host, + const char *port) +{ + git_stream *stream; + int error; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(host); + GIT_ASSERT_ARG(port); + + if ((error = git_socket_stream_new(&stream, host, port)) < 0) + return error; + + if ((error = schannel_stream_wrap(out, stream, host, 1)) < 0) { + git_stream_close(stream); + git_stream_free(stream); + } + + return error; +} + +extern int git_schannel_stream_wrap( + git_stream **out, + git_stream *in, + const char *host) +{ + return schannel_stream_wrap(out, in, host, 0); +} + +#endif diff --git a/vendor/libgit2/src/libgit2/streams/schannel.h b/vendor/libgit2/src/libgit2/streams/schannel.h new file mode 100644 index 00000000..3584970d --- /dev/null +++ b/vendor/libgit2/src/libgit2/streams/schannel.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_steams_schannel_h__ +#define INCLUDE_steams_schannel_h__ + +#include "common.h" + +#include "git2/sys/stream.h" + +#ifdef GIT_SCHANNEL + +extern int git_schannel_stream_new( + git_stream **out, + const char *host, + const char *port); + +extern int git_schannel_stream_wrap( + git_stream **out, + git_stream *in, + const char *host); + +#endif + +#endif diff --git a/vendor/libgit2/src/libgit2/streams/socket.c b/vendor/libgit2/src/libgit2/streams/socket.c new file mode 100644 index 00000000..a463312f --- /dev/null +++ b/vendor/libgit2/src/libgit2/streams/socket.c @@ -0,0 +1,428 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "streams/socket.h" + +#include "posix.h" +#include "registry.h" +#include "runtime.h" +#include "stream.h" + +#ifndef _WIN32 +# include +# include +# include +# include +# include +# include +# include +#else +# include +# include +# ifdef _MSC_VER +# pragma comment(lib, "ws2_32") +# endif +#endif + +int git_socket_stream__connect_timeout = 0; +int git_socket_stream__timeout = 0; + +#ifdef GIT_WIN32 +static void net_set_error(const char *str) +{ + int error = WSAGetLastError(); + char * win32_error = git_win32_get_error_message(error); + + if (win32_error) { + git_error_set(GIT_ERROR_NET, "%s: %s", str, win32_error); + git__free(win32_error); + } else { + git_error_set(GIT_ERROR_NET, "%s", str); + } +} +#else +static void net_set_error(const char *str) +{ + git_error_set(GIT_ERROR_NET, "%s: %s", str, strerror(errno)); +} +#endif + +static int close_socket(GIT_SOCKET s) +{ + if (s == INVALID_SOCKET) + return 0; + +#ifdef GIT_WIN32 + if (closesocket(s) != 0) { + net_set_error("could not close socket"); + return -1; + } + + return 0; +#else + return close(s); +#endif + +} + +static int set_nonblocking(GIT_SOCKET s) +{ +#ifdef GIT_WIN32 + unsigned long nonblocking = 1; + + if (ioctlsocket(s, FIONBIO, &nonblocking) != 0) { + net_set_error("could not set socket non-blocking"); + return -1; + } +#else + int flags; + + if ((flags = fcntl(s, F_GETFL, 0)) == -1) { + net_set_error("could not query socket flags"); + return -1; + } + + flags |= O_NONBLOCK; + + if (fcntl(s, F_SETFL, flags) != 0) { + net_set_error("could not set socket non-blocking"); + return -1; + } +#endif + + return 0; +} + +/* Promote a sockerr to an errno for our error handling routines */ +static int handle_sockerr(GIT_SOCKET socket) +{ + int sockerr; + socklen_t errlen = sizeof(sockerr); + + if (getsockopt(socket, SOL_SOCKET, SO_ERROR, + (void *)&sockerr, &errlen) < 0) + return -1; + + if (sockerr == ETIMEDOUT) + return GIT_TIMEOUT; + + errno = sockerr; + return -1; +} + +GIT_INLINE(bool) connect_would_block(int error) +{ +#ifdef GIT_WIN32 + if (error == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK) + return true; +#endif + + if (error == -1 && errno == EINPROGRESS) + return true; + + return false; +} + +static int connect_with_timeout( + GIT_SOCKET socket, + const struct sockaddr *address, + socklen_t address_len, + int timeout) +{ + struct pollfd fd; + int error; + + if (timeout && (error = set_nonblocking(socket)) < 0) + return error; + + error = connect(socket, address, address_len); + + if (error == 0 || !connect_would_block(error)) + return error; + + fd.fd = socket; + fd.events = POLLOUT; + fd.revents = 0; + + error = p_poll(&fd, 1, timeout); + + if (error == 0) { + return GIT_TIMEOUT; + } else if (error != 1) { + return -1; + } else if ((fd.revents & (POLLPRI | POLLHUP | POLLERR))) { + return handle_sockerr(socket); + } else if ((fd.revents & POLLOUT) != POLLOUT) { + git_error_set(GIT_ERROR_NET, + "unknown error while polling for connect: %d", + fd.revents); + return -1; + } + + return 0; +} + +static int socket_connect(git_stream *stream) +{ + git_socket_stream *st = (git_socket_stream *) stream; + GIT_SOCKET s = INVALID_SOCKET; + struct addrinfo *info = NULL, *p; + struct addrinfo hints; + int error; + + memset(&hints, 0x0, sizeof(struct addrinfo)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_UNSPEC; + + if ((error = p_getaddrinfo(st->host, st->port, &hints, &info)) != 0) { + git_error_set(GIT_ERROR_NET, + "failed to resolve address for %s: %s", + st->host, p_gai_strerror(error)); + return -1; + } + + for (p = info; p != NULL; p = p->ai_next) { + s = socket(p->ai_family, p->ai_socktype | SOCK_CLOEXEC, p->ai_protocol); + + if (s == INVALID_SOCKET) + continue; + + error = connect_with_timeout(s, p->ai_addr, + (socklen_t)p->ai_addrlen, + st->parent.connect_timeout); + + if (error == 0) + break; + + /* If we can't connect, try the next one */ + close_socket(s); + s = INVALID_SOCKET; + + if (error == GIT_TIMEOUT) + break; + } + + /* Oops, we couldn't connect to any address */ + if (s == INVALID_SOCKET) { + if (error == GIT_TIMEOUT) + git_error_set(GIT_ERROR_NET, "failed to connect to %s: Operation timed out", st->host); + else + git_error_set(GIT_ERROR_OS, "failed to connect to %s", st->host); + error = -1; + goto done; + } + + if (st->parent.timeout && !st->parent.connect_timeout && + (error = set_nonblocking(s)) < 0) + return error; + + st->s = s; + error = 0; + +done: + p_freeaddrinfo(info); + return error; +} + +static ssize_t socket_write( + git_stream *stream, + const char *data, + size_t len, + int flags) +{ + git_socket_stream *st = (git_socket_stream *) stream; + struct pollfd fd; + ssize_t ret; + + GIT_ASSERT(flags == 0); + GIT_UNUSED(flags); + + ret = p_send(st->s, data, len, 0); + + if (st->parent.timeout && ret < 0 && + (errno == EAGAIN || errno != EWOULDBLOCK)) { + fd.fd = st->s; + fd.events = POLLOUT; + fd.revents = 0; + + ret = p_poll(&fd, 1, st->parent.timeout); + + if (ret == 1) { + ret = p_send(st->s, data, len, 0); + } else if (ret == 0) { + git_error_set(GIT_ERROR_NET, + "could not write to socket: timed out"); + return GIT_TIMEOUT; + } + } + + if (ret < 0) { + net_set_error("error receiving data from socket"); + return -1; + } + + return ret; +} + +static ssize_t socket_read( + git_stream *stream, + void *data, + size_t len) +{ + git_socket_stream *st = (git_socket_stream *) stream; + struct pollfd fd; + ssize_t ret; + + ret = p_recv(st->s, data, len, 0); + + if (st->parent.timeout && ret < 0 && + (errno == EAGAIN || errno != EWOULDBLOCK)) { + fd.fd = st->s; + fd.events = POLLIN; + fd.revents = 0; + + ret = p_poll(&fd, 1, st->parent.timeout); + + if (ret == 1) { + ret = p_recv(st->s, data, len, 0); + } else if (ret == 0) { + git_error_set(GIT_ERROR_NET, + "could not read from socket: timed out"); + return GIT_TIMEOUT; + } + } + + if (ret < 0) { + net_set_error("error receiving data from socket"); + return -1; + } + + return ret; +} + +static int socket_close(git_stream *stream) +{ + git_socket_stream *st = (git_socket_stream *) stream; + int error; + + error = close_socket(st->s); + st->s = INVALID_SOCKET; + + return error; +} + +static void socket_free(git_stream *stream) +{ + git_socket_stream *st = (git_socket_stream *) stream; + + git__free(st->host); + git__free(st->port); + git__free(st); +} + +static int default_socket_stream_new( + git_stream **out, + const char *host, + const char *port) +{ + git_socket_stream *st; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(host); + GIT_ASSERT_ARG(port); + + st = git__calloc(1, sizeof(git_socket_stream)); + GIT_ERROR_CHECK_ALLOC(st); + + st->host = git__strdup(host); + GIT_ERROR_CHECK_ALLOC(st->host); + + if (port) { + st->port = git__strdup(port); + GIT_ERROR_CHECK_ALLOC(st->port); + } + + st->parent.version = GIT_STREAM_VERSION; + st->parent.timeout = git_socket_stream__timeout; + st->parent.connect_timeout = git_socket_stream__connect_timeout; + st->parent.connect = socket_connect; + st->parent.write = socket_write; + st->parent.read = socket_read; + st->parent.close = socket_close; + st->parent.free = socket_free; + st->s = INVALID_SOCKET; + + *out = (git_stream *) st; + return 0; +} + +int git_socket_stream_new( + git_stream **out, + const char *host, + const char *port) +{ + int (*init)(git_stream **, const char *, const char *) = NULL; + git_stream_registration custom = {0}; + int error; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(host); + GIT_ASSERT_ARG(port); + + if ((error = git_stream_registry_lookup(&custom, GIT_STREAM_STANDARD)) == 0) + init = custom.init; + else if (error == GIT_ENOTFOUND) + init = default_socket_stream_new; + else + return error; + + if (!init) { + git_error_set(GIT_ERROR_NET, "there is no socket stream available"); + return -1; + } + + return init(out, host, port); +} + +#ifdef GIT_WIN32 + +static void socket_stream_global_shutdown(void) +{ + WSACleanup(); +} + +int git_socket_stream_global_init(void) +{ + WORD winsock_version; + WSADATA wsa_data; + + winsock_version = MAKEWORD(2, 2); + + if (WSAStartup(winsock_version, &wsa_data) != 0) { + git_error_set(GIT_ERROR_OS, "could not initialize Windows Socket Library"); + return -1; + } + + if (LOBYTE(wsa_data.wVersion) != 2 || + HIBYTE(wsa_data.wVersion) != 2) { + git_error_set(GIT_ERROR_SSL, "Windows Socket Library does not support Winsock 2.2"); + return -1; + } + + return git_runtime_shutdown_register(socket_stream_global_shutdown); +} + +#else + +#include "stream.h" + +int git_socket_stream_global_init(void) +{ + return 0; +} + + #endif diff --git a/vendor/libgit2/src/streams/socket.h b/vendor/libgit2/src/libgit2/streams/socket.h similarity index 87% rename from vendor/libgit2/src/streams/socket.h rename to vendor/libgit2/src/libgit2/streams/socket.h index 3235f316..73e8de09 100644 --- a/vendor/libgit2/src/streams/socket.h +++ b/vendor/libgit2/src/libgit2/streams/socket.h @@ -9,7 +9,7 @@ #include "common.h" -#include "netops.h" +#include "stream.h" typedef struct { git_stream parent; @@ -20,4 +20,6 @@ typedef struct { extern int git_socket_stream_new(git_stream **out, const char *host, const char *port); +extern int git_socket_stream_global_init(void); + #endif diff --git a/vendor/libgit2/src/streams/stransport.c b/vendor/libgit2/src/libgit2/streams/stransport.c similarity index 88% rename from vendor/libgit2/src/streams/stransport.c rename to vendor/libgit2/src/libgit2/streams/stransport.c index 3f31d254..7a3585e2 100644 --- a/vendor/libgit2/src/streams/stransport.c +++ b/vendor/libgit2/src/libgit2/streams/stransport.c @@ -44,6 +44,7 @@ typedef struct { git_stream parent; git_stream *io; int owned; + int error; SSLContextRef ctx; CFDataRef der_data; git_cert_x509 cert_info; @@ -61,7 +62,10 @@ static int stransport_connect(git_stream *stream) return error; ret = SSLHandshake(st->ctx); - if (ret != errSSLServerAuthCompleted) { + + if (ret != errSSLServerAuthCompleted && st->error != 0) + return -1; + else if (ret != errSSLServerAuthCompleted) { git_error_set(GIT_ERROR_SSL, "unexpected return value from ssl handshake %d", (int)ret); return -1; } @@ -147,10 +151,20 @@ static int stransport_set_proxy( */ static OSStatus write_cb(SSLConnectionRef conn, const void *data, size_t *len) { - git_stream *io = (git_stream *) conn; + stransport_stream *st = (stransport_stream *)conn; + git_stream *io = st->io; + OSStatus ret; - if (git_stream__write_full(io, data, *len, 0) < 0) - return -36; /* "ioErr" from MacErrors.h which is not available on iOS */ + st->error = 0; + + ret = git_stream__write_full(io, data, *len, 0); + + if (ret < 0) { + st->error = ret; + return (ret == GIT_TIMEOUT) ? + -9853 /* errSSLNetworkTimeout */: + -36 /* ioErr */; + } return noErr; } @@ -164,8 +178,12 @@ static ssize_t stransport_write(git_stream *stream, const char *data, size_t len GIT_UNUSED(flags); data_len = min(len, SSIZE_MAX); - if ((ret = SSLWrite(st->ctx, data, data_len, &processed)) != noErr) + if ((ret = SSLWrite(st->ctx, data, data_len, &processed)) != noErr) { + if (st->error == GIT_TIMEOUT) + return GIT_TIMEOUT; + return stransport_error(ret); + } GIT_ASSERT(processed < SSIZE_MAX); return (ssize_t)processed; @@ -182,18 +200,24 @@ static ssize_t stransport_write(git_stream *stream, const char *data, size_t len */ static OSStatus read_cb(SSLConnectionRef conn, void *data, size_t *len) { - git_stream *io = (git_stream *) conn; + stransport_stream *st = (stransport_stream *)conn; + git_stream *io = st->io; OSStatus error = noErr; size_t off = 0; ssize_t ret; + st->error = 0; + do { ret = git_stream_read(io, data + off, *len - off); + if (ret < 0) { - error = -36; /* "ioErr" from MacErrors.h which is not available on iOS */ + st->error = ret; + error = (ret == GIT_TIMEOUT) ? + -9853 /* errSSLNetworkTimeout */: + -36 /* ioErr */; break; - } - if (ret == 0) { + } else if (ret == 0) { error = errSSLClosedGraceful; break; } @@ -207,12 +231,16 @@ static OSStatus read_cb(SSLConnectionRef conn, void *data, size_t *len) static ssize_t stransport_read(git_stream *stream, void *data, size_t len) { - stransport_stream *st = (stransport_stream *) stream; + stransport_stream *st = (stransport_stream *)stream; size_t processed; OSStatus ret; - if ((ret = SSLRead(st->ctx, data, len, &processed)) != noErr) + if ((ret = SSLRead(st->ctx, data, len, &processed)) != noErr) { + if (st->error == GIT_TIMEOUT) + return GIT_TIMEOUT; + return stransport_error(ret); + } return processed; } @@ -269,7 +297,7 @@ static int stransport_wrap( } if ((ret = SSLSetIOFuncs(st->ctx, read_cb, write_cb)) != noErr || - (ret = SSLSetConnection(st->ctx, st->io)) != noErr || + (ret = SSLSetConnection(st->ctx, st)) != noErr || (ret = SSLSetSessionOption(st->ctx, kSSLSessionOptionBreakOnServerAuth, true)) != noErr || (ret = SSLSetProtocolVersionMin(st->ctx, kTLSProtocol1)) != noErr || (ret = SSLSetProtocolVersionMax(st->ctx, kTLSProtocol12)) != noErr || diff --git a/vendor/libgit2/src/streams/stransport.h b/vendor/libgit2/src/libgit2/streams/stransport.h similarity index 100% rename from vendor/libgit2/src/streams/stransport.h rename to vendor/libgit2/src/libgit2/streams/stransport.h diff --git a/vendor/libgit2/src/streams/tls.c b/vendor/libgit2/src/libgit2/streams/tls.c similarity index 92% rename from vendor/libgit2/src/streams/tls.c rename to vendor/libgit2/src/libgit2/streams/tls.c index e063a33f..246ac9ca 100644 --- a/vendor/libgit2/src/streams/tls.c +++ b/vendor/libgit2/src/libgit2/streams/tls.c @@ -13,6 +13,7 @@ #include "streams/mbedtls.h" #include "streams/openssl.h" #include "streams/stransport.h" +#include "streams/schannel.h" int git_tls_stream_new(git_stream **out, const char *host, const char *port) { @@ -33,6 +34,8 @@ int git_tls_stream_new(git_stream **out, const char *host, const char *port) init = git_openssl_stream_new; #elif defined(GIT_MBEDTLS) init = git_mbedtls_stream_new; +#elif defined(GIT_SCHANNEL) + init = git_schannel_stream_new; #endif } else { return error; @@ -63,6 +66,8 @@ int git_tls_stream_wrap(git_stream **out, git_stream *in, const char *host) wrap = git_openssl_stream_wrap; #elif defined(GIT_MBEDTLS) wrap = git_mbedtls_stream_wrap; +#elif defined(GIT_SCHANNEL) + wrap = git_schannel_stream_wrap; #endif } diff --git a/vendor/libgit2/src/streams/tls.h b/vendor/libgit2/src/libgit2/streams/tls.h similarity index 100% rename from vendor/libgit2/src/streams/tls.h rename to vendor/libgit2/src/libgit2/streams/tls.h diff --git a/vendor/libgit2/src/submodule.c b/vendor/libgit2/src/libgit2/submodule.c similarity index 99% rename from vendor/libgit2/src/submodule.c rename to vendor/libgit2/src/libgit2/submodule.c index 0f4f0726..830d41c7 100644 --- a/vendor/libgit2/src/submodule.c +++ b/vendor/libgit2/src/libgit2/submodule.c @@ -196,7 +196,7 @@ static void free_submodule_names(git_strmap *names) */ static int load_submodule_names(git_strmap **out, git_repository *repo, git_config *cfg) { - const char *key = "submodule\\..*\\.path"; + const char *key = "^submodule\\..*\\.path$"; git_config_iterator *iter = NULL; git_config_entry *entry; git_str buf = GIT_STR_INIT; @@ -332,7 +332,7 @@ int git_submodule__lookup_with_cache( /* If it's not configured or we're looking by path */ if (location == 0 || location == GIT_SUBMODULE_STATUS_IN_WD) { git_config_backend *mods; - const char *pattern = "submodule\\..*\\.path"; + const char *pattern = "^submodule\\..*\\.path$"; git_str path = GIT_STR_INIT; fbp_data data = { NULL, NULL }; @@ -1338,7 +1338,11 @@ int git_submodule_update(git_submodule *sm, int init, git_submodule_update_optio /* Get the status of the submodule to determine if it is already initialized */ if ((error = git_submodule_status(&submodule_status, sm->repo, sm->name, GIT_SUBMODULE_IGNORE_UNSPECIFIED)) < 0) goto done; - + + /* If the submodule is configured but hasn't been added, skip it */ + if (submodule_status == GIT_SUBMODULE_STATUS_IN_CONFIG) + goto done; + /* * If submodule work dir is not already initialized, check to see * what we need to do (initialize, clone, return error...) @@ -1389,7 +1393,7 @@ int git_submodule_update(git_submodule *sm, int init, git_submodule_update_optio */ clone_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE; - if ((error = git_clone(&sub_repo, submodule_url, sm->path, &clone_options)) < 0 || + if ((error = git_clone__submodule(&sub_repo, submodule_url, sm->path, &clone_options)) < 0 || (error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm))) < 0 || (error = git_checkout_head(sub_repo, &update_options.checkout_opts)) != 0) goto done; diff --git a/vendor/libgit2/src/submodule.h b/vendor/libgit2/src/libgit2/submodule.h similarity index 96% rename from vendor/libgit2/src/submodule.h rename to vendor/libgit2/src/libgit2/submodule.h index 7fa98248..40b7b70f 100644 --- a/vendor/libgit2/src/submodule.h +++ b/vendor/libgit2/src/libgit2/submodule.h @@ -69,9 +69,9 @@ * - `repo` is the parent repository that contains this submodule. * - `flags` after for internal use, tracking where this submodule has been * found (head, index, config, workdir) and known status info, etc. - * - `head_oid` is the SHA1 for the submodule path in the repo HEAD. - * - `index_oid` is the SHA1 for the submodule recorded in the index. - * - `wd_oid` is the SHA1 for the HEAD of the checked out submodule. + * - `head_oid` is the oid for the submodule path in the repo HEAD. + * - `index_oid` is the oid for the submodule recorded in the index. + * - `wd_oid` is the oid for the HEAD of the checked out submodule. * * If the submodule has been added to .gitmodules but not yet git added, * then the `index_oid` will be zero but still marked valid. If the diff --git a/vendor/libgit2/src/libgit2/sysdir.c b/vendor/libgit2/src/libgit2/sysdir.c new file mode 100644 index 00000000..7838a678 --- /dev/null +++ b/vendor/libgit2/src/libgit2/sysdir.c @@ -0,0 +1,650 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "sysdir.h" + +#include "runtime.h" +#include "str.h" +#include "fs_path.h" +#include +#if GIT_WIN32 +# include "fs_path.h" +# include "win32/path_w32.h" +# include "win32/utf-conv.h" +#else +# include +# include +#endif + +#ifdef GIT_WIN32 +# define REG_GITFORWINDOWS_KEY L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1" +# define REG_GITFORWINDOWS_KEY_WOW64 L"SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1" + +static int expand_win32_path(git_win32_path dest, const wchar_t *src) +{ + DWORD len = ExpandEnvironmentStringsW(src, dest, GIT_WIN_PATH_UTF16); + + if (!len || len > GIT_WIN_PATH_UTF16) + return -1; + + return 0; +} + +static int win32_path_to_utf8(git_str *dest, const wchar_t *src) +{ + git_win32_utf8_path utf8_path; + + if (git_win32_path_to_utf8(utf8_path, src) < 0) { + git_error_set(GIT_ERROR_OS, "unable to convert path to UTF-8"); + return -1; + } + + /* Convert backslashes to forward slashes */ + git_fs_path_mkposix(utf8_path); + + return git_str_sets(dest, utf8_path); +} + +static git_win32_path mock_registry; +static bool mock_registry_set; + +extern int git_win32__set_registry_system_dir(const wchar_t *mock_sysdir) +{ + if (!mock_sysdir) { + mock_registry[0] = L'\0'; + mock_registry_set = false; + } else { + size_t len = wcslen(mock_sysdir); + + if (len > GIT_WIN_PATH_MAX) { + git_error_set(GIT_ERROR_INVALID, "mock path too long"); + return -1; + } + + wcscpy(mock_registry, mock_sysdir); + mock_registry_set = true; + } + + return 0; +} + +static int lookup_registry_key( + git_win32_path out, + const HKEY hive, + const wchar_t* key, + const wchar_t *value) +{ + HKEY hkey; + DWORD type, size; + int error = GIT_ENOTFOUND; + + /* + * Registry data may not be NUL terminated, provide room to do + * it ourselves. + */ + size = (DWORD)((sizeof(git_win32_path) - 1) * sizeof(wchar_t)); + + if (RegOpenKeyExW(hive, key, 0, KEY_READ, &hkey) != 0) + return GIT_ENOTFOUND; + + if (RegQueryValueExW(hkey, value, NULL, &type, (LPBYTE)out, &size) == 0 && + type == REG_SZ && + size > 0 && + size < sizeof(git_win32_path)) { + size_t wsize = size / sizeof(wchar_t); + size_t len = wsize - 1; + + if (out[wsize - 1] != L'\0') { + len = wsize; + out[wsize] = L'\0'; + } + + if (out[len - 1] == L'\\') + out[len - 1] = L'\0'; + + if (_waccess(out, F_OK) == 0) + error = 0; + } + + RegCloseKey(hkey); + return error; +} + +static int find_sysdir_in_registry(git_win32_path out) +{ + if (mock_registry_set) { + if (mock_registry[0] == L'\0') + return GIT_ENOTFOUND; + + wcscpy(out, mock_registry); + return 0; + } + + if (lookup_registry_key(out, HKEY_CURRENT_USER, REG_GITFORWINDOWS_KEY, L"InstallLocation") == 0 || + lookup_registry_key(out, HKEY_CURRENT_USER, REG_GITFORWINDOWS_KEY_WOW64, L"InstallLocation") == 0 || + lookup_registry_key(out, HKEY_LOCAL_MACHINE, REG_GITFORWINDOWS_KEY, L"InstallLocation") == 0 || + lookup_registry_key(out, HKEY_LOCAL_MACHINE, REG_GITFORWINDOWS_KEY_WOW64, L"InstallLocation") == 0) + return 0; + + return GIT_ENOTFOUND; +} + +static int find_sysdir_in_path(git_win32_path out) +{ + size_t out_len; + + if (git_win32_path_find_executable(out, L"git.exe") < 0 && + git_win32_path_find_executable(out, L"git.cmd") < 0) + return GIT_ENOTFOUND; + + out_len = wcslen(out); + + /* Trim the file name */ + if (out_len <= CONST_STRLEN(L"git.exe")) + return GIT_ENOTFOUND; + + out_len -= CONST_STRLEN(L"git.exe"); + + if (out_len && out[out_len - 1] == L'\\') + out_len--; + + /* + * Git for Windows usually places the command in a 'bin' or + * 'cmd' directory, trim that. + */ + if (out_len >= CONST_STRLEN(L"\\bin") && + wcsncmp(&out[out_len - CONST_STRLEN(L"\\bin")], L"\\bin", CONST_STRLEN(L"\\bin")) == 0) + out_len -= CONST_STRLEN(L"\\bin"); + else if (out_len >= CONST_STRLEN(L"\\cmd") && + wcsncmp(&out[out_len - CONST_STRLEN(L"\\cmd")], L"\\cmd", CONST_STRLEN(L"\\cmd")) == 0) + out_len -= CONST_STRLEN(L"\\cmd"); + + if (!out_len) + return GIT_ENOTFOUND; + + out[out_len] = L'\0'; + return 0; +} + +static int find_win32_dirs( + git_str *out, + const wchar_t* tmpl[]) +{ + git_win32_path path16; + git_str buf = GIT_STR_INIT; + + git_str_clear(out); + + for (; *tmpl != NULL; tmpl++) { + if (!expand_win32_path(path16, *tmpl) && + path16[0] != L'%' && + !_waccess(path16, F_OK)) { + win32_path_to_utf8(&buf, path16); + + if (buf.size) + git_str_join(out, GIT_PATH_LIST_SEPARATOR, out->ptr, buf.ptr); + } + } + + git_str_dispose(&buf); + + return (git_str_oom(out) ? -1 : 0); +} + +static int append_subdir(git_str *out, git_str *path, const char *subdir) +{ + static const char* architecture_roots[] = { + "", + "mingw64", + "mingw32", + NULL + }; + const char **root; + size_t orig_path_len = path->size; + + for (root = architecture_roots; *root; root++) { + if ((*root[0] && git_str_joinpath(path, path->ptr, *root) < 0) || + git_str_joinpath(path, path->ptr, subdir) < 0) + return -1; + + if (git_fs_path_exists(path->ptr) && + git_str_join(out, GIT_PATH_LIST_SEPARATOR, out->ptr, path->ptr) < 0) + return -1; + + git_str_truncate(path, orig_path_len); + } + + return 0; +} + +int git_win32__find_system_dirs(git_str *out, const char *subdir) +{ + git_win32_path pathdir, regdir; + git_str path8 = GIT_STR_INIT; + bool has_pathdir, has_regdir; + int error; + + has_pathdir = (find_sysdir_in_path(pathdir) == 0); + has_regdir = (find_sysdir_in_registry(regdir) == 0); + + if (!has_pathdir && !has_regdir) + return 0; + + /* + * Usually the git in the path is the same git in the registry, + * in this case there's no need to duplicate the paths. + */ + if (has_pathdir && has_regdir && wcscmp(pathdir, regdir) == 0) + has_regdir = false; + + if (has_pathdir) { + if ((error = win32_path_to_utf8(&path8, pathdir)) < 0 || + (error = append_subdir(out, &path8, subdir)) < 0) + goto done; + } + + if (has_regdir) { + if ((error = win32_path_to_utf8(&path8, regdir)) < 0 || + (error = append_subdir(out, &path8, subdir)) < 0) + goto done; + } + +done: + git_str_dispose(&path8); + return error; +} +#endif /* WIN32 */ + +static int git_sysdir_guess_programdata_dirs(git_str *out) +{ +#ifdef GIT_WIN32 + static const wchar_t *programdata_tmpls[2] = { + L"%PROGRAMDATA%\\Git", + NULL, + }; + + return find_win32_dirs(out, programdata_tmpls); +#else + git_str_clear(out); + return 0; +#endif +} + +static int git_sysdir_guess_system_dirs(git_str *out) +{ +#ifdef GIT_WIN32 + return git_win32__find_system_dirs(out, "etc"); +#else + return git_str_sets(out, "/etc"); +#endif +} + +#ifndef GIT_WIN32 +static int get_passwd_home(git_str *out, uid_t uid) +{ + struct passwd pwd, *pwdptr; + char *buf = NULL; + long buflen; + int error; + + GIT_ASSERT_ARG(out); + + if ((buflen = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) + buflen = 1024; + + do { + buf = git__realloc(buf, buflen); + error = getpwuid_r(uid, &pwd, buf, buflen, &pwdptr); + buflen *= 2; + } while (error == ERANGE && buflen <= 8192); + + if (error) { + git_error_set(GIT_ERROR_OS, "failed to get passwd entry"); + goto out; + } + + if (!pwdptr) { + git_error_set(GIT_ERROR_OS, "no passwd entry found for user"); + goto out; + } + + if ((error = git_str_puts(out, pwdptr->pw_dir)) < 0) + goto out; + +out: + git__free(buf); + return error; +} +#endif + +static int git_sysdir_guess_home_dirs(git_str *out) +{ +#ifdef GIT_WIN32 + static const wchar_t *global_tmpls[4] = { + L"%HOME%\\", + L"%HOMEDRIVE%%HOMEPATH%\\", + L"%USERPROFILE%\\", + NULL, + }; + + return find_win32_dirs(out, global_tmpls); +#else + int error; + uid_t uid, euid; + const char *sandbox_id; + + uid = getuid(); + euid = geteuid(); + + /** + * If APP_SANDBOX_CONTAINER_ID is set, we are running in a + * sandboxed environment on macOS. + */ + sandbox_id = getenv("APP_SANDBOX_CONTAINER_ID"); + + /* + * In case we are running setuid, use the configuration + * of the effective user. + * + * If we are running in a sandboxed environment on macOS, + * we have to get the HOME dir from the password entry file. + */ + if (!sandbox_id && uid == euid) + error = git__getenv(out, "HOME"); + else + error = get_passwd_home(out, euid); + + if (error == GIT_ENOTFOUND) { + git_error_clear(); + error = 0; + } + + return error; +#endif +} + +static int git_sysdir_guess_global_dirs(git_str *out) +{ + return git_sysdir_guess_home_dirs(out); +} + +static int git_sysdir_guess_xdg_dirs(git_str *out) +{ +#ifdef GIT_WIN32 + static const wchar_t *global_tmpls[7] = { + L"%XDG_CONFIG_HOME%\\git", + L"%APPDATA%\\git", + L"%LOCALAPPDATA%\\git", + L"%HOME%\\.config\\git", + L"%HOMEDRIVE%%HOMEPATH%\\.config\\git", + L"%USERPROFILE%\\.config\\git", + NULL, + }; + + return find_win32_dirs(out, global_tmpls); +#else + git_str env = GIT_STR_INIT; + int error; + uid_t uid, euid; + + uid = getuid(); + euid = geteuid(); + + /* + * In case we are running setuid, only look up passwd + * directory of the effective user. + */ + if (uid == euid) { + if ((error = git__getenv(&env, "XDG_CONFIG_HOME")) == 0) + error = git_str_joinpath(out, env.ptr, "git"); + + if (error == GIT_ENOTFOUND && (error = git__getenv(&env, "HOME")) == 0) + error = git_str_joinpath(out, env.ptr, ".config/git"); + } else { + if ((error = get_passwd_home(&env, euid)) == 0) + error = git_str_joinpath(out, env.ptr, ".config/git"); + } + + if (error == GIT_ENOTFOUND) { + git_error_clear(); + error = 0; + } + + git_str_dispose(&env); + return error; +#endif +} + +static int git_sysdir_guess_template_dirs(git_str *out) +{ +#ifdef GIT_WIN32 + return git_win32__find_system_dirs(out, "share/git-core/templates"); +#else + return git_str_sets(out, "/usr/share/git-core/templates"); +#endif +} + +struct git_sysdir__dir { + git_str buf; + int (*guess)(git_str *out); +}; + +static struct git_sysdir__dir git_sysdir__dirs[] = { + { GIT_STR_INIT, git_sysdir_guess_system_dirs }, + { GIT_STR_INIT, git_sysdir_guess_global_dirs }, + { GIT_STR_INIT, git_sysdir_guess_xdg_dirs }, + { GIT_STR_INIT, git_sysdir_guess_programdata_dirs }, + { GIT_STR_INIT, git_sysdir_guess_template_dirs }, + { GIT_STR_INIT, git_sysdir_guess_home_dirs } +}; + +static void git_sysdir_global_shutdown(void) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(git_sysdir__dirs); ++i) + git_str_dispose(&git_sysdir__dirs[i].buf); +} + +int git_sysdir_global_init(void) +{ + size_t i; + int error = 0; + + for (i = 0; !error && i < ARRAY_SIZE(git_sysdir__dirs); i++) + error = git_sysdir__dirs[i].guess(&git_sysdir__dirs[i].buf); + + if (error) + return error; + + return git_runtime_shutdown_register(git_sysdir_global_shutdown); +} + +int git_sysdir_reset(void) +{ + size_t i; + int error = 0; + + for (i = 0; !error && i < ARRAY_SIZE(git_sysdir__dirs); ++i) { + git_str_dispose(&git_sysdir__dirs[i].buf); + error = git_sysdir__dirs[i].guess(&git_sysdir__dirs[i].buf); + } + + return error; +} + +static int git_sysdir_check_selector(git_sysdir_t which) +{ + if (which < ARRAY_SIZE(git_sysdir__dirs)) + return 0; + + git_error_set(GIT_ERROR_INVALID, "config directory selector out of range"); + return -1; +} + + +int git_sysdir_get(const git_str **out, git_sysdir_t which) +{ + GIT_ASSERT_ARG(out); + + *out = NULL; + + GIT_ERROR_CHECK_ERROR(git_sysdir_check_selector(which)); + + *out = &git_sysdir__dirs[which].buf; + return 0; +} + +#define PATH_MAGIC "$PATH" + +int git_sysdir_set(git_sysdir_t which, const char *search_path) +{ + const char *expand_path = NULL; + git_str merge = GIT_STR_INIT; + + GIT_ERROR_CHECK_ERROR(git_sysdir_check_selector(which)); + + if (search_path != NULL) + expand_path = strstr(search_path, PATH_MAGIC); + + /* reset the default if this path has been cleared */ + if (!search_path) + git_sysdir__dirs[which].guess(&git_sysdir__dirs[which].buf); + + /* if $PATH is not referenced, then just set the path */ + if (!expand_path) { + if (search_path) + git_str_sets(&git_sysdir__dirs[which].buf, search_path); + + goto done; + } + + /* otherwise set to join(before $PATH, old value, after $PATH) */ + if (expand_path > search_path) + git_str_set(&merge, search_path, expand_path - search_path); + + if (git_str_len(&git_sysdir__dirs[which].buf)) + git_str_join(&merge, GIT_PATH_LIST_SEPARATOR, + merge.ptr, git_sysdir__dirs[which].buf.ptr); + + expand_path += strlen(PATH_MAGIC); + if (*expand_path) + git_str_join(&merge, GIT_PATH_LIST_SEPARATOR, merge.ptr, expand_path); + + git_str_swap(&git_sysdir__dirs[which].buf, &merge); + git_str_dispose(&merge); + +done: + if (git_str_oom(&git_sysdir__dirs[which].buf)) + return -1; + + return 0; +} + +static int git_sysdir_find_in_dirlist( + git_str *path, + const char *name, + git_sysdir_t which, + const char *label) +{ + size_t len; + const char *scan, *next = NULL; + const git_str *syspath; + + GIT_ERROR_CHECK_ERROR(git_sysdir_get(&syspath, which)); + if (!syspath || !git_str_len(syspath)) + goto done; + + for (scan = git_str_cstr(syspath); scan; scan = next) { + /* find unescaped separator or end of string */ + for (next = scan; *next; ++next) { + if (*next == GIT_PATH_LIST_SEPARATOR && + (next <= scan || next[-1] != '\\')) + break; + } + + len = (size_t)(next - scan); + next = (*next ? next + 1 : NULL); + if (!len) + continue; + + GIT_ERROR_CHECK_ERROR(git_str_set(path, scan, len)); + if (name) + GIT_ERROR_CHECK_ERROR(git_str_joinpath(path, path->ptr, name)); + + if (git_fs_path_exists(path->ptr)) + return 0; + } + +done: + if (name) + git_error_set(GIT_ERROR_OS, "the %s file '%s' doesn't exist", label, name); + else + git_error_set(GIT_ERROR_OS, "the %s directory doesn't exist", label); + git_str_dispose(path); + return GIT_ENOTFOUND; +} + +int git_sysdir_find_system_file(git_str *path, const char *filename) +{ + return git_sysdir_find_in_dirlist( + path, filename, GIT_SYSDIR_SYSTEM, "system"); +} + +int git_sysdir_find_global_file(git_str *path, const char *filename) +{ + return git_sysdir_find_in_dirlist( + path, filename, GIT_SYSDIR_GLOBAL, "global"); +} + +int git_sysdir_find_xdg_file(git_str *path, const char *filename) +{ + return git_sysdir_find_in_dirlist( + path, filename, GIT_SYSDIR_XDG, "global/xdg"); +} + +int git_sysdir_find_programdata_file(git_str *path, const char *filename) +{ + return git_sysdir_find_in_dirlist( + path, filename, GIT_SYSDIR_PROGRAMDATA, "ProgramData"); +} + +int git_sysdir_find_template_dir(git_str *path) +{ + return git_sysdir_find_in_dirlist( + path, NULL, GIT_SYSDIR_TEMPLATE, "template"); +} + +int git_sysdir_find_homedir(git_str *path) +{ + return git_sysdir_find_in_dirlist( + path, NULL, GIT_SYSDIR_HOME, "home directory"); +} + +int git_sysdir_expand_global_file(git_str *path, const char *filename) +{ + int error; + + if ((error = git_sysdir_find_global_file(path, NULL)) == 0) { + if (filename) + error = git_str_joinpath(path, path->ptr, filename); + } + + return error; +} + +int git_sysdir_expand_homedir_file(git_str *path, const char *filename) +{ + int error; + + if ((error = git_sysdir_find_homedir(path)) == 0) { + if (filename) + error = git_str_joinpath(path, path->ptr, filename); + } + + return error; +} diff --git a/vendor/libgit2/src/libgit2/sysdir.h b/vendor/libgit2/src/libgit2/sysdir.h new file mode 100644 index 00000000..03f59e1d --- /dev/null +++ b/vendor/libgit2/src/libgit2/sysdir.h @@ -0,0 +1,145 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_sysdir_h__ +#define INCLUDE_sysdir_h__ + +#include "common.h" + +#include "posix.h" +#include "str.h" + +/** + * Find a "global" file (i.e. one in a user's home directory). + * + * @param path buffer to write the full path into + * @param filename name of file to find in the home directory + * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error + */ +extern int git_sysdir_find_global_file(git_str *path, const char *filename); + +/** + * Find an "XDG" file (i.e. one in user's XDG config path). + * + * @param path buffer to write the full path into + * @param filename name of file to find in the home directory + * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error + */ +extern int git_sysdir_find_xdg_file(git_str *path, const char *filename); + +/** + * Find a "system" file (i.e. one shared for all users of the system). + * + * @param path buffer to write the full path into + * @param filename name of file to find in the home directory + * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error + */ +extern int git_sysdir_find_system_file(git_str *path, const char *filename); + +/** + * Find a "ProgramData" file (i.e. one in %PROGRAMDATA%) + * + * @param path buffer to write the full path into + * @param filename name of file to find in the ProgramData directory + * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error + */ +extern int git_sysdir_find_programdata_file(git_str *path, const char *filename); + +/** + * Find template directory. + * + * @param path buffer to write the full path into + * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error + */ +extern int git_sysdir_find_template_dir(git_str *path); + +/** + * Find the home directory. On Windows, this will look at the `HOME`, + * `HOMEPATH`, and `USERPROFILE` environment variables (in that order) + * and return the first path that is set and exists. On other systems, + * this will simply return the contents of the `HOME` environment variable. + * + * @param path buffer to write the full path into + * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error + */ +extern int git_sysdir_find_homedir(git_str *path); + +/** + * Expand the name of a "global" file -- by default inside the user's + * home directory, but can be overridden by the user configuration. + * Unlike `find_global_file` (above), this makes no attempt to check + * for the existence of the file, and is useful if you want the full + * path regardless of existence. + * + * @param path buffer to write the full path into + * @param filename name of file in the home directory + * @return 0 on success or -1 on error + */ +extern int git_sysdir_expand_global_file(git_str *path, const char *filename); + +/** + * Expand the name of a file in the user's home directory. This + * function makes no attempt to check for the existence of the file, + * and is useful if you want the full path regardless of existence. + * + * @param path buffer to write the full path into + * @param filename name of file in the home directory + * @return 0 on success or -1 on error + */ +extern int git_sysdir_expand_homedir_file(git_str *path, const char *filename); + +typedef enum { + GIT_SYSDIR_SYSTEM = 0, + GIT_SYSDIR_GLOBAL = 1, + GIT_SYSDIR_XDG = 2, + GIT_SYSDIR_PROGRAMDATA = 3, + GIT_SYSDIR_TEMPLATE = 4, + GIT_SYSDIR_HOME = 5, + GIT_SYSDIR__MAX = 6 +} git_sysdir_t; + +/** + * Configures global data for configuration file search paths. + * + * @return 0 on success, <0 on failure + */ +extern int git_sysdir_global_init(void); + +/** + * Get the search path for global/system/xdg files + * + * @param out pointer to git_str containing search path + * @param which which list of paths to return + * @return 0 on success, <0 on failure + */ +extern int git_sysdir_get(const git_str **out, git_sysdir_t which); + +/** + * Set search paths for global/system/xdg files + * + * The first occurrence of the magic string "$PATH" in the new value will + * be replaced with the old value of the search path. + * + * @param which Which search path to modify + * @param paths New search path (separated by GIT_PATH_LIST_SEPARATOR) + * @return 0 on success, <0 on failure (allocation error) + */ +extern int git_sysdir_set(git_sysdir_t which, const char *paths); + +/** + * Reset search paths for global/system/xdg files. + */ +extern int git_sysdir_reset(void); + +#ifdef GIT_WIN32 +/** Sets the registry system dir to a mock; for testing. */ +extern int git_win32__set_registry_system_dir(const wchar_t *mock_sysdir); + +/** Find the given system dir; for testing. */ +extern int git_win32__find_system_dirs(git_str *out, const char *subdir); +#endif + +#endif diff --git a/vendor/libgit2/src/tag.c b/vendor/libgit2/src/libgit2/tag.c similarity index 92% rename from vendor/libgit2/src/tag.c rename to vendor/libgit2/src/libgit2/tag.c index 5734106f..562ec13e 100644 --- a/vendor/libgit2/src/tag.c +++ b/vendor/libgit2/src/libgit2/tag.c @@ -65,7 +65,11 @@ static int tag_error(const char *str) return GIT_EINVALID; } -static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) +static int tag_parse( + git_tag *tag, + const char *buffer, + const char *buffer_end, + git_oid_t oid_type) { static const char *tag_types[] = { NULL, "commit\n", "tree\n", "blob\n", "tag\n" @@ -75,7 +79,8 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) unsigned int i; int error; - if (git_oid__parse(&tag->target, &buffer, buffer_end, "object ") < 0) + if (git_object__parse_oid_header(&tag->target, + &buffer, buffer_end, "object ", oid_type) < 0) return tag_error("object field invalid"); if (buffer + 5 >= buffer_end) @@ -160,18 +165,25 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) return 0; } -int git_tag__parse_raw(void *_tag, const char *data, size_t size) +int git_tag__parse_raw( + void *_tag, + const char *data, + size_t size, + git_oid_t oid_type) { - return tag_parse(_tag, data, data + size); + return tag_parse(_tag, data, data + size, oid_type); } -int git_tag__parse(void *_tag, git_odb_object *odb_obj) +int git_tag__parse( + void *_tag, + git_odb_object *odb_obj, + git_oid_t oid_type) { git_tag *tag = _tag; const char *buffer = git_odb_object_data(odb_obj); const char *buffer_end = buffer + git_odb_object_size(odb_obj); - return tag_parse(tag, buffer, buffer_end); + return tag_parse(tag, buffer, buffer_end, oid_type); } static int retrieve_tag_reference( @@ -220,7 +232,9 @@ static int write_tag_annotation( git_str tag = GIT_STR_INIT; git_odb *odb; - git_oid__writebuf(&tag, "object ", git_object_id(target)); + if (git_object__write_oid_header(&tag, "object ", git_object_id(target)) < 0) + goto on_error; + git_str_printf(&tag, "type %s\n", git_object_type2string(git_object_type(target))); git_str_printf(&tag, "tag %s\n", tag_name); git_signature__writebuf(&tag, "tagger ", tagger); @@ -244,6 +258,15 @@ static int write_tag_annotation( return -1; } +static bool tag_name_is_valid(const char *tag_name) +{ + /* + * Discourage tag name starting with dash, + * https://github.com/git/git/commit/4f0accd638b8d2 + */ + return tag_name[0] != '-'; +} + static int git_tag_create__internal( git_oid *oid, git_repository *repo, @@ -269,6 +292,11 @@ static int git_tag_create__internal( return -1; } + if (!tag_name_is_valid(tag_name)) { + git_error_set(GIT_ERROR_TAG, "'%s' is not a valid tag name", tag_name); + return -1; + } + error = retrieve_tag_reference_oid(oid, &ref_name, repo, tag_name); if (error < 0 && error != GIT_ENOTFOUND) goto cleanup; @@ -282,8 +310,10 @@ static int git_tag_create__internal( } if (create_tag_annotation) { - if (write_tag_annotation(oid, repo, tag_name, target, tagger, message) < 0) + if (write_tag_annotation(oid, repo, tag_name, target, tagger, message) < 0) { + git_str_dispose(&ref_name); return -1; + } } else git_oid_cpy(oid, git_object_id(target)); @@ -355,7 +385,7 @@ int git_tag_create_from_buffer(git_oid *oid, git_repository *repo, const char *b return -1; /* validate the buffer */ - if (tag_parse(&tag, buffer, buffer + strlen(buffer)) < 0) + if (tag_parse(&tag, buffer, buffer + strlen(buffer), repo->oid_type) < 0) return -1; /* validate the target */ @@ -380,14 +410,17 @@ int git_tag_create_from_buffer(git_oid *oid, git_repository *repo, const char *b /** Ensure the tag name doesn't conflict with an already existing * reference unless overwriting has explicitly been requested **/ if (error == 0 && !allow_ref_overwrite) { + git_str_dispose(&ref_name); git_error_set(GIT_ERROR_TAG, "tag already exists"); return GIT_EEXISTS; } /* write the buffer */ if ((error = git_odb_open_wstream( - &stream, odb, strlen(buffer), GIT_OBJECT_TAG)) < 0) + &stream, odb, strlen(buffer), GIT_OBJECT_TAG)) < 0) { + git_str_dispose(&ref_name); return error; + } if (!(error = git_odb_stream_write(stream, buffer, strlen(buffer)))) error = git_odb_stream_finalize_write(oid, stream); @@ -542,11 +575,7 @@ int git_tag_name_is_valid(int *valid, const char *name) *valid = 0; - /* - * Discourage tag name starting with dash, - * https://github.com/git/git/commit/4f0accd638b8d2 - */ - if (!name || name[0] == '-') + if (!name || !tag_name_is_valid(name)) goto done; if ((error = git_str_puts(&ref_name, GIT_REFS_TAGS_DIR)) < 0 || diff --git a/vendor/libgit2/src/tag.h b/vendor/libgit2/src/libgit2/tag.h similarity index 76% rename from vendor/libgit2/src/tag.h rename to vendor/libgit2/src/libgit2/tag.h index 76ae1508..fdaaa463 100644 --- a/vendor/libgit2/src/tag.h +++ b/vendor/libgit2/src/libgit2/tag.h @@ -25,7 +25,7 @@ struct git_tag { }; void git_tag__free(void *tag); -int git_tag__parse(void *tag, git_odb_object *obj); -int git_tag__parse_raw(void *tag, const char *data, size_t size); +int git_tag__parse(void *tag, git_odb_object *obj, git_oid_t oid_type); +int git_tag__parse_raw(void *tag, const char *data, size_t size, git_oid_t oid_type); #endif diff --git a/vendor/libgit2/src/trace.c b/vendor/libgit2/src/libgit2/trace.c similarity index 100% rename from vendor/libgit2/src/trace.c rename to vendor/libgit2/src/libgit2/trace.c diff --git a/vendor/libgit2/src/trace.h b/vendor/libgit2/src/libgit2/trace.h similarity index 100% rename from vendor/libgit2/src/trace.h rename to vendor/libgit2/src/libgit2/trace.h diff --git a/vendor/libgit2/src/libgit2/trailer.c b/vendor/libgit2/src/libgit2/trailer.c new file mode 100644 index 00000000..c7579fb3 --- /dev/null +++ b/vendor/libgit2/src/libgit2/trailer.c @@ -0,0 +1,430 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#include "array.h" +#include "common.h" +#include "git2/message.h" + +#include +#include +#include + +#define COMMENT_LINE_CHAR '#' +#define TRAILER_SEPARATORS ":" + +static const char *const git_generated_prefixes[] = { + "Signed-off-by: ", + "(cherry picked from commit ", + NULL +}; + +static int is_blank_line(const char *str) +{ + const char *s = str; + while (*s && *s != '\n' && git__isspace(*s)) + s++; + return !*s || *s == '\n'; +} + +static const char *next_line(const char *str) +{ + const char *nl = strchr(str, '\n'); + + if (nl) { + return nl + 1; + } else { + /* return pointer to the NUL terminator: */ + return str + strlen(str); + } +} + +/* + * Return the position of the start of the last line. If len is 0, return 0. + */ +static bool last_line(size_t *out, const char *buf, size_t len) +{ + size_t i; + + *out = 0; + + if (len == 0) + return false; + if (len == 1) + return true; + + /* + * Skip the last character (in addition to the null terminator), + * because if the last character is a newline, it is considered as part + * of the last line anyway. + */ + i = len - 2; + + for (; i > 0; i--) { + if (buf[i] == '\n') { + *out = i + 1; + return true; + } + } + return true; +} + +/* + * If the given line is of the form + * "..." or "...", sets out + * to the location of the separator and returns true. Otherwise, returns + * false. The optional whitespace is allowed there primarily to allow things + * like "Bug #43" where is "Bug" and is "#". + * + * The separator-starts-line case (in which this function returns true and + * sets out to 0) is distinguished from the non-well-formed-line case (in + * which this function returns false) because some callers of this function + * need such a distinction. + */ +static bool find_separator(size_t *out, const char *line, const char *separators) +{ + int whitespace_found = 0; + const char *c; + for (c = line; *c; c++) { + if (strchr(separators, *c)) { + *out = c - line; + return true; + } + + if (!whitespace_found && (git__isalnum(*c) || *c == '-')) + continue; + if (c != line && (*c == ' ' || *c == '\t')) { + whitespace_found = 1; + continue; + } + break; + } + return false; +} + +/* + * Inspect the given string and determine the true "end" of the log message, in + * order to find where to put a new Signed-off-by: line. Ignored are + * trailing comment lines and blank lines. To support "git commit -s + * --amend" on an existing commit, we also ignore "Conflicts:". To + * support "git commit -v", we truncate at cut lines. + * + * Returns the number of bytes from the tail to ignore, to be fed as + * the second parameter to append_signoff(). + */ +static size_t ignore_non_trailer(const char *buf, size_t len) +{ + size_t boc = 0, bol = 0; + int in_old_conflicts_block = 0; + size_t cutoff = len; + + while (bol < cutoff) { + const char *next_line = memchr(buf + bol, '\n', len - bol); + + if (!next_line) + next_line = buf + len; + else + next_line++; + + if (buf[bol] == COMMENT_LINE_CHAR || buf[bol] == '\n') { + /* is this the first of the run of comments? */ + if (!boc) + boc = bol; + /* otherwise, it is just continuing */ + } else if (git__prefixcmp(buf + bol, "Conflicts:\n") == 0) { + in_old_conflicts_block = 1; + if (!boc) + boc = bol; + } else if (in_old_conflicts_block && buf[bol] == '\t') { + ; /* a pathname in the conflicts block */ + } else if (boc) { + /* the previous was not trailing comment */ + boc = 0; + in_old_conflicts_block = 0; + } + bol = next_line - buf; + } + return boc ? len - boc : len - cutoff; +} + +/* + * Return the position of the start of the patch or the length of str if there + * is no patch in the message. + */ +static size_t find_patch_start(const char *str) +{ + const char *s; + + for (s = str; *s; s = next_line(s)) { + if (git__prefixcmp(s, "---") == 0 && git__isspace(s[3])) + return s - str; + } + + return s - str; +} + +/* + * Return the position of the first trailer line or len if there are no + * trailers. + */ +static size_t find_trailer_start(const char *buf, size_t len) +{ + const char *s; + size_t end_of_title, l; + int only_spaces = 1; + int recognized_prefix = 0, trailer_lines = 0, non_trailer_lines = 0; + /* + * Number of possible continuation lines encountered. This will be + * reset to 0 if we encounter a trailer (since those lines are to be + * considered continuations of that trailer), and added to + * non_trailer_lines if we encounter a non-trailer (since those lines + * are to be considered non-trailers). + */ + int possible_continuation_lines = 0; + + /* The first paragraph is the title and cannot be trailers */ + for (s = buf; s < buf + len; s = next_line(s)) { + if (s[0] == COMMENT_LINE_CHAR) + continue; + if (is_blank_line(s)) + break; + } + end_of_title = s - buf; + + /* + * Get the start of the trailers by looking starting from the end for a + * blank line before a set of non-blank lines that (i) are all + * trailers, or (ii) contains at least one Git-generated trailer and + * consists of at least 25% trailers. + */ + l = len; + while (last_line(&l, buf, l) && l >= end_of_title) { + const char *bol = buf + l; + const char *const *p; + size_t separator_pos = 0; + + if (bol[0] == COMMENT_LINE_CHAR) { + non_trailer_lines += possible_continuation_lines; + possible_continuation_lines = 0; + continue; + } + if (is_blank_line(bol)) { + if (only_spaces) + continue; + non_trailer_lines += possible_continuation_lines; + if (recognized_prefix && + trailer_lines * 3 >= non_trailer_lines) + return next_line(bol) - buf; + else if (trailer_lines && !non_trailer_lines) + return next_line(bol) - buf; + return len; + } + only_spaces = 0; + + for (p = git_generated_prefixes; *p; p++) { + if (git__prefixcmp(bol, *p) == 0) { + trailer_lines++; + possible_continuation_lines = 0; + recognized_prefix = 1; + goto continue_outer_loop; + } + } + + find_separator(&separator_pos, bol, TRAILER_SEPARATORS); + if (separator_pos >= 1 && !git__isspace(bol[0])) { + trailer_lines++; + possible_continuation_lines = 0; + if (recognized_prefix) + continue; + } else if (git__isspace(bol[0])) + possible_continuation_lines++; + else { + non_trailer_lines++; + non_trailer_lines += possible_continuation_lines; + possible_continuation_lines = 0; + } +continue_outer_loop: + ; + } + + return len; +} + +/* Return the position of the end of the trailers. */ +static size_t find_trailer_end(const char *buf, size_t len) +{ + return len - ignore_non_trailer(buf, len); +} + +static char *extract_trailer_block(const char *message, size_t *len) +{ + size_t patch_start = find_patch_start(message); + size_t trailer_end = find_trailer_end(message, patch_start); + size_t trailer_start = find_trailer_start(message, trailer_end); + + size_t trailer_len = trailer_end - trailer_start; + + char *buffer = git__malloc(trailer_len + 1); + if (buffer == NULL) + return NULL; + + memcpy(buffer, message + trailer_start, trailer_len); + buffer[trailer_len] = 0; + + *len = trailer_len; + + return buffer; +} + +enum trailer_state { + S_START = 0, + S_KEY = 1, + S_KEY_WS = 2, + S_SEP_WS = 3, + S_VALUE = 4, + S_VALUE_NL = 5, + S_VALUE_END = 6, + S_IGNORE = 7 +}; + +#define NEXT(st) { state = (st); ptr++; continue; } +#define GOTO(st) { state = (st); continue; } + +typedef git_array_t(git_message_trailer) git_array_trailer_t; + +int git_message_trailers(git_message_trailer_array *trailer_arr, const char *message) +{ + enum trailer_state state = S_START; + int rc = 0; + char *ptr; + char *key = NULL; + char *value = NULL; + git_array_trailer_t arr = GIT_ARRAY_INIT; + + size_t trailer_len; + char *trailer = extract_trailer_block(message, &trailer_len); + if (trailer == NULL) + return -1; + + for (ptr = trailer;;) { + switch (state) { + case S_START: { + if (*ptr == 0) { + goto ret; + } + + key = ptr; + GOTO(S_KEY); + } + case S_KEY: { + if (*ptr == 0) { + goto ret; + } + + if (git__isalnum(*ptr) || *ptr == '-') { + /* legal key character */ + NEXT(S_KEY); + } + + if (*ptr == ' ' || *ptr == '\t') { + /* optional whitespace before separator */ + *ptr = 0; + NEXT(S_KEY_WS); + } + + if (strchr(TRAILER_SEPARATORS, *ptr)) { + *ptr = 0; + NEXT(S_SEP_WS); + } + + /* illegal character */ + GOTO(S_IGNORE); + } + case S_KEY_WS: { + if (*ptr == 0) { + goto ret; + } + + if (*ptr == ' ' || *ptr == '\t') { + NEXT(S_KEY_WS); + } + + if (strchr(TRAILER_SEPARATORS, *ptr)) { + NEXT(S_SEP_WS); + } + + /* illegal character */ + GOTO(S_IGNORE); + } + case S_SEP_WS: { + if (*ptr == 0) { + goto ret; + } + + if (*ptr == ' ' || *ptr == '\t') { + NEXT(S_SEP_WS); + } + + value = ptr; + NEXT(S_VALUE); + } + case S_VALUE: { + if (*ptr == 0) { + GOTO(S_VALUE_END); + } + + if (*ptr == '\n') { + NEXT(S_VALUE_NL); + } + + NEXT(S_VALUE); + } + case S_VALUE_NL: { + if (*ptr == ' ') { + /* continuation; */ + NEXT(S_VALUE); + } + + ptr[-1] = 0; + GOTO(S_VALUE_END); + } + case S_VALUE_END: { + git_message_trailer *t = git_array_alloc(arr); + + t->key = key; + t->value = value; + + key = NULL; + value = NULL; + + GOTO(S_START); + } + case S_IGNORE: { + if (*ptr == 0) { + goto ret; + } + + if (*ptr == '\n') { + NEXT(S_START); + } + + NEXT(S_IGNORE); + } + } + } + +ret: + trailer_arr->_trailer_block = trailer; + trailer_arr->trailers = arr.ptr; + trailer_arr->count = arr.size; + + return rc; +} + +void git_message_trailer_array_free(git_message_trailer_array *arr) +{ + git__free(arr->_trailer_block); + git__free(arr->trailers); +} diff --git a/vendor/libgit2/src/transaction.c b/vendor/libgit2/src/libgit2/transaction.c similarity index 96% rename from vendor/libgit2/src/transaction.c rename to vendor/libgit2/src/libgit2/transaction.c index ccffa998..96341619 100644 --- a/vendor/libgit2/src/transaction.c +++ b/vendor/libgit2/src/libgit2/transaction.c @@ -49,12 +49,16 @@ struct git_transaction { git_repository *repo; git_refdb *db; git_config *cfg; + void *cfg_data; git_strmap *locks; git_pool pool; }; -int git_transaction_config_new(git_transaction **out, git_config *cfg) +int git_transaction_config_new( + git_transaction **out, + git_config *cfg, + void *data) { git_transaction *tx; @@ -66,6 +70,8 @@ int git_transaction_config_new(git_transaction **out, git_config *cfg) tx->type = TRANSACTION_CONFIG; tx->cfg = cfg; + tx->cfg_data = data; + *out = tx; return 0; } @@ -333,8 +339,9 @@ int git_transaction_commit(git_transaction *tx) GIT_ASSERT_ARG(tx); if (tx->type == TRANSACTION_CONFIG) { - error = git_config_unlock(tx->cfg, true); + error = git_config_unlock(tx->cfg, tx->cfg_data, true); tx->cfg = NULL; + tx->cfg_data = NULL; return error; } @@ -369,10 +376,8 @@ void git_transaction_free(git_transaction *tx) return; if (tx->type == TRANSACTION_CONFIG) { - if (tx->cfg) { - git_config_unlock(tx->cfg, false); - git_config_free(tx->cfg); - } + if (tx->cfg) + git_config_unlock(tx->cfg, tx->cfg_data, false); git__free(tx); return; diff --git a/vendor/libgit2/src/transaction.h b/vendor/libgit2/src/libgit2/transaction.h similarity index 77% rename from vendor/libgit2/src/transaction.h rename to vendor/libgit2/src/libgit2/transaction.h index 780c0683..cb26017a 100644 --- a/vendor/libgit2/src/transaction.h +++ b/vendor/libgit2/src/libgit2/transaction.h @@ -9,6 +9,9 @@ #include "common.h" -int git_transaction_config_new(git_transaction **out, git_config *cfg); +int git_transaction_config_new( + git_transaction **out, + git_config *cfg, + void *data); #endif diff --git a/vendor/libgit2/src/transport.c b/vendor/libgit2/src/libgit2/transport.c similarity index 99% rename from vendor/libgit2/src/transport.c rename to vendor/libgit2/src/libgit2/transport.c index 640ccaca..c61d0a68 100644 --- a/vendor/libgit2/src/transport.c +++ b/vendor/libgit2/src/libgit2/transport.c @@ -22,6 +22,7 @@ typedef struct transport_definition { static git_smart_subtransport_definition http_subtransport_definition = { git_smart_subtransport_http, 1, NULL }; static git_smart_subtransport_definition git_subtransport_definition = { git_smart_subtransport_git, 0, NULL }; + #ifdef GIT_SSH static git_smart_subtransport_definition ssh_subtransport_definition = { git_smart_subtransport_ssh, 0, NULL }; #endif @@ -33,11 +34,13 @@ static transport_definition transports[] = { { "http://", git_transport_smart, &http_subtransport_definition }, { "https://", git_transport_smart, &http_subtransport_definition }, { "file://", git_transport_local, NULL }, + #ifdef GIT_SSH { "ssh://", git_transport_smart, &ssh_subtransport_definition }, { "ssh+git://", git_transport_smart, &ssh_subtransport_definition }, { "git+ssh://", git_transport_smart, &ssh_subtransport_definition }, #endif + { NULL, 0, 0 } }; diff --git a/vendor/libgit2/src/transports/auth.c b/vendor/libgit2/src/libgit2/transports/auth.c similarity index 100% rename from vendor/libgit2/src/transports/auth.c rename to vendor/libgit2/src/libgit2/transports/auth.c diff --git a/vendor/libgit2/src/transports/auth.h b/vendor/libgit2/src/libgit2/transports/auth.h similarity index 98% rename from vendor/libgit2/src/transports/auth.h rename to vendor/libgit2/src/libgit2/transports/auth.h index 64680cc5..9f6f8fd3 100644 --- a/vendor/libgit2/src/transports/auth.h +++ b/vendor/libgit2/src/libgit2/transports/auth.h @@ -9,8 +9,7 @@ #define INCLUDE_transports_auth_h__ #include "common.h" - -#include "netops.h" +#include "net.h" typedef enum { GIT_HTTP_AUTH_BASIC = 1, diff --git a/vendor/libgit2/src/libgit2/transports/auth_gssapi.c b/vendor/libgit2/src/libgit2/transports/auth_gssapi.c new file mode 100644 index 00000000..50055384 --- /dev/null +++ b/vendor/libgit2/src/libgit2/transports/auth_gssapi.c @@ -0,0 +1,314 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "auth_negotiate.h" + +#if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK) + +#include "git2.h" +#include "auth.h" +#include "git2/sys/credential.h" + +#ifdef GIT_GSSFRAMEWORK +#import +#elif defined(GIT_GSSAPI) +#include +#include +#endif + +static gss_OID_desc gssapi_oid_spnego = + { 6, (void *) "\x2b\x06\x01\x05\x05\x02" }; +static gss_OID_desc gssapi_oid_krb5 = + { 9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }; + +static gss_OID gssapi_oids[] = + { &gssapi_oid_spnego, &gssapi_oid_krb5, NULL }; + +typedef struct { + git_http_auth_context parent; + unsigned configured : 1, + complete : 1; + git_str target; + char *challenge; + gss_ctx_id_t gss_context; + gss_OID oid; +} http_auth_gssapi_context; + +static void gssapi_err_set( + OM_uint32 status_major, + OM_uint32 status_minor, + const char *message) +{ + gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER; + OM_uint32 status_display, context = 0; + + if (gss_display_status(&status_display, status_major, GSS_C_GSS_CODE, + GSS_C_NO_OID, &context, &buffer) == GSS_S_COMPLETE) { + git_error_set(GIT_ERROR_NET, "%s: %.*s (%d.%d)", + message, (int)buffer.length, (const char *)buffer.value, + status_major, status_minor); + gss_release_buffer(&status_minor, &buffer); + } else { + git_error_set(GIT_ERROR_NET, "%s: unknown negotiate error (%d.%d)", + message, status_major, status_minor); + } +} + +static int gssapi_set_challenge( + git_http_auth_context *c, + const char *challenge) +{ + http_auth_gssapi_context *ctx = (http_auth_gssapi_context *)c; + + GIT_ASSERT_ARG(ctx); + GIT_ASSERT_ARG(challenge); + GIT_ASSERT(ctx->configured); + + git__free(ctx->challenge); + + ctx->challenge = git__strdup(challenge); + GIT_ERROR_CHECK_ALLOC(ctx->challenge); + + return 0; +} + +static void gssapi_context_dispose(http_auth_gssapi_context *ctx) +{ + OM_uint32 status_minor; + + if (ctx->gss_context != GSS_C_NO_CONTEXT) { + gss_delete_sec_context( + &status_minor, &ctx->gss_context, GSS_C_NO_BUFFER); + ctx->gss_context = GSS_C_NO_CONTEXT; + } + + git_str_dispose(&ctx->target); + + git__free(ctx->challenge); + ctx->challenge = NULL; +} + +static int gssapi_next_token( + git_str *buf, + git_http_auth_context *c, + git_credential *cred) +{ + http_auth_gssapi_context *ctx = (http_auth_gssapi_context *)c; + OM_uint32 status_major, status_minor; + gss_buffer_desc target_buffer = GSS_C_EMPTY_BUFFER, + input_token = GSS_C_EMPTY_BUFFER, + output_token = GSS_C_EMPTY_BUFFER; + gss_buffer_t input_token_ptr = GSS_C_NO_BUFFER; + git_str input_buf = GIT_STR_INIT; + gss_name_t server = NULL; + gss_OID mech; + size_t challenge_len; + int error = 0; + + GIT_ASSERT_ARG(buf); + GIT_ASSERT_ARG(ctx); + GIT_ASSERT_ARG(cred); + + GIT_ASSERT(ctx->configured); + GIT_ASSERT(cred->credtype == GIT_CREDENTIAL_DEFAULT); + + if (ctx->complete) + return 0; + + target_buffer.value = (void *)ctx->target.ptr; + target_buffer.length = ctx->target.size; + + status_major = gss_import_name(&status_minor, &target_buffer, + GSS_C_NT_HOSTBASED_SERVICE, &server); + + if (GSS_ERROR(status_major)) { + gssapi_err_set(status_major, status_minor, + "could not parse principal"); + error = -1; + goto done; + } + + challenge_len = ctx->challenge ? strlen(ctx->challenge) : 0; + + if (challenge_len < 9 || memcmp(ctx->challenge, "Negotiate", 9) != 0) { + git_error_set(GIT_ERROR_NET, "server did not request negotiate"); + error = -1; + goto done; + } + + if (challenge_len > 9) { + if (git_str_decode_base64(&input_buf, + ctx->challenge + 10, challenge_len - 10) < 0) { + git_error_set(GIT_ERROR_NET, "invalid negotiate challenge from server"); + error = -1; + goto done; + } + + input_token.value = input_buf.ptr; + input_token.length = input_buf.size; + input_token_ptr = &input_token; + } else if (ctx->gss_context != GSS_C_NO_CONTEXT) { + gssapi_context_dispose(ctx); + } + + mech = &gssapi_oid_spnego; + + status_major = gss_init_sec_context( + &status_minor, + GSS_C_NO_CREDENTIAL, + &ctx->gss_context, + server, + mech, + GSS_C_DELEG_FLAG | GSS_C_MUTUAL_FLAG, + GSS_C_INDEFINITE, + GSS_C_NO_CHANNEL_BINDINGS, + input_token_ptr, + NULL, + &output_token, + NULL, + NULL); + + if (GSS_ERROR(status_major)) { + gssapi_err_set(status_major, status_minor, "negotiate failure"); + error = -1; + goto done; + } + + /* This message merely told us auth was complete; we do not respond. */ + if (status_major == GSS_S_COMPLETE) { + gssapi_context_dispose(ctx); + ctx->complete = 1; + goto done; + } + + if (output_token.length == 0) { + git_error_set(GIT_ERROR_NET, "GSSAPI did not return token"); + error = -1; + goto done; + } + + git_str_puts(buf, "Negotiate "); + git_str_encode_base64(buf, output_token.value, output_token.length); + + if (git_str_oom(buf)) + error = -1; + +done: + gss_release_name(&status_minor, &server); + gss_release_buffer(&status_minor, (gss_buffer_t) &output_token); + git_str_dispose(&input_buf); + return error; +} + +static int gssapi_is_complete(git_http_auth_context *c) +{ + http_auth_gssapi_context *ctx = (http_auth_gssapi_context *)c; + + GIT_ASSERT_ARG(ctx); + + return (ctx->complete == 1); +} + +static void gssapi_context_free(git_http_auth_context *c) +{ + http_auth_gssapi_context *ctx = (http_auth_gssapi_context *)c; + + gssapi_context_dispose(ctx); + + ctx->configured = 0; + ctx->complete = 0; + ctx->oid = NULL; + + git__free(ctx); +} + +static int gssapi_init_context( + http_auth_gssapi_context *ctx, + const git_net_url *url) +{ + OM_uint32 status_major, status_minor; + gss_OID item, *oid; + gss_OID_set mechanism_list; + size_t i; + + /* Query supported mechanisms looking for SPNEGO) */ + status_major = gss_indicate_mechs(&status_minor, &mechanism_list); + + if (GSS_ERROR(status_major)) { + gssapi_err_set(status_major, status_minor, + "could not query mechanisms"); + return -1; + } + + if (mechanism_list) { + for (oid = gssapi_oids; *oid; oid++) { + for (i = 0; i < mechanism_list->count; i++) { + item = &mechanism_list->elements[i]; + + if (item->length == (*oid)->length && + memcmp(item->elements, (*oid)->elements, item->length) == 0) { + ctx->oid = *oid; + break; + } + + } + + if (ctx->oid) + break; + } + } + + gss_release_oid_set(&status_minor, &mechanism_list); + + if (!ctx->oid) { + git_error_set(GIT_ERROR_NET, "negotiate authentication is not supported"); + return GIT_EAUTH; + } + + git_str_puts(&ctx->target, "HTTP@"); + git_str_puts(&ctx->target, url->host); + + if (git_str_oom(&ctx->target)) + return -1; + + ctx->gss_context = GSS_C_NO_CONTEXT; + ctx->configured = 1; + + return 0; +} + +int git_http_auth_negotiate( + git_http_auth_context **out, + const git_net_url *url) +{ + http_auth_gssapi_context *ctx; + + *out = NULL; + + ctx = git__calloc(1, sizeof(http_auth_gssapi_context)); + GIT_ERROR_CHECK_ALLOC(ctx); + + if (gssapi_init_context(ctx, url) < 0) { + git__free(ctx); + return -1; + } + + ctx->parent.type = GIT_HTTP_AUTH_NEGOTIATE; + ctx->parent.credtypes = GIT_CREDENTIAL_DEFAULT; + ctx->parent.connection_affinity = 1; + ctx->parent.set_challenge = gssapi_set_challenge; + ctx->parent.next_token = gssapi_next_token; + ctx->parent.is_complete = gssapi_is_complete; + ctx->parent.free = gssapi_context_free; + + *out = (git_http_auth_context *)ctx; + + return 0; +} + +#endif /* GIT_GSSAPI */ + diff --git a/vendor/libgit2/src/transports/auth_negotiate.h b/vendor/libgit2/src/libgit2/transports/auth_negotiate.h similarity index 88% rename from vendor/libgit2/src/transports/auth_negotiate.h rename to vendor/libgit2/src/libgit2/transports/auth_negotiate.h index 34aff295..4360785c 100644 --- a/vendor/libgit2/src/transports/auth_negotiate.h +++ b/vendor/libgit2/src/libgit2/transports/auth_negotiate.h @@ -12,7 +12,7 @@ #include "git2.h" #include "auth.h" -#if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK) +#if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK) || defined(GIT_WIN32) extern int git_http_auth_negotiate( git_http_auth_context **out, diff --git a/vendor/libgit2/src/transports/auth_ntlm.h b/vendor/libgit2/src/libgit2/transports/auth_ntlm.h similarity index 94% rename from vendor/libgit2/src/transports/auth_ntlm.h rename to vendor/libgit2/src/libgit2/transports/auth_ntlm.h index 40689498..33406ae9 100644 --- a/vendor/libgit2/src/transports/auth_ntlm.h +++ b/vendor/libgit2/src/libgit2/transports/auth_ntlm.h @@ -13,7 +13,7 @@ /* NTLM requires a full request/challenge/response */ #define GIT_AUTH_STEPS_NTLM 2 -#ifdef GIT_NTLM +#if defined(GIT_NTLM) || defined(GIT_WIN32) #if defined(GIT_OPENSSL) # define CRYPT_OPENSSL diff --git a/vendor/libgit2/src/libgit2/transports/auth_ntlmclient.c b/vendor/libgit2/src/libgit2/transports/auth_ntlmclient.c new file mode 100644 index 00000000..6f26a617 --- /dev/null +++ b/vendor/libgit2/src/libgit2/transports/auth_ntlmclient.c @@ -0,0 +1,227 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "auth_ntlm.h" + +#include "common.h" +#include "str.h" +#include "auth.h" +#include "git2/sys/credential.h" + +#ifdef GIT_NTLM + +#include "ntlmclient.h" + +typedef struct { + git_http_auth_context parent; + ntlm_client *ntlm; + char *challenge; + bool complete; +} http_auth_ntlm_context; + +static int ntlmclient_set_challenge( + git_http_auth_context *c, + const char *challenge) +{ + http_auth_ntlm_context *ctx = (http_auth_ntlm_context *)c; + + GIT_ASSERT_ARG(ctx); + GIT_ASSERT_ARG(challenge); + + git__free(ctx->challenge); + + ctx->challenge = git__strdup(challenge); + GIT_ERROR_CHECK_ALLOC(ctx->challenge); + + return 0; +} + +static int ntlmclient_set_credentials(http_auth_ntlm_context *ctx, git_credential *_cred) +{ + git_credential_userpass_plaintext *cred; + const char *sep, *username; + char *domain = NULL, *domainuser = NULL; + int error = 0; + + GIT_ASSERT(_cred->credtype == GIT_CREDENTIAL_USERPASS_PLAINTEXT); + cred = (git_credential_userpass_plaintext *)_cred; + + if ((sep = strchr(cred->username, '\\')) != NULL) { + domain = git__strndup(cred->username, (sep - cred->username)); + GIT_ERROR_CHECK_ALLOC(domain); + + domainuser = git__strdup(sep + 1); + GIT_ERROR_CHECK_ALLOC(domainuser); + + username = domainuser; + } else { + username = cred->username; + } + + if (ntlm_client_set_credentials(ctx->ntlm, + username, domain, cred->password) < 0) { + git_error_set(GIT_ERROR_NET, "could not set credentials: %s", + ntlm_client_errmsg(ctx->ntlm)); + error = -1; + goto done; + } + +done: + git__free(domain); + git__free(domainuser); + return error; +} + +static int ntlmclient_next_token( + git_str *buf, + git_http_auth_context *c, + git_credential *cred) +{ + http_auth_ntlm_context *ctx = (http_auth_ntlm_context *)c; + git_str input_buf = GIT_STR_INIT; + const unsigned char *msg; + size_t challenge_len, msg_len; + int error = GIT_EAUTH; + + GIT_ASSERT_ARG(buf); + GIT_ASSERT_ARG(ctx); + + GIT_ASSERT(ctx->ntlm); + + challenge_len = ctx->challenge ? strlen(ctx->challenge) : 0; + + if (ctx->complete) + ntlm_client_reset(ctx->ntlm); + + /* + * Set us complete now since it's the default case; the one + * incomplete case (successfully created a client request) + * will explicitly set that it requires a second step. + */ + ctx->complete = true; + + if (cred && ntlmclient_set_credentials(ctx, cred) != 0) + goto done; + + if (challenge_len < 4) { + git_error_set(GIT_ERROR_NET, "no ntlm challenge sent from server"); + goto done; + } else if (challenge_len == 4) { + if (memcmp(ctx->challenge, "NTLM", 4) != 0) { + git_error_set(GIT_ERROR_NET, "server did not request NTLM"); + goto done; + } + + if (ntlm_client_negotiate(&msg, &msg_len, ctx->ntlm) != 0) { + git_error_set(GIT_ERROR_NET, "ntlm authentication failed: %s", + ntlm_client_errmsg(ctx->ntlm)); + goto done; + } + + ctx->complete = false; + } else { + if (memcmp(ctx->challenge, "NTLM ", 5) != 0) { + git_error_set(GIT_ERROR_NET, "challenge from server was not NTLM"); + goto done; + } + + if (git_str_decode_base64(&input_buf, + ctx->challenge + 5, challenge_len - 5) < 0) { + git_error_set(GIT_ERROR_NET, "invalid NTLM challenge from server"); + goto done; + } + + if (ntlm_client_set_challenge(ctx->ntlm, + (const unsigned char *)input_buf.ptr, input_buf.size) != 0) { + git_error_set(GIT_ERROR_NET, "ntlm challenge failed: %s", + ntlm_client_errmsg(ctx->ntlm)); + goto done; + } + + if (ntlm_client_response(&msg, &msg_len, ctx->ntlm) != 0) { + git_error_set(GIT_ERROR_NET, "ntlm authentication failed: %s", + ntlm_client_errmsg(ctx->ntlm)); + goto done; + } + } + + git_str_puts(buf, "NTLM "); + git_str_encode_base64(buf, (const char *)msg, msg_len); + + if (git_str_oom(buf)) + goto done; + + error = 0; + +done: + git_str_dispose(&input_buf); + return error; +} + +static int ntlmclient_is_complete(git_http_auth_context *c) +{ + http_auth_ntlm_context *ctx = (http_auth_ntlm_context *)c; + + GIT_ASSERT_ARG(ctx); + return (ctx->complete == true); +} + +static void ntlmclient_context_free(git_http_auth_context *c) +{ + http_auth_ntlm_context *ctx = (http_auth_ntlm_context *)c; + + ntlm_client_free(ctx->ntlm); + git__free(ctx->challenge); + git__free(ctx); +} + +static int ntlmclient_init_context( + http_auth_ntlm_context *ctx, + const git_net_url *url) +{ + GIT_UNUSED(url); + + if ((ctx->ntlm = ntlm_client_init(NTLM_CLIENT_DEFAULTS)) == NULL) { + git_error_set_oom(); + return -1; + } + + return 0; +} + +int git_http_auth_ntlm( + git_http_auth_context **out, + const git_net_url *url) +{ + http_auth_ntlm_context *ctx; + + GIT_UNUSED(url); + + *out = NULL; + + ctx = git__calloc(1, sizeof(http_auth_ntlm_context)); + GIT_ERROR_CHECK_ALLOC(ctx); + + if (ntlmclient_init_context(ctx, url) < 0) { + git__free(ctx); + return -1; + } + + ctx->parent.type = GIT_HTTP_AUTH_NTLM; + ctx->parent.credtypes = GIT_CREDENTIAL_USERPASS_PLAINTEXT; + ctx->parent.connection_affinity = 1; + ctx->parent.set_challenge = ntlmclient_set_challenge; + ctx->parent.next_token = ntlmclient_next_token; + ctx->parent.is_complete = ntlmclient_is_complete; + ctx->parent.free = ntlmclient_context_free; + + *out = (git_http_auth_context *)ctx; + + return 0; +} + +#endif /* GIT_NTLM */ diff --git a/vendor/libgit2/src/libgit2/transports/auth_sspi.c b/vendor/libgit2/src/libgit2/transports/auth_sspi.c new file mode 100644 index 00000000..f8269365 --- /dev/null +++ b/vendor/libgit2/src/libgit2/transports/auth_sspi.c @@ -0,0 +1,341 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "auth_ntlm.h" +#include "auth_negotiate.h" + +#ifdef GIT_WIN32 + +#define SECURITY_WIN32 + +#include "git2.h" +#include "auth.h" +#include "git2/sys/credential.h" + +#include +#include + +typedef struct { + git_http_auth_context parent; + wchar_t *target; + + const char *package_name; + size_t package_name_len; + wchar_t *package_name_w; + SecPkgInfoW *package_info; + SEC_WINNT_AUTH_IDENTITY_W identity; + CredHandle cred; + CtxtHandle context; + + int has_identity : 1, + has_credentials : 1, + has_context : 1, + complete : 1; + git_str challenge; +} http_auth_sspi_context; + +static void sspi_reset_context(http_auth_sspi_context *ctx) +{ + if (ctx->has_identity) { + git__free(ctx->identity.User); + git__free(ctx->identity.Domain); + git__free(ctx->identity.Password); + + memset(&ctx->identity, 0, sizeof(SEC_WINNT_AUTH_IDENTITY_W)); + + ctx->has_identity = 0; + } + + if (ctx->has_credentials) { + FreeCredentialsHandle(&ctx->cred); + memset(&ctx->cred, 0, sizeof(CredHandle)); + + ctx->has_credentials = 0; + } + + if (ctx->has_context) { + DeleteSecurityContext(&ctx->context); + memset(&ctx->context, 0, sizeof(CtxtHandle)); + + ctx->has_context = 0; + } + + ctx->complete = 0; + + git_str_dispose(&ctx->challenge); +} + +static int sspi_set_challenge( + git_http_auth_context *c, + const char *challenge) +{ + http_auth_sspi_context *ctx = (http_auth_sspi_context *)c; + size_t challenge_len = strlen(challenge); + + git_str_clear(&ctx->challenge); + + if (strncmp(challenge, ctx->package_name, ctx->package_name_len) != 0) { + git_error_set(GIT_ERROR_NET, "invalid %s challenge from server", ctx->package_name); + return -1; + } + + /* + * A package type indicator without a base64 payload indicates the + * mechanism; it's not an actual challenge. Ignore it. + */ + if (challenge[ctx->package_name_len] == 0) { + return 0; + } else if (challenge[ctx->package_name_len] != ' ') { + git_error_set(GIT_ERROR_NET, "invalid %s challenge from server", ctx->package_name); + return -1; + } + + if (git_str_decode_base64(&ctx->challenge, + challenge + (ctx->package_name_len + 1), + challenge_len - (ctx->package_name_len + 1)) < 0) { + git_error_set(GIT_ERROR_NET, "invalid %s challenge from server", ctx->package_name); + return -1; + } + + GIT_ASSERT(ctx->challenge.size <= ULONG_MAX); + return 0; +} + +static int create_identity( + SEC_WINNT_AUTH_IDENTITY_W **out, + http_auth_sspi_context *ctx, + git_credential *cred) +{ + git_credential_userpass_plaintext *userpass; + wchar_t *username = NULL, *domain = NULL, *password = NULL; + int username_len = 0, domain_len = 0, password_len = 0; + const char *sep; + + if (cred->credtype == GIT_CREDENTIAL_DEFAULT) { + *out = NULL; + return 0; + } + + if (cred->credtype != GIT_CREDENTIAL_USERPASS_PLAINTEXT) { + git_error_set(GIT_ERROR_NET, "unknown credential type: %d", cred->credtype); + return -1; + } + + userpass = (git_credential_userpass_plaintext *)cred; + + if ((sep = strchr(userpass->username, '\\')) != NULL) { + GIT_ASSERT(sep - userpass->username < INT_MAX); + + username_len = git_utf8_to_16_alloc(&username, sep + 1); + domain_len = git_utf8_to_16_alloc_with_len(&domain, + userpass->username, (int)(sep - userpass->username)); + } else { + username_len = git_utf8_to_16_alloc(&username, + userpass->username); + } + + password_len = git_utf8_to_16_alloc(&password, userpass->password); + + if (username_len < 0 || domain_len < 0 || password_len < 0) { + git__free(username); + git__free(domain); + git__free(password); + return -1; + } + + ctx->identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; + ctx->identity.User = username; + ctx->identity.UserLength = (unsigned long)username_len; + ctx->identity.Password = password; + ctx->identity.PasswordLength = (unsigned long)password_len; + ctx->identity.Domain = domain; + ctx->identity.DomainLength = (unsigned long)domain_len; + + ctx->has_identity = 1; + + *out = &ctx->identity; + + return 0; +} + +static int sspi_next_token( + git_str *buf, + git_http_auth_context *c, + git_credential *cred) +{ + http_auth_sspi_context *ctx = (http_auth_sspi_context *)c; + SEC_WINNT_AUTH_IDENTITY_W *identity = NULL; + TimeStamp timestamp; + DWORD context_flags; + SecBuffer input_buf = { 0, SECBUFFER_TOKEN, NULL }; + SecBuffer output_buf = { 0, SECBUFFER_TOKEN, NULL }; + SecBufferDesc input_buf_desc = { SECBUFFER_VERSION, 1, &input_buf }; + SecBufferDesc output_buf_desc = { SECBUFFER_VERSION, 1, &output_buf }; + SECURITY_STATUS status; + + if (ctx->complete) + sspi_reset_context(ctx); + + if (!ctx->has_context) { + if (create_identity(&identity, ctx, cred) < 0) + return -1; + + status = AcquireCredentialsHandleW(NULL, ctx->package_name_w, + SECPKG_CRED_BOTH, NULL, identity, NULL, + NULL, &ctx->cred, ×tamp); + + if (status != SEC_E_OK) { + git_error_set(GIT_ERROR_OS, "could not acquire credentials"); + return -1; + } + + ctx->has_credentials = 1; + } + + context_flags = ISC_REQ_ALLOCATE_MEMORY | + ISC_REQ_CONFIDENTIALITY | + ISC_REQ_MUTUAL_AUTH; + + if (ctx->challenge.size > 0) { + input_buf.BufferType = SECBUFFER_TOKEN; + input_buf.cbBuffer = (unsigned long)ctx->challenge.size; + input_buf.pvBuffer = ctx->challenge.ptr; + } + + status = InitializeSecurityContextW(&ctx->cred, + ctx->has_context ? &ctx->context : NULL, + ctx->target, + context_flags, + 0, + SECURITY_NETWORK_DREP, + ctx->has_context ? &input_buf_desc : NULL, + 0, + ctx->has_context ? NULL : &ctx->context, + &output_buf_desc, + &context_flags, + NULL); + + if (status == SEC_I_COMPLETE_AND_CONTINUE || + status == SEC_I_COMPLETE_NEEDED) + status = CompleteAuthToken(&ctx->context, &output_buf_desc); + + if (status == SEC_E_OK) { + ctx->complete = 1; + } else if (status != SEC_I_CONTINUE_NEEDED) { + git_error_set(GIT_ERROR_OS, "could not initialize security context"); + return -1; + } + + ctx->has_context = 1; + git_str_clear(&ctx->challenge); + + if (output_buf.cbBuffer > 0) { + git_str_put(buf, ctx->package_name, ctx->package_name_len); + git_str_putc(buf, ' '); + git_str_encode_base64(buf, output_buf.pvBuffer, output_buf.cbBuffer); + + FreeContextBuffer(output_buf.pvBuffer); + + if (git_str_oom(buf)) + return -1; + } + + return 0; +} + +static int sspi_is_complete(git_http_auth_context *c) +{ + http_auth_sspi_context *ctx = (http_auth_sspi_context *)c; + + return ctx->complete; +} + +static void sspi_context_free(git_http_auth_context *c) +{ + http_auth_sspi_context *ctx = (http_auth_sspi_context *)c; + + sspi_reset_context(ctx); + + FreeContextBuffer(ctx->package_info); + git__free(ctx->target); + git__free(ctx); +} + +static int sspi_init_context( + git_http_auth_context **out, + git_http_auth_t type, + const git_net_url *url) +{ + http_auth_sspi_context *ctx; + git_str target = GIT_STR_INIT; + + *out = NULL; + + ctx = git__calloc(1, sizeof(http_auth_sspi_context)); + GIT_ERROR_CHECK_ALLOC(ctx); + + switch (type) { + case GIT_HTTP_AUTH_NTLM: + ctx->package_name = "NTLM"; + ctx->package_name_len = CONST_STRLEN("NTLM"); + ctx->package_name_w = L"NTLM"; + ctx->parent.credtypes = GIT_CREDENTIAL_USERPASS_PLAINTEXT | + GIT_CREDENTIAL_DEFAULT; + break; + case GIT_HTTP_AUTH_NEGOTIATE: + ctx->package_name = "Negotiate"; + ctx->package_name_len = CONST_STRLEN("Negotiate"); + ctx->package_name_w = L"Negotiate"; + ctx->parent.credtypes = GIT_CREDENTIAL_DEFAULT; + break; + default: + git_error_set(GIT_ERROR_NET, "unknown SSPI auth type: %d", ctx->parent.type); + git__free(ctx); + return -1; + } + + if (QuerySecurityPackageInfoW(ctx->package_name_w, &ctx->package_info) != SEC_E_OK) { + git_error_set(GIT_ERROR_OS, "could not query security package"); + git__free(ctx); + return -1; + } + + if (git_str_printf(&target, "http/%s", url->host) < 0 || + git_utf8_to_16_alloc(&ctx->target, target.ptr) < 0) { + FreeContextBuffer(ctx->package_info); + git__free(ctx); + return -1; + } + + ctx->parent.type = type; + ctx->parent.connection_affinity = 1; + ctx->parent.set_challenge = sspi_set_challenge; + ctx->parent.next_token = sspi_next_token; + ctx->parent.is_complete = sspi_is_complete; + ctx->parent.free = sspi_context_free; + + *out = (git_http_auth_context *)ctx; + + git_str_dispose(&target); + return 0; +} + +int git_http_auth_negotiate( + git_http_auth_context **out, + const git_net_url *url) +{ + return sspi_init_context(out, GIT_HTTP_AUTH_NEGOTIATE, url); +} + +int git_http_auth_ntlm( + git_http_auth_context **out, + const git_net_url *url) +{ + return sspi_init_context(out, GIT_HTTP_AUTH_NTLM, url); +} + +#endif /* GIT_WIN32 */ diff --git a/vendor/libgit2/src/transports/credential.c b/vendor/libgit2/src/libgit2/transports/credential.c similarity index 99% rename from vendor/libgit2/src/transports/credential.c rename to vendor/libgit2/src/libgit2/transports/credential.c index 6e00b028..7d0eacec 100644 --- a/vendor/libgit2/src/transports/credential.c +++ b/vendor/libgit2/src/libgit2/transports/credential.c @@ -161,7 +161,7 @@ static void ssh_custom_free(struct git_credential *cred) if (c->publickey) { /* Zero the memory which previously held the publickey */ - size_t key_len = strlen(c->publickey); + size_t key_len = c->publickey_len; git__memzero(c->publickey, key_len); git__free(c->publickey); } @@ -204,7 +204,7 @@ int git_credential_ssh_key_memory_new( const char *privatekey, const char *passphrase) { -#ifdef GIT_SSH_MEMORY_CREDENTIALS +#ifdef GIT_SSH_LIBSSH2_MEMORY_CREDENTIALS return git_credential_ssh_key_type_new( cred, username, diff --git a/vendor/libgit2/src/transports/credential_helpers.c b/vendor/libgit2/src/libgit2/transports/credential_helpers.c similarity index 100% rename from vendor/libgit2/src/transports/credential_helpers.c rename to vendor/libgit2/src/libgit2/transports/credential_helpers.c diff --git a/vendor/libgit2/src/transports/git.c b/vendor/libgit2/src/libgit2/transports/git.c similarity index 97% rename from vendor/libgit2/src/transports/git.c rename to vendor/libgit2/src/libgit2/transports/git.c index 591e2ab0..53611f2a 100644 --- a/vendor/libgit2/src/transports/git.c +++ b/vendor/libgit2/src/libgit2/transports/git.c @@ -7,7 +7,7 @@ #include "common.h" -#include "netops.h" +#include "net.h" #include "stream.h" #include "streams/socket.h" #include "git2/sys/transport.h" @@ -95,22 +95,21 @@ static int git_proto_stream_read( size_t buf_size, size_t *bytes_read) { - int error; git_proto_stream *s = (git_proto_stream *)stream; - gitno_buffer buf; + ssize_t ret; + int error; *bytes_read = 0; if (!s->sent_command && (error = send_command(s)) < 0) return error; - gitno_buffer_setup_fromstream(s->io, &buf, buffer, buf_size); + ret = git_stream_read(s->io, buffer, min(buf_size, INT_MAX)); - if ((error = gitno_recv(&buf)) < 0) - return error; - - *bytes_read = buf.offset; + if (ret < 0) + return -1; + *bytes_read = (size_t)ret; return 0; } diff --git a/vendor/libgit2/src/libgit2/transports/http.c b/vendor/libgit2/src/libgit2/transports/http.c new file mode 100644 index 00000000..ea819952 --- /dev/null +++ b/vendor/libgit2/src/libgit2/transports/http.c @@ -0,0 +1,765 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "common.h" + +#ifndef GIT_WINHTTP + +#include "net.h" +#include "remote.h" +#include "smart.h" +#include "auth.h" +#include "http.h" +#include "auth_negotiate.h" +#include "auth_ntlm.h" +#include "trace.h" +#include "streams/tls.h" +#include "streams/socket.h" +#include "httpclient.h" +#include "git2/sys/credential.h" + +bool git_http__expect_continue = false; + +typedef enum { + HTTP_STATE_NONE = 0, + HTTP_STATE_SENDING_REQUEST, + HTTP_STATE_RECEIVING_RESPONSE, + HTTP_STATE_DONE +} http_state; + +typedef struct { + git_http_method method; + const char *url; + const char *request_type; + const char *response_type; + unsigned int initial : 1, + chunked : 1; +} http_service; + +typedef struct { + git_smart_subtransport_stream parent; + const http_service *service; + http_state state; + unsigned replay_count; +} http_stream; + +typedef struct { + git_net_url url; + + git_credential *cred; + unsigned auth_schemetypes; + unsigned url_cred_presented : 1; +} http_server; + +typedef struct { + git_smart_subtransport parent; + transport_smart *owner; + + http_server server; + http_server proxy; + + git_http_client *http_client; +} http_subtransport; + +static const http_service upload_pack_ls_service = { + GIT_HTTP_METHOD_GET, "/info/refs?service=git-upload-pack", + NULL, + "application/x-git-upload-pack-advertisement", + 1, + 0 +}; +static const http_service upload_pack_service = { + GIT_HTTP_METHOD_POST, "/git-upload-pack", + "application/x-git-upload-pack-request", + "application/x-git-upload-pack-result", + 0, + 0 +}; +static const http_service receive_pack_ls_service = { + GIT_HTTP_METHOD_GET, "/info/refs?service=git-receive-pack", + NULL, + "application/x-git-receive-pack-advertisement", + 1, + 0 +}; +static const http_service receive_pack_service = { + GIT_HTTP_METHOD_POST, "/git-receive-pack", + "application/x-git-receive-pack-request", + "application/x-git-receive-pack-result", + 0, + 1 +}; + +#define SERVER_TYPE_REMOTE "remote" +#define SERVER_TYPE_PROXY "proxy" + +#define OWNING_SUBTRANSPORT(s) ((http_subtransport *)(s)->parent.subtransport) + +static int apply_url_credentials( + git_credential **cred, + unsigned int allowed_types, + const char *username, + const char *password) +{ + GIT_ASSERT_ARG(username); + + if (!password) + password = ""; + + if (allowed_types & GIT_CREDENTIAL_USERPASS_PLAINTEXT) + return git_credential_userpass_plaintext_new(cred, username, password); + + if ((allowed_types & GIT_CREDENTIAL_DEFAULT) && *username == '\0' && *password == '\0') + return git_credential_default_new(cred); + + return GIT_PASSTHROUGH; +} + +GIT_INLINE(void) free_cred(git_credential **cred) +{ + if (*cred) { + git_credential_free(*cred); + (*cred) = NULL; + } +} + +static int handle_auth( + http_server *server, + const char *server_type, + const char *url, + unsigned int allowed_schemetypes, + unsigned int allowed_credtypes, + git_credential_acquire_cb callback, + void *callback_payload) +{ + int error = 1; + + if (server->cred) + free_cred(&server->cred); + + /* Start with URL-specified credentials, if there were any. */ + if ((allowed_credtypes & GIT_CREDENTIAL_USERPASS_PLAINTEXT) && + !server->url_cred_presented && + server->url.username) { + error = apply_url_credentials(&server->cred, allowed_credtypes, server->url.username, server->url.password); + server->url_cred_presented = 1; + + /* treat GIT_PASSTHROUGH as if callback isn't set */ + if (error == GIT_PASSTHROUGH) + error = 1; + } + + if (error > 0 && callback) { + error = callback(&server->cred, url, server->url.username, allowed_credtypes, callback_payload); + + /* treat GIT_PASSTHROUGH as if callback isn't set */ + if (error == GIT_PASSTHROUGH) + error = 1; + } + + if (error > 0) { + git_error_set(GIT_ERROR_HTTP, "%s authentication required but no callback set", server_type); + error = GIT_EAUTH; + } + + if (!error) + server->auth_schemetypes = allowed_schemetypes; + + return error; +} + +GIT_INLINE(int) handle_remote_auth( + http_stream *stream, + git_http_response *response) +{ + http_subtransport *transport = OWNING_SUBTRANSPORT(stream); + git_remote_connect_options *connect_opts = &transport->owner->connect_opts; + + if (response->server_auth_credtypes == 0) { + git_error_set(GIT_ERROR_HTTP, "server requires authentication that we do not support"); + return GIT_EAUTH; + } + + /* Otherwise, prompt for credentials. */ + return handle_auth( + &transport->server, + SERVER_TYPE_REMOTE, + transport->owner->url, + response->server_auth_schemetypes, + response->server_auth_credtypes, + connect_opts->callbacks.credentials, + connect_opts->callbacks.payload); +} + +GIT_INLINE(int) handle_proxy_auth( + http_stream *stream, + git_http_response *response) +{ + http_subtransport *transport = OWNING_SUBTRANSPORT(stream); + git_remote_connect_options *connect_opts = &transport->owner->connect_opts; + + if (response->proxy_auth_credtypes == 0) { + git_error_set(GIT_ERROR_HTTP, "proxy requires authentication that we do not support"); + return GIT_EAUTH; + } + + /* Otherwise, prompt for credentials. */ + return handle_auth( + &transport->proxy, + SERVER_TYPE_PROXY, + connect_opts->proxy_opts.url, + response->server_auth_schemetypes, + response->proxy_auth_credtypes, + connect_opts->proxy_opts.credentials, + connect_opts->proxy_opts.payload); +} + +static bool allow_redirect(http_stream *stream) +{ + http_subtransport *transport = OWNING_SUBTRANSPORT(stream); + + switch (transport->owner->connect_opts.follow_redirects) { + case GIT_REMOTE_REDIRECT_INITIAL: + return (stream->service->initial == 1); + case GIT_REMOTE_REDIRECT_ALL: + return true; + default: + return false; + } +} + +static int handle_response( + bool *complete, + http_stream *stream, + git_http_response *response, + bool allow_replay) +{ + http_subtransport *transport = OWNING_SUBTRANSPORT(stream); + int error; + + *complete = false; + + if (allow_replay && git_http_response_is_redirect(response)) { + if (!response->location) { + git_error_set(GIT_ERROR_HTTP, "redirect without location"); + return -1; + } + + if (git_net_url_apply_redirect(&transport->server.url, response->location, allow_redirect(stream), stream->service->url) < 0) { + return -1; + } + + return 0; + } else if (git_http_response_is_redirect(response)) { + git_error_set(GIT_ERROR_HTTP, "unexpected redirect"); + return -1; + } + + /* If we're in the middle of challenge/response auth, continue. */ + if (allow_replay && response->resend_credentials) { + return 0; + } else if (allow_replay && response->status == GIT_HTTP_STATUS_UNAUTHORIZED) { + if ((error = handle_remote_auth(stream, response)) < 0) + return error; + + return git_http_client_skip_body(transport->http_client); + } else if (allow_replay && response->status == GIT_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED) { + if ((error = handle_proxy_auth(stream, response)) < 0) + return error; + + return git_http_client_skip_body(transport->http_client); + } else if (response->status == GIT_HTTP_STATUS_UNAUTHORIZED || + response->status == GIT_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED) { + git_error_set(GIT_ERROR_HTTP, "unexpected authentication failure"); + return GIT_EAUTH; + } + + if (response->status != GIT_HTTP_STATUS_OK) { + git_error_set(GIT_ERROR_HTTP, "unexpected http status code: %d", response->status); + return -1; + } + + /* The response must contain a Content-Type header. */ + if (!response->content_type) { + git_error_set(GIT_ERROR_HTTP, "no content-type header in response"); + return -1; + } + + /* The Content-Type header must match our expectation. */ + if (strcmp(response->content_type, stream->service->response_type) != 0) { + git_error_set(GIT_ERROR_HTTP, "invalid content-type: '%s'", response->content_type); + return -1; + } + + *complete = true; + stream->state = HTTP_STATE_RECEIVING_RESPONSE; + return 0; +} + +static int lookup_proxy( + bool *out_use, + http_subtransport *transport) +{ + git_remote_connect_options *connect_opts = &transport->owner->connect_opts; + const char *proxy; + git_remote *remote; + char *config = NULL; + int error = 0; + + *out_use = false; + git_net_url_dispose(&transport->proxy.url); + + switch (connect_opts->proxy_opts.type) { + case GIT_PROXY_SPECIFIED: + proxy = connect_opts->proxy_opts.url; + break; + + case GIT_PROXY_AUTO: + remote = transport->owner->owner; + + error = git_remote__http_proxy(&config, remote, &transport->server.url); + + if (error || !config) + goto done; + + proxy = config; + break; + + default: + return 0; + } + + if (!proxy || !*proxy || + (error = git_net_url_parse_http(&transport->proxy.url, proxy)) < 0) + goto done; + + if (!git_net_url_valid(&transport->proxy.url)) { + git_error_set(GIT_ERROR_HTTP, "invalid URL: '%s'", proxy); + error = -1; + goto done; + } + + *out_use = true; + +done: + git__free(config); + return error; +} + +static int generate_request( + git_net_url *url, + git_http_request *request, + http_stream *stream, + size_t len) +{ + http_subtransport *transport = OWNING_SUBTRANSPORT(stream); + bool use_proxy = false; + int error; + + if ((error = git_net_url_joinpath(url, + &transport->server.url, stream->service->url)) < 0 || + (error = lookup_proxy(&use_proxy, transport)) < 0) + return error; + + request->method = stream->service->method; + request->url = url; + request->credentials = transport->server.cred; + request->proxy = use_proxy ? &transport->proxy.url : NULL; + request->proxy_credentials = transport->proxy.cred; + request->custom_headers = &transport->owner->connect_opts.custom_headers; + + if (stream->service->method == GIT_HTTP_METHOD_POST) { + request->chunked = stream->service->chunked; + request->content_length = stream->service->chunked ? 0 : len; + request->content_type = stream->service->request_type; + request->accept = stream->service->response_type; + request->expect_continue = git_http__expect_continue; + } + + return 0; +} + +/* + * Read from an HTTP transport - for the first invocation of this function + * (ie, when stream->state == HTTP_STATE_NONE), we'll send a GET request + * to the remote host. We will stream that data back on all subsequent + * calls. + */ +static int http_stream_read( + git_smart_subtransport_stream *s, + char *buffer, + size_t buffer_size, + size_t *out_len) +{ + http_stream *stream = (http_stream *)s; + http_subtransport *transport = OWNING_SUBTRANSPORT(stream); + git_net_url url = GIT_NET_URL_INIT; + git_net_url proxy_url = GIT_NET_URL_INIT; + git_http_request request = {0}; + git_http_response response = {0}; + bool complete; + int error; + + *out_len = 0; + + if (stream->state == HTTP_STATE_NONE) { + stream->state = HTTP_STATE_SENDING_REQUEST; + stream->replay_count = 0; + } + + /* + * Formulate the URL, send the request and read the response + * headers. Some of the request body may also be read. + */ + while (stream->state == HTTP_STATE_SENDING_REQUEST && + stream->replay_count < GIT_HTTP_REPLAY_MAX) { + git_net_url_dispose(&url); + git_net_url_dispose(&proxy_url); + git_http_response_dispose(&response); + + if ((error = generate_request(&url, &request, stream, 0)) < 0 || + (error = git_http_client_send_request( + transport->http_client, &request)) < 0 || + (error = git_http_client_read_response( + &response, transport->http_client)) < 0 || + (error = handle_response(&complete, stream, &response, true)) < 0) + goto done; + + if (complete) + break; + + stream->replay_count++; + } + + if (stream->state == HTTP_STATE_SENDING_REQUEST) { + git_error_set(GIT_ERROR_HTTP, "too many redirects or authentication replays"); + error = GIT_ERROR; /* not GIT_EAUTH, because the exact cause is unclear */ + goto done; + } + + GIT_ASSERT(stream->state == HTTP_STATE_RECEIVING_RESPONSE); + + error = git_http_client_read_body(transport->http_client, buffer, buffer_size); + + if (error > 0) { + *out_len = error; + error = 0; + } + +done: + git_net_url_dispose(&url); + git_net_url_dispose(&proxy_url); + git_http_response_dispose(&response); + + return error; +} + +static bool needs_probe(http_stream *stream) +{ + http_subtransport *transport = OWNING_SUBTRANSPORT(stream); + + return (transport->server.auth_schemetypes == GIT_HTTP_AUTH_NTLM || + transport->server.auth_schemetypes == GIT_HTTP_AUTH_NEGOTIATE); +} + +static int send_probe(http_stream *stream) +{ + http_subtransport *transport = OWNING_SUBTRANSPORT(stream); + git_http_client *client = transport->http_client; + const char *probe = "0000"; + size_t len = 4; + git_net_url url = GIT_NET_URL_INIT; + git_http_request request = {0}; + git_http_response response = {0}; + bool complete = false; + size_t step, steps = 1; + int error; + + /* NTLM requires a full challenge/response */ + if (transport->server.auth_schemetypes == GIT_HTTP_AUTH_NTLM) + steps = GIT_AUTH_STEPS_NTLM; + + /* + * Send at most two requests: one without any authentication to see + * if we get prompted to authenticate. If we do, send a second one + * with the first authentication message. The final authentication + * message with the response will occur with the *actual* POST data. + */ + for (step = 0; step < steps && !complete; step++) { + git_net_url_dispose(&url); + git_http_response_dispose(&response); + + if ((error = generate_request(&url, &request, stream, len)) < 0 || + (error = git_http_client_send_request(client, &request)) < 0 || + (error = git_http_client_send_body(client, probe, len)) < 0 || + (error = git_http_client_read_response(&response, client)) < 0 || + (error = git_http_client_skip_body(client)) < 0 || + (error = handle_response(&complete, stream, &response, true)) < 0) + goto done; + } + +done: + git_http_response_dispose(&response); + git_net_url_dispose(&url); + return error; +} + +/* +* Write to an HTTP transport - for the first invocation of this function +* (ie, when stream->state == HTTP_STATE_NONE), we'll send a POST request +* to the remote host. If we're sending chunked data, then subsequent calls +* will write the additional data given in the buffer. If we're not chunking, +* then the caller should have given us all the data in the original call. +* The caller should call http_stream_read_response to get the result. +*/ +static int http_stream_write( + git_smart_subtransport_stream *s, + const char *buffer, + size_t len) +{ + http_stream *stream = GIT_CONTAINER_OF(s, http_stream, parent); + http_subtransport *transport = OWNING_SUBTRANSPORT(stream); + git_net_url url = GIT_NET_URL_INIT; + git_http_request request = {0}; + git_http_response response = {0}; + int error; + + while (stream->state == HTTP_STATE_NONE && + stream->replay_count < GIT_HTTP_REPLAY_MAX) { + + git_net_url_dispose(&url); + git_http_response_dispose(&response); + + /* + * If we're authenticating with a connection-based mechanism + * (NTLM, Kerberos), send a "probe" packet. Servers SHOULD + * authenticate an entire keep-alive connection, so ideally + * we should not need to authenticate but some servers do + * not support this. By sending a probe packet, we'll be + * able to follow up with a second POST using the actual + * data (and, in the degenerate case, the authentication + * header as well). + */ + if (needs_probe(stream) && (error = send_probe(stream)) < 0) + goto done; + + /* Send the regular POST request. */ + if ((error = generate_request(&url, &request, stream, len)) < 0 || + (error = git_http_client_send_request( + transport->http_client, &request)) < 0) + goto done; + + if (request.expect_continue && + git_http_client_has_response(transport->http_client)) { + bool complete; + + /* + * If we got a response to an expect/continue, then + * it's something other than a 100 and we should + * deal with the response somehow. + */ + if ((error = git_http_client_read_response(&response, transport->http_client)) < 0 || + (error = handle_response(&complete, stream, &response, true)) < 0) + goto done; + } else { + stream->state = HTTP_STATE_SENDING_REQUEST; + } + + stream->replay_count++; + } + + if (stream->state == HTTP_STATE_NONE) { + git_error_set(GIT_ERROR_HTTP, + "too many redirects or authentication replays"); + error = GIT_ERROR; /* not GIT_EAUTH because the exact cause is unclear */ + goto done; + } + + GIT_ASSERT(stream->state == HTTP_STATE_SENDING_REQUEST); + + error = git_http_client_send_body(transport->http_client, buffer, len); + +done: + git_http_response_dispose(&response); + git_net_url_dispose(&url); + return error; +} + +/* +* Read from an HTTP transport after it has been written to. This is the +* response from a POST request made by http_stream_write. +*/ +static int http_stream_read_response( + git_smart_subtransport_stream *s, + char *buffer, + size_t buffer_size, + size_t *out_len) +{ + http_stream *stream = (http_stream *)s; + http_subtransport *transport = OWNING_SUBTRANSPORT(stream); + git_http_client *client = transport->http_client; + git_http_response response = {0}; + bool complete; + int error; + + *out_len = 0; + + if (stream->state == HTTP_STATE_SENDING_REQUEST) { + if ((error = git_http_client_read_response(&response, client)) < 0 || + (error = handle_response(&complete, stream, &response, false)) < 0) + goto done; + + GIT_ASSERT(complete); + stream->state = HTTP_STATE_RECEIVING_RESPONSE; + } + + error = git_http_client_read_body(client, buffer, buffer_size); + + if (error > 0) { + *out_len = error; + error = 0; + } + +done: + git_http_response_dispose(&response); + return error; +} + +static void http_stream_free(git_smart_subtransport_stream *stream) +{ + http_stream *s = GIT_CONTAINER_OF(stream, http_stream, parent); + git__free(s); +} + +static const http_service *select_service(git_smart_service_t action) +{ + switch (action) { + case GIT_SERVICE_UPLOADPACK_LS: + return &upload_pack_ls_service; + case GIT_SERVICE_UPLOADPACK: + return &upload_pack_service; + case GIT_SERVICE_RECEIVEPACK_LS: + return &receive_pack_ls_service; + case GIT_SERVICE_RECEIVEPACK: + return &receive_pack_service; + } + + return NULL; +} + +static int http_action( + git_smart_subtransport_stream **out, + git_smart_subtransport *t, + const char *url, + git_smart_service_t action) +{ + http_subtransport *transport = GIT_CONTAINER_OF(t, http_subtransport, parent); + git_remote_connect_options *connect_opts = &transport->owner->connect_opts; + git_http_client_options opts = {0}; + http_stream *stream; + const http_service *service; + int error; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(t); + + *out = NULL; + + /* + * If we've seen a redirect then preserve the location that we've + * been given. This is important to continue authorization against + * the redirect target, not the user-given source; the endpoint may + * have redirected us from HTTP->HTTPS and is using an auth mechanism + * that would be insecure in plaintext (eg, HTTP Basic). + */ + if (!git_net_url_valid(&transport->server.url) && + (error = git_net_url_parse(&transport->server.url, url)) < 0) + return error; + + if ((service = select_service(action)) == NULL) { + git_error_set(GIT_ERROR_HTTP, "invalid action"); + return -1; + } + + stream = git__calloc(sizeof(http_stream), 1); + GIT_ERROR_CHECK_ALLOC(stream); + + opts.server_certificate_check_cb = connect_opts->callbacks.certificate_check; + opts.server_certificate_check_payload = connect_opts->callbacks.payload; + opts.proxy_certificate_check_cb = connect_opts->proxy_opts.certificate_check; + opts.proxy_certificate_check_payload = connect_opts->proxy_opts.payload; + + if (transport->http_client) { + git_http_client_set_options(transport->http_client, &opts); + } else { + if (git_http_client_new(&transport->http_client, &opts) < 0) + return -1; + } + + stream->service = service; + stream->parent.subtransport = &transport->parent; + + if (service->method == GIT_HTTP_METHOD_GET) { + stream->parent.read = http_stream_read; + } else { + stream->parent.write = http_stream_write; + stream->parent.read = http_stream_read_response; + } + + stream->parent.free = http_stream_free; + + *out = (git_smart_subtransport_stream *)stream; + return 0; +} + +static int http_close(git_smart_subtransport *t) +{ + http_subtransport *transport = GIT_CONTAINER_OF(t, http_subtransport, parent); + + free_cred(&transport->server.cred); + free_cred(&transport->proxy.cred); + + transport->server.url_cred_presented = false; + transport->proxy.url_cred_presented = false; + + git_net_url_dispose(&transport->server.url); + git_net_url_dispose(&transport->proxy.url); + + return 0; +} + +static void http_free(git_smart_subtransport *t) +{ + http_subtransport *transport = GIT_CONTAINER_OF(t, http_subtransport, parent); + + git_http_client_free(transport->http_client); + + http_close(t); + git__free(transport); +} + +int git_smart_subtransport_http(git_smart_subtransport **out, git_transport *owner, void *param) +{ + http_subtransport *transport; + + GIT_UNUSED(param); + + GIT_ASSERT_ARG(out); + + transport = git__calloc(sizeof(http_subtransport), 1); + GIT_ERROR_CHECK_ALLOC(transport); + + transport->owner = (transport_smart *)owner; + transport->parent.action = http_action; + transport->parent.close = http_close; + transport->parent.free = http_free; + + *out = (git_smart_subtransport *) transport; + return 0; +} + +#endif /* !GIT_WINHTTP */ diff --git a/vendor/libgit2/src/libgit2/transports/http.h b/vendor/libgit2/src/libgit2/transports/http.h new file mode 100644 index 00000000..7410202a --- /dev/null +++ b/vendor/libgit2/src/libgit2/transports/http.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_transports_http_h__ +#define INCLUDE_transports_http_h__ + +#include "settings.h" +#include "httpclient.h" + +#define GIT_HTTP_REPLAY_MAX 15 + +extern bool git_http__expect_continue; + +#endif diff --git a/vendor/libgit2/src/transports/httpclient.c b/vendor/libgit2/src/libgit2/transports/httpclient.c similarity index 91% rename from vendor/libgit2/src/transports/httpclient.c rename to vendor/libgit2/src/libgit2/transports/httpclient.c index 75782da8..a0c4002e 100644 --- a/vendor/libgit2/src/transports/httpclient.c +++ b/vendor/libgit2/src/libgit2/transports/httpclient.c @@ -7,7 +7,7 @@ #include "common.h" #include "git2.h" -#include "http_parser.h" + #include "vector.h" #include "trace.h" #include "httpclient.h" @@ -21,6 +21,7 @@ #include "streams/socket.h" #include "streams/tls.h" #include "auth.h" +#include "httpparser.h" static git_http_auth_scheme auth_schemes[] = { { GIT_HTTP_AUTH_NEGOTIATE, "Negotiate", GIT_CREDENTIAL_DEFAULT, git_http_auth_negotiate }, @@ -108,7 +109,7 @@ struct git_http_client { git_http_server_t current_server; http_client_state state; - http_parser parser; + git_http_parser parser; git_http_server server; git_http_server proxy; @@ -154,7 +155,7 @@ void git_http_response_dispose(git_http_response *response) memset(response, 0, sizeof(git_http_response)); } -static int on_header_complete(http_parser *parser) +static int on_header_complete(git_http_parser *parser) { http_parser_context *ctx = (http_parser_context *) parser->data; git_http_client *client = ctx->client; @@ -219,7 +220,7 @@ static int on_header_complete(http_parser *parser) return 0; } -static int on_header_field(http_parser *parser, const char *str, size_t len) +static int on_header_field(git_http_parser *parser, const char *str, size_t len) { http_parser_context *ctx = (http_parser_context *) parser->data; @@ -254,7 +255,7 @@ static int on_header_field(http_parser *parser, const char *str, size_t len) return 0; } -static int on_header_value(http_parser *parser, const char *str, size_t len) +static int on_header_value(git_http_parser *parser, const char *str, size_t len) { http_parser_context *ctx = (http_parser_context *) parser->data; @@ -342,7 +343,7 @@ static int resend_needed(git_http_client *client, git_http_response *response) return 0; } -static int on_headers_complete(http_parser *parser) +static int on_headers_complete(git_http_parser *parser) { http_parser_context *ctx = (http_parser_context *) parser->data; @@ -364,8 +365,8 @@ static int on_headers_complete(http_parser *parser) return ctx->parse_status = PARSE_STATUS_ERROR; } - ctx->response->status = parser->status_code; - ctx->client->keepalive = http_should_keep_alive(parser); + ctx->response->status = git_http_parser_status_code(parser); + ctx->client->keepalive = git_http_parser_keep_alive(parser); /* Prepare for authentication */ collect_authinfo(&ctx->response->server_auth_schemetypes, @@ -378,24 +379,21 @@ static int on_headers_complete(http_parser *parser) ctx->response->resend_credentials = resend_needed(ctx->client, ctx->response); - /* Stop parsing. */ - http_parser_pause(parser, 1); - if (ctx->response->content_type || ctx->response->chunked) ctx->client->state = READING_BODY; else ctx->client->state = DONE; - return 0; + return git_http_parser_pause(parser); } -static int on_body(http_parser *parser, const char *buf, size_t len) +static int on_body(git_http_parser *parser, const char *buf, size_t len) { http_parser_context *ctx = (http_parser_context *) parser->data; size_t max_len; /* Saw data when we expected not to (eg, in consume_response_body) */ - if (ctx->output_buf == NULL && ctx->output_size == 0) { + if (ctx->output_buf == NULL || ctx->output_size == 0) { ctx->parse_status = PARSE_STATUS_NO_OUTPUT; return 0; } @@ -411,7 +409,7 @@ static int on_body(http_parser *parser, const char *buf, size_t len) return 0; } -static int on_message_complete(http_parser *parser) +static int on_message_complete(git_http_parser *parser) { http_parser_context *ctx = (http_parser_context *) parser->data; @@ -651,6 +649,30 @@ static int puts_host_and_port(git_str *buf, git_net_url *url, bool force_port) return git_str_oom(buf) ? -1 : 0; } +static int append_user_agent(git_str *buf) +{ + const char *product = git_settings__user_agent_product(); + const char *comment = git_settings__user_agent(); + + GIT_ASSERT(product && comment); + + if (!*product) + return 0; + + git_str_puts(buf, "User-Agent: "); + git_str_puts(buf, product); + + if (*comment) { + git_str_puts(buf, " ("); + git_str_puts(buf, comment); + git_str_puts(buf, ")"); + } + + git_str_puts(buf, "\r\n"); + + return git_str_oom(buf) ? -1 : 0; +} + static int generate_connect_request( git_http_client *client, git_http_request *request) @@ -665,9 +687,7 @@ static int generate_connect_request( puts_host_and_port(buf, &client->server.url, true); git_str_puts(buf, " HTTP/1.1\r\n"); - git_str_puts(buf, "User-Agent: "); - git_http__user_agent(buf); - git_str_puts(buf, "\r\n"); + append_user_agent(buf); git_str_puts(buf, "Host: "); puts_host_and_port(buf, &client->server.url, true); @@ -711,9 +731,7 @@ static int generate_request( git_str_puts(buf, " HTTP/1.1\r\n"); - git_str_puts(buf, "User-Agent: "); - git_http__user_agent(buf); - git_str_puts(buf, "\r\n"); + append_user_agent(buf); git_str_puts(buf, "Host: "); puts_host_and_port(buf, request->url, false); @@ -768,25 +786,37 @@ static int check_certificate( void *cert_cb_payload) { git_cert *cert; - git_error_state last_error = {0}; + git_error *last_error; int error; if ((error = git_stream_certificate(&cert, stream)) < 0) return error; - git_error_state_capture(&last_error, GIT_ECERTIFICATE); + /* + * Allow callers to set an error - but save ours and clear + * it, so that we can detect if they set one and restore it + * if we need to. + */ + git_error_save(&last_error); + git_error_clear(); error = cert_cb(cert, is_valid, url->host, cert_cb_payload); - if (error == GIT_PASSTHROUGH && !is_valid) - return git_error_state_restore(&last_error); - else if (error == GIT_PASSTHROUGH) - error = 0; - else if (error && !git_error_last()) - git_error_set(GIT_ERROR_HTTP, - "user rejected certificate for %s", url->host); + if (error == GIT_PASSTHROUGH) { + error = is_valid ? 0 : -1; - git_error_state_free(&last_error); + if (error) { + git_error_restore(last_error); + last_error = NULL; + } + } else if (error) { + if (!git_error_exists()) + git_error_set(GIT_ERROR_HTTP, + "user rejected certificate for %s", + url->host); + } + + git_error_free(last_error); return error; } @@ -837,6 +867,11 @@ GIT_INLINE(int) server_setup_from_url( git_http_server *server, git_net_url *url) { + GIT_ASSERT_ARG(url); + GIT_ASSERT_ARG(url->scheme); + GIT_ASSERT_ARG(url->host); + GIT_ASSERT_ARG(url->port); + if (!server->url.scheme || strcmp(server->url.scheme, url->scheme) || !server->url.host || strcmp(server->url.host, url->host) || !server->url.port || strcmp(server->url.port, url->port)) { @@ -859,9 +894,29 @@ GIT_INLINE(int) server_setup_from_url( return 0; } +static bool parser_settings_initialized; +static git_http_parser_settings parser_settings; + +GIT_INLINE(git_http_parser_settings *) http_client_parser_settings(void) +{ + if (!parser_settings_initialized) { + parser_settings.on_header_field = on_header_field; + parser_settings.on_header_value = on_header_value; + parser_settings.on_headers_complete = on_headers_complete; + parser_settings.on_body = on_body; + parser_settings.on_message_complete = on_message_complete; + + parser_settings_initialized = true; + } + + return &parser_settings; +} + static void reset_parser(git_http_client *client) { - http_parser_init(&client->parser, HTTP_RESPONSE); + git_http_parser_init(&client->parser, + GIT_HTTP_PARSER_RESPONSE, + http_client_parser_settings()); } static int setup_hosts( @@ -1104,27 +1159,9 @@ GIT_INLINE(int) client_read(git_http_client *client) return (int)read_len; } -static bool parser_settings_initialized; -static http_parser_settings parser_settings; - -GIT_INLINE(http_parser_settings *) http_client_parser_settings(void) -{ - if (!parser_settings_initialized) { - parser_settings.on_header_field = on_header_field; - parser_settings.on_header_value = on_header_value; - parser_settings.on_headers_complete = on_headers_complete; - parser_settings.on_body = on_body; - parser_settings.on_message_complete = on_message_complete; - - parser_settings_initialized = true; - } - - return &parser_settings; -} - GIT_INLINE(int) client_read_and_parse(git_http_client *client) { - http_parser *parser = &client->parser; + git_http_parser *parser = &client->parser; http_parser_context *ctx = (http_parser_context *) parser->data; unsigned char http_errno; int read_len; @@ -1138,11 +1175,10 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client) if (!client->read_buf.size && (read_len = client_read(client)) < 0) return read_len; - parsed_len = http_parser_execute(parser, - http_client_parser_settings(), + parsed_len = git_http_parser_execute(parser, client->read_buf.ptr, client->read_buf.size); - http_errno = client->parser.http_errno; + http_errno = git_http_parser_errno(parser); if (parsed_len > INT_MAX) { git_error_set(GIT_ERROR_HTTP, "unexpectedly large parse"); @@ -1161,26 +1197,29 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client) * (This can happen in response to an expect/continue request, * where the server gives you a 100 and 200 simultaneously.) */ - if (http_errno == HPE_PAUSED) { + if (http_errno == GIT_HTTP_PARSER_PAUSED) { + size_t additional_size; + + git_http_parser_resume(parser); + /* - * http-parser has a "feature" where it will not deliver the - * final byte when paused in a callback. Consume that byte. - * https://github.com/nodejs/http-parser/issues/97 + * http-parser has a "feature" where it will not deliver + * the final byte when paused in a callback. Consume + * that byte. */ - GIT_ASSERT(client->read_buf.size > parsed_len); + if ((additional_size = git_http_parser_remain_after_pause(parser)) > 0) { + GIT_ASSERT((client->read_buf.size - parsed_len) >= additional_size); - http_parser_pause(parser, 0); - - parsed_len += http_parser_execute(parser, - http_client_parser_settings(), - client->read_buf.ptr + parsed_len, - 1); + parsed_len += git_http_parser_execute(parser, + client->read_buf.ptr + parsed_len, + additional_size); + } } /* Most failures will be reported in http_errno */ - else if (parser->http_errno != HPE_OK) { + else if (git_http_parser_errno(parser) != GIT_HTTP_PARSER_OK) { git_error_set(GIT_ERROR_HTTP, "http parser error: %s", - http_errno_description(http_errno)); + git_http_parser_errmsg(parser, http_errno)); return -1; } @@ -1188,7 +1227,7 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client) else if (parsed_len != client->read_buf.size) { git_error_set(GIT_ERROR_HTTP, "http parser did not consume entire buffer: %s", - http_errno_description(http_errno)); + git_http_parser_errmsg(parser, http_errno)); return -1; } @@ -1227,7 +1266,7 @@ static void complete_response_body(git_http_client *client) /* If there was an error, just close the connection. */ if (client_read_and_parse(client) < 0 || - parser_context.error != HPE_OK || + parser_context.error != GIT_HTTP_PARSER_OK || (parser_context.parse_status != PARSE_STATUS_OK && parser_context.parse_status != PARSE_STATUS_NO_OUTPUT)) { git_error_clear(); @@ -1235,6 +1274,7 @@ static void complete_response_body(git_http_client *client) } done: + client->parser.data = NULL; git_str_clear(&client->read_buf); } @@ -1424,6 +1464,7 @@ int git_http_client_read_response( done: git_str_dispose(&parser_context.parse_header_name); git_str_dispose(&parser_context.parse_header_value); + client->parser.data = NULL; return error; } @@ -1479,6 +1520,8 @@ int git_http_client_read_body( if (error < 0) client->connected = 0; + client->parser.data = NULL; + return error; } @@ -1501,7 +1544,7 @@ int git_http_client_skip_body(git_http_client *client) do { error = client_read_and_parse(client); - if (parser_context.error != HPE_OK || + if (parser_context.error != GIT_HTTP_PARSER_OK || (parser_context.parse_status != PARSE_STATUS_OK && parser_context.parse_status != PARSE_STATUS_NO_OUTPUT)) { git_error_set(GIT_ERROR_HTTP, @@ -1513,6 +1556,8 @@ int git_http_client_skip_body(git_http_client *client) if (error < 0) client->connected = 0; + client->parser.data = NULL; + return error; } @@ -1541,6 +1586,15 @@ int git_http_client_new( return 0; } +/* Update the options of an existing httpclient instance. */ +void git_http_client_set_options( + git_http_client *client, + git_http_client_options *opts) +{ + if (opts) + memcpy(&client->opts, opts, sizeof(git_http_client_options)); +} + GIT_INLINE(void) http_server_close(git_http_server *server) { if (server->stream) { diff --git a/vendor/libgit2/src/transports/httpclient.h b/vendor/libgit2/src/libgit2/transports/httpclient.h similarity index 95% rename from vendor/libgit2/src/transports/httpclient.h rename to vendor/libgit2/src/libgit2/transports/httpclient.h index 6d0ef9ed..22c4dd09 100644 --- a/vendor/libgit2/src/transports/httpclient.h +++ b/vendor/libgit2/src/libgit2/transports/httpclient.h @@ -88,6 +88,16 @@ extern int git_http_client_new( git_http_client **out, git_http_client_options *opts); +/** + * Update the options of an existing httpclient instance. + * + * @param client the httpclient instance to modify + * @param opts new options or NULL to keep existing options + */ +extern void git_http_client_set_options( + git_http_client *client, + git_http_client_options *opts); + /* * Sends a request to the host specified by the request URL. If the * method is POST, either the content_length or the chunked flag must diff --git a/vendor/libgit2/src/libgit2/transports/httpparser.c b/vendor/libgit2/src/libgit2/transports/httpparser.c new file mode 100644 index 00000000..84833e61 --- /dev/null +++ b/vendor/libgit2/src/libgit2/transports/httpparser.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "httpparser.h" + +#include + +#if defined(GIT_HTTPPARSER_HTTPPARSER) + +#include "http_parser.h" + +static int on_message_begin(http_parser *p) +{ + git_http_parser *parser = (git_http_parser *)p; + return parser->settings.on_message_begin(parser); +} + +static int on_url(http_parser *p, const char *str, size_t len) +{ + git_http_parser *parser = (git_http_parser *)p; + return parser->settings.on_url(parser, str, len); +} + +static int on_header_field(http_parser *p, const char *str, size_t len) +{ + git_http_parser *parser = (git_http_parser *)p; + return parser->settings.on_header_field(parser, str, len); +} + +static int on_header_value(http_parser *p, const char *str, size_t len) +{ + git_http_parser *parser = (git_http_parser *)p; + return parser->settings.on_header_value(parser, str, len); +} + +static int on_headers_complete(http_parser *p) +{ + git_http_parser *parser = (git_http_parser *)p; + return parser->settings.on_headers_complete(parser); +} + +static int on_body(http_parser *p, const char *buf, size_t len) +{ + git_http_parser *parser = (git_http_parser *)p; + return parser->settings.on_body(parser, buf, len); +} + +static int on_message_complete(http_parser *p) +{ + git_http_parser *parser = (git_http_parser *)p; + return parser->settings.on_message_complete(parser); +} + +void git_http_parser_init( + git_http_parser *parser, + git_http_parser_t type, + git_http_parser_settings *settings) +{ + http_parser_init(&parser->parser, (enum http_parser_type)type); + memcpy(&parser->settings, settings, sizeof(git_http_parser_settings)); +} + +size_t git_http_parser_execute( + git_http_parser *parser, + const char *data, + size_t len) +{ + struct http_parser_settings settings_proxy; + + memset(&settings_proxy, 0, sizeof(struct http_parser_settings)); + + settings_proxy.on_message_begin = parser->settings.on_message_begin ? on_message_begin : NULL; + settings_proxy.on_url = parser->settings.on_url ? on_url : NULL; + settings_proxy.on_header_field = parser->settings.on_header_field ? on_header_field : NULL; + settings_proxy.on_header_value = parser->settings.on_header_value ? on_header_value : NULL; + settings_proxy.on_headers_complete = parser->settings.on_headers_complete ? on_headers_complete : NULL; + settings_proxy.on_body = parser->settings.on_body ? on_body : NULL; + settings_proxy.on_message_complete = parser->settings.on_message_complete ? on_message_complete : NULL; + + return http_parser_execute(&parser->parser, &settings_proxy, data, len); +} + +#elif defined(GIT_HTTPPARSER_LLHTTP) || defined(GIT_HTTPPARSER_BUILTIN) + +# include + +size_t git_http_parser_execute( + git_http_parser *parser, + const char* data, + size_t len) +{ + llhttp_errno_t error; + size_t parsed_len; + + /* + * Unlike http_parser, which returns the number of parsed + * bytes in the _execute() call, llhttp returns an error + * code. + */ + + if (data == NULL || len == 0) + error = llhttp_finish(parser); + else + error = llhttp_execute(parser, data, len); + + parsed_len = len; + + /* + * Adjust number of parsed bytes in case of error. + */ + if (error != HPE_OK) { + parsed_len = llhttp_get_error_pos(parser) - data; + + /* This isn't a real pause, just a way to stop parsing early. */ + if (error == HPE_PAUSED_UPGRADE) + llhttp_resume_after_upgrade(parser); + } + + return parsed_len; +} + +#else +# error unknown http-parser +#endif diff --git a/vendor/libgit2/src/libgit2/transports/httpparser.h b/vendor/libgit2/src/libgit2/transports/httpparser.h new file mode 100644 index 00000000..1fe0dcf6 --- /dev/null +++ b/vendor/libgit2/src/libgit2/transports/httpparser.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_transports_httpparser_h__ +#define INCLUDE_transports_httpparser_h__ + +#include "git2_util.h" + +#if defined(GIT_HTTPPARSER_HTTPPARSER) + +# include + +typedef enum { + GIT_HTTP_PARSER_OK = HPE_OK, + GIT_HTTP_PARSER_PAUSED = HPE_PAUSED, +} git_http_parser_error_t; + +typedef enum { + GIT_HTTP_PARSER_REQUEST = HTTP_REQUEST, + GIT_HTTP_PARSER_RESPONSE = HTTP_RESPONSE, +} git_http_parser_t; + +typedef struct git_http_parser git_http_parser; + +typedef struct { + int (*on_message_begin)(git_http_parser *); + int (*on_url)(git_http_parser *, const char *, size_t); + int (*on_header_field)(git_http_parser *, const char *, size_t); + int (*on_header_value)(git_http_parser *, const char *, size_t); + int (*on_headers_complete)(git_http_parser *); + int (*on_body)(git_http_parser *, const char *, size_t); + int (*on_message_complete)(git_http_parser *); +} git_http_parser_settings; + +struct git_http_parser { + http_parser parser; + git_http_parser_settings settings; + void *data; +}; + +void git_http_parser_init( + git_http_parser *parser, + git_http_parser_t type, + git_http_parser_settings *settings); + +size_t git_http_parser_execute( + git_http_parser *parser, + const char *data, + size_t len); + +# define git_http_parser_status_code(parser) parser->parser.status_code +# define git_http_parser_keep_alive(parser) http_should_keep_alive(&parser->parser) +# define git_http_parser_pause(parser) (http_parser_pause(&parser->parser, 1), 0) +# define git_http_parser_resume(parser) http_parser_pause(&parser->parser, 0) +# define git_http_parser_remain_after_pause(parser) 1 +# define git_http_parser_errno(parser) parser->parser.http_errno +# define git_http_parser_errmsg(parser, errno) http_errno_description(errno) + +#elif defined(GIT_HTTPPARSER_LLHTTP) || defined(GIT_HTTPPARSER_BUILTIN) + +# include + +typedef enum { + GIT_HTTP_PARSER_OK = HPE_OK, + GIT_HTTP_PARSER_PAUSED = HPE_PAUSED, +} git_http_parser_error_t; + +typedef enum { + GIT_HTTP_PARSER_REQUEST = HTTP_REQUEST, + GIT_HTTP_PARSER_RESPONSE = HTTP_RESPONSE, +} git_http_parser_t; + +typedef llhttp_t git_http_parser; +typedef llhttp_settings_t git_http_parser_settings; + +# define git_http_parser_init(parser, direction, settings) llhttp_init(parser, (llhttp_type_t)direction, settings) + +size_t git_http_parser_execute( + git_http_parser *parser, + const char *data, + size_t len); + +# define git_http_parser_status_code(parser) parser->status_code +# define git_http_parser_keep_alive(parser) llhttp_should_keep_alive(parser) +# define git_http_parser_pause(parser) (llhttp_pause(parser), GIT_HTTP_PARSER_PAUSED) +# define git_http_parser_resume(parser) llhttp_resume(parser) +# define git_http_parser_remain_after_pause(parser) 0 +# define git_http_parser_errno(parser) parser->error +# define git_http_parser_errmsg(parser, errno) llhttp_get_error_reason(parser) + +#else +# error unknown http-parser +#endif + +#endif diff --git a/vendor/libgit2/src/libgit2/transports/local.c b/vendor/libgit2/src/libgit2/transports/local.c new file mode 100644 index 00000000..68ff1c1c --- /dev/null +++ b/vendor/libgit2/src/libgit2/transports/local.c @@ -0,0 +1,782 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "common.h" + +#include "pack-objects.h" +#include "refs.h" +#include "posix.h" +#include "fs_path.h" +#include "repository.h" +#include "odb.h" +#include "push.h" +#include "remote.h" +#include "proxy.h" + +#include "git2/types.h" +#include "git2/net.h" +#include "git2/repository.h" +#include "git2/object.h" +#include "git2/tag.h" +#include "git2/transport.h" +#include "git2/revwalk.h" +#include "git2/odb_backend.h" +#include "git2/pack.h" +#include "git2/commit.h" +#include "git2/revparse.h" +#include "git2/sys/remote.h" + +typedef struct { + git_transport parent; + git_remote *owner; + char *url; + int direction; + git_atomic32 cancelled; + git_repository *repo; + git_remote_connect_options connect_opts; + git_vector refs; + unsigned connected : 1, + have_refs : 1; +} transport_local; + +static void free_head(git_remote_head *head) +{ + git__free(head->name); + git__free(head->symref_target); + git__free(head); +} + +static void free_heads(git_vector *heads) +{ + git_remote_head *head; + size_t i; + + git_vector_foreach(heads, i, head) + free_head(head); + + git_vector_free(heads); +} + +static int add_ref(transport_local *t, const char *name) +{ + const char peeled[] = "^{}"; + git_reference *ref, *resolved; + git_remote_head *head; + git_oid obj_id; + git_object *obj = NULL, *target = NULL; + git_str buf = GIT_STR_INIT; + int error; + + if ((error = git_reference_lookup(&ref, t->repo, name)) < 0) + return error; + + error = git_reference_resolve(&resolved, ref); + if (error < 0) { + git_reference_free(ref); + if (!strcmp(name, GIT_HEAD_FILE) && error == GIT_ENOTFOUND) { + /* This is actually okay. Empty repos often have a HEAD that + * points to a nonexistent "refs/heads/master". */ + git_error_clear(); + return 0; + } + return error; + } + + git_oid_cpy(&obj_id, git_reference_target(resolved)); + git_reference_free(resolved); + + head = git__calloc(1, sizeof(git_remote_head)); + GIT_ERROR_CHECK_ALLOC(head); + + head->name = git__strdup(name); + GIT_ERROR_CHECK_ALLOC(head->name); + + git_oid_cpy(&head->oid, &obj_id); + + if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) { + head->symref_target = git__strdup(git_reference_symbolic_target(ref)); + GIT_ERROR_CHECK_ALLOC(head->symref_target); + } + git_reference_free(ref); + + if ((error = git_vector_insert(&t->refs, head)) < 0) { + free_head(head); + return error; + } + + /* If it's not a tag, we don't need to try to peel it */ + if (git__prefixcmp(name, GIT_REFS_TAGS_DIR)) + return 0; + + if ((error = git_object_lookup(&obj, t->repo, &head->oid, GIT_OBJECT_ANY)) < 0) + return error; + + head = NULL; + + /* If it's not an annotated tag, or if we're mocking + * git-receive-pack, just get out */ + if (git_object_type(obj) != GIT_OBJECT_TAG || + t->direction != GIT_DIRECTION_FETCH) { + git_object_free(obj); + return 0; + } + + /* And if it's a tag, peel it, and add it to the list */ + head = git__calloc(1, sizeof(git_remote_head)); + GIT_ERROR_CHECK_ALLOC(head); + + if (git_str_join(&buf, 0, name, peeled) < 0) { + free_head(head); + return -1; + } + head->name = git_str_detach(&buf); + + if (!(error = git_tag_peel(&target, (git_tag *)obj))) { + git_oid_cpy(&head->oid, git_object_id(target)); + + if ((error = git_vector_insert(&t->refs, head)) < 0) { + free_head(head); + } + } + + git_object_free(obj); + git_object_free(target); + + return error; +} + +static int store_refs(transport_local *t) +{ + size_t i; + git_remote_head *head; + git_strarray ref_names = {0}; + + GIT_ASSERT_ARG(t); + + if (git_reference_list(&ref_names, t->repo) < 0) + goto on_error; + + /* Clear all heads we might have fetched in a previous connect */ + git_vector_foreach(&t->refs, i, head) { + git__free(head->name); + git__free(head); + } + + /* Clear the vector so we can reuse it */ + git_vector_clear(&t->refs); + + /* Sort the references first */ + git__tsort((void **)ref_names.strings, ref_names.count, &git__strcmp_cb); + + /* Add HEAD iff direction is fetch */ + if (t->direction == GIT_DIRECTION_FETCH && add_ref(t, GIT_HEAD_FILE) < 0) + goto on_error; + + for (i = 0; i < ref_names.count; ++i) { + if (add_ref(t, ref_names.strings[i]) < 0) + goto on_error; + } + + t->have_refs = 1; + git_strarray_dispose(&ref_names); + return 0; + +on_error: + git_vector_free(&t->refs); + git_strarray_dispose(&ref_names); + return -1; +} + +/* + * Try to open the url as a git directory. The direction doesn't + * matter in this case because we're calculating the heads ourselves. + */ +static int local_connect( + git_transport *transport, + const char *url, + int direction, + const git_remote_connect_options *connect_opts) +{ + git_repository *repo; + int error; + transport_local *t = (transport_local *)transport; + const char *path; + git_str buf = GIT_STR_INIT; + + if (t->connected) + return 0; + + if (git_remote_connect_options_normalize(&t->connect_opts, t->owner->repo, connect_opts) < 0) + return -1; + + free_heads(&t->refs); + + t->url = git__strdup(url); + GIT_ERROR_CHECK_ALLOC(t->url); + t->direction = direction; + + /* 'url' may be a url or path; convert to a path */ + if ((error = git_fs_path_from_url_or_path(&buf, url)) < 0) { + git_str_dispose(&buf); + return error; + } + path = git_str_cstr(&buf); + + error = git_repository_open(&repo, path); + + git_str_dispose(&buf); + + if (error < 0) + return -1; + + t->repo = repo; + + if (store_refs(t) < 0) + return -1; + + t->connected = 1; + + return 0; +} + +static int local_set_connect_opts( + git_transport *transport, + const git_remote_connect_options *connect_opts) +{ + transport_local *t = (transport_local *)transport; + + if (!t->connected) { + git_error_set(GIT_ERROR_NET, "cannot reconfigure a transport that is not connected"); + return -1; + } + + return git_remote_connect_options_normalize(&t->connect_opts, t->owner->repo, connect_opts); +} + +static int local_capabilities(unsigned int *capabilities, git_transport *transport) +{ + GIT_UNUSED(transport); + + *capabilities = GIT_REMOTE_CAPABILITY_TIP_OID | + GIT_REMOTE_CAPABILITY_REACHABLE_OID; + return 0; +} + +#ifdef GIT_EXPERIMENTAL_SHA256 +static int local_oid_type(git_oid_t *out, git_transport *transport) +{ + transport_local *t = (transport_local *)transport; + + *out = t->repo->oid_type; + + return 0; +} +#endif + +static int local_ls(const git_remote_head ***out, size_t *size, git_transport *transport) +{ + transport_local *t = (transport_local *)transport; + + if (!t->have_refs) { + git_error_set(GIT_ERROR_NET, "the transport has not yet loaded the refs"); + return -1; + } + + *out = (const git_remote_head **)t->refs.contents; + *size = t->refs.length; + + return 0; +} + +static int local_negotiate_fetch( + git_transport *transport, + git_repository *repo, + const git_fetch_negotiation *wants) +{ + transport_local *t = (transport_local*)transport; + git_remote_head *rhead; + unsigned int i; + + GIT_UNUSED(wants); + + if (wants->depth) { + git_error_set(GIT_ERROR_NET, "shallow fetch is not supported by the local transport"); + return GIT_ENOTSUPPORTED; + } + + /* Fill in the loids */ + git_vector_foreach(&t->refs, i, rhead) { + git_object *obj; + + int error = git_revparse_single(&obj, repo, rhead->name); + if (!error) + git_oid_cpy(&rhead->loid, git_object_id(obj)); + else if (error != GIT_ENOTFOUND) + return error; + else + git_error_clear(); + git_object_free(obj); + } + + return 0; +} + +static int local_shallow_roots( + git_oidarray *out, + git_transport *transport) +{ + GIT_UNUSED(out); + GIT_UNUSED(transport); + + return 0; +} + +static int local_push_update_remote_ref( + git_repository *remote_repo, + const char *lref, + const char *rref, + git_oid *loid, + git_oid *roid) +{ + int error; + git_reference *remote_ref = NULL; + + /* check for lhs, if it's empty it means to delete */ + if (lref[0] != '\0') { + /* Create or update a ref */ + error = git_reference_create(NULL, remote_repo, rref, loid, + !git_oid_is_zero(roid), NULL); + } else { + /* Delete a ref */ + if ((error = git_reference_lookup(&remote_ref, remote_repo, rref)) < 0) { + if (error == GIT_ENOTFOUND) + error = 0; + return error; + } + + error = git_reference_delete(remote_ref); + git_reference_free(remote_ref); + } + + return error; +} + +static int transfer_to_push_transfer(const git_indexer_progress *stats, void *payload) +{ + const git_remote_callbacks *cbs = payload; + + if (!cbs || !cbs->push_transfer_progress) + return 0; + + return cbs->push_transfer_progress(stats->received_objects, stats->total_objects, stats->received_bytes, + cbs->payload); +} + +static int local_push( + git_transport *transport, + git_push *push) +{ + transport_local *t = (transport_local *)transport; + git_remote_callbacks *cbs = &t->connect_opts.callbacks; + git_repository *remote_repo = NULL; + push_spec *spec; + char *url = NULL; + const char *path; + git_str buf = GIT_STR_INIT, odb_path = GIT_STR_INIT; + int error; + size_t j; + + /* 'push->remote->url' may be a url or path; convert to a path */ + if ((error = git_fs_path_from_url_or_path(&buf, push->remote->url)) < 0) { + git_str_dispose(&buf); + return error; + } + path = git_str_cstr(&buf); + + error = git_repository_open(&remote_repo, path); + + git_str_dispose(&buf); + + if (error < 0) + return error; + + /* We don't currently support pushing locally to non-bare repos. Proper + non-bare repo push support would require checking configs to see if + we should override the default 'don't let this happen' behavior. + + Note that this is only an issue when pushing to the current branch, + but we forbid all pushes just in case */ + if (!remote_repo->is_bare) { + error = GIT_EBAREREPO; + git_error_set(GIT_ERROR_INVALID, "local push doesn't (yet) support pushing to non-bare repos."); + goto on_error; + } + + if ((error = git_repository__item_path(&odb_path, remote_repo, GIT_REPOSITORY_ITEM_OBJECTS)) < 0 + || (error = git_str_joinpath(&odb_path, odb_path.ptr, "pack")) < 0) + goto on_error; + + error = git_packbuilder_write(push->pb, odb_path.ptr, 0, transfer_to_push_transfer, (void *) cbs); + git_str_dispose(&odb_path); + + if (error < 0) + goto on_error; + + push->unpack_ok = 1; + + git_vector_foreach(&push->specs, j, spec) { + push_status *status; + const git_error *last; + char *ref = spec->refspec.dst; + + status = git__calloc(1, sizeof(push_status)); + if (!status) + goto on_error; + + status->ref = git__strdup(ref); + if (!status->ref) { + git_push_status_free(status); + goto on_error; + } + + error = local_push_update_remote_ref(remote_repo, spec->refspec.src, spec->refspec.dst, + &spec->loid, &spec->roid); + + switch (error) { + case GIT_OK: + break; + case GIT_EINVALIDSPEC: + status->msg = git__strdup("funny refname"); + break; + case GIT_ENOTFOUND: + status->msg = git__strdup("Remote branch not found to delete"); + break; + default: + last = git_error_last(); + + if (last->klass != GIT_ERROR_NONE) + status->msg = git__strdup(last->message); + else + status->msg = git__strdup("Unspecified error encountered"); + break; + } + + /* failed to allocate memory for a status message */ + if (error < 0 && !status->msg) { + git_push_status_free(status); + goto on_error; + } + + /* failed to insert the ref update status */ + if ((error = git_vector_insert(&push->status, status)) < 0) { + git_push_status_free(status); + goto on_error; + } + } + + if (push->specs.length) { + url = git__strdup(t->url); + + if (!url || t->parent.close(&t->parent) < 0 || + t->parent.connect(&t->parent, url, + GIT_DIRECTION_PUSH, NULL)) + goto on_error; + } + + error = 0; + +on_error: + git_repository_free(remote_repo); + git__free(url); + + return error; +} + +typedef struct foreach_data { + git_indexer_progress *stats; + git_indexer_progress_cb progress_cb; + void *progress_payload; + git_odb_writepack *writepack; +} foreach_data; + +static int foreach_cb(void *buf, size_t len, void *payload) +{ + foreach_data *data = (foreach_data*)payload; + + data->stats->received_bytes += len; + return data->writepack->append(data->writepack, buf, len, data->stats); +} + +static const char *counting_objects_fmt = "Counting objects %d\r"; +static const char *compressing_objects_fmt = "Compressing objects: %.0f%% (%d/%d)"; + +static int local_counting(int stage, unsigned int current, unsigned int total, void *payload) +{ + git_str progress_info = GIT_STR_INIT; + transport_local *t = payload; + int error; + + if (!t->connect_opts.callbacks.sideband_progress) + return 0; + + if (stage == GIT_PACKBUILDER_ADDING_OBJECTS) { + git_str_printf(&progress_info, counting_objects_fmt, current); + } else if (stage == GIT_PACKBUILDER_DELTAFICATION) { + float perc = (((float) current) / total) * 100; + git_str_printf(&progress_info, compressing_objects_fmt, perc, current, total); + if (current == total) + git_str_printf(&progress_info, ", done\n"); + else + git_str_putc(&progress_info, '\r'); + + } + + if (git_str_oom(&progress_info)) + return -1; + + if (progress_info.size > INT_MAX) { + git_error_set(GIT_ERROR_NET, "remote sent overly large progress data"); + git_str_dispose(&progress_info); + return -1; + } + + + error = t->connect_opts.callbacks.sideband_progress( + progress_info.ptr, + (int)progress_info.size, + t->connect_opts.callbacks.payload); + + git_str_dispose(&progress_info); + return error; +} + +static int foreach_reference_cb(git_reference *reference, void *payload) +{ + git_revwalk *walk = (git_revwalk *)payload; + int error; + + if (git_reference_type(reference) != GIT_REFERENCE_DIRECT) { + git_reference_free(reference); + return 0; + } + + error = git_revwalk_hide(walk, git_reference_target(reference)); + /* The reference is in the local repository, so the target may not + * exist on the remote. It also may not be a commit. */ + if (error == GIT_ENOTFOUND || error == GIT_ERROR_INVALID) { + git_error_clear(); + error = 0; + } + + git_reference_free(reference); + + return error; +} + +static int local_download_pack( + git_transport *transport, + git_repository *repo, + git_indexer_progress *stats) +{ + transport_local *t = (transport_local*)transport; + git_revwalk *walk = NULL; + git_remote_head *rhead; + unsigned int i; + int error = -1; + git_packbuilder *pack = NULL; + git_odb_writepack *writepack = NULL; + git_odb *odb = NULL; + git_str progress_info = GIT_STR_INIT; + foreach_data data = {0}; + + if ((error = git_revwalk_new(&walk, t->repo)) < 0) + goto cleanup; + + git_revwalk_sorting(walk, GIT_SORT_TIME); + + if ((error = git_packbuilder_new(&pack, t->repo)) < 0) + goto cleanup; + + git_packbuilder_set_callbacks(pack, local_counting, t); + + stats->total_objects = 0; + stats->indexed_objects = 0; + stats->received_objects = 0; + stats->received_bytes = 0; + + git_vector_foreach(&t->refs, i, rhead) { + git_object *obj; + if ((error = git_object_lookup(&obj, t->repo, &rhead->oid, GIT_OBJECT_ANY)) < 0) + goto cleanup; + + if (git_object_type(obj) == GIT_OBJECT_COMMIT) { + /* Revwalker includes only wanted commits */ + error = git_revwalk_push(walk, &rhead->oid); + } else { + /* Tag or some other wanted object. Add it on its own */ + error = git_packbuilder_insert_recur(pack, &rhead->oid, rhead->name); + } + git_object_free(obj); + if (error < 0) + goto cleanup; + } + + if ((error = git_reference_foreach(repo, foreach_reference_cb, walk))) + goto cleanup; + + if ((error = git_packbuilder_insert_walk(pack, walk))) + goto cleanup; + + if (t->connect_opts.callbacks.sideband_progress) { + if ((error = git_str_printf( + &progress_info, + counting_objects_fmt, + git_packbuilder_object_count(pack))) < 0 || + (error = t->connect_opts.callbacks.sideband_progress( + progress_info.ptr, + (int)progress_info.size, + t->connect_opts.callbacks.payload)) < 0) + goto cleanup; + } + + /* Walk the objects, building a packfile */ + if ((error = git_repository_odb__weakptr(&odb, repo)) < 0) + goto cleanup; + + /* One last one with the newline */ + if (t->connect_opts.callbacks.sideband_progress) { + git_str_clear(&progress_info); + + if ((error = git_str_printf( + &progress_info, + counting_objects_fmt, + git_packbuilder_object_count(pack))) < 0 || + (error = git_str_putc(&progress_info, '\n')) < 0 || + (error = t->connect_opts.callbacks.sideband_progress( + progress_info.ptr, + (int)progress_info.size, + t->connect_opts.callbacks.payload)) < 0) + goto cleanup; + } + + if ((error = git_odb_write_pack( + &writepack, + odb, + t->connect_opts.callbacks.transfer_progress, + t->connect_opts.callbacks.payload)) < 0) + goto cleanup; + + /* Write the data to the ODB */ + data.stats = stats; + data.progress_cb = t->connect_opts.callbacks.transfer_progress; + data.progress_payload = t->connect_opts.callbacks.payload; + data.writepack = writepack; + + /* autodetect */ + git_packbuilder_set_threads(pack, 0); + + if ((error = git_packbuilder_foreach(pack, foreach_cb, &data)) != 0) + goto cleanup; + + error = writepack->commit(writepack, stats); + +cleanup: + if (writepack) writepack->free(writepack); + git_str_dispose(&progress_info); + git_packbuilder_free(pack); + git_revwalk_free(walk); + return error; +} + +static int local_is_connected(git_transport *transport) +{ + transport_local *t = (transport_local *)transport; + + return t->connected; +} + +static void local_cancel(git_transport *transport) +{ + transport_local *t = (transport_local *)transport; + + git_atomic32_set(&t->cancelled, 1); +} + +static int local_close(git_transport *transport) +{ + transport_local *t = (transport_local *)transport; + + t->connected = 0; + + if (t->repo) { + git_repository_free(t->repo); + t->repo = NULL; + } + + if (t->url) { + git__free(t->url); + t->url = NULL; + } + + return 0; +} + +static void local_free(git_transport *transport) +{ + transport_local *t = (transport_local *)transport; + + free_heads(&t->refs); + + /* Close the transport, if it's still open. */ + local_close(transport); + + /* Free the transport */ + git__free(t); +} + +/************** + * Public API * + **************/ + +int git_transport_local(git_transport **out, git_remote *owner, void *param) +{ + int error; + transport_local *t; + + GIT_UNUSED(param); + + t = git__calloc(1, sizeof(transport_local)); + GIT_ERROR_CHECK_ALLOC(t); + + t->parent.version = GIT_TRANSPORT_VERSION; + t->parent.connect = local_connect; + t->parent.set_connect_opts = local_set_connect_opts; + t->parent.capabilities = local_capabilities; +#ifdef GIT_EXPERIMENTAL_SHA256 + t->parent.oid_type = local_oid_type; +#endif + t->parent.negotiate_fetch = local_negotiate_fetch; + t->parent.shallow_roots = local_shallow_roots; + t->parent.download_pack = local_download_pack; + t->parent.push = local_push; + t->parent.close = local_close; + t->parent.free = local_free; + t->parent.ls = local_ls; + t->parent.is_connected = local_is_connected; + t->parent.cancel = local_cancel; + + if ((error = git_vector_init(&t->refs, 0, NULL)) < 0) { + git__free(t); + return error; + } + + t->owner = owner; + + *out = (git_transport *) t; + + return 0; +} diff --git a/vendor/libgit2/src/transports/smart.c b/vendor/libgit2/src/libgit2/transports/smart.c similarity index 81% rename from vendor/libgit2/src/transports/smart.c rename to vendor/libgit2/src/libgit2/transports/smart.c index 801fcbe5..be0cb7b0 100644 --- a/vendor/libgit2/src/transports/smart.c +++ b/vendor/libgit2/src/libgit2/transports/smart.c @@ -13,30 +13,42 @@ #include "refspec.h" #include "proxy.h" -static int git_smart__recv_cb(gitno_buffer *buf) +int git_smart__recv(transport_smart *t) { - transport_smart *t = (transport_smart *) buf->cb_data; - size_t old_len, bytes_read; - int error; + size_t bytes_read; + int ret; + GIT_ASSERT_ARG(t); GIT_ASSERT(t->current_stream); - old_len = buf->offset; + if (git_staticstr_remain(&t->buffer) == 0) { + git_error_set(GIT_ERROR_NET, "out of buffer space"); + return -1; + } - if ((error = t->current_stream->read(t->current_stream, buf->data + buf->offset, buf->len - buf->offset, &bytes_read)) < 0) - return error; + ret = t->current_stream->read(t->current_stream, + git_staticstr_offset(&t->buffer), + git_staticstr_remain(&t->buffer), + &bytes_read); + + if (ret < 0) + return ret; + + GIT_ASSERT(bytes_read <= INT_MAX); + GIT_ASSERT(bytes_read <= git_staticstr_remain(&t->buffer)); - buf->offset += bytes_read; + git_staticstr_increase(&t->buffer, bytes_read); if (t->packetsize_cb && !t->cancelled.val) { - error = t->packetsize_cb(bytes_read, t->packetsize_payload); - if (error) { + ret = t->packetsize_cb(bytes_read, t->packetsize_payload); + + if (ret) { git_atomic32_set(&t->cancelled, 1); return GIT_EUSER; } } - return (int)(buf->offset - old_len); + return (int)bytes_read; } GIT_INLINE(int) git_smart__reset_stream(transport_smart *t, bool close_subtransport) @@ -54,6 +66,12 @@ GIT_INLINE(int) git_smart__reset_stream(transport_smart *t, bool close_subtransp return -1; } + git__free(t->caps.object_format); + t->caps.object_format = NULL; + + git__free(t->caps.agent); + t->caps.agent = NULL; + return 0; } @@ -149,8 +167,6 @@ static int git_smart__connect( /* Save off the current stream (i.e. socket) that we are working with */ t->current_stream = stream; - gitno_buffer_setup_callback(&t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t); - /* 2 flushes for RPC; 1 for stateful */ if ((error = git_smart__store_refs(t, t->rpc ? 2 : 1)) < 0) return error; @@ -233,6 +249,9 @@ static int git_smart__capabilities(unsigned int *capabilities, git_transport *tr *capabilities = 0; + if (t->caps.push_options) + *capabilities |= GIT_REMOTE_CAPABILITY_PUSH_OPTIONS; + if (t->caps.want_tip_sha1) *capabilities |= GIT_REMOTE_CAPABILITY_TIP_OID; @@ -242,6 +261,30 @@ static int git_smart__capabilities(unsigned int *capabilities, git_transport *tr return 0; } +#ifdef GIT_EXPERIMENTAL_SHA256 +static int git_smart__oid_type(git_oid_t *out, git_transport *transport) +{ + transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent); + + *out = 0; + + if (t->caps.object_format == NULL) { + *out = GIT_OID_DEFAULT; + } else { + *out = git_oid_type_fromstr(t->caps.object_format); + + if (!*out) { + git_error_set(GIT_ERROR_INVALID, + "unknown object format '%s'", + t->caps.object_format); + return -1; + } + } + + return 0; +} +#endif + static int git_smart__ls(const git_remote_head ***out, size_t *size, git_transport *transport) { transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent); @@ -283,8 +326,6 @@ int git_smart__negotiation_step(git_transport *transport, void *data, size_t len if ((error = stream->write(stream, (const char *)data, len)) < 0) return error; - gitno_buffer_setup_callback(&t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t); - return 0; } @@ -309,8 +350,6 @@ int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream /* Save off the current stream (i.e. socket) that we are working with */ t->current_stream = *stream; - gitno_buffer_setup_callback(&t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t); - return 0; } @@ -334,17 +373,27 @@ static int git_smart__close(git_transport *transport) git_vector *common = &t->common; unsigned int i; git_pkt *p; + git_smart_service_t service; int ret; git_smart_subtransport_stream *stream; const char flush[] = "0000"; + if (t->direction == GIT_DIRECTION_FETCH) { + service = GIT_SERVICE_UPLOADPACK; + } else if (t->direction == GIT_DIRECTION_PUSH) { + service = GIT_SERVICE_RECEIVEPACK; + } else { + git_error_set(GIT_ERROR_NET, "invalid direction"); + return -1; + } + /* * If we're still connected at this point and not using RPC, * we should say goodbye by sending a flush, or git-daemon * will complain that we disconnected unexpectedly. */ if (t->connected && !t->rpc && - !t->wrapped->action(&stream, t->wrapped, t->url, GIT_SERVICE_UPLOADPACK)) { + !t->wrapped->action(&stream, t->wrapped, t->url, service)) { t->current_stream->write(t->current_stream, flush, 4); } @@ -386,6 +435,10 @@ static void git_smart__free(git_transport *transport) git_remote_connect_options_dispose(&t->connect_opts); + git_array_dispose(t->shallow_roots); + + git__free(t->caps.object_format); + git__free(t->caps.agent); git__free(t); } @@ -425,6 +478,18 @@ int git_transport_smart_credentials(git_credential **out, git_transport *transpo return connect_opts->callbacks.credentials(out, t->url, user, methods, connect_opts->callbacks.payload); } +int git_transport_remote_connect_options( + git_remote_connect_options *out, + git_transport *transport) +{ + transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent); + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(transport); + + return git_remote_connect_options_dup(out, &t->connect_opts); +} + int git_transport_smart(git_transport **out, git_remote *owner, void *param) { transport_smart *t; @@ -440,9 +505,13 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param) t->parent.connect = git_smart__connect; t->parent.set_connect_opts = git_smart__set_connect_opts; t->parent.capabilities = git_smart__capabilities; +#ifdef GIT_EXPERIMENTAL_SHA256 + t->parent.oid_type = git_smart__oid_type; +#endif t->parent.close = git_smart__close; t->parent.free = git_smart__free; t->parent.negotiate_fetch = git_smart__negotiate_fetch; + t->parent.shallow_roots = git_smart__shallow_roots; t->parent.download_pack = git_smart__download_pack; t->parent.push = git_smart__push; t->parent.ls = git_smart__ls; @@ -452,20 +521,16 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param) t->owner = owner; t->rpc = definition->rpc; - if (git_vector_init(&t->refs, 16, ref_name_cmp) < 0) { - git__free(t); - return -1; - } - - if (git_vector_init(&t->heads, 16, ref_name_cmp) < 0) { + if (git_vector_init(&t->refs, 16, ref_name_cmp) < 0 || + git_vector_init(&t->heads, 16, ref_name_cmp) < 0 || + definition->callback(&t->wrapped, &t->parent, definition->param) < 0) { + git_vector_free(&t->refs); + git_vector_free(&t->heads); git__free(t); return -1; } - if (definition->callback(&t->wrapped, &t->parent, definition->param) < 0) { - git__free(t); - return -1; - } + git_staticstr_init(&t->buffer, GIT_SMART_BUFFER_SIZE); *out = (git_transport *) t; return 0; diff --git a/vendor/libgit2/src/transports/smart.h b/vendor/libgit2/src/libgit2/transports/smart.h similarity index 81% rename from vendor/libgit2/src/transports/smart.h rename to vendor/libgit2/src/libgit2/transports/smart.h index 9323d6c4..c987d93b 100644 --- a/vendor/libgit2/src/transports/smart.h +++ b/vendor/libgit2/src/libgit2/transports/smart.h @@ -11,11 +11,14 @@ #include "git2.h" #include "vector.h" -#include "netops.h" #include "push.h" #include "str.h" +#include "oidarray.h" +#include "staticstr.h" #include "git2/sys/transport.h" +#define GIT_SMART_BUFFER_SIZE 65536 + #define GIT_SIDE_BAND_DATA 1 #define GIT_SIDE_BAND_PROGRESS 2 #define GIT_SIDE_BAND_ERROR 3 @@ -32,6 +35,10 @@ #define GIT_CAP_SYMREF "symref" #define GIT_CAP_WANT_TIP_SHA1 "allow-tip-sha1-in-want" #define GIT_CAP_WANT_REACHABLE_SHA1 "allow-reachable-sha1-in-want" +#define GIT_CAP_SHALLOW "shallow" +#define GIT_CAP_OBJECT_FORMAT "object-format=" +#define GIT_CAP_AGENT "agent=" +#define GIT_CAP_PUSH_OPTIONS "push-options" extern bool git_smart__ofs_delta_enabled; @@ -48,7 +55,9 @@ typedef enum { GIT_PKT_PROGRESS, GIT_PKT_OK, GIT_PKT_NG, - GIT_PKT_UNPACK + GIT_PKT_UNPACK, + GIT_PKT_SHALLOW, + GIT_PKT_UNSHALLOW } git_pkt_type; /* Used for multi_ack and multi_ack_detailed */ @@ -120,6 +129,11 @@ typedef struct { int unpack_ok; } git_pkt_unpack; +typedef struct { + git_pkt_type type; + git_oid oid; +} git_pkt_shallow; + typedef struct transport_smart_caps { unsigned int common:1, ofs_delta:1, @@ -132,7 +146,11 @@ typedef struct transport_smart_caps { report_status:1, thin_pack:1, want_tip_sha1:1, - want_reachable_sha1:1; + want_reachable_sha1:1, + shallow:1, + push_options:1; + char *object_format; + char *agent; } transport_smart_caps; typedef int (*packetsize_cb)(size_t received, void *payload); @@ -149,14 +167,14 @@ typedef struct { git_vector refs; git_vector heads; git_vector common; + git_array_oid_t shallow_roots; git_atomic32 cancelled; packetsize_cb packetsize_cb; void *packetsize_payload; unsigned rpc : 1, have_refs : 1, connected : 1; - gitno_buffer buffer; - char buffer_data[65536]; + git_staticstr_with_size(GIT_SMART_BUFFER_SIZE) buffer; } transport_smart; /* smart_protocol.c */ @@ -167,8 +185,9 @@ int git_smart__push(git_transport *transport, git_push *push); int git_smart__negotiate_fetch( git_transport *transport, git_repository *repo, - const git_remote_head * const *refs, - size_t count); + const git_fetch_negotiation *wants); + +int git_smart__shallow_roots(git_oidarray *out, git_transport *transport); int git_smart__download_pack( git_transport *transport, @@ -176,17 +195,24 @@ int git_smart__download_pack( git_indexer_progress *stats); /* smart.c */ +int git_smart__recv(transport_smart *t); + int git_smart__negotiation_step(git_transport *transport, void *data, size_t len); int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream **out); int git_smart__update_heads(transport_smart *t, git_vector *symrefs); /* smart_pkt.c */ -int git_pkt_parse_line(git_pkt **head, const char **endptr, const char *line, size_t linelen); +typedef struct { + git_oid_t oid_type; + unsigned int seen_capabilities: 1; +} git_pkt_parse_data; + +int git_pkt_parse_line(git_pkt **head, const char **endptr, const char *line, size_t linelen, git_pkt_parse_data *data); int git_pkt_buffer_flush(git_str *buf); int git_pkt_send_flush(GIT_SOCKET s); int git_pkt_buffer_done(git_str *buf); -int git_pkt_buffer_wants(const git_remote_head * const *refs, size_t count, transport_smart_caps *caps, git_str *buf); +int git_pkt_buffer_wants(const git_fetch_negotiation *wants, transport_smart_caps *caps, git_str *buf); int git_pkt_buffer_have(git_oid *oid, git_str *buf); void git_pkt_free(git_pkt *pkt); diff --git a/vendor/libgit2/src/libgit2/transports/smart_pkt.c b/vendor/libgit2/src/libgit2/transports/smart_pkt.c new file mode 100644 index 00000000..7ea8676e --- /dev/null +++ b/vendor/libgit2/src/libgit2/transports/smart_pkt.c @@ -0,0 +1,870 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "common.h" + +#include "smart.h" +#include "util.h" +#include "posix.h" +#include "str.h" +#include "oid.h" + +#include "git2/types.h" +#include "git2/errors.h" +#include "git2/refs.h" +#include "git2/revwalk.h" + +#include + +#define PKT_DONE_STR "0009done\n" +#define PKT_FLUSH_STR "0000" +#define PKT_HAVE_PREFIX "have " +#define PKT_WANT_PREFIX "want " + +#define PKT_LEN_SIZE 4 +#define PKT_MAX_SIZE 0xffff +#define PKT_MAX_WANTLEN (PKT_LEN_SIZE + CONST_STRLEN(PKT_WANT_PREFIX) + GIT_OID_MAX_HEXSIZE + 1) + +static int flush_pkt(git_pkt **out) +{ + git_pkt *pkt; + + pkt = git__malloc(sizeof(git_pkt)); + GIT_ERROR_CHECK_ALLOC(pkt); + + pkt->type = GIT_PKT_FLUSH; + *out = pkt; + + return 0; +} + +/* the rest of the line will be useful for multi_ack and multi_ack_detailed */ +static int ack_pkt( + git_pkt **out, + const char *line, + size_t len, + git_pkt_parse_data *data) +{ + git_pkt_ack *pkt; + size_t oid_hexsize = git_oid_hexsize(data->oid_type); + + GIT_ASSERT(data && data->oid_type); + + pkt = git__calloc(1, sizeof(git_pkt_ack)); + GIT_ERROR_CHECK_ALLOC(pkt); + pkt->type = GIT_PKT_ACK; + + if (git__prefixncmp(line, len, "ACK ")) + goto out_err; + line += 4; + len -= 4; + + if (len < oid_hexsize || + git_oid__fromstr(&pkt->oid, line, data->oid_type) < 0) + goto out_err; + line += oid_hexsize; + len -= oid_hexsize; + + if (len && line[0] == ' ') { + line++; + len--; + + if (!git__prefixncmp(line, len, "continue")) + pkt->status = GIT_ACK_CONTINUE; + else if (!git__prefixncmp(line, len, "common")) + pkt->status = GIT_ACK_COMMON; + else if (!git__prefixncmp(line, len, "ready")) + pkt->status = GIT_ACK_READY; + else + goto out_err; + } + + *out = (git_pkt *) pkt; + + return 0; + +out_err: + git_error_set(GIT_ERROR_NET, "error parsing ACK pkt-line"); + git__free(pkt); + return -1; +} + +static int nak_pkt(git_pkt **out) +{ + git_pkt *pkt; + + pkt = git__malloc(sizeof(git_pkt)); + GIT_ERROR_CHECK_ALLOC(pkt); + + pkt->type = GIT_PKT_NAK; + *out = pkt; + + return 0; +} + +static int comment_pkt(git_pkt **out, const char *line, size_t len) +{ + git_pkt_comment *pkt; + size_t alloclen; + + GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_pkt_comment), len); + GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1); + pkt = git__malloc(alloclen); + GIT_ERROR_CHECK_ALLOC(pkt); + + pkt->type = GIT_PKT_COMMENT; + memcpy(pkt->comment, line, len); + pkt->comment[len] = '\0'; + + *out = (git_pkt *) pkt; + + return 0; +} + +static int err_pkt(git_pkt **out, const char *line, size_t len) +{ + git_pkt_err *pkt = NULL; + size_t alloclen; + + /* Remove "ERR " from the line */ + if (git__prefixncmp(line, len, "ERR ")) + goto out_err; + line += 4; + len -= 4; + + GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_pkt_progress), len); + GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1); + pkt = git__malloc(alloclen); + GIT_ERROR_CHECK_ALLOC(pkt); + pkt->type = GIT_PKT_ERR; + pkt->len = len; + + memcpy(pkt->error, line, len); + pkt->error[len] = '\0'; + + *out = (git_pkt *) pkt; + + return 0; + +out_err: + git_error_set(GIT_ERROR_NET, "error parsing ERR pkt-line"); + git__free(pkt); + return -1; +} + +static int data_pkt(git_pkt **out, const char *line, size_t len) +{ + git_pkt_data *pkt; + size_t alloclen; + + line++; + len--; + + GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_pkt_progress), len); + pkt = git__malloc(alloclen); + GIT_ERROR_CHECK_ALLOC(pkt); + + pkt->type = GIT_PKT_DATA; + pkt->len = len; + memcpy(pkt->data, line, len); + + *out = (git_pkt *) pkt; + + return 0; +} + +static int sideband_progress_pkt(git_pkt **out, const char *line, size_t len) +{ + git_pkt_progress *pkt; + size_t alloclen; + + line++; + len--; + + GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_pkt_progress), len); + pkt = git__malloc(alloclen); + GIT_ERROR_CHECK_ALLOC(pkt); + + pkt->type = GIT_PKT_PROGRESS; + pkt->len = len; + memcpy(pkt->data, line, len); + + *out = (git_pkt *) pkt; + + return 0; +} + +static int sideband_error_pkt(git_pkt **out, const char *line, size_t len) +{ + git_pkt_err *pkt; + size_t alloc_len; + + line++; + len--; + + GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, sizeof(git_pkt_err), len); + GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 1); + pkt = git__malloc(alloc_len); + GIT_ERROR_CHECK_ALLOC(pkt); + + pkt->type = GIT_PKT_ERR; + pkt->len = (int)len; + memcpy(pkt->error, line, len); + pkt->error[len] = '\0'; + + *out = (git_pkt *)pkt; + + return 0; +} + +static int set_data( + git_pkt_parse_data *data, + const char *line, + size_t len) +{ + const char *caps, *format_str = NULL, *eos; + size_t format_len; + git_oid_t remote_oid_type; + + GIT_ASSERT_ARG(data); + + if ((caps = memchr(line, '\0', len)) != NULL && + len > (size_t)((caps - line) + 1)) { + caps++; + + if (strncmp(caps, "object-format=", CONST_STRLEN("object-format=")) == 0) + format_str = caps + CONST_STRLEN("object-format="); + else if ((format_str = strstr(caps, " object-format=")) != NULL) + format_str += CONST_STRLEN(" object-format="); + } + + if (format_str) { + if ((eos = strchr(format_str, ' ')) == NULL) + eos = strchr(format_str, '\0'); + + GIT_ASSERT(eos); + + format_len = eos - format_str; + + if ((remote_oid_type = git_oid_type_fromstrn(format_str, format_len)) == 0) { + git_error_set(GIT_ERROR_INVALID, "unknown remote object format '%.*s'", (int)format_len, format_str); + return -1; + } + } else { + remote_oid_type = GIT_OID_SHA1; + } + + if (!data->oid_type) { + data->oid_type = remote_oid_type; + } else if (data->oid_type != remote_oid_type) { + git_error_set(GIT_ERROR_INVALID, + "the local object format '%s' does not match the remote object format '%s'", + git_oid_type_name(data->oid_type), + git_oid_type_name(remote_oid_type)); + return -1; + } + + return 0; +} + +/* + * Parse an other-ref line. + */ +static int ref_pkt( + git_pkt **out, + const char *line, + size_t len, + git_pkt_parse_data *data) +{ + git_pkt_ref *pkt; + size_t alloclen, oid_hexsize; + + pkt = git__calloc(1, sizeof(git_pkt_ref)); + GIT_ERROR_CHECK_ALLOC(pkt); + pkt->type = GIT_PKT_REF; + + /* Determine OID type from capabilities */ + if (!data->seen_capabilities && set_data(data, line, len) < 0) + return -1; + + GIT_ASSERT(data->oid_type); + oid_hexsize = git_oid_hexsize(data->oid_type); + + if (len < oid_hexsize || + git_oid__fromstr(&pkt->head.oid, line, data->oid_type) < 0) + goto out_err; + line += oid_hexsize; + len -= oid_hexsize; + + if (git__prefixncmp(line, len, " ")) + goto out_err; + + line++; + len--; + + if (!len) + goto out_err; + + if (line[len - 1] == '\n') + --len; + + GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, len, 1); + pkt->head.name = git__malloc(alloclen); + GIT_ERROR_CHECK_ALLOC(pkt->head.name); + + memcpy(pkt->head.name, line, len); + pkt->head.name[len] = '\0'; + + if (strlen(pkt->head.name) < len) { + if (!data->seen_capabilities) + pkt->capabilities = strchr(pkt->head.name, '\0') + 1; + else + goto out_err; + } + + data->seen_capabilities = 1; + + *out = (git_pkt *)pkt; + return 0; + +out_err: + git_error_set(GIT_ERROR_NET, "error parsing REF pkt-line"); + if (pkt) + git__free(pkt->head.name); + git__free(pkt); + return -1; +} + +static int ok_pkt(git_pkt **out, const char *line, size_t len) +{ + git_pkt_ok *pkt; + size_t alloc_len; + + pkt = git__malloc(sizeof(*pkt)); + GIT_ERROR_CHECK_ALLOC(pkt); + pkt->type = GIT_PKT_OK; + + if (git__prefixncmp(line, len, "ok ")) + goto out_err; + line += 3; + len -= 3; + + if (len && line[len - 1] == '\n') + --len; + + GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, len, 1); + pkt->ref = git__malloc(alloc_len); + GIT_ERROR_CHECK_ALLOC(pkt->ref); + + memcpy(pkt->ref, line, len); + pkt->ref[len] = '\0'; + + *out = (git_pkt *)pkt; + return 0; + +out_err: + git_error_set(GIT_ERROR_NET, "error parsing OK pkt-line"); + git__free(pkt); + return -1; +} + +static int ng_pkt(git_pkt **out, const char *line, size_t len) +{ + git_pkt_ng *pkt; + const char *ptr, *eol; + size_t alloclen; + + pkt = git__malloc(sizeof(*pkt)); + GIT_ERROR_CHECK_ALLOC(pkt); + + pkt->ref = NULL; + pkt->type = GIT_PKT_NG; + + eol = line + len; + + if (git__prefixncmp(line, len, "ng ")) + goto out_err; + line += 3; + + if (!(ptr = memchr(line, ' ', eol - line))) + goto out_err; + len = ptr - line; + + GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, len, 1); + pkt->ref = git__malloc(alloclen); + GIT_ERROR_CHECK_ALLOC(pkt->ref); + + memcpy(pkt->ref, line, len); + pkt->ref[len] = '\0'; + + line = ptr + 1; + if (line >= eol) + goto out_err; + + if (!(ptr = memchr(line, '\n', eol - line))) + goto out_err; + len = ptr - line; + + GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, len, 1); + pkt->msg = git__malloc(alloclen); + GIT_ERROR_CHECK_ALLOC(pkt->msg); + + memcpy(pkt->msg, line, len); + pkt->msg[len] = '\0'; + + *out = (git_pkt *)pkt; + return 0; + +out_err: + git_error_set(GIT_ERROR_NET, "invalid packet line"); + git__free(pkt->ref); + git__free(pkt); + return -1; +} + +static int unpack_pkt(git_pkt **out, const char *line, size_t len) +{ + git_pkt_unpack *pkt; + + pkt = git__malloc(sizeof(*pkt)); + GIT_ERROR_CHECK_ALLOC(pkt); + pkt->type = GIT_PKT_UNPACK; + + if (!git__prefixncmp(line, len, "unpack ok")) + pkt->unpack_ok = 1; + else + pkt->unpack_ok = 0; + + *out = (git_pkt *)pkt; + return 0; +} + +static int shallow_pkt( + git_pkt **out, + const char *line, + size_t len, + git_pkt_parse_data *data) +{ + git_pkt_shallow *pkt; + size_t oid_hexsize = git_oid_hexsize(data->oid_type); + + GIT_ASSERT(data && data->oid_type); + + pkt = git__calloc(1, sizeof(git_pkt_shallow)); + GIT_ERROR_CHECK_ALLOC(pkt); + + pkt->type = GIT_PKT_SHALLOW; + + if (git__prefixncmp(line, len, "shallow ")) + goto out_err; + + line += 8; + len -= 8; + + if (len != oid_hexsize) + goto out_err; + + git_oid__fromstr(&pkt->oid, line, data->oid_type); + line += oid_hexsize + 1; + len -= oid_hexsize + 1; + + *out = (git_pkt *)pkt; + + return 0; + +out_err: + git_error_set(GIT_ERROR_NET, "invalid packet line"); + git__free(pkt); + return -1; +} + +static int unshallow_pkt( + git_pkt **out, + const char *line, + size_t len, + git_pkt_parse_data *data) +{ + git_pkt_shallow *pkt; + size_t oid_hexsize = git_oid_hexsize(data->oid_type); + + GIT_ASSERT(data && data->oid_type); + + pkt = git__calloc(1, sizeof(git_pkt_shallow)); + GIT_ERROR_CHECK_ALLOC(pkt); + + pkt->type = GIT_PKT_UNSHALLOW; + + if (git__prefixncmp(line, len, "unshallow ")) + goto out_err; + + line += 10; + len -= 10; + + if (len != oid_hexsize) + goto out_err; + + git_oid__fromstr(&pkt->oid, line, data->oid_type); + line += oid_hexsize + 1; + len -= oid_hexsize + 1; + + *out = (git_pkt *) pkt; + + return 0; + +out_err: + git_error_set(GIT_ERROR_NET, "invalid packet line"); + git__free(pkt); + return -1; +} + +static int parse_len(size_t *out, const char *line, size_t linelen) +{ + char num[PKT_LEN_SIZE + 1]; + int i, k, error; + int32_t len; + const char *num_end; + + /* Not even enough for the length */ + if (linelen < PKT_LEN_SIZE) + return GIT_EBUFS; + + memcpy(num, line, PKT_LEN_SIZE); + num[PKT_LEN_SIZE] = '\0'; + + for (i = 0; i < PKT_LEN_SIZE; ++i) { + if (!git__isxdigit(num[i])) { + /* Make sure there are no special characters before passing to error message */ + for (k = 0; k < PKT_LEN_SIZE; ++k) { + if(!git__isprint(num[k])) { + num[k] = '.'; + } + } + + git_error_set(GIT_ERROR_NET, "invalid hex digit in length: '%s'", num); + return -1; + } + } + + if ((error = git__strntol32(&len, num, PKT_LEN_SIZE, &num_end, 16)) < 0) + return error; + + if (len < 0) + return -1; + + *out = (size_t) len; + return 0; +} + +/* + * As per the documentation, the syntax is: + * + * pkt-line = data-pkt / flush-pkt + * data-pkt = pkt-len pkt-payload + * pkt-len = 4*(HEXDIG) + * pkt-payload = (pkt-len -4)*(OCTET) + * flush-pkt = "0000" + * + * Which means that the first four bytes are the length of the line, + * in ASCII hexadecimal (including itself) + */ + +int git_pkt_parse_line( + git_pkt **pkt, + const char **endptr, + const char *line, + size_t linelen, + git_pkt_parse_data *data) +{ + int error; + size_t len; + + if ((error = parse_len(&len, line, linelen)) < 0) { + /* + * If we fail to parse the length, it might be + * because the server is trying to send us the + * packfile already or because we do not yet have + * enough data. + */ + if (error == GIT_EBUFS) + ; + else if (!git__prefixncmp(line, linelen, "PACK")) + git_error_set(GIT_ERROR_NET, "unexpected pack file"); + else + git_error_set(GIT_ERROR_NET, "bad packet length"); + return error; + } + + /* + * Make sure there is enough in the buffer to satisfy + * this line. + */ + if (linelen < len) + return GIT_EBUFS; + + /* + * The length has to be exactly 0 in case of a flush + * packet or greater than PKT_LEN_SIZE, as the decoded + * length includes its own encoded length of four bytes. + */ + if (len != 0 && len < PKT_LEN_SIZE) + return GIT_ERROR; + + line += PKT_LEN_SIZE; + /* + * The Git protocol does not specify empty lines as part + * of the protocol. Not knowing what to do with an empty + * line, we should return an error upon hitting one. + */ + if (len == PKT_LEN_SIZE) { + git_error_set_str(GIT_ERROR_NET, "Invalid empty packet"); + return GIT_ERROR; + } + + if (len == 0) { /* Flush pkt */ + *endptr = line; + return flush_pkt(pkt); + } + + len -= PKT_LEN_SIZE; /* the encoded length includes its own size */ + + if (*line == GIT_SIDE_BAND_DATA) + error = data_pkt(pkt, line, len); + else if (*line == GIT_SIDE_BAND_PROGRESS) + error = sideband_progress_pkt(pkt, line, len); + else if (*line == GIT_SIDE_BAND_ERROR) + error = sideband_error_pkt(pkt, line, len); + else if (!git__prefixncmp(line, len, "ACK")) + error = ack_pkt(pkt, line, len, data); + else if (!git__prefixncmp(line, len, "NAK")) + error = nak_pkt(pkt); + else if (!git__prefixncmp(line, len, "ERR")) + error = err_pkt(pkt, line, len); + else if (*line == '#') + error = comment_pkt(pkt, line, len); + else if (!git__prefixncmp(line, len, "ok")) + error = ok_pkt(pkt, line, len); + else if (!git__prefixncmp(line, len, "ng")) + error = ng_pkt(pkt, line, len); + else if (!git__prefixncmp(line, len, "unpack")) + error = unpack_pkt(pkt, line, len); + else if (!git__prefixcmp(line, "shallow")) + error = shallow_pkt(pkt, line, len, data); + else if (!git__prefixcmp(line, "unshallow")) + error = unshallow_pkt(pkt, line, len, data); + else + error = ref_pkt(pkt, line, len, data); + + *endptr = line + len; + + return error; +} + +void git_pkt_free(git_pkt *pkt) +{ + if (pkt == NULL) { + return; + } + if (pkt->type == GIT_PKT_REF) { + git_pkt_ref *p = (git_pkt_ref *) pkt; + git__free(p->head.name); + git__free(p->head.symref_target); + } + + if (pkt->type == GIT_PKT_OK) { + git_pkt_ok *p = (git_pkt_ok *) pkt; + git__free(p->ref); + } + + if (pkt->type == GIT_PKT_NG) { + git_pkt_ng *p = (git_pkt_ng *) pkt; + git__free(p->ref); + git__free(p->msg); + } + + git__free(pkt); +} + +int git_pkt_buffer_flush(git_str *buf) +{ + return git_str_put(buf, PKT_FLUSH_STR, CONST_STRLEN(PKT_FLUSH_STR)); +} + +static int buffer_want_with_caps( + const git_remote_head *head, + transport_smart_caps *caps, + git_oid_t oid_type, + git_str *buf) +{ + git_str str = GIT_STR_INIT; + char oid[GIT_OID_MAX_HEXSIZE]; + size_t oid_hexsize, len; + + oid_hexsize = git_oid_hexsize(oid_type); + git_oid_fmt(oid, &head->oid); + + /* Prefer multi_ack_detailed */ + if (caps->multi_ack_detailed) + git_str_puts(&str, GIT_CAP_MULTI_ACK_DETAILED " "); + else if (caps->multi_ack) + git_str_puts(&str, GIT_CAP_MULTI_ACK " "); + + /* Prefer side-band-64k if the server supports both */ + if (caps->side_band_64k) + git_str_printf(&str, "%s ", GIT_CAP_SIDE_BAND_64K); + else if (caps->side_band) + git_str_printf(&str, "%s ", GIT_CAP_SIDE_BAND); + + if (caps->include_tag) + git_str_puts(&str, GIT_CAP_INCLUDE_TAG " "); + + if (caps->thin_pack) + git_str_puts(&str, GIT_CAP_THIN_PACK " "); + + if (caps->ofs_delta) + git_str_puts(&str, GIT_CAP_OFS_DELTA " "); + + if (caps->shallow) + git_str_puts(&str, GIT_CAP_SHALLOW " "); + + if (git_str_oom(&str)) + return -1; + + if (str.size > (PKT_MAX_SIZE - (PKT_MAX_WANTLEN + 1))) { + git_error_set(GIT_ERROR_NET, + "tried to produce packet with invalid caps length %" PRIuZ, str.size); + return -1; + } + + len = PKT_LEN_SIZE + CONST_STRLEN(PKT_WANT_PREFIX) + + oid_hexsize + 1 /* NUL */ + + git_str_len(&str) + 1 /* LF */; + + git_str_grow_by(buf, len); + git_str_printf(buf, + "%04x%s%.*s %s\n", (unsigned int)len, PKT_WANT_PREFIX, + (int)oid_hexsize, oid, git_str_cstr(&str)); + git_str_dispose(&str); + + GIT_ERROR_CHECK_ALLOC_STR(buf); + + return 0; +} + +/* + * All "want" packets have the same length and format, so what we do + * is overwrite the OID each time. + */ + +int git_pkt_buffer_wants( + const git_fetch_negotiation *wants, + transport_smart_caps *caps, + git_str *buf) +{ + const git_remote_head *head; + char oid[GIT_OID_MAX_HEXSIZE]; + git_oid_t oid_type; + size_t oid_hexsize, want_len, i = 0; + +#ifdef GIT_EXPERIMENTAL_SHA256 + oid_type = wants->refs_len > 0 ? wants->refs[0]->oid.type : GIT_OID_SHA1; +#else + oid_type = GIT_OID_SHA1; +#endif + + oid_hexsize = git_oid_hexsize(oid_type); + + want_len = PKT_LEN_SIZE + CONST_STRLEN(PKT_WANT_PREFIX) + + oid_hexsize + 1 /* LF */; + + if (caps->common) { + for (; i < wants->refs_len; ++i) { + head = wants->refs[i]; + if (!head->local) + break; + } + + if (buffer_want_with_caps(wants->refs[i], caps, oid_type, buf) < 0) + return -1; + + i++; + } + + for (; i < wants->refs_len; ++i) { + head = wants->refs[i]; + + if (head->local) + continue; + + git_oid_fmt(oid, &head->oid); + + git_str_printf(buf, "%04x%s%.*s\n", + (unsigned int)want_len, PKT_WANT_PREFIX, + (int)oid_hexsize, oid); + + if (git_str_oom(buf)) + return -1; + } + + /* Tell the server about our shallow objects */ + for (i = 0; i < wants->shallow_roots_len; i++) { + char oid[GIT_OID_MAX_HEXSIZE + 1]; + git_str shallow_buf = GIT_STR_INIT; + + git_oid_tostr(oid, GIT_OID_MAX_HEXSIZE + 1, &wants->shallow_roots[i]); + git_str_puts(&shallow_buf, "shallow "); + git_str_puts(&shallow_buf, oid); + git_str_putc(&shallow_buf, '\n'); + + git_str_printf(buf, "%04x%s", (unsigned int)git_str_len(&shallow_buf) + 4, git_str_cstr(&shallow_buf)); + + git_str_dispose(&shallow_buf); + + if (git_str_oom(buf)) + return -1; + } + + if (wants->depth > 0) { + git_str deepen_buf = GIT_STR_INIT; + + git_str_printf(&deepen_buf, "deepen %d\n", wants->depth); + git_str_printf(buf,"%04x%s", (unsigned int)git_str_len(&deepen_buf) + 4, git_str_cstr(&deepen_buf)); + + git_str_dispose(&deepen_buf); + + if (git_str_oom(buf)) + return -1; + } + + return git_pkt_buffer_flush(buf); +} + +int git_pkt_buffer_have(git_oid *oid, git_str *buf) +{ + char oid_str[GIT_OID_MAX_HEXSIZE]; + git_oid_t oid_type; + size_t oid_hexsize, have_len; + +#ifdef GIT_EXPERIMENTAL_SHA256 + oid_type = oid->type; +#else + oid_type = GIT_OID_SHA1; +#endif + + oid_hexsize = git_oid_hexsize(oid_type); + have_len = PKT_LEN_SIZE + CONST_STRLEN(PKT_HAVE_PREFIX) + + oid_hexsize + 1 /* LF */; + + git_oid_fmt(oid_str, oid); + return git_str_printf(buf, "%04x%s%.*s\n", + (unsigned int)have_len, PKT_HAVE_PREFIX, + (int)oid_hexsize, oid_str); +} + +int git_pkt_buffer_done(git_str *buf) +{ + return git_str_put(buf, PKT_DONE_STR, CONST_STRLEN(PKT_DONE_STR)); +} diff --git a/vendor/libgit2/src/transports/smart_protocol.c b/vendor/libgit2/src/libgit2/transports/smart_protocol.c similarity index 77% rename from vendor/libgit2/src/transports/smart_protocol.c rename to vendor/libgit2/src/libgit2/transports/smart_protocol.c index 8cf02713..df1c190c 100644 --- a/vendor/libgit2/src/transports/smart_protocol.c +++ b/vendor/libgit2/src/libgit2/transports/smart_protocol.c @@ -27,11 +27,11 @@ bool git_smart__ofs_delta_enabled = true; int git_smart__store_refs(transport_smart *t, int flushes) { - gitno_buffer *buf = &t->buffer; git_vector *refs = &t->refs; int error, flush = 0, recvd; const char *line_end = NULL; git_pkt *pkt = NULL; + git_pkt_parse_data pkt_parse_data = { 0 }; size_t i; /* Clear existing refs in case git_remote_connect() is called again @@ -44,8 +44,10 @@ int git_smart__store_refs(transport_smart *t, int flushes) pkt = NULL; do { - if (buf->offset > 0) - error = git_pkt_parse_line(&pkt, &line_end, buf->data, buf->offset); + if (t->buffer.len > 0) + error = git_pkt_parse_line(&pkt, &line_end, + t->buffer.data, t->buffer.len, + &pkt_parse_data); else error = GIT_EBUFS; @@ -53,19 +55,18 @@ int git_smart__store_refs(transport_smart *t, int flushes) return error; if (error == GIT_EBUFS) { - if ((recvd = gitno_recv(buf)) < 0) + if ((recvd = git_smart__recv(t)) < 0) return recvd; if (recvd == 0) { - git_error_set(GIT_ERROR_NET, "early EOF"); + git_error_set(GIT_ERROR_NET, "could not read refs from remote repository"); return GIT_EEOF; } continue; } - if (gitno_consume(buf, line_end) < 0) - return -1; + git_staticstr_consume(&t->buffer, line_end); if (pkt->type == GIT_PKT_ERR) { git_error_set(GIT_ERROR_NET, "remote error: %s", ((git_pkt_err *)pkt)->error); @@ -133,9 +134,12 @@ static int append_symref(const char **out, git_vector *symrefs, const char *ptr) return -1; } -int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vector *symrefs) +int git_smart__detect_caps( + git_pkt_ref *pkt, + transport_smart_caps *caps, + git_vector *symrefs) { - const char *ptr; + const char *ptr, *start; /* No refs or capabilities, odd but not a problem */ if (pkt == NULL || pkt->capabilities == NULL) @@ -190,6 +194,12 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vec continue; } + if (!git__prefixcmp(ptr, GIT_CAP_PUSH_OPTIONS)) { + caps->common = caps->push_options = 1; + ptr += strlen(GIT_CAP_PUSH_OPTIONS); + continue; + } + if (!git__prefixcmp(ptr, GIT_CAP_THIN_PACK)) { caps->common = caps->thin_pack = 1; ptr += strlen(GIT_CAP_THIN_PACK); @@ -207,13 +217,41 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vec if (!git__prefixcmp(ptr, GIT_CAP_WANT_TIP_SHA1)) { caps->common = caps->want_tip_sha1 = 1; - ptr += strlen(GIT_CAP_DELETE_REFS); + ptr += strlen(GIT_CAP_WANT_TIP_SHA1); continue; } if (!git__prefixcmp(ptr, GIT_CAP_WANT_REACHABLE_SHA1)) { caps->common = caps->want_reachable_sha1 = 1; - ptr += strlen(GIT_CAP_DELETE_REFS); + ptr += strlen(GIT_CAP_WANT_REACHABLE_SHA1); + continue; + } + + if (!git__prefixcmp(ptr, GIT_CAP_OBJECT_FORMAT)) { + ptr += strlen(GIT_CAP_OBJECT_FORMAT); + + start = ptr; + ptr = strchr(ptr, ' '); + + if ((caps->object_format = git__strndup(start, (ptr - start))) == NULL) + return -1; + continue; + } + + if (!git__prefixcmp(ptr, GIT_CAP_AGENT)) { + ptr += strlen(GIT_CAP_AGENT); + + start = ptr; + ptr = strchr(ptr, ' '); + + if ((caps->agent = git__strndup(start, (ptr - start))) == NULL) + return -1; + continue; + } + + if (!git__prefixcmp(ptr, GIT_CAP_SHALLOW)) { + caps->common = caps->shallow = 1; + ptr += strlen(GIT_CAP_SHALLOW); continue; } @@ -224,15 +262,23 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vec return 0; } -static int recv_pkt(git_pkt **out_pkt, git_pkt_type *out_type, gitno_buffer *buf) +static int recv_pkt( + git_pkt **out_pkt, + git_pkt_type *out_type, + transport_smart *t) { - const char *ptr = buf->data, *line_end = ptr; + const char *ptr = t->buffer.data, *line_end = ptr; git_pkt *pkt = NULL; + git_pkt_parse_data pkt_parse_data = { 0 }; int error = 0, ret; + pkt_parse_data.oid_type = t->owner->repo->oid_type; + pkt_parse_data.seen_capabilities = 1; + do { - if (buf->offset > 0) - error = git_pkt_parse_line(&pkt, &line_end, ptr, buf->offset); + if (t->buffer.len > 0) + error = git_pkt_parse_line(&pkt, &line_end, ptr, + t->buffer.len, &pkt_parse_data); else error = GIT_EBUFS; @@ -242,16 +288,15 @@ static int recv_pkt(git_pkt **out_pkt, git_pkt_type *out_type, gitno_buffer *buf if (error < 0 && error != GIT_EBUFS) return error; - if ((ret = gitno_recv(buf)) < 0) { + if ((ret = git_smart__recv(t)) < 0) { return ret; } else if (ret == 0) { - git_error_set(GIT_ERROR_NET, "early EOF"); + git_error_set(GIT_ERROR_NET, "could not read from remote repository"); return GIT_EEOF; } } while (error); - if (gitno_consume(buf, line_end) < 0) - return -1; + git_staticstr_consume(&t->buffer, line_end); if (out_type != NULL) *out_type = pkt->type; @@ -266,11 +311,10 @@ static int recv_pkt(git_pkt **out_pkt, git_pkt_type *out_type, gitno_buffer *buf static int store_common(transport_smart *t) { git_pkt *pkt = NULL; - gitno_buffer *buf = &t->buffer; int error; do { - if ((error = recv_pkt(&pkt, NULL, buf)) < 0) + if ((error = recv_pkt(&pkt, NULL, t)) < 0) return error; if (pkt->type != GIT_PKT_ACK) { @@ -287,7 +331,7 @@ static int store_common(transport_smart *t) return 0; } -static int wait_while_ack(gitno_buffer *buf) +static int wait_while_ack(transport_smart *t) { int error; git_pkt *pkt = NULL; @@ -296,7 +340,7 @@ static int wait_while_ack(gitno_buffer *buf) while (1) { git_pkt_free(pkt); - if ((error = recv_pkt(&pkt, NULL, buf)) < 0) + if ((error = recv_pkt(&pkt, NULL, t)) < 0) return error; if (pkt->type == GIT_PKT_NAK) @@ -317,11 +361,51 @@ static int wait_while_ack(gitno_buffer *buf) return 0; } -int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, const git_remote_head * const *wants, size_t count) +static int cap_not_sup_err(const char *cap_name) +{ + git_error_set(GIT_ERROR_NET, "server doesn't support %s", cap_name); + return GIT_EINVALID; +} + +/* Disables server capabilities we're not interested in */ +static int setup_caps( + transport_smart_caps *caps, + const git_fetch_negotiation *wants) +{ + if (wants->depth > 0) { + if (!caps->shallow) + return cap_not_sup_err(GIT_CAP_SHALLOW); + } else { + caps->shallow = 0; + } + + return 0; +} + +static int setup_shallow_roots( + git_array_oid_t *out, + const git_fetch_negotiation *wants) +{ + git_array_clear(*out); + + if (wants->shallow_roots_len > 0) { + git_array_init_to_size(*out, wants->shallow_roots_len); + GIT_ERROR_CHECK_ALLOC(out->ptr); + + memcpy(out->ptr, wants->shallow_roots, + sizeof(git_oid) * wants->shallow_roots_len); + } + + return 0; +} + +int git_smart__negotiate_fetch( + git_transport *transport, + git_repository *repo, + const git_fetch_negotiation *wants) { transport_smart *t = (transport_smart *)transport; git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT; - gitno_buffer *buf = &t->buffer; git_str data = GIT_STR_INIT; git_revwalk *walk = NULL; int error = -1; @@ -329,7 +413,11 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c unsigned int i; git_oid oid; - if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0) + if ((error = setup_caps(&t->caps, wants)) < 0 || + (error = setup_shallow_roots(&t->shallow_roots, wants)) < 0) + return error; + + if ((error = git_pkt_buffer_wants(wants, &t->caps, &data)) < 0) return error; if ((error = git_revwalk_new(&walk, repo)) < 0) @@ -339,6 +427,37 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c if ((error = git_revwalk__push_glob(walk, "refs/*", &opts)) < 0) goto on_error; + if (wants->depth > 0) { + git_pkt_shallow *pkt; + + if ((error = git_smart__negotiation_step(&t->parent, data.ptr, data.size)) < 0) + goto on_error; + + while ((error = recv_pkt((git_pkt **)&pkt, NULL, t)) == 0) { + bool complete = false; + + if (pkt->type == GIT_PKT_SHALLOW) { + error = git_oidarray__add(&t->shallow_roots, &pkt->oid); + } else if (pkt->type == GIT_PKT_UNSHALLOW) { + git_oidarray__remove(&t->shallow_roots, &pkt->oid); + } else if (pkt->type == GIT_PKT_FLUSH) { + /* Server is done, stop processing shallow oids */ + complete = true; + } else { + git_error_set(GIT_ERROR_NET, "unexpected packet type"); + error = -1; + } + + git_pkt_free((git_pkt *) pkt); + + if (complete || error < 0) + break; + } + + if (error < 0) + goto on_error; + } + /* * Our support for ACK extensions is simply to parse them. On * the first ACK we will accept that as enough common @@ -379,7 +498,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c if ((error = store_common(t)) < 0) goto on_error; } else { - if ((error = recv_pkt(NULL, &pkt_type, buf)) < 0) + if ((error = recv_pkt(NULL, &pkt_type, t)) < 0) goto on_error; if (pkt_type == GIT_PKT_ACK) { @@ -401,7 +520,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c git_pkt_ack *pkt; unsigned int j; - if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0) + if ((error = git_pkt_buffer_wants(wants, &t->caps, &data)) < 0) goto on_error; git_vector_foreach(&t->common, j, pkt) { @@ -421,7 +540,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c git_pkt_ack *pkt; unsigned int j; - if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0) + if ((error = git_pkt_buffer_wants(wants, &t->caps, &data)) < 0) goto on_error; git_vector_foreach(&t->common, j, pkt) { @@ -439,10 +558,11 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c goto on_error; if (t->cancelled.val) { - git_error_set(GIT_ERROR_NET, "The fetch was cancelled by the user"); + git_error_set(GIT_ERROR_NET, "the fetch was cancelled"); error = GIT_EUSER; goto on_error; } + if ((error = git_smart__negotiation_step(&t->parent, data.ptr, data.size)) < 0) goto on_error; @@ -451,7 +571,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c /* Now let's eat up whatever the server gives us */ if (!t->caps.multi_ack && !t->caps.multi_ack_detailed) { - if ((error = recv_pkt(NULL, &pkt_type, buf)) < 0) + if ((error = recv_pkt(NULL, &pkt_type, t)) < 0) return error; if (pkt_type != GIT_PKT_ACK && pkt_type != GIT_PKT_NAK) { @@ -459,7 +579,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c return -1; } } else { - error = wait_while_ack(buf); + error = wait_while_ack(t); } return error; @@ -470,7 +590,29 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c return error; } -static int no_sideband(transport_smart *t, struct git_odb_writepack *writepack, gitno_buffer *buf, git_indexer_progress *stats) +int git_smart__shallow_roots(git_oidarray *out, git_transport *transport) +{ + transport_smart *t = (transport_smart *)transport; + size_t len; + + GIT_ERROR_CHECK_ALLOC_MULTIPLY(&len, t->shallow_roots.size, sizeof(git_oid)); + + out->count = t->shallow_roots.size; + + if (len) { + out->ids = git__malloc(len); + memcpy(out->ids, t->shallow_roots.ptr, len); + } else { + out->ids = NULL; + } + + return 0; +} + +static int no_sideband( + transport_smart *t, + struct git_odb_writepack *writepack, + git_indexer_progress *stats) { int recvd; @@ -480,12 +622,12 @@ static int no_sideband(transport_smart *t, struct git_odb_writepack *writepack, return GIT_EUSER; } - if (writepack->append(writepack, buf->data, buf->offset, stats) < 0) + if (writepack->append(writepack, t->buffer.data, t->buffer.len, stats) < 0) return -1; - gitno_consume_n(buf, buf->offset); + git_staticstr_clear(&t->buffer); - if ((recvd = gitno_recv(buf)) < 0) + if ((recvd = git_smart__recv(t)) < 0) return recvd; } while(recvd > 0); @@ -527,7 +669,6 @@ int git_smart__download_pack( git_indexer_progress *stats) { transport_smart *t = (transport_smart *)transport; - gitno_buffer *buf = &t->buffer; git_odb *odb; struct git_odb_writepack *writepack = NULL; int error = 0; @@ -546,9 +687,10 @@ int git_smart__download_pack( t->packetsize_payload = &npp; /* We might have something in the buffer already from negotiate_fetch */ - if (t->buffer.offset > 0 && !t->cancelled.val) - if (t->packetsize_cb(t->buffer.offset, t->packetsize_payload)) + if (t->buffer.len > 0 && !t->cancelled.val) { + if (t->packetsize_cb(t->buffer.len, t->packetsize_payload)) git_atomic32_set(&t->cancelled, 1); + } } if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 || @@ -561,7 +703,7 @@ int git_smart__download_pack( * check which one belongs there. */ if (!t->caps.side_band && !t->caps.side_band_64k) { - error = no_sideband(t, writepack, buf, stats); + error = no_sideband(t, writepack, stats); goto done; } @@ -575,7 +717,7 @@ int git_smart__download_pack( goto done; } - if ((error = recv_pkt(&pkt, NULL, buf)) >= 0) { + if ((error = recv_pkt(&pkt, NULL, t)) >= 0) { /* Check cancellation after network call */ if (t->cancelled.val) { git_error_clear(); @@ -642,33 +784,54 @@ int git_smart__download_pack( static int gen_pktline(git_str *buf, git_push *push) { push_spec *spec; + char *option; size_t i, len; - char old_id[GIT_OID_HEXSZ+1], new_id[GIT_OID_HEXSZ+1]; - - old_id[GIT_OID_HEXSZ] = '\0'; new_id[GIT_OID_HEXSZ] = '\0'; + char old_id[GIT_OID_MAX_HEXSIZE + 1], new_id[GIT_OID_MAX_HEXSIZE + 1]; + size_t old_id_len, new_id_len; git_vector_foreach(&push->specs, i, spec) { - len = 2*GIT_OID_HEXSZ + 7 + strlen(spec->refspec.dst); + len = strlen(spec->refspec.dst) + 7; if (i == 0) { - ++len; /* '\0' */ + /* Need a leading \0 */ + ++len; + if (push->report_status) len += strlen(GIT_CAP_REPORT_STATUS) + 1; + + if (git_vector_length(&push->remote_push_options) > 0) + len += strlen(GIT_CAP_PUSH_OPTIONS) + 1; + len += strlen(GIT_CAP_SIDE_BAND_64K) + 1; } + old_id_len = git_oid_hexsize(git_oid_type(&spec->roid)); + new_id_len = git_oid_hexsize(git_oid_type(&spec->loid)); + + len += (old_id_len + new_id_len); + git_oid_fmt(old_id, &spec->roid); + old_id[old_id_len] = '\0'; + git_oid_fmt(new_id, &spec->loid); + new_id[new_id_len] = '\0'; - git_str_printf(buf, "%04"PRIxZ"%s %s %s", len, old_id, new_id, spec->refspec.dst); + git_str_printf(buf, "%04"PRIxZ"%.*s %.*s %s", len, + (int)old_id_len, old_id, (int)new_id_len, new_id, + spec->refspec.dst); if (i == 0) { git_str_putc(buf, '\0'); + /* Core git always starts their capabilities string with a space */ if (push->report_status) { git_str_putc(buf, ' '); git_str_printf(buf, GIT_CAP_REPORT_STATUS); } + if (git_vector_length(&push->remote_push_options) > 0) { + git_str_putc(buf, ' '); + git_str_printf(buf, GIT_CAP_PUSH_OPTIONS); + } git_str_putc(buf, ' '); git_str_printf(buf, GIT_CAP_SIDE_BAND_64K); } @@ -676,6 +839,13 @@ static int gen_pktline(git_str *buf, git_push *push) git_str_putc(buf, '\n'); } + if (git_vector_length(&push->remote_push_options) > 0) { + git_str_printf(buf, "0000"); + git_vector_foreach(&push->remote_push_options, i, option) { + git_str_printf(buf, "%04"PRIxZ"%s", strlen(option) + 4 , option); + } + } + git_str_puts(buf, "0000"); return git_str_oom(buf) ? -1 : 0; } @@ -723,6 +893,7 @@ static int add_push_report_pkt(git_push *push, git_pkt *pkt) static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt, git_str *data_pkt_buf) { git_pkt *pkt; + git_pkt_parse_data pkt_parse_data = { 0 }; const char *line, *line_end = NULL; size_t line_len; int error; @@ -741,7 +912,7 @@ static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt, } while (line_len > 0) { - error = git_pkt_parse_line(&pkt, &line_end, line, line_len); + error = git_pkt_parse_line(&pkt, &line_end, line, line_len, &pkt_parse_data); if (error == GIT_EBUFS) { /* Buffer the data when the inner packet is split @@ -777,15 +948,17 @@ static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt, static int parse_report(transport_smart *transport, git_push *push) { git_pkt *pkt = NULL; + git_pkt_parse_data pkt_parse_data = { 0 }; const char *line_end = NULL; - gitno_buffer *buf = &transport->buffer; int error, recvd; git_str data_pkt_buf = GIT_STR_INIT; for (;;) { - if (buf->offset > 0) + if (transport->buffer.len > 0) error = git_pkt_parse_line(&pkt, &line_end, - buf->data, buf->offset); + transport->buffer.data, + transport->buffer.len, + &pkt_parse_data); else error = GIT_EBUFS; @@ -795,22 +968,20 @@ static int parse_report(transport_smart *transport, git_push *push) } if (error == GIT_EBUFS) { - if ((recvd = gitno_recv(buf)) < 0) { + if ((recvd = git_smart__recv(transport)) < 0) { error = recvd; goto done; } if (recvd == 0) { - git_error_set(GIT_ERROR_NET, "early EOF"); + git_error_set(GIT_ERROR_NET, "could not read report from remote repository"); error = GIT_EEOF; goto done; } continue; } - if (gitno_consume(buf, line_end) < 0) - return -1; - + git_staticstr_consume(&transport->buffer, line_end); error = 0; switch (pkt->type) { @@ -975,7 +1146,7 @@ struct push_packbuilder_payload git_push_transfer_progress_cb cb; void *cb_payload; size_t last_bytes; - double last_progress_report_time; + uint64_t last_progress_report_time; }; static int stream_thunk(void *buf, size_t size, void *data) @@ -987,11 +1158,11 @@ static int stream_thunk(void *buf, size_t size, void *data) return error; if (payload->cb) { - double current_time = git__timer(); - double elapsed = current_time - payload->last_progress_report_time; + uint64_t current_time = git_time_monotonic(); + uint64_t elapsed = current_time - payload->last_progress_report_time; payload->last_bytes += size; - if (elapsed < 0 || elapsed >= MIN_PROGRESS_UPDATE_INTERVAL) { + if (elapsed >= MIN_PROGRESS_UPDATE_INTERVAL) { payload->last_progress_report_time = current_time; error = payload->cb(payload->pb->nr_written, payload->pb->nr_objects, payload->last_bytes, payload->cb_payload); } @@ -1020,7 +1191,7 @@ int git_smart__push(git_transport *transport, git_push *push) #ifdef PUSH_DEBUG { git_remote_head *head; - char hex[GIT_OID_HEXSZ+1]; hex[GIT_OID_HEXSZ] = '\0'; + char hex[GIT_OID_MAX_HEXSIZE+1], hex[GIT_OID_MAX_HEXSIZE] = '\0'; git_vector_foreach(&push->remote->refs, i, head) { git_oid_fmt(hex, &head->oid); diff --git a/vendor/libgit2/src/libgit2/transports/ssh.c b/vendor/libgit2/src/libgit2/transports/ssh.c new file mode 100644 index 00000000..3f3a127f --- /dev/null +++ b/vendor/libgit2/src/libgit2/transports/ssh.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "ssh_exec.h" +#include "ssh_libssh2.h" + +#include "transports/smart.h" + +int git_smart_subtransport_ssh( + git_smart_subtransport **out, + git_transport *owner, + void *param) +{ +#ifdef GIT_SSH_LIBSSH2 + return git_smart_subtransport_ssh_libssh2(out, owner, param); +#elif GIT_SSH_EXEC + return git_smart_subtransport_ssh_exec(out, owner, param); +#else + GIT_UNUSED(out); + GIT_UNUSED(owner); + GIT_UNUSED(param); + + git_error_set(GIT_ERROR_INVALID, "cannot create SSH transport; library was built without SSH support"); + return -1; +#endif +} + +static int transport_set_paths(git_transport *t, git_strarray *paths) +{ + transport_smart *smart = (transport_smart *)t; + +#ifdef GIT_SSH_LIBSSH2 + return git_smart_subtransport_ssh_libssh2_set_paths( + (git_smart_subtransport *)smart->wrapped, + paths->strings[0], + paths->strings[1]); +#elif GIT_SSH_EXEC + return git_smart_subtransport_ssh_exec_set_paths( + (git_smart_subtransport *)smart->wrapped, + paths->strings[0], + paths->strings[1]); +#else + GIT_UNUSED(t); + GIT_UNUSED(smart); + GIT_UNUSED(paths); + + GIT_ASSERT(!"cannot create SSH library; library was built without SSH support"); + return -1; +#endif +} + +int git_transport_ssh_with_paths( + git_transport **out, + git_remote *owner, + void *payload) +{ + git_strarray *paths = (git_strarray *) payload; + git_transport *transport; + int error; + + git_smart_subtransport_definition ssh_definition = { + git_smart_subtransport_ssh, + 0, /* no RPC */ + NULL + }; + + if (paths->count != 2) { + git_error_set(GIT_ERROR_SSH, "invalid ssh paths, must be two strings"); + return GIT_EINVALIDSPEC; + } + + if ((error = git_transport_smart(&transport, owner, &ssh_definition)) < 0) + return error; + + if ((error = transport_set_paths(transport, paths)) < 0) + return error; + + *out = transport; + return 0; +} + diff --git a/vendor/libgit2/src/libgit2/transports/ssh_exec.c b/vendor/libgit2/src/libgit2/transports/ssh_exec.c new file mode 100644 index 00000000..b0699f53 --- /dev/null +++ b/vendor/libgit2/src/libgit2/transports/ssh_exec.c @@ -0,0 +1,385 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "ssh_exec.h" + +#ifdef GIT_SSH_EXEC + +#include "common.h" + +#include "config.h" +#include "net.h" +#include "path.h" +#include "futils.h" +#include "process.h" +#include "transports/smart.h" + +typedef struct { + git_smart_subtransport_stream parent; +} ssh_exec_subtransport_stream; + +typedef struct { + git_smart_subtransport parent; + git_transport *owner; + + ssh_exec_subtransport_stream *current_stream; + + char *cmd_uploadpack; + char *cmd_receivepack; + + git_smart_service_t action; + git_process *process; +} ssh_exec_subtransport; + +static int ssh_exec_subtransport_stream_read( + git_smart_subtransport_stream *s, + char *buffer, + size_t buf_size, + size_t *bytes_read) +{ + ssh_exec_subtransport *transport; + ssh_exec_subtransport_stream *stream = (ssh_exec_subtransport_stream *)s; + ssize_t ret; + + GIT_ASSERT_ARG(stream); + GIT_ASSERT(stream->parent.subtransport); + + transport = (ssh_exec_subtransport *)stream->parent.subtransport; + + if ((ret = git_process_read(transport->process, buffer, buf_size)) < 0) { + return (int)ret; + } + + *bytes_read = (size_t)ret; + return 0; +} + +static int ssh_exec_subtransport_stream_write( + git_smart_subtransport_stream *s, + const char *buffer, + size_t len) +{ + ssh_exec_subtransport *transport; + ssh_exec_subtransport_stream *stream = (ssh_exec_subtransport_stream *)s; + ssize_t ret; + + GIT_ASSERT(stream && stream->parent.subtransport); + + transport = (ssh_exec_subtransport *)stream->parent.subtransport; + + while (len > 0) { + if ((ret = git_process_write(transport->process, buffer, len)) < 0) + return (int)ret; + + len -= ret; + } + + return 0; +} + +static void ssh_exec_subtransport_stream_free(git_smart_subtransport_stream *s) +{ + ssh_exec_subtransport_stream *stream = (ssh_exec_subtransport_stream *)s; + + git__free(stream); +} + +static int ssh_exec_subtransport_stream_init( + ssh_exec_subtransport_stream **out, + ssh_exec_subtransport *transport) +{ + GIT_ASSERT_ARG(out); + + *out = git__calloc(sizeof(ssh_exec_subtransport_stream), 1); + GIT_ERROR_CHECK_ALLOC(*out); + + (*out)->parent.subtransport = &transport->parent; + (*out)->parent.read = ssh_exec_subtransport_stream_read; + (*out)->parent.write = ssh_exec_subtransport_stream_write; + (*out)->parent.free = ssh_exec_subtransport_stream_free; + + return 0; +} + +GIT_INLINE(int) ensure_transport_state( + ssh_exec_subtransport *transport, + git_smart_service_t expected, + git_smart_service_t next) +{ + if (transport->action != expected && transport->action != next) { + git_error_set(GIT_ERROR_NET, "invalid transport state"); + + return -1; + } + + return 0; +} + +static int get_ssh_cmdline( + git_vector *args, + bool *use_shell, + ssh_exec_subtransport *transport, + git_net_url *url, + const char *command) +{ + git_remote *remote = ((transport_smart *)transport->owner)->owner; + git_repository *repo = remote->repo; + git_config *cfg; + git_str ssh_cmd = GIT_STR_INIT, url_and_host = GIT_STR_INIT, + remote_cmd = GIT_STR_INIT; + const char *default_ssh_cmd = "ssh"; + char *p, *port; + int error; + + /* + * Safety check: like git, we forbid paths that look like an + * option as that could lead to injection to ssh that can make + * us do unexpected things + */ + if (git_process__is_cmdline_option(url->username)) { + git_error_set(GIT_ERROR_NET, "cannot ssh: username '%s' is ambiguous with command-line option", url->username); + return -1; + } else if (git_process__is_cmdline_option(url->host)) { + git_error_set(GIT_ERROR_NET, "cannot ssh: host '%s' is ambiguous with command-line option", url->host); + return -1; + } else if (git_process__is_cmdline_option(url->path)) { + git_error_set(GIT_ERROR_NET, "cannot ssh: path '%s' is ambiguous with command-line option", url->path); + return -1; + } + + if ((error = git_repository_config_snapshot(&cfg, repo)) < 0) + return error; + + if ((error = git__getenv(&ssh_cmd, "GIT_SSH_COMMAND")) == 0) + *use_shell = true; + else if (error != GIT_ENOTFOUND) + goto done; + else if ((error = git__getenv(&ssh_cmd, "GIT_SSH")) == 0) + *use_shell = false; + else if (error != GIT_ENOTFOUND) + goto done; + else if ((error = git_config__get_string_buf(&ssh_cmd, cfg, "core.sshcommand")) < 0 && error != GIT_ENOTFOUND) + goto done; + + git_error_clear(); + + if (!ssh_cmd.size && + git_str_puts(&ssh_cmd, default_ssh_cmd) < 0) + goto done; + + if ((error = git_vector_insert(args, git_str_detach(&ssh_cmd))) < 0) + goto done; + + p = git__strdup("-p"); + port = git__strdup(url->port); + + if (!p || !port || + (error = git_vector_insert(args, p)) < 0 || + (error = git_vector_insert(args, port)) < 0) + goto done; + + if (url->username) { + if ((error = git_str_puts(&url_and_host, url->username)) < 0 || + (error = git_str_putc(&url_and_host, '@')) < 0) + goto done; + } + + if ((error = git_str_puts(&url_and_host, url->host)) < 0 || + (error = git_vector_insert(args, git_str_detach(&url_and_host))) < 0) + goto done; + + if ((error = git_str_puts(&remote_cmd, command)) < 0 || + (error = git_str_puts(&remote_cmd, " '")) < 0 || + (error = git_str_puts_escaped(&remote_cmd, url->path, "'!", "'\\", "'")) < 0 || + (error = git_str_puts(&remote_cmd, "'")) < 0 || + (error = git_vector_insert(args, git_str_detach(&remote_cmd))) < 0) + goto done; + +done: + git_str_dispose(&ssh_cmd); + git_str_dispose(&url_and_host); + git_str_dispose(&remote_cmd); + git_config_free(cfg); + return error; +} + +static int start_ssh( + ssh_exec_subtransport *transport, + git_smart_service_t action, + const char *sshpath) +{ + const char *env[] = { "GIT_DIR=" }; + + git_process_options process_opts = GIT_PROCESS_OPTIONS_INIT; + git_net_url url = GIT_NET_URL_INIT; + git_vector args = GIT_VECTOR_INIT; + bool use_shell = false; + const char *command; + int error; + + process_opts.capture_in = 1; + process_opts.capture_out = 1; + process_opts.capture_err = 0; + + switch (action) { + case GIT_SERVICE_UPLOADPACK_LS: + command = transport->cmd_uploadpack ? + transport->cmd_uploadpack : "git-upload-pack"; + break; + case GIT_SERVICE_RECEIVEPACK_LS: + command = transport->cmd_receivepack ? + transport->cmd_receivepack : "git-receive-pack"; + break; + default: + git_error_set(GIT_ERROR_NET, "invalid action"); + error = -1; + goto done; + } + + if (git_net_str_is_url(sshpath)) + error = git_net_url_parse(&url, sshpath); + else + error = git_net_url_parse_scp(&url, sshpath); + + if (error < 0) + goto done; + + if ((error = get_ssh_cmdline(&args, &use_shell, + transport, &url, command)) < 0) + goto done; + + process_opts.use_shell = use_shell; + + if ((error = git_process_new(&transport->process, + (const char **)args.contents, args.length, + env, ARRAY_SIZE(env), &process_opts)) < 0 || + (error = git_process_start(transport->process)) < 0) { + git_process_free(transport->process); + transport->process = NULL; + goto done; + } + +done: + git_vector_free_deep(&args); + git_net_url_dispose(&url); + return error; +} + +static int ssh_exec_subtransport_action( + git_smart_subtransport_stream **out, + git_smart_subtransport *t, + const char *sshpath, + git_smart_service_t action) +{ + ssh_exec_subtransport *transport = (ssh_exec_subtransport *)t; + ssh_exec_subtransport_stream *stream = NULL; + git_smart_service_t expected; + int error; + + switch (action) { + case GIT_SERVICE_UPLOADPACK_LS: + case GIT_SERVICE_RECEIVEPACK_LS: + if ((error = ensure_transport_state(transport, 0, 0)) < 0 || + (error = ssh_exec_subtransport_stream_init(&stream, transport)) < 0 || + (error = start_ssh(transport, action, sshpath)) < 0) + goto on_error; + + transport->current_stream = stream; + break; + + case GIT_SERVICE_UPLOADPACK: + case GIT_SERVICE_RECEIVEPACK: + expected = (action == GIT_SERVICE_UPLOADPACK) ? + GIT_SERVICE_UPLOADPACK_LS : GIT_SERVICE_RECEIVEPACK_LS; + + if ((error = ensure_transport_state(transport, expected, action)) < 0) + goto on_error; + + break; + + default: + git_error_set(GIT_ERROR_INVALID, "invalid service request"); + goto on_error; + } + + transport->action = action; + *out = &transport->current_stream->parent; + + return 0; + +on_error: + if (stream != NULL) + ssh_exec_subtransport_stream_free(&stream->parent); + + return -1; +} + +static int ssh_exec_subtransport_close(git_smart_subtransport *t) +{ + ssh_exec_subtransport *transport = (ssh_exec_subtransport *)t; + + if (transport->process) { + git_process_close(transport->process); + git_process_free(transport->process); + transport->process = NULL; + } + + transport->action = 0; + + return 0; +} + +static void ssh_exec_subtransport_free(git_smart_subtransport *t) +{ + ssh_exec_subtransport *transport = (ssh_exec_subtransport *)t; + + git__free(transport->cmd_uploadpack); + git__free(transport->cmd_receivepack); + git__free(transport); +} + +int git_smart_subtransport_ssh_exec( + git_smart_subtransport **out, + git_transport *owner, + void *payload) +{ + ssh_exec_subtransport *transport; + + GIT_UNUSED(payload); + + transport = git__calloc(sizeof(ssh_exec_subtransport), 1); + GIT_ERROR_CHECK_ALLOC(transport); + + transport->owner = owner; + transport->parent.action = ssh_exec_subtransport_action; + transport->parent.close = ssh_exec_subtransport_close; + transport->parent.free = ssh_exec_subtransport_free; + + *out = (git_smart_subtransport *) transport; + return 0; +} + +int git_smart_subtransport_ssh_exec_set_paths( + git_smart_subtransport *subtransport, + const char *cmd_uploadpack, + const char *cmd_receivepack) +{ + ssh_exec_subtransport *t = (ssh_exec_subtransport *)subtransport; + + git__free(t->cmd_uploadpack); + git__free(t->cmd_receivepack); + + t->cmd_uploadpack = git__strdup(cmd_uploadpack); + GIT_ERROR_CHECK_ALLOC(t->cmd_uploadpack); + + t->cmd_receivepack = git__strdup(cmd_receivepack); + GIT_ERROR_CHECK_ALLOC(t->cmd_receivepack); + + return 0; +} + +#endif diff --git a/vendor/libgit2/src/libgit2/transports/ssh_exec.h b/vendor/libgit2/src/libgit2/transports/ssh_exec.h new file mode 100644 index 00000000..4bcba06b --- /dev/null +++ b/vendor/libgit2/src/libgit2/transports/ssh_exec.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_transports_ssh_exec_h__ +#define INCLUDE_transports_ssh_exec_h__ + +#include "common.h" + +#include "git2.h" +#include "git2/transport.h" +#include "git2/sys/transport.h" + +int git_smart_subtransport_ssh_exec( + git_smart_subtransport **out, + git_transport *owner, + void *param); + +int git_smart_subtransport_ssh_exec_set_paths( + git_smart_subtransport *subtransport, + const char *cmd_uploadpack, + const char *cmd_receivepack); + +#endif diff --git a/vendor/libgit2/src/libgit2/transports/ssh_libssh2.c b/vendor/libgit2/src/libgit2/transports/ssh_libssh2.c new file mode 100644 index 00000000..1993ffe5 --- /dev/null +++ b/vendor/libgit2/src/libgit2/transports/ssh_libssh2.c @@ -0,0 +1,1124 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "ssh_libssh2.h" + +#ifdef GIT_SSH_LIBSSH2 + +#include + +#include "runtime.h" +#include "net.h" +#include "smart.h" +#include "process.h" +#include "streams/socket.h" +#include "sysdir.h" + +#include "git2/credential.h" +#include "git2/sys/credential.h" + +#define OWNING_SUBTRANSPORT(s) ((ssh_subtransport *)(s)->parent.subtransport) + +extern int git_socket_stream__timeout; + +static const char cmd_uploadpack[] = "git-upload-pack"; +static const char cmd_receivepack[] = "git-receive-pack"; + +typedef struct { + git_smart_subtransport_stream parent; + git_stream *io; + LIBSSH2_SESSION *session; + LIBSSH2_CHANNEL *channel; + const char *cmd; + git_net_url url; + unsigned sent_command : 1; +} ssh_stream; + +typedef struct { + git_smart_subtransport parent; + transport_smart *owner; + ssh_stream *current_stream; + git_credential *cred; + char *cmd_uploadpack; + char *cmd_receivepack; +} ssh_subtransport; + +static int list_auth_methods(int *out, LIBSSH2_SESSION *session, const char *username); + +static void ssh_error(LIBSSH2_SESSION *session, const char *errmsg) +{ + char *ssherr; + libssh2_session_last_error(session, &ssherr, NULL, 0); + + git_error_set(GIT_ERROR_SSH, "%s: %s", errmsg, ssherr); +} + +/* + * Create a git protocol request. + * + * For example: git-upload-pack '/libgit2/libgit2' + */ +static int gen_proto(git_str *request, const char *cmd, git_net_url *url) +{ + const char *repo; + + repo = url->path; + + if (repo && repo[0] == '/' && repo[1] == '~') + repo++; + + if (!repo || !repo[0]) { + git_error_set(GIT_ERROR_NET, "malformed git protocol URL"); + return -1; + } + + git_str_puts(request, cmd); + git_str_puts(request, " '"); + git_str_puts(request, repo); + git_str_puts(request, "'"); + + if (git_str_oom(request)) + return -1; + + return 0; +} + +static int send_command(ssh_stream *s) +{ + int error; + git_str request = GIT_STR_INIT; + + error = gen_proto(&request, s->cmd, &s->url); + if (error < 0) + goto cleanup; + + error = libssh2_channel_exec(s->channel, request.ptr); + if (error < LIBSSH2_ERROR_NONE) { + ssh_error(s->session, "SSH could not execute request"); + goto cleanup; + } + + s->sent_command = 1; + +cleanup: + git_str_dispose(&request); + return error; +} + +static int ssh_stream_read( + git_smart_subtransport_stream *stream, + char *buffer, + size_t buf_size, + size_t *bytes_read) +{ + int rc; + ssh_stream *s = GIT_CONTAINER_OF(stream, ssh_stream, parent); + + *bytes_read = 0; + + if (!s->sent_command && send_command(s) < 0) + return -1; + + if ((rc = libssh2_channel_read(s->channel, buffer, buf_size)) < LIBSSH2_ERROR_NONE) { + ssh_error(s->session, "SSH could not read data"); + return -1; + } + + /* + * If we can't get anything out of stdout, it's typically a + * not-found error, so read from stderr and signal EOF on + * stderr. + */ + if (rc == 0) { + if ((rc = libssh2_channel_read_stderr(s->channel, buffer, buf_size)) > 0) { + git_error_set(GIT_ERROR_SSH, "%*s", rc, buffer); + return GIT_EEOF; + } else if (rc < LIBSSH2_ERROR_NONE) { + ssh_error(s->session, "SSH could not read stderr"); + return -1; + } + } + + + *bytes_read = rc; + + return 0; +} + +static int ssh_stream_write( + git_smart_subtransport_stream *stream, + const char *buffer, + size_t len) +{ + ssh_stream *s = GIT_CONTAINER_OF(stream, ssh_stream, parent); + size_t off = 0; + ssize_t ret = 0; + + if (!s->sent_command && send_command(s) < 0) + return -1; + + do { + ret = libssh2_channel_write(s->channel, buffer + off, len - off); + if (ret < 0) + break; + + off += ret; + + } while (off < len); + + if (ret < 0) { + ssh_error(s->session, "SSH could not write data"); + return -1; + } + + return 0; +} + +static void ssh_stream_free(git_smart_subtransport_stream *stream) +{ + ssh_stream *s = GIT_CONTAINER_OF(stream, ssh_stream, parent); + ssh_subtransport *t; + + if (!stream) + return; + + t = OWNING_SUBTRANSPORT(s); + t->current_stream = NULL; + + if (s->channel) { + libssh2_channel_close(s->channel); + libssh2_channel_free(s->channel); + s->channel = NULL; + } + + if (s->session) { + libssh2_session_disconnect(s->session, "closing transport"); + libssh2_session_free(s->session); + s->session = NULL; + } + + if (s->io) { + git_stream_close(s->io); + git_stream_free(s->io); + s->io = NULL; + } + + git_net_url_dispose(&s->url); + git__free(s); +} + +static int ssh_stream_alloc( + ssh_subtransport *t, + const char *cmd, + git_smart_subtransport_stream **stream) +{ + ssh_stream *s; + + GIT_ASSERT_ARG(stream); + + s = git__calloc(sizeof(ssh_stream), 1); + GIT_ERROR_CHECK_ALLOC(s); + + s->parent.subtransport = &t->parent; + s->parent.read = ssh_stream_read; + s->parent.write = ssh_stream_write; + s->parent.free = ssh_stream_free; + + s->cmd = cmd; + + *stream = &s->parent; + return 0; +} + +static int ssh_agent_auth(LIBSSH2_SESSION *session, git_credential_ssh_key *c) { + int rc = LIBSSH2_ERROR_NONE; + + struct libssh2_agent_publickey *curr, *prev = NULL; + + LIBSSH2_AGENT *agent = libssh2_agent_init(session); + + if (agent == NULL) + return -1; + + rc = libssh2_agent_connect(agent); + + if (rc != LIBSSH2_ERROR_NONE) { + rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED; + goto shutdown; + } + + rc = libssh2_agent_list_identities(agent); + + if (rc != LIBSSH2_ERROR_NONE) + goto shutdown; + + while (1) { + rc = libssh2_agent_get_identity(agent, &curr, prev); + + if (rc < 0) + goto shutdown; + + /* rc is set to 1 whenever the ssh agent ran out of keys to check. + * Set the error code to authentication failure rather than erroring + * out with an untranslatable error code. + */ + if (rc == 1) { + rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED; + goto shutdown; + } + + rc = libssh2_agent_userauth(agent, c->username, curr); + + if (rc == 0) + break; + + prev = curr; + } + +shutdown: + + if (rc != LIBSSH2_ERROR_NONE) + ssh_error(session, "error authenticating"); + + libssh2_agent_disconnect(agent); + libssh2_agent_free(agent); + + return rc; +} + +static int _git_ssh_authenticate_session( + LIBSSH2_SESSION *session, + git_credential *cred) +{ + int rc; + + do { + git_error_clear(); + switch (cred->credtype) { + case GIT_CREDENTIAL_USERPASS_PLAINTEXT: { + git_credential_userpass_plaintext *c = (git_credential_userpass_plaintext *)cred; + rc = libssh2_userauth_password(session, c->username, c->password); + break; + } + case GIT_CREDENTIAL_SSH_KEY: { + git_credential_ssh_key *c = (git_credential_ssh_key *)cred; + + if (c->privatekey) + rc = libssh2_userauth_publickey_fromfile( + session, c->username, c->publickey, + c->privatekey, c->passphrase); + else + rc = ssh_agent_auth(session, c); + + break; + } + case GIT_CREDENTIAL_SSH_CUSTOM: { + git_credential_ssh_custom *c = (git_credential_ssh_custom *)cred; + + rc = libssh2_userauth_publickey( + session, c->username, (const unsigned char *)c->publickey, + c->publickey_len, c->sign_callback, &c->payload); + break; + } + case GIT_CREDENTIAL_SSH_INTERACTIVE: { + void **abstract = libssh2_session_abstract(session); + git_credential_ssh_interactive *c = (git_credential_ssh_interactive *)cred; + + /* ideally, we should be able to set this by calling + * libssh2_session_init_ex() instead of libssh2_session_init(). + * libssh2's API is inconsistent here i.e. libssh2_userauth_publickey() + * allows you to pass the `abstract` as part of the call, whereas + * libssh2_userauth_keyboard_interactive() does not! + * + * The only way to set the `abstract` pointer is by calling + * libssh2_session_abstract(), which will replace the existing + * pointer as is done below. This is safe for now (at time of writing), + * but may not be valid in future. + */ + *abstract = c->payload; + + rc = libssh2_userauth_keyboard_interactive( + session, c->username, c->prompt_callback); + break; + } +#ifdef GIT_SSH_LIBSSH2_MEMORY_CREDENTIALS + case GIT_CREDENTIAL_SSH_MEMORY: { + git_credential_ssh_key *c = (git_credential_ssh_key *)cred; + + GIT_ASSERT(c->username); + GIT_ASSERT(c->privatekey); + + rc = libssh2_userauth_publickey_frommemory( + session, + c->username, + strlen(c->username), + c->publickey, + c->publickey ? strlen(c->publickey) : 0, + c->privatekey, + strlen(c->privatekey), + c->passphrase); + break; + } +#endif + default: + rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED; + } + } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); + + if (rc == LIBSSH2_ERROR_PASSWORD_EXPIRED || + rc == LIBSSH2_ERROR_AUTHENTICATION_FAILED || + rc == LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED) + return GIT_EAUTH; + + if (rc != LIBSSH2_ERROR_NONE) { + if (git_error_last()->klass == GIT_ERROR_NONE) + ssh_error(session, "failed to authenticate SSH session"); + return -1; + } + + return 0; +} + +static int request_creds(git_credential **out, ssh_subtransport *t, const char *user, int auth_methods) +{ + int error, no_callback = 0; + git_credential *cred = NULL; + + if (!t->owner->connect_opts.callbacks.credentials) { + no_callback = 1; + } else { + error = t->owner->connect_opts.callbacks.credentials( + &cred, + t->owner->url, + user, + auth_methods, + t->owner->connect_opts.callbacks.payload); + + if (error == GIT_PASSTHROUGH) { + no_callback = 1; + } else if (error < 0) { + return error; + } else if (!cred) { + git_error_set(GIT_ERROR_SSH, "callback failed to initialize SSH credentials"); + return -1; + } + } + + if (no_callback) { + git_error_set(GIT_ERROR_SSH, "authentication required but no callback set"); + return GIT_EAUTH; + } + + if (!(cred->credtype & auth_methods)) { + cred->free(cred); + git_error_set(GIT_ERROR_SSH, "authentication callback returned unsupported credentials type"); + return GIT_EAUTH; + } + + *out = cred; + + return 0; +} + +#define SSH_DIR ".ssh" +#define KNOWN_HOSTS_FILE "known_hosts" + +/* + * Load the known_hosts file. + * + * Returns success but leaves the output NULL if we couldn't find the file. + */ +static int load_known_hosts(LIBSSH2_KNOWNHOSTS **hosts, LIBSSH2_SESSION *session) +{ + git_str path = GIT_STR_INIT, sshdir = GIT_STR_INIT; + LIBSSH2_KNOWNHOSTS *known_hosts = NULL; + int error; + + GIT_ASSERT_ARG(hosts); + + if ((error = git_sysdir_expand_homedir_file(&sshdir, SSH_DIR)) < 0 || + (error = git_str_joinpath(&path, git_str_cstr(&sshdir), KNOWN_HOSTS_FILE)) < 0) + goto out; + + if ((known_hosts = libssh2_knownhost_init(session)) == NULL) { + ssh_error(session, "error initializing known hosts"); + error = -1; + goto out; + } + + /* + * Try to read the file and consider not finding it as not trusting the + * host rather than an error. + */ + error = libssh2_knownhost_readfile(known_hosts, git_str_cstr(&path), LIBSSH2_KNOWNHOST_FILE_OPENSSH); + if (error == LIBSSH2_ERROR_FILE) + error = 0; + if (error < 0) + ssh_error(session, "error reading known_hosts"); + +out: + *hosts = known_hosts; + + git_str_dispose(&sshdir); + git_str_dispose(&path); + + return error; +} + +static void add_hostkey_pref_if_avail( + LIBSSH2_KNOWNHOSTS *known_hosts, + const char *hostname, + int port, + git_str *prefs, + int type, + const char *type_name) +{ + struct libssh2_knownhost *host = NULL; + const char key = '\0'; + int mask = LIBSSH2_KNOWNHOST_TYPE_PLAIN | LIBSSH2_KNOWNHOST_KEYENC_RAW | type; + int error; + + error = libssh2_knownhost_checkp(known_hosts, hostname, port, &key, 1, mask, &host); + if (error == LIBSSH2_KNOWNHOST_CHECK_MISMATCH) { + if (git_str_len(prefs) > 0) { + git_str_putc(prefs, ','); + } + git_str_puts(prefs, type_name); + } +} + +/* + * We figure out what kind of key we want to ask the remote for by trying to + * look it up with a nonsense key and using that mismatch to figure out what key + * we do have stored for the host. + * + * Populates prefs with the string to pass to libssh2_session_method_pref. + */ +static void find_hostkey_preference( + LIBSSH2_KNOWNHOSTS *known_hosts, + const char *hostname, + int port, + git_str *prefs) +{ + /* + * The order here is important as it indicates the priority of what will + * be preferred. + */ +#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519 + add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_ED25519, "ssh-ed25519"); +#endif +#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256 + add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_ECDSA_256, "ecdsa-sha2-nistp256"); + add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_ECDSA_384, "ecdsa-sha2-nistp384"); + add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_ECDSA_521, "ecdsa-sha2-nistp521"); +#endif + add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_SSHRSA, "ssh-rsa"); +} + +static int _git_ssh_session_create( + LIBSSH2_SESSION **session, + LIBSSH2_KNOWNHOSTS **hosts, + const char *hostname, + int port, + git_stream *io) +{ + git_socket_stream *socket = GIT_CONTAINER_OF(io, git_socket_stream, parent); + LIBSSH2_SESSION *s; + LIBSSH2_KNOWNHOSTS *known_hosts; + git_str prefs = GIT_STR_INIT; + int rc = 0; + + GIT_ASSERT_ARG(session); + GIT_ASSERT_ARG(hosts); + + s = libssh2_session_init(); + if (!s) { + git_error_set(GIT_ERROR_NET, "failed to initialize SSH session"); + return -1; + } + + if (git_socket_stream__timeout > 0) { + libssh2_session_set_timeout(s, git_socket_stream__timeout); + } + + if ((rc = load_known_hosts(&known_hosts, s)) < 0) { + ssh_error(s, "error loading known_hosts"); + libssh2_session_free(s); + return -1; + } + + find_hostkey_preference(known_hosts, hostname, port, &prefs); + if (git_str_len(&prefs) > 0) { + do { + rc = libssh2_session_method_pref(s, LIBSSH2_METHOD_HOSTKEY, git_str_cstr(&prefs)); + } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); + if (rc != LIBSSH2_ERROR_NONE) { + ssh_error(s, "failed to set hostkey preference"); + goto on_error; + } + } + git_str_dispose(&prefs); + + do { + rc = libssh2_session_handshake(s, socket->s); + } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); + + if (rc != LIBSSH2_ERROR_NONE) { + ssh_error(s, "failed to start SSH session"); + goto on_error; + } + + libssh2_session_set_blocking(s, 1); + + *session = s; + *hosts = known_hosts; + + return 0; + +on_error: + libssh2_knownhost_free(known_hosts); + libssh2_session_free(s); + return -1; +} + + +/* + * Returns the typemask argument to pass to libssh2_knownhost_check{,p} based on + * the type of key that libssh2_session_hostkey returns. + */ +static int fingerprint_type_mask(int keytype) +{ + int mask = LIBSSH2_KNOWNHOST_TYPE_PLAIN | LIBSSH2_KNOWNHOST_KEYENC_RAW; + return mask; + + switch (keytype) { + case LIBSSH2_HOSTKEY_TYPE_RSA: + mask |= LIBSSH2_KNOWNHOST_KEY_SSHRSA; + break; + case LIBSSH2_HOSTKEY_TYPE_DSS: + mask |= LIBSSH2_KNOWNHOST_KEY_SSHDSS; + break; +#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256 + case LIBSSH2_HOSTKEY_TYPE_ECDSA_256: + mask |= LIBSSH2_KNOWNHOST_KEY_ECDSA_256; + break; + case LIBSSH2_HOSTKEY_TYPE_ECDSA_384: + mask |= LIBSSH2_KNOWNHOST_KEY_ECDSA_384; + break; + case LIBSSH2_HOSTKEY_TYPE_ECDSA_521: + mask |= LIBSSH2_KNOWNHOST_KEY_ECDSA_521; + break; +#endif +#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519 + case LIBSSH2_HOSTKEY_TYPE_ED25519: + mask |= LIBSSH2_KNOWNHOST_KEY_ED25519; + break; +#endif + } + + return mask; +} + +/* + * Check the host against the user's known_hosts file. + * + * Returns 1/0 for valid/''not-valid or <0 for an error + */ +static int check_against_known_hosts( + LIBSSH2_SESSION *session, + LIBSSH2_KNOWNHOSTS *known_hosts, + const char *hostname, + int port, + const char *key, + size_t key_len, + int key_type) +{ + int check, typemask, ret = 0; + struct libssh2_knownhost *host = NULL; + + if (known_hosts == NULL) + return 0; + + typemask = fingerprint_type_mask(key_type); + check = libssh2_knownhost_checkp(known_hosts, hostname, port, key, key_len, typemask, &host); + if (check == LIBSSH2_KNOWNHOST_CHECK_FAILURE) { + ssh_error(session, "error checking for known host"); + return -1; + } + + ret = check == LIBSSH2_KNOWNHOST_CHECK_MATCH ? 1 : 0; + + return ret; +} + +/* + * Perform the check for the session's certificate against known hosts if + * possible and then ask the user if they have a callback. + * + * Returns 1/0 for valid/not-valid or <0 for an error + */ +static int check_certificate( + LIBSSH2_SESSION *session, + LIBSSH2_KNOWNHOSTS *known_hosts, + git_transport_certificate_check_cb check_cb, + void *check_cb_payload, + const char *host, + int port) +{ + git_cert_hostkey cert = {{ 0 }}; + const char *key; + size_t cert_len; + int cert_type, cert_valid = 0, error = GIT_ECERTIFICATE; + + if ((key = libssh2_session_hostkey(session, &cert_len, &cert_type)) == NULL) { + ssh_error(session, "failed to retrieve hostkey"); + return -1; + } + + if ((cert_valid = check_against_known_hosts(session, known_hosts, host, port, key, cert_len, cert_type)) < 0) + return -1; + + cert.parent.cert_type = GIT_CERT_HOSTKEY_LIBSSH2; + if (key != NULL) { + cert.type |= GIT_CERT_SSH_RAW; + cert.hostkey = key; + cert.hostkey_len = cert_len; + switch (cert_type) { + case LIBSSH2_HOSTKEY_TYPE_RSA: + cert.raw_type = GIT_CERT_SSH_RAW_TYPE_RSA; + break; + case LIBSSH2_HOSTKEY_TYPE_DSS: + cert.raw_type = GIT_CERT_SSH_RAW_TYPE_DSS; + break; + +#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256 + case LIBSSH2_HOSTKEY_TYPE_ECDSA_256: + cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_256; + break; + case LIBSSH2_HOSTKEY_TYPE_ECDSA_384: + cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_384; + break; + case LIBSSH2_KNOWNHOST_KEY_ECDSA_521: + cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_521; + break; +#endif + +#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519 + case LIBSSH2_HOSTKEY_TYPE_ED25519: + cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ED25519; + break; +#endif + default: + cert.raw_type = GIT_CERT_SSH_RAW_TYPE_UNKNOWN; + } + } + +#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 + key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA256); + if (key != NULL) { + cert.type |= GIT_CERT_SSH_SHA256; + memcpy(&cert.hash_sha256, key, 32); + } +#endif + + key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1); + if (key != NULL) { + cert.type |= GIT_CERT_SSH_SHA1; + memcpy(&cert.hash_sha1, key, 20); + } + + key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5); + if (key != NULL) { + cert.type |= GIT_CERT_SSH_MD5; + memcpy(&cert.hash_md5, key, 16); + } + + if (cert.type == 0) { + git_error_set(GIT_ERROR_SSH, "unable to get the host key"); + return -1; + } + + if (check_cb != NULL) { + git_cert_hostkey *cert_ptr = &cert; + + error = check_cb((git_cert *)cert_ptr, cert_valid, host, + check_cb_payload); + + if (error == 0) + cert_valid = 1; + else if (error != GIT_PASSTHROUGH) + cert_valid = 0; + } + + if (!cert_valid) { + git_error_set(GIT_ERROR_SSH, "invalid or unknown remote ssh hostkey"); + return (error == GIT_PASSTHROUGH) ? GIT_ECERTIFICATE : error; + } + + return 0; +} + +#define SSH_DEFAULT_PORT "22" + +static int _git_ssh_setup_conn( + ssh_subtransport *t, + const char *url, + const char *cmd, + git_smart_subtransport_stream **stream) +{ + int auth_methods, error = 0, port; + ssh_stream *s; + git_credential *cred = NULL; + LIBSSH2_SESSION *session=NULL; + LIBSSH2_CHANNEL *channel=NULL; + LIBSSH2_KNOWNHOSTS *known_hosts = NULL; + + t->current_stream = NULL; + + *stream = NULL; + if (ssh_stream_alloc(t, cmd, stream) < 0) + return -1; + + s = (ssh_stream *)*stream; + s->session = NULL; + s->channel = NULL; + + if (git_net_str_is_url(url)) + error = git_net_url_parse(&s->url, url); + else + error = git_net_url_parse_scp(&s->url, url); + + if (error < 0) + goto done; + + /* Safety check: like git, we forbid paths that look like an option as + * that could lead to injection on the remote side */ + if (git_process__is_cmdline_option(s->url.path)) { + git_error_set(GIT_ERROR_NET, "cannot ssh: path '%s' is ambiguous with command-line option", s->url.path); + error = -1; + goto done; + } + + + if ((error = git_socket_stream_new(&s->io, s->url.host, s->url.port)) < 0 || + (error = git_stream_connect(s->io)) < 0) + goto done; + + /* + * Try to parse the port as a number, if we can't then fall back to + * default. It would be nice if we could get the port that was resolved + * as part of the stream connection, but that's not something that's + * exposed. + */ + if (git__strntol32(&port, s->url.port, strlen(s->url.port), NULL, 10) < 0) + port = -1; + + if ((error = _git_ssh_session_create(&session, &known_hosts, s->url.host, port, s->io)) < 0) + goto done; + + if ((error = check_certificate(session, known_hosts, t->owner->connect_opts.callbacks.certificate_check, t->owner->connect_opts.callbacks.payload, s->url.host, port)) < 0) + goto done; + + /* we need the username to ask for auth methods */ + if (!s->url.username) { + if ((error = request_creds(&cred, t, NULL, GIT_CREDENTIAL_USERNAME)) < 0) + goto done; + + s->url.username = git__strdup(((git_credential_username *) cred)->username); + cred->free(cred); + cred = NULL; + if (!s->url.username) + goto done; + } else if (s->url.username && s->url.password) { + if ((error = git_credential_userpass_plaintext_new(&cred, s->url.username, s->url.password)) < 0) + goto done; + } + + if ((error = list_auth_methods(&auth_methods, session, s->url.username)) < 0) + goto done; + + error = GIT_EAUTH; + /* if we already have something to try */ + if (cred && auth_methods & cred->credtype) + error = _git_ssh_authenticate_session(session, cred); + + while (error == GIT_EAUTH) { + if (cred) { + cred->free(cred); + cred = NULL; + } + + if ((error = request_creds(&cred, t, s->url.username, auth_methods)) < 0) + goto done; + + if (strcmp(s->url.username, git_credential_get_username(cred))) { + git_error_set(GIT_ERROR_SSH, "username does not match previous request"); + error = -1; + goto done; + } + + error = _git_ssh_authenticate_session(session, cred); + + if (error == GIT_EAUTH) { + /* refresh auth methods */ + if ((error = list_auth_methods(&auth_methods, session, s->url.username)) < 0) + goto done; + else + error = GIT_EAUTH; + } + } + + if (error < 0) + goto done; + + channel = libssh2_channel_open_session(session); + if (!channel) { + error = -1; + ssh_error(session, "Failed to open SSH channel"); + goto done; + } + + libssh2_channel_set_blocking(channel, 1); + + s->session = session; + s->channel = channel; + + t->current_stream = s; + +done: + if (known_hosts) + libssh2_knownhost_free(known_hosts); + + if (error < 0) { + ssh_stream_free(*stream); + + if (session) + libssh2_session_free(session); + } + + if (cred) + cred->free(cred); + + return error; +} + +static int ssh_uploadpack_ls( + ssh_subtransport *t, + const char *url, + git_smart_subtransport_stream **stream) +{ + const char *cmd = t->cmd_uploadpack ? t->cmd_uploadpack : cmd_uploadpack; + + return _git_ssh_setup_conn(t, url, cmd, stream); +} + +static int ssh_uploadpack( + ssh_subtransport *t, + const char *url, + git_smart_subtransport_stream **stream) +{ + GIT_UNUSED(url); + + if (t->current_stream) { + *stream = &t->current_stream->parent; + return 0; + } + + git_error_set(GIT_ERROR_NET, "must call UPLOADPACK_LS before UPLOADPACK"); + return -1; +} + +static int ssh_receivepack_ls( + ssh_subtransport *t, + const char *url, + git_smart_subtransport_stream **stream) +{ + const char *cmd = t->cmd_receivepack ? t->cmd_receivepack : cmd_receivepack; + + + return _git_ssh_setup_conn(t, url, cmd, stream); +} + +static int ssh_receivepack( + ssh_subtransport *t, + const char *url, + git_smart_subtransport_stream **stream) +{ + GIT_UNUSED(url); + + if (t->current_stream) { + *stream = &t->current_stream->parent; + return 0; + } + + git_error_set(GIT_ERROR_NET, "must call RECEIVEPACK_LS before RECEIVEPACK"); + return -1; +} + +static int _ssh_action( + git_smart_subtransport_stream **stream, + git_smart_subtransport *subtransport, + const char *url, + git_smart_service_t action) +{ + ssh_subtransport *t = GIT_CONTAINER_OF(subtransport, ssh_subtransport, parent); + + switch (action) { + case GIT_SERVICE_UPLOADPACK_LS: + return ssh_uploadpack_ls(t, url, stream); + + case GIT_SERVICE_UPLOADPACK: + return ssh_uploadpack(t, url, stream); + + case GIT_SERVICE_RECEIVEPACK_LS: + return ssh_receivepack_ls(t, url, stream); + + case GIT_SERVICE_RECEIVEPACK: + return ssh_receivepack(t, url, stream); + } + + *stream = NULL; + return -1; +} + +static int _ssh_close(git_smart_subtransport *subtransport) +{ + ssh_subtransport *t = GIT_CONTAINER_OF(subtransport, ssh_subtransport, parent); + + GIT_ASSERT(!t->current_stream); + + GIT_UNUSED(t); + + return 0; +} + +static void _ssh_free(git_smart_subtransport *subtransport) +{ + ssh_subtransport *t = GIT_CONTAINER_OF(subtransport, ssh_subtransport, parent); + + git__free(t->cmd_uploadpack); + git__free(t->cmd_receivepack); + git__free(t); +} + +#define SSH_AUTH_PUBLICKEY "publickey" +#define SSH_AUTH_PASSWORD "password" +#define SSH_AUTH_KEYBOARD_INTERACTIVE "keyboard-interactive" + +static int list_auth_methods(int *out, LIBSSH2_SESSION *session, const char *username) +{ + const char *list, *ptr; + + *out = 0; + + list = libssh2_userauth_list(session, username, strlen(username)); + + /* either error, or the remote accepts NONE auth, which is bizarre, let's punt */ + if (list == NULL && !libssh2_userauth_authenticated(session)) { + ssh_error(session, "remote rejected authentication"); + return GIT_EAUTH; + } + + ptr = list; + while (ptr) { + if (*ptr == ',') + ptr++; + + if (!git__prefixcmp(ptr, SSH_AUTH_PUBLICKEY)) { + *out |= GIT_CREDENTIAL_SSH_KEY; + *out |= GIT_CREDENTIAL_SSH_CUSTOM; +#ifdef GIT_SSH_LIBSSH2_MEMORY_CREDENTIALS + *out |= GIT_CREDENTIAL_SSH_MEMORY; +#endif + ptr += strlen(SSH_AUTH_PUBLICKEY); + continue; + } + + if (!git__prefixcmp(ptr, SSH_AUTH_PASSWORD)) { + *out |= GIT_CREDENTIAL_USERPASS_PLAINTEXT; + ptr += strlen(SSH_AUTH_PASSWORD); + continue; + } + + if (!git__prefixcmp(ptr, SSH_AUTH_KEYBOARD_INTERACTIVE)) { + *out |= GIT_CREDENTIAL_SSH_INTERACTIVE; + ptr += strlen(SSH_AUTH_KEYBOARD_INTERACTIVE); + continue; + } + + /* Skip it if we don't know it */ + ptr = strchr(ptr, ','); + } + + return 0; +} + +int git_smart_subtransport_ssh_libssh2( + git_smart_subtransport **out, + git_transport *owner, + void *param) +{ + ssh_subtransport *t; + + GIT_ASSERT_ARG(out); + + GIT_UNUSED(param); + + t = git__calloc(sizeof(ssh_subtransport), 1); + GIT_ERROR_CHECK_ALLOC(t); + + t->owner = (transport_smart *)owner; + t->parent.action = _ssh_action; + t->parent.close = _ssh_close; + t->parent.free = _ssh_free; + + *out = (git_smart_subtransport *) t; + return 0; +} + +int git_smart_subtransport_ssh_libssh2_set_paths( + git_smart_subtransport *subtransport, + const char *cmd_uploadpack, + const char *cmd_receivepack) +{ + ssh_subtransport *t = (ssh_subtransport *)subtransport; + + git__free(t->cmd_uploadpack); + git__free(t->cmd_receivepack); + + t->cmd_uploadpack = git__strdup(cmd_uploadpack); + GIT_ERROR_CHECK_ALLOC(t->cmd_uploadpack); + + t->cmd_receivepack = git__strdup(cmd_receivepack); + GIT_ERROR_CHECK_ALLOC(t->cmd_receivepack); + + return 0; +} + +static void shutdown_libssh2(void) +{ + libssh2_exit(); +} + +int git_transport_ssh_libssh2_global_init(void) +{ + if (libssh2_init(0) < 0) { + git_error_set(GIT_ERROR_SSH, "unable to initialize libssh2"); + return -1; + } + + return git_runtime_shutdown_register(shutdown_libssh2); +} + +#else /* GIT_SSH */ + +int git_transport_ssh_libssh2_global_init(void) +{ + return 0; +} + +#endif diff --git a/vendor/libgit2/src/libgit2/transports/ssh_libssh2.h b/vendor/libgit2/src/libgit2/transports/ssh_libssh2.h new file mode 100644 index 00000000..3f8cc2a8 --- /dev/null +++ b/vendor/libgit2/src/libgit2/transports/ssh_libssh2.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_transports_libssh2_h__ +#define INCLUDE_transports_libssh2_h__ + +#include "common.h" + +#include "git2.h" +#include "git2/transport.h" +#include "git2/sys/transport.h" + +int git_transport_ssh_libssh2_global_init(void); + +int git_smart_subtransport_ssh_libssh2( + git_smart_subtransport **out, + git_transport *owner, + void *param); + +int git_smart_subtransport_ssh_libssh2_set_paths( + git_smart_subtransport *subtransport, + const char *cmd_uploadpack, + const char *cmd_receivepack); + +#endif diff --git a/vendor/libgit2/src/transports/winhttp.c b/vendor/libgit2/src/libgit2/transports/winhttp.c similarity index 95% rename from vendor/libgit2/src/transports/winhttp.c rename to vendor/libgit2/src/libgit2/transports/winhttp.c index 8ec5b37c..b83ef990 100644 --- a/vendor/libgit2/src/transports/winhttp.c +++ b/vendor/libgit2/src/libgit2/transports/winhttp.c @@ -13,7 +13,6 @@ #include "git2/transport.h" #include "posix.h" #include "str.h" -#include "netops.h" #include "smart.h" #include "remote.h" #include "repository.h" @@ -158,10 +157,10 @@ static int apply_userpass_credentials(HINTERNET request, DWORD target, int mecha goto done; } - if ((error = user_len = git__utf8_to_16_alloc(&user, c->username)) < 0) + if ((error = user_len = git_utf8_to_16_alloc(&user, c->username)) < 0) goto done; - if ((error = pass_len = git__utf8_to_16_alloc(&pass, c->password)) < 0) + if ((error = pass_len = git_utf8_to_16_alloc(&pass, c->password)) < 0) goto done; if (!WinHttpSetCredentials(request, target, native_scheme, user, pass, NULL)) { @@ -242,7 +241,7 @@ static int acquire_fallback_cred( HRESULT hCoInitResult; /* Convert URL to wide characters */ - if (git__utf8_to_16_alloc(&wide_url, url) < 0) { + if (git_utf8_to_16_alloc(&wide_url, url) < 0) { git_error_set(GIT_ERROR_OS, "failed to convert string to wide form"); return -1; } @@ -294,7 +293,7 @@ static int certificate_check(winhttp_stream *s, int valid) /* If there is no override, we should fail if WinHTTP doesn't think it's fine */ if (t->owner->connect_opts.callbacks.certificate_check == NULL && !valid) { - if (!git_error_last()) + if (git_error_last()->klass == GIT_ERROR_NONE) git_error_set(GIT_ERROR_HTTP, "unknown certificate check failure"); return GIT_ECERTIFICATE; @@ -318,7 +317,7 @@ static int certificate_check(winhttp_stream *s, int valid) if (error == GIT_PASSTHROUGH) error = valid ? 0 : GIT_ECERTIFICATE; - if (error < 0 && !git_error_last()) + if (error < 0 && git_error_last()->klass == GIT_ERROR_NONE) git_error_set(GIT_ERROR_HTTP, "user cancelled certificate check"); return error; @@ -397,7 +396,7 @@ static int winhttp_stream_connect(winhttp_stream *s) return -1; /* Convert URL to wide characters */ - if (git__utf8_to_16_alloc(&s->request_uri, git_str_cstr(&buf)) < 0) { + if (git_utf8_to_16_alloc(&s->request_uri, git_str_cstr(&buf)) < 0) { git_error_set(GIT_ERROR_OS, "failed to convert string to wide form"); goto on_error; } @@ -437,17 +436,17 @@ static int winhttp_stream_connect(winhttp_stream *s) GIT_ERROR_CHECK_ALLOC(proxy_url); } - if (proxy_url) { + if (proxy_url && *proxy_url) { git_str processed_url = GIT_STR_INIT; WINHTTP_PROXY_INFO proxy_info; wchar_t *proxy_wide; git_net_url_dispose(&t->proxy.url); - if ((error = git_net_url_parse(&t->proxy.url, proxy_url)) < 0) + if ((error = git_net_url_parse_http(&t->proxy.url, proxy_url)) < 0) goto on_error; - if (strcmp(t->proxy.url.scheme, "http") != 0 && strcmp(t->proxy.url.scheme, "https") != 0) { + if (!git_net_url_valid(&t->proxy.url)) { git_error_set(GIT_ERROR_HTTP, "invalid URL: '%s'", proxy_url); error = -1; goto on_error; @@ -473,7 +472,7 @@ static int winhttp_stream_connect(winhttp_stream *s) } /* Convert URL to wide characters */ - error = git__utf8_to_16_alloc(&proxy_wide, processed_url.ptr); + error = git_utf8_to_16_alloc(&proxy_wide, processed_url.ptr); git_str_dispose(&processed_url); if (error < 0) goto on_error; @@ -531,7 +530,7 @@ static int winhttp_stream_connect(winhttp_stream *s) s->service) < 0) goto on_error; - if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_str_cstr(&buf)) < 0) { + if (git_utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_str_cstr(&buf)) < 0) { git_error_set(GIT_ERROR_OS, "failed to convert content-type to wide characters"); goto on_error; } @@ -548,7 +547,7 @@ static int winhttp_stream_connect(winhttp_stream *s) s->service) < 0) goto on_error; - if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_str_cstr(&buf)) < 0) { + if (git_utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_str_cstr(&buf)) < 0) { git_error_set(GIT_ERROR_OS, "failed to convert accept header to wide characters"); goto on_error; } @@ -562,18 +561,23 @@ static int winhttp_stream_connect(winhttp_stream *s) for (i = 0; i < t->owner->connect_opts.custom_headers.count; i++) { if (t->owner->connect_opts.custom_headers.strings[i]) { + wchar_t *custom_header_wide = NULL; + git_str_clear(&buf); git_str_puts(&buf, t->owner->connect_opts.custom_headers.strings[i]); - if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_str_cstr(&buf)) < 0) { - git_error_set(GIT_ERROR_OS, "failed to convert custom header to wide characters"); + + /* Convert header to wide characters */ + if ((error = git_utf8_to_16_alloc(&custom_header_wide, git_str_cstr(&buf))) < 0) goto on_error; - } - if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG)-1L, + if (!WinHttpAddRequestHeaders(s->request, custom_header_wide, (ULONG)-1L, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) { git_error_set(GIT_ERROR_OS, "failed to add a header to the request"); + git__free(custom_header_wide); goto on_error; } + + git__free(custom_header_wide); } } @@ -742,6 +746,33 @@ static void CALLBACK winhttp_status( } } +static int user_agent(bool *exists, git_str *out) +{ + const char *product = git_settings__user_agent_product(); + const char *comment = git_settings__user_agent(); + + GIT_ASSERT(product && comment); + + if (!*product) { + *exists = false; + return 0; + } + + git_str_puts(out, product); + + if (*comment) { + git_str_puts(out, " ("); + git_str_puts(out, comment); + git_str_puts(out, ")"); + } + + if (git_str_oom(out)) + return -1; + + *exists = true; + return 0; +} + static int winhttp_connect( winhttp_subtransport *t) { @@ -753,6 +784,7 @@ static int winhttp_connect( int error = -1; int default_timeout = TIMEOUT_INFINITE; int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT; + bool has_ua = true; DWORD protocols = WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 | @@ -778,16 +810,16 @@ static int winhttp_connect( } /* Prepare host */ - if (git__utf8_to_16_alloc(&wide_host, host) < 0) { + if (git_utf8_to_16_alloc(&wide_host, host) < 0) { git_error_set(GIT_ERROR_OS, "unable to convert host to wide characters"); goto on_error; } - - if (git_http__user_agent(&ua) < 0) + if (user_agent(&has_ua, &ua) < 0) goto on_error; - if (git__utf8_to_16_alloc(&wide_ua, git_str_cstr(&ua)) < 0) { + if (has_ua && + git_utf8_to_16_alloc(&wide_ua, git_str_cstr(&ua)) < 0) { git_error_set(GIT_ERROR_OS, "unable to convert host to wide characters"); goto on_error; } @@ -929,7 +961,7 @@ static int send_request(winhttp_stream *s, size_t len, bool chunked) (!request_failed && s->status_sending_request_reached)) { git_error_clear(); if ((error = certificate_check(s, cert_valid)) < 0) { - if (!git_error_last()) + if (git_error_last()->klass == GIT_ERROR_NONE) git_error_set(GIT_ERROR_OS, "user cancelled certificate check"); return error; @@ -1177,7 +1209,7 @@ static int winhttp_stream_read( } /* Convert the Location header to UTF-8 */ - if (git__utf16_to_8_alloc(&location8, location) < 0) { + if (git_utf8_from_16_alloc(&location8, location) < 0) { git_error_set(GIT_ERROR_OS, "failed to convert Location header to UTF-8"); git__free(location); return -1; @@ -1249,7 +1281,7 @@ static int winhttp_stream_read( else p_snprintf(expected_content_type_8, MAX_CONTENT_TYPE_LEN, "application/x-git-%s-advertisement", s->service); - if (git__utf8_to_16(expected_content_type, MAX_CONTENT_TYPE_LEN, expected_content_type_8) < 0) { + if (git_utf8_to_16(expected_content_type, MAX_CONTENT_TYPE_LEN, expected_content_type_8) < 0) { git_error_set(GIT_ERROR_OS, "failed to convert expected content-type to wide characters"); return -1; } diff --git a/vendor/libgit2/src/tree-cache.c b/vendor/libgit2/src/libgit2/tree-cache.c similarity index 85% rename from vendor/libgit2/src/tree-cache.c rename to vendor/libgit2/src/libgit2/tree-cache.c index 0977c92f..95d87986 100644 --- a/vendor/libgit2/src/tree-cache.c +++ b/vendor/libgit2/src/libgit2/tree-cache.c @@ -71,12 +71,16 @@ const git_tree_cache *git_tree_cache_get(const git_tree_cache *tree, const char } } -static int read_tree_internal(git_tree_cache **out, - const char **buffer_in, const char *buffer_end, - git_pool *pool) +static int read_tree_internal( + git_tree_cache **out, + const char **buffer_in, + const char *buffer_end, + git_oid_t oid_type, + git_pool *pool) { git_tree_cache *tree = NULL; const char *name_start, *buffer; + size_t oid_size = git_oid_size(oid_type); int count; buffer = name_start = *buffer_in; @@ -87,7 +91,7 @@ static int read_tree_internal(git_tree_cache **out, if (++buffer >= buffer_end) goto corrupted; - if (git_tree_cache_new(&tree, name_start, pool) < 0) + if (git_tree_cache_new(&tree, name_start, oid_type, pool) < 0) return -1; /* Blank-terminated ASCII decimal number of entries in this tree */ @@ -108,14 +112,14 @@ static int read_tree_internal(git_tree_cache **out, if (*buffer != '\n' || ++buffer > buffer_end) goto corrupted; - /* The SHA1 is only there if it's not invalidated */ + /* The OID is only there if it's not invalidated */ if (tree->entry_count >= 0) { /* 160-bit SHA-1 for this tree and it's children */ - if (buffer + GIT_OID_RAWSZ > buffer_end) + if (buffer + oid_size > buffer_end) goto corrupted; - git_oid_fromraw(&tree->oid, (const unsigned char *)buffer); - buffer += GIT_OID_RAWSZ; + git_oid__fromraw(&tree->oid, (const unsigned char *)buffer, oid_type); + buffer += oid_size; } /* Parse children: */ @@ -130,7 +134,7 @@ static int read_tree_internal(git_tree_cache **out, memset(tree->children, 0x0, bufsize); for (i = 0; i < tree->children_count; ++i) { - if (read_tree_internal(&tree->children[i], &buffer, buffer_end, pool) < 0) + if (read_tree_internal(&tree->children[i], &buffer, buffer_end, oid_type, pool) < 0) goto corrupted; } } @@ -144,11 +148,16 @@ static int read_tree_internal(git_tree_cache **out, return -1; } -int git_tree_cache_read(git_tree_cache **tree, const char *buffer, size_t buffer_size, git_pool *pool) +int git_tree_cache_read( + git_tree_cache **tree, + const char *buffer, + size_t buffer_size, + git_oid_t oid_type, + git_pool *pool) { const char *buffer_end = buffer + buffer_size; - if (read_tree_internal(tree, &buffer, buffer_end, pool) < 0) + if (read_tree_internal(tree, &buffer, buffer_end, oid_type, pool) < 0) return -1; if (buffer < buffer_end) { @@ -201,7 +210,7 @@ static int read_tree_recursive(git_tree_cache *cache, const git_tree *tree, git_ continue; } - if ((error = git_tree_cache_new(&cache->children[j], git_tree_entry_name(entry), pool)) < 0) + if ((error = git_tree_cache_new(&cache->children[j], git_tree_entry_name(entry), cache->oid_type, pool)) < 0) return error; if ((error = git_tree_lookup(&subtree, repo, git_tree_entry_id(entry))) < 0) @@ -219,12 +228,12 @@ static int read_tree_recursive(git_tree_cache *cache, const git_tree *tree, git_ return 0; } -int git_tree_cache_read_tree(git_tree_cache **out, const git_tree *tree, git_pool *pool) +int git_tree_cache_read_tree(git_tree_cache **out, const git_tree *tree, git_oid_t oid_type, git_pool *pool) { int error; git_tree_cache *cache; - if ((error = git_tree_cache_new(&cache, "", pool)) < 0) + if ((error = git_tree_cache_new(&cache, "", oid_type, pool)) < 0) return error; if ((error = read_tree_recursive(cache, tree, pool)) < 0) @@ -234,7 +243,7 @@ int git_tree_cache_read_tree(git_tree_cache **out, const git_tree *tree, git_poo return 0; } -int git_tree_cache_new(git_tree_cache **out, const char *name, git_pool *pool) +int git_tree_cache_new(git_tree_cache **out, const char *name, git_oid_t oid_type, git_pool *pool) { size_t name_len, alloc_size; git_tree_cache *tree; @@ -248,6 +257,7 @@ int git_tree_cache_new(git_tree_cache **out, const char *name, git_pool *pool) memset(tree, 0x0, sizeof(git_tree_cache)); /* NUL-terminated tree name */ + tree->oid_type = oid_type; tree->namelen = name_len; memcpy(tree->name, name, name_len); tree->name[name_len] = '\0'; @@ -263,7 +273,7 @@ static void write_tree(git_str *out, git_tree_cache *tree) git_str_printf(out, "%s%c%"PRIdZ" %"PRIuZ"\n", tree->name, 0, tree->entry_count, tree->children_count); if (tree->entry_count != -1) - git_str_put(out, (const char *) &tree->oid, GIT_OID_RAWSZ); + git_str_put(out, (char *)&tree->oid.id, git_oid_size(tree->oid_type)); for (i = 0; i < tree->children_count; i++) write_tree(out, tree->children[i]); diff --git a/vendor/libgit2/src/tree-cache.h b/vendor/libgit2/src/libgit2/tree-cache.h similarity index 87% rename from vendor/libgit2/src/tree-cache.h rename to vendor/libgit2/src/libgit2/tree-cache.h index a27e3046..e4a73f27 100644 --- a/vendor/libgit2/src/tree-cache.h +++ b/vendor/libgit2/src/libgit2/tree-cache.h @@ -18,6 +18,8 @@ typedef struct git_tree_cache { struct git_tree_cache **children; size_t children_count; + git_oid_t oid_type; + ssize_t entry_count; git_oid oid; size_t namelen; @@ -25,14 +27,14 @@ typedef struct git_tree_cache { } git_tree_cache; int git_tree_cache_write(git_str *out, git_tree_cache *tree); -int git_tree_cache_read(git_tree_cache **tree, const char *buffer, size_t buffer_size, git_pool *pool); +int git_tree_cache_read(git_tree_cache **tree, const char *buffer, size_t buffer_size, git_oid_t oid_type, git_pool *pool); void git_tree_cache_invalidate_path(git_tree_cache *tree, const char *path); const git_tree_cache *git_tree_cache_get(const git_tree_cache *tree, const char *path); -int git_tree_cache_new(git_tree_cache **out, const char *name, git_pool *pool); +int git_tree_cache_new(git_tree_cache **out, const char *name, git_oid_t oid_type, git_pool *pool); /** * Read a tree as the root of the tree cache (like for `git read-tree`) */ -int git_tree_cache_read_tree(git_tree_cache **out, const git_tree *tree, git_pool *pool); +int git_tree_cache_read_tree(git_tree_cache **out, const git_tree *tree, git_oid_t oid_type, git_pool *pool); void git_tree_cache_free(git_tree_cache *tree); #endif diff --git a/vendor/libgit2/src/libgit2/tree.c b/vendor/libgit2/src/libgit2/tree.c new file mode 100644 index 00000000..18278d34 --- /dev/null +++ b/vendor/libgit2/src/libgit2/tree.c @@ -0,0 +1,1330 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "tree.h" + +#include "commit.h" +#include "git2/repository.h" +#include "git2/object.h" +#include "futils.h" +#include "tree-cache.h" +#include "index.h" +#include "path.h" + +#define DEFAULT_TREE_SIZE 16 +#define MAX_FILEMODE_BYTES 6 + +#define TREE_ENTRY_CHECK_NAMELEN(n) \ + if (n > UINT16_MAX) { git_error_set(GIT_ERROR_INVALID, "tree entry path too long"); } + +static bool valid_filemode(const int filemode) +{ + return (filemode == GIT_FILEMODE_TREE + || filemode == GIT_FILEMODE_BLOB + || filemode == GIT_FILEMODE_BLOB_EXECUTABLE + || filemode == GIT_FILEMODE_LINK + || filemode == GIT_FILEMODE_COMMIT); +} + +GIT_INLINE(git_filemode_t) normalize_filemode(git_filemode_t filemode) +{ + /* Tree bits set, but it's not a commit */ + if (GIT_MODE_TYPE(filemode) == GIT_FILEMODE_TREE) + return GIT_FILEMODE_TREE; + + /* If any of the x bits are set */ + if (GIT_PERMS_IS_EXEC(filemode)) + return GIT_FILEMODE_BLOB_EXECUTABLE; + + /* 16XXXX means commit */ + if (GIT_MODE_TYPE(filemode) == GIT_FILEMODE_COMMIT) + return GIT_FILEMODE_COMMIT; + + /* 12XXXX means symlink */ + if (GIT_MODE_TYPE(filemode) == GIT_FILEMODE_LINK) + return GIT_FILEMODE_LINK; + + /* Otherwise, return a blob */ + return GIT_FILEMODE_BLOB; +} + +static int valid_entry_name(git_repository *repo, const char *filename) +{ + return *filename != '\0' && + git_path_is_valid(repo, filename, 0, + GIT_FS_PATH_REJECT_TRAVERSAL | GIT_PATH_REJECT_DOT_GIT | GIT_FS_PATH_REJECT_SLASH); +} + +static int entry_sort_cmp(const void *a, const void *b) +{ + const git_tree_entry *e1 = (const git_tree_entry *)a; + const git_tree_entry *e2 = (const git_tree_entry *)b; + + return git_fs_path_cmp( + e1->filename, e1->filename_len, git_tree_entry__is_tree(e1), + e2->filename, e2->filename_len, git_tree_entry__is_tree(e2), + git__strncmp); +} + +int git_tree_entry_cmp(const git_tree_entry *e1, const git_tree_entry *e2) +{ + return entry_sort_cmp(e1, e2); +} + +/** + * Allocate a new self-contained entry, with enough space after it to + * store the filename and the id. + */ +static git_tree_entry *alloc_entry(const char *filename, size_t filename_len, const git_oid *id) +{ + git_tree_entry *entry = NULL; + char *filename_ptr; + size_t tree_len; + +#ifdef GIT_EXPERIMENTAL_SHA256 + size_t oid_size = git_oid_size(id->type); +#else + size_t oid_size = GIT_OID_SHA1_SIZE; +#endif + + TREE_ENTRY_CHECK_NAMELEN(filename_len); + + if (GIT_ADD_SIZET_OVERFLOW(&tree_len, sizeof(git_tree_entry), filename_len) || + GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, 1) || + GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, oid_size)) + return NULL; + + entry = git__calloc(1, tree_len); + if (!entry) + return NULL; + + filename_ptr = ((char *) entry) + sizeof(git_tree_entry); + memcpy(filename_ptr, filename, filename_len); + entry->filename = filename_ptr; + entry->filename_len = (uint16_t)filename_len; + + git_oid_cpy(&entry->oid, id); + + return entry; +} + +struct tree_key_search { + const char *filename; + uint16_t filename_len; +}; + +static int homing_search_cmp(const void *key, const void *array_member) +{ + const struct tree_key_search *ksearch = key; + const git_tree_entry *entry = array_member; + + const uint16_t len1 = ksearch->filename_len; + const uint16_t len2 = entry->filename_len; + + return memcmp( + ksearch->filename, + entry->filename, + len1 < len2 ? len1 : len2 + ); +} + +/* + * Search for an entry in a given tree. + * + * Note that this search is performed in two steps because + * of the way tree entries are sorted internally in git: + * + * Entries in a tree are not sorted alphabetically; two entries + * with the same root prefix will have different positions + * depending on whether they are folders (subtrees) or normal files. + * + * Consequently, it is not possible to find an entry on the tree + * with a binary search if you don't know whether the filename + * you're looking for is a folder or a normal file. + * + * To work around this, we first perform a homing binary search + * on the tree, using the minimal length root prefix of our filename. + * Once the comparisons for this homing search start becoming + * ambiguous because of folder vs file sorting, we look linearly + * around the area for our target file. + */ +static int tree_key_search( + size_t *at_pos, + const git_tree *tree, + const char *filename, + size_t filename_len) +{ + struct tree_key_search ksearch; + const git_tree_entry *entry; + size_t homing, i; + + TREE_ENTRY_CHECK_NAMELEN(filename_len); + + ksearch.filename = filename; + ksearch.filename_len = (uint16_t)filename_len; + + /* Initial homing search; find an entry on the tree with + * the same prefix as the filename we're looking for */ + + if (git_array_search(&homing, + tree->entries, &homing_search_cmp, &ksearch) < 0) + return GIT_ENOTFOUND; /* just a signal error; not passed back to user */ + + /* We found a common prefix. Look forward as long as + * there are entries that share the common prefix */ + for (i = homing; i < tree->entries.size; ++i) { + entry = git_array_get(tree->entries, i); + + if (homing_search_cmp(&ksearch, entry) < 0) + break; + + if (entry->filename_len == filename_len && + memcmp(filename, entry->filename, filename_len) == 0) { + if (at_pos) + *at_pos = i; + + return 0; + } + } + + /* If we haven't found our filename yet, look backwards + * too as long as we have entries with the same prefix */ + if (homing > 0) { + i = homing - 1; + + do { + entry = git_array_get(tree->entries, i); + + if (homing_search_cmp(&ksearch, entry) > 0) + break; + + if (entry->filename_len == filename_len && + memcmp(filename, entry->filename, filename_len) == 0) { + if (at_pos) + *at_pos = i; + + return 0; + } + } while (i-- > 0); + } + + /* The filename doesn't exist at all */ + return GIT_ENOTFOUND; +} + +void git_tree_entry_free(git_tree_entry *entry) +{ + if (entry == NULL) + return; + + git__free(entry); +} + +int git_tree_entry_dup(git_tree_entry **dest, const git_tree_entry *source) +{ + git_tree_entry *cpy; + + GIT_ASSERT_ARG(source); + + cpy = alloc_entry(source->filename, source->filename_len, &source->oid); + if (cpy == NULL) + return -1; + + cpy->attr = source->attr; + + *dest = cpy; + return 0; +} + +void git_tree__free(void *_tree) +{ + git_tree *tree = _tree; + + git_odb_object_free(tree->odb_obj); + git_array_clear(tree->entries); + git__free(tree); +} + +git_filemode_t git_tree_entry_filemode(const git_tree_entry *entry) +{ + return normalize_filemode(entry->attr); +} + +git_filemode_t git_tree_entry_filemode_raw(const git_tree_entry *entry) +{ + return entry->attr; +} + +const char *git_tree_entry_name(const git_tree_entry *entry) +{ + GIT_ASSERT_ARG_WITH_RETVAL(entry, NULL); + return entry->filename; +} + +const git_oid *git_tree_entry_id(const git_tree_entry *entry) +{ + GIT_ASSERT_ARG_WITH_RETVAL(entry, NULL); + return &entry->oid; +} + +git_object_t git_tree_entry_type(const git_tree_entry *entry) +{ + GIT_ASSERT_ARG_WITH_RETVAL(entry, GIT_OBJECT_INVALID); + + if (S_ISGITLINK(entry->attr)) + return GIT_OBJECT_COMMIT; + else if (S_ISDIR(entry->attr)) + return GIT_OBJECT_TREE; + else + return GIT_OBJECT_BLOB; +} + +int git_tree_entry_to_object( + git_object **object_out, + git_repository *repo, + const git_tree_entry *entry) +{ + GIT_ASSERT_ARG(entry); + GIT_ASSERT_ARG(object_out); + + return git_object_lookup(object_out, repo, &entry->oid, GIT_OBJECT_ANY); +} + +static const git_tree_entry *entry_fromname( + const git_tree *tree, const char *name, size_t name_len) +{ + size_t idx; + + if (tree_key_search(&idx, tree, name, name_len) < 0) + return NULL; + + return git_array_get(tree->entries, idx); +} + +const git_tree_entry *git_tree_entry_byname( + const git_tree *tree, const char *filename) +{ + GIT_ASSERT_ARG_WITH_RETVAL(tree, NULL); + GIT_ASSERT_ARG_WITH_RETVAL(filename, NULL); + + return entry_fromname(tree, filename, strlen(filename)); +} + +const git_tree_entry *git_tree_entry_byindex( + const git_tree *tree, size_t idx) +{ + GIT_ASSERT_ARG_WITH_RETVAL(tree, NULL); + return git_array_get(tree->entries, idx); +} + +const git_tree_entry *git_tree_entry_byid( + const git_tree *tree, const git_oid *id) +{ + size_t i; + const git_tree_entry *e; + + GIT_ASSERT_ARG_WITH_RETVAL(tree, NULL); + + git_array_foreach(tree->entries, i, e) { + if (git_oid_equal(&e->oid, id)) + return e; + } + + return NULL; +} + +size_t git_tree_entrycount(const git_tree *tree) +{ + GIT_ASSERT_ARG_WITH_RETVAL(tree, 0); + return tree->entries.size; +} + +size_t git_treebuilder_entrycount(git_treebuilder *bld) +{ + GIT_ASSERT_ARG_WITH_RETVAL(bld, 0); + + return git_strmap_size(bld->map); +} + +GIT_INLINE(void) set_error(const char *str, const char *path) +{ + if (path) + git_error_set(GIT_ERROR_TREE, "%s - %s", str, path); + else + git_error_set(GIT_ERROR_TREE, "%s", str); +} + +static int tree_error(const char *str, const char *path) +{ + set_error(str, path); + return -1; +} + +static int tree_parse_error(const char *str, const char *path) +{ + set_error(str, path); + return GIT_EINVALID; +} + +static int parse_mode(uint16_t *mode_out, const char *buffer, size_t buffer_len, const char **buffer_out) +{ + int32_t mode; + int error; + + if (!buffer_len || git__isspace(*buffer)) + return -1; + + if ((error = git__strntol32(&mode, buffer, buffer_len, buffer_out, 8)) < 0) + return error; + + if (mode < 0 || (uint32_t)mode > UINT16_MAX) + return -1; + + *mode_out = mode; + + return 0; +} + +int git_tree__parse_raw(void *_tree, const char *data, size_t size, git_oid_t oid_type) +{ + git_tree *tree = _tree; + const char *buffer; + const char *buffer_end; + const long oid_size = (long)git_oid_size(oid_type); + + buffer = data; + buffer_end = buffer + size; + + tree->odb_obj = NULL; + git_array_init_to_size(tree->entries, DEFAULT_TREE_SIZE); + GIT_ERROR_CHECK_ARRAY(tree->entries); + + while (buffer < buffer_end) { + git_tree_entry *entry; + size_t filename_len; + const char *nul; + uint16_t attr; + + if (parse_mode(&attr, buffer, buffer_end - buffer, &buffer) < 0 || !buffer) + return tree_parse_error("failed to parse tree: can't parse filemode", NULL); + + if (buffer >= buffer_end || (*buffer++) != ' ') + return tree_parse_error("failed to parse tree: missing space after filemode", NULL); + + if ((nul = memchr(buffer, 0, buffer_end - buffer)) == NULL) + return tree_parse_error("failed to parse tree: object is corrupted", NULL); + + if ((filename_len = nul - buffer) == 0 || filename_len > UINT16_MAX) + return tree_parse_error("failed to parse tree: can't parse filename", NULL); + + if ((buffer_end - (nul + 1)) < (long)oid_size) + return tree_parse_error("failed to parse tree: can't parse OID", NULL); + + /* Allocate the entry */ + entry = git_array_alloc(tree->entries); + GIT_ERROR_CHECK_ALLOC(entry); + + entry->attr = attr; + entry->filename_len = (uint16_t)filename_len; + entry->filename = buffer; + buffer += filename_len + 1; + + git_oid__fromraw(&entry->oid, (unsigned char *)buffer, oid_type); + buffer += oid_size; + } + + return 0; +} + +int git_tree__parse(void *_tree, git_odb_object *odb_obj, git_oid_t oid_type) +{ + git_tree *tree = _tree; + const char *data = git_odb_object_data(odb_obj); + size_t size = git_odb_object_size(odb_obj); + int error; + + if ((error = git_tree__parse_raw(tree, data, size, oid_type)) < 0 || + (error = git_odb_object_dup(&tree->odb_obj, odb_obj)) < 0) + return error; + + return error; +} + +static size_t find_next_dir(const char *dirname, git_index *index, size_t start) +{ + size_t dirlen, i, entries = git_index_entrycount(index); + + dirlen = strlen(dirname); + for (i = start; i < entries; ++i) { + const git_index_entry *entry = git_index_get_byindex(index, i); + if (strlen(entry->path) < dirlen || + memcmp(entry->path, dirname, dirlen) || + (dirlen > 0 && entry->path[dirlen] != '/')) { + break; + } + } + + return i; +} + +static git_object_t otype_from_mode(git_filemode_t filemode) +{ + switch (filemode) { + case GIT_FILEMODE_TREE: + return GIT_OBJECT_TREE; + case GIT_FILEMODE_COMMIT: + return GIT_OBJECT_COMMIT; + default: + return GIT_OBJECT_BLOB; + } +} + +static int check_entry(git_repository *repo, const char *filename, const git_oid *id, git_filemode_t filemode) +{ + if (!valid_filemode(filemode)) + return tree_error("failed to insert entry: invalid filemode for file", filename); + + if (!valid_entry_name(repo, filename)) + return tree_error("failed to insert entry: invalid name for a tree entry", filename); + + if (git_oid_is_zero(id)) + return tree_error("failed to insert entry: invalid null OID", filename); + + if (filemode != GIT_FILEMODE_COMMIT && + !git_object__is_valid(repo, id, otype_from_mode(filemode))) + return tree_error("failed to insert entry: invalid object specified", filename); + + return 0; +} + +static int git_treebuilder__write_with_buffer( + git_oid *oid, + git_treebuilder *bld, + git_str *buf) +{ + int error = 0; + size_t i, entrycount; + git_odb *odb; + git_tree_entry *entry; + git_vector entries = GIT_VECTOR_INIT; + size_t oid_size = git_oid_size(bld->repo->oid_type); + + git_str_clear(buf); + + entrycount = git_strmap_size(bld->map); + if ((error = git_vector_init(&entries, entrycount, entry_sort_cmp)) < 0) + goto out; + + if (buf->asize == 0 && + (error = git_str_grow(buf, entrycount * 72)) < 0) + goto out; + + git_strmap_foreach_value(bld->map, entry, { + if ((error = git_vector_insert(&entries, entry)) < 0) + goto out; + }); + + git_vector_sort(&entries); + + for (i = 0; i < entries.length && !error; ++i) { + entry = git_vector_get(&entries, i); + + git_str_printf(buf, "%o ", entry->attr); + git_str_put(buf, entry->filename, entry->filename_len + 1); + git_str_put(buf, (char *)entry->oid.id, oid_size); + + if (git_str_oom(buf)) { + error = -1; + goto out; + } + } + + if ((error = git_repository_odb__weakptr(&odb, bld->repo)) == 0) + error = git_odb_write(oid, odb, buf->ptr, buf->size, GIT_OBJECT_TREE); + +out: + git_vector_free(&entries); + + return error; +} + +static int append_entry( + git_treebuilder *bld, + const char *filename, + const git_oid *id, + git_filemode_t filemode, + bool validate) +{ + git_tree_entry *entry; + int error = 0; + + if (validate && ((error = check_entry(bld->repo, filename, id, filemode)) < 0)) + return error; + + entry = alloc_entry(filename, strlen(filename), id); + GIT_ERROR_CHECK_ALLOC(entry); + + entry->attr = (uint16_t)filemode; + + if ((error = git_strmap_set(bld->map, entry->filename, entry)) < 0) { + git_tree_entry_free(entry); + git_error_set(GIT_ERROR_TREE, "failed to append entry %s to the tree builder", filename); + return -1; + } + + return 0; +} + +static int write_tree( + git_oid *oid, + git_repository *repo, + git_index *index, + const char *dirname, + size_t start, + git_str *shared_buf) +{ + git_treebuilder *bld = NULL; + size_t i, entries = git_index_entrycount(index); + int error; + size_t dirname_len = strlen(dirname); + const git_tree_cache *cache; + + cache = git_tree_cache_get(index->tree, dirname); + if (cache != NULL && cache->entry_count >= 0){ + git_oid_cpy(oid, &cache->oid); + return (int)find_next_dir(dirname, index, start); + } + + if ((error = git_treebuilder_new(&bld, repo, NULL)) < 0 || bld == NULL) + return -1; + + /* + * This loop is unfortunate, but necessary. The index doesn't have + * any directories, so we need to handle that manually, and we + * need to keep track of the current position. + */ + for (i = start; i < entries; ++i) { + const git_index_entry *entry = git_index_get_byindex(index, i); + const char *filename, *next_slash; + + /* + * If we've left our (sub)tree, exit the loop and return. The + * first check is an early out (and security for the + * third). The second check is a simple prefix comparison. The + * third check catches situations where there is a directory + * win32/sys and a file win32mmap.c. Without it, the following + * code believes there is a file win32/mmap.c + */ + if (strlen(entry->path) < dirname_len || + memcmp(entry->path, dirname, dirname_len) || + (dirname_len > 0 && entry->path[dirname_len] != '/')) { + break; + } + + filename = entry->path + dirname_len; + if (*filename == '/') + filename++; + next_slash = strchr(filename, '/'); + if (next_slash) { + git_oid sub_oid; + int written; + char *subdir, *last_comp; + + subdir = git__strndup(entry->path, next_slash - entry->path); + GIT_ERROR_CHECK_ALLOC(subdir); + + /* Write out the subtree */ + written = write_tree(&sub_oid, repo, index, subdir, i, shared_buf); + if (written < 0) { + git__free(subdir); + goto on_error; + } else { + i = written - 1; /* -1 because of the loop increment */ + } + + /* + * We need to figure out what we want toinsert + * into this tree. If we're traversing + * deps/zlib/, then we only want to write + * 'zlib' into the tree. + */ + last_comp = strrchr(subdir, '/'); + if (last_comp) { + last_comp++; /* Get rid of the '/' */ + } else { + last_comp = subdir; + } + + error = append_entry(bld, last_comp, &sub_oid, S_IFDIR, true); + git__free(subdir); + if (error < 0) + goto on_error; + } else { + error = append_entry(bld, filename, &entry->id, entry->mode, true); + if (error < 0) + goto on_error; + } + } + + if (git_treebuilder__write_with_buffer(oid, bld, shared_buf) < 0) + goto on_error; + + git_treebuilder_free(bld); + return (int)i; + +on_error: + git_treebuilder_free(bld); + return -1; +} + +int git_tree__write_index( + git_oid *oid, git_index *index, git_repository *repo) +{ + int ret; + git_tree *tree; + git_str shared_buf = GIT_STR_INIT; + bool old_ignore_case = false; + + GIT_ASSERT_ARG(oid); + GIT_ASSERT_ARG(index); + GIT_ASSERT_ARG(repo); + + if (git_index_has_conflicts(index)) { + git_error_set(GIT_ERROR_INDEX, + "cannot create a tree from a not fully merged index."); + return GIT_EUNMERGED; + } + + if (index->tree != NULL && index->tree->entry_count >= 0) { + git_oid_cpy(oid, &index->tree->oid); + return 0; + } + + /* The tree cache didn't help us; we'll have to write + * out a tree. If the index is ignore_case, we must + * make it case-sensitive for the duration of the tree-write + * operation. */ + + if (index->ignore_case) { + old_ignore_case = true; + git_index__set_ignore_case(index, false); + } + + ret = write_tree(oid, repo, index, "", 0, &shared_buf); + git_str_dispose(&shared_buf); + + if (old_ignore_case) + git_index__set_ignore_case(index, true); + + index->tree = NULL; + + if (ret < 0) + return ret; + + git_pool_clear(&index->tree_pool); + + if ((ret = git_tree_lookup(&tree, repo, oid)) < 0) + return ret; + + /* Read the tree cache into the index */ + ret = git_tree_cache_read_tree(&index->tree, tree, index->oid_type, &index->tree_pool); + git_tree_free(tree); + + return ret; +} + +int git_treebuilder_new( + git_treebuilder **builder_p, + git_repository *repo, + const git_tree *source) +{ + git_treebuilder *bld; + size_t i; + + GIT_ASSERT_ARG(builder_p); + GIT_ASSERT_ARG(repo); + + bld = git__calloc(1, sizeof(git_treebuilder)); + GIT_ERROR_CHECK_ALLOC(bld); + + bld->repo = repo; + + if (git_strmap_new(&bld->map) < 0) { + git__free(bld); + return -1; + } + + if (source != NULL) { + git_tree_entry *entry_src; + + git_array_foreach(source->entries, i, entry_src) { + if (append_entry( + bld, entry_src->filename, + &entry_src->oid, + entry_src->attr, + false) < 0) + goto on_error; + } + } + + *builder_p = bld; + return 0; + +on_error: + git_treebuilder_free(bld); + return -1; +} + +int git_treebuilder_insert( + const git_tree_entry **entry_out, + git_treebuilder *bld, + const char *filename, + const git_oid *id, + git_filemode_t filemode) +{ + git_tree_entry *entry; + int error; + + GIT_ASSERT_ARG(bld); + GIT_ASSERT_ARG(id); + GIT_ASSERT_ARG(filename); + + if ((error = check_entry(bld->repo, filename, id, filemode)) < 0) + return error; + + if ((entry = git_strmap_get(bld->map, filename)) != NULL) { + git_oid_cpy(&entry->oid, id); + } else { + entry = alloc_entry(filename, strlen(filename), id); + GIT_ERROR_CHECK_ALLOC(entry); + + if ((error = git_strmap_set(bld->map, entry->filename, entry)) < 0) { + git_tree_entry_free(entry); + git_error_set(GIT_ERROR_TREE, "failed to insert %s", filename); + return -1; + } + } + + entry->attr = filemode; + + if (entry_out) + *entry_out = entry; + + return 0; +} + +static git_tree_entry *treebuilder_get(git_treebuilder *bld, const char *filename) +{ + GIT_ASSERT_ARG_WITH_RETVAL(bld, NULL); + GIT_ASSERT_ARG_WITH_RETVAL(filename, NULL); + + return git_strmap_get(bld->map, filename); +} + +const git_tree_entry *git_treebuilder_get(git_treebuilder *bld, const char *filename) +{ + return treebuilder_get(bld, filename); +} + +int git_treebuilder_remove(git_treebuilder *bld, const char *filename) +{ + git_tree_entry *entry = treebuilder_get(bld, filename); + + if (entry == NULL) + return tree_error("failed to remove entry: file isn't in the tree", filename); + + git_strmap_delete(bld->map, filename); + git_tree_entry_free(entry); + + return 0; +} + +int git_treebuilder_write(git_oid *oid, git_treebuilder *bld) +{ + GIT_ASSERT_ARG(oid); + GIT_ASSERT_ARG(bld); + + return git_treebuilder__write_with_buffer(oid, bld, &bld->write_cache); +} + +int git_treebuilder_filter( + git_treebuilder *bld, + git_treebuilder_filter_cb filter, + void *payload) +{ + const char *filename; + git_tree_entry *entry; + + GIT_ASSERT_ARG(bld); + GIT_ASSERT_ARG(filter); + + git_strmap_foreach(bld->map, filename, entry, { + if (filter(entry, payload)) { + git_strmap_delete(bld->map, filename); + git_tree_entry_free(entry); + } + }); + + return 0; +} + +int git_treebuilder_clear(git_treebuilder *bld) +{ + git_tree_entry *e; + + GIT_ASSERT_ARG(bld); + + git_strmap_foreach_value(bld->map, e, git_tree_entry_free(e)); + git_strmap_clear(bld->map); + + return 0; +} + +void git_treebuilder_free(git_treebuilder *bld) +{ + if (bld == NULL) + return; + + git_str_dispose(&bld->write_cache); + git_treebuilder_clear(bld); + git_strmap_free(bld->map); + git__free(bld); +} + +static size_t subpath_len(const char *path) +{ + const char *slash_pos = strchr(path, '/'); + if (slash_pos == NULL) + return strlen(path); + + return slash_pos - path; +} + +int git_tree_entry_bypath( + git_tree_entry **entry_out, + const git_tree *root, + const char *path) +{ + int error = 0; + git_tree *subtree; + const git_tree_entry *entry; + size_t filename_len; + + /* Find how long is the current path component (i.e. + * the filename between two slashes */ + filename_len = subpath_len(path); + + if (filename_len == 0) { + git_error_set(GIT_ERROR_TREE, "invalid tree path given"); + return GIT_ENOTFOUND; + } + + entry = entry_fromname(root, path, filename_len); + + if (entry == NULL) { + git_error_set(GIT_ERROR_TREE, + "the path '%.*s' does not exist in the given tree", (int) filename_len, path); + return GIT_ENOTFOUND; + } + + switch (path[filename_len]) { + case '/': + /* If there are more components in the path... + * then this entry *must* be a tree */ + if (!git_tree_entry__is_tree(entry)) { + git_error_set(GIT_ERROR_TREE, + "the path '%.*s' exists but is not a tree", (int) filename_len, path); + return GIT_ENOTFOUND; + } + + /* If there's only a slash left in the path, we + * return the current entry; otherwise, we keep + * walking down the path */ + if (path[filename_len + 1] != '\0') + break; + /* fall through */ + case '\0': + /* If there are no more components in the path, return + * this entry */ + return git_tree_entry_dup(entry_out, entry); + } + + if (git_tree_lookup(&subtree, root->object.repo, &entry->oid) < 0) + return -1; + + error = git_tree_entry_bypath( + entry_out, + subtree, + path + filename_len + 1 + ); + + git_tree_free(subtree); + return error; +} + +static int tree_walk( + const git_tree *tree, + git_treewalk_cb callback, + git_str *path, + void *payload, + bool preorder) +{ + int error = 0; + size_t i; + const git_tree_entry *entry; + + git_array_foreach(tree->entries, i, entry) { + if (preorder) { + error = callback(path->ptr, entry, payload); + if (error < 0) { /* negative value stops iteration */ + git_error_set_after_callback_function(error, "git_tree_walk"); + break; + } + if (error > 0) { /* positive value skips this entry */ + error = 0; + continue; + } + } + + if (git_tree_entry__is_tree(entry)) { + git_tree *subtree; + size_t path_len = git_str_len(path); + + error = git_tree_lookup(&subtree, tree->object.repo, &entry->oid); + if (error < 0) + break; + + /* append the next entry to the path */ + git_str_puts(path, entry->filename); + git_str_putc(path, '/'); + + if (git_str_oom(path)) + error = -1; + else + error = tree_walk(subtree, callback, path, payload, preorder); + + git_tree_free(subtree); + if (error != 0) + break; + + git_str_truncate(path, path_len); + } + + if (!preorder) { + error = callback(path->ptr, entry, payload); + if (error < 0) { /* negative value stops iteration */ + git_error_set_after_callback_function(error, "git_tree_walk"); + break; + } + error = 0; + } + } + + return error; +} + +int git_tree_walk( + const git_tree *tree, + git_treewalk_mode mode, + git_treewalk_cb callback, + void *payload) +{ + int error = 0; + git_str root_path = GIT_STR_INIT; + + if (mode != GIT_TREEWALK_POST && mode != GIT_TREEWALK_PRE) { + git_error_set(GIT_ERROR_INVALID, "invalid walking mode for tree walk"); + return -1; + } + + error = tree_walk( + tree, callback, &root_path, payload, (mode == GIT_TREEWALK_PRE)); + + git_str_dispose(&root_path); + + return error; +} + +static int compare_entries(const void *_a, const void *_b) +{ + const git_tree_update *a = (git_tree_update *) _a; + const git_tree_update *b = (git_tree_update *) _b; + + return strcmp(a->path, b->path); +} + +static int on_dup_entry(void **old, void *new) +{ + GIT_UNUSED(old); GIT_UNUSED(new); + + git_error_set(GIT_ERROR_TREE, "duplicate entries given for update"); + return -1; +} + +/* + * We keep the previous tree and the new one at each level of the + * stack. When we leave a level we're done with that tree and we can + * write it out to the odb. + */ +typedef struct { + git_treebuilder *bld; + git_tree *tree; + char *name; +} tree_stack_entry; + +/** Count how many slashes (i.e. path components) there are in this string */ +GIT_INLINE(size_t) count_slashes(const char *path) +{ + size_t count = 0; + const char *slash; + + while ((slash = strchr(path, '/')) != NULL) { + count++; + path = slash + 1; + } + + return count; +} + +static bool next_component(git_str *out, const char *in) +{ + const char *slash = strchr(in, '/'); + + git_str_clear(out); + + if (slash) + git_str_put(out, in, slash - in); + + return !!slash; +} + +static int create_popped_tree(tree_stack_entry *current, tree_stack_entry *popped, git_str *component) +{ + int error; + git_oid new_tree; + + git_tree_free(popped->tree); + + /* If the tree would be empty, remove it from the one higher up */ + if (git_treebuilder_entrycount(popped->bld) == 0) { + git_treebuilder_free(popped->bld); + error = git_treebuilder_remove(current->bld, popped->name); + git__free(popped->name); + return error; + } + + error = git_treebuilder_write(&new_tree, popped->bld); + git_treebuilder_free(popped->bld); + + if (error < 0) { + git__free(popped->name); + return error; + } + + /* We've written out the tree, now we have to put the new value into its parent */ + git_str_clear(component); + git_str_puts(component, popped->name); + git__free(popped->name); + + GIT_ERROR_CHECK_ALLOC(component->ptr); + + /* Error out if this would create a D/F conflict in this update */ + if (current->tree) { + const git_tree_entry *to_replace; + to_replace = git_tree_entry_byname(current->tree, component->ptr); + if (to_replace && git_tree_entry_type(to_replace) != GIT_OBJECT_TREE) { + git_error_set(GIT_ERROR_TREE, "D/F conflict when updating tree"); + return -1; + } + } + + return git_treebuilder_insert(NULL, current->bld, component->ptr, &new_tree, GIT_FILEMODE_TREE); +} + +int git_tree_create_updated(git_oid *out, git_repository *repo, git_tree *baseline, size_t nupdates, const git_tree_update *updates) +{ + git_array_t(tree_stack_entry) stack = GIT_ARRAY_INIT; + tree_stack_entry *root_elem; + git_vector entries; + int error; + size_t i; + git_str component = GIT_STR_INIT; + + if ((error = git_vector_init(&entries, nupdates, compare_entries)) < 0) + return error; + + /* Sort the entries for treversal */ + for (i = 0 ; i < nupdates; i++) { + if ((error = git_vector_insert_sorted(&entries, (void *) &updates[i], on_dup_entry)) < 0) + goto cleanup; + } + + root_elem = git_array_alloc(stack); + GIT_ERROR_CHECK_ALLOC(root_elem); + memset(root_elem, 0, sizeof(*root_elem)); + + if (baseline && (error = git_tree_dup(&root_elem->tree, baseline)) < 0) + goto cleanup; + + if ((error = git_treebuilder_new(&root_elem->bld, repo, root_elem->tree)) < 0) + goto cleanup; + + for (i = 0; i < nupdates; i++) { + const git_tree_update *last_update = i == 0 ? NULL : git_vector_get(&entries, i-1); + const git_tree_update *update = git_vector_get(&entries, i); + size_t common_prefix = 0, steps_up, j; + const char *path; + + /* Figure out how much we need to change from the previous tree */ + if (last_update) + common_prefix = git_fs_path_common_dirlen(last_update->path, update->path); + + /* + * The entries are sorted, so when we find we're no + * longer in the same directory, we need to abandon + * the old tree (steps up) and dive down to the next + * one. + */ + steps_up = last_update == NULL ? 0 : count_slashes(&last_update->path[common_prefix]); + + for (j = 0; j < steps_up; j++) { + tree_stack_entry *current, *popped = git_array_pop(stack); + GIT_ASSERT(popped); + + current = git_array_last(stack); + GIT_ASSERT(current); + + if ((error = create_popped_tree(current, popped, &component)) < 0) + goto cleanup; + } + + /* Now that we've created the trees we popped from the stack, let's go back down */ + path = &update->path[common_prefix]; + while (next_component(&component, path)) { + tree_stack_entry *last, *new_entry; + const git_tree_entry *entry; + + last = git_array_last(stack); + entry = last->tree ? git_tree_entry_byname(last->tree, component.ptr) : NULL; + if (!entry) + entry = treebuilder_get(last->bld, component.ptr); + + if (entry && git_tree_entry_type(entry) != GIT_OBJECT_TREE) { + git_error_set(GIT_ERROR_TREE, "D/F conflict when updating tree"); + error = -1; + goto cleanup; + } + + new_entry = git_array_alloc(stack); + GIT_ERROR_CHECK_ALLOC(new_entry); + memset(new_entry, 0, sizeof(*new_entry)); + + new_entry->tree = NULL; + if (entry && (error = git_tree_lookup(&new_entry->tree, repo, git_tree_entry_id(entry))) < 0) + goto cleanup; + + if ((error = git_treebuilder_new(&new_entry->bld, repo, new_entry->tree)) < 0) + goto cleanup; + + new_entry->name = git__strdup(component.ptr); + GIT_ERROR_CHECK_ALLOC(new_entry->name); + + /* Get to the start of the next component */ + path += component.size + 1; + } + + /* After all that, we're finally at the place where we want to perform the update */ + switch (update->action) { + case GIT_TREE_UPDATE_UPSERT: + { + /* Make sure we're replacing something of the same type */ + tree_stack_entry *last = git_array_last(stack); + char *basename = git_fs_path_basename(update->path); + const git_tree_entry *e = git_treebuilder_get(last->bld, basename); + if (e && git_tree_entry_type(e) != git_object__type_from_filemode(update->filemode)) { + git__free(basename); + git_error_set(GIT_ERROR_TREE, "cannot replace '%s' with '%s' at '%s'", + git_object_type2string(git_tree_entry_type(e)), + git_object_type2string(git_object__type_from_filemode(update->filemode)), + update->path); + error = -1; + goto cleanup; + } + + error = git_treebuilder_insert(NULL, last->bld, basename, &update->id, update->filemode); + git__free(basename); + break; + } + case GIT_TREE_UPDATE_REMOVE: + { + tree_stack_entry *last = git_array_last(stack); + char *basename = git_fs_path_basename(update->path); + error = git_treebuilder_remove(last->bld, basename); + git__free(basename); + break; + } + default: + git_error_set(GIT_ERROR_TREE, "unknown action for update"); + error = -1; + goto cleanup; + } + + if (error < 0) + goto cleanup; + } + + /* We're done, go up the stack again and write out the tree */ + { + tree_stack_entry *current = NULL, *popped = NULL; + while ((popped = git_array_pop(stack)) != NULL) { + current = git_array_last(stack); + /* We've reached the top, current is the root tree */ + if (!current) + break; + + if ((error = create_popped_tree(current, popped, &component)) < 0) + goto cleanup; + } + + /* Write out the root tree */ + git__free(popped->name); + git_tree_free(popped->tree); + + error = git_treebuilder_write(out, popped->bld); + git_treebuilder_free(popped->bld); + if (error < 0) + goto cleanup; + } + +cleanup: + { + tree_stack_entry *e; + while ((e = git_array_pop(stack)) != NULL) { + git_treebuilder_free(e->bld); + git_tree_free(e->tree); + git__free(e->name); + } + } + + git_str_dispose(&component); + git_array_clear(stack); + git_vector_free(&entries); + return error; +} + +/* Deprecated Functions */ + +#ifndef GIT_DEPRECATE_HARD + +int git_treebuilder_write_with_buffer(git_oid *oid, git_treebuilder *bld, git_buf *buf) +{ + GIT_UNUSED(buf); + + return git_treebuilder_write(oid, bld); +} + +#endif diff --git a/vendor/libgit2/src/tree.h b/vendor/libgit2/src/libgit2/tree.h similarity index 91% rename from vendor/libgit2/src/tree.h rename to vendor/libgit2/src/libgit2/tree.h index 6bd9ed65..5088450a 100644 --- a/vendor/libgit2/src/tree.h +++ b/vendor/libgit2/src/libgit2/tree.h @@ -19,7 +19,7 @@ struct git_tree_entry { uint16_t attr; uint16_t filename_len; - const git_oid *oid; + git_oid oid; const char *filename; }; @@ -41,8 +41,8 @@ GIT_INLINE(bool) git_tree_entry__is_tree(const struct git_tree_entry *e) } void git_tree__free(void *tree); -int git_tree__parse(void *tree, git_odb_object *obj); -int git_tree__parse_raw(void *_tree, const char *data, size_t size); +int git_tree__parse(void *tree, git_odb_object *obj, git_oid_t oid_type); +int git_tree__parse_raw(void *_tree, const char *data, size_t size, git_oid_t oid_type); /** * Write a tree to the given repository diff --git a/vendor/libgit2/src/userdiff.h b/vendor/libgit2/src/libgit2/userdiff.h similarity index 100% rename from vendor/libgit2/src/userdiff.h rename to vendor/libgit2/src/libgit2/userdiff.h diff --git a/vendor/libgit2/src/libgit2/worktree.c b/vendor/libgit2/src/libgit2/worktree.c new file mode 100644 index 00000000..00ff9e7d --- /dev/null +++ b/vendor/libgit2/src/libgit2/worktree.c @@ -0,0 +1,669 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "worktree.h" + +#include "buf.h" +#include "repository.h" +#include "path.h" + +#include "git2/branch.h" +#include "git2/commit.h" +#include "git2/worktree.h" + +static bool is_worktree_dir(const char *dir) +{ + git_str buf = GIT_STR_INIT; + int error; + + if (git_str_sets(&buf, dir) < 0) + return -1; + + error = git_fs_path_contains_file(&buf, "commondir") + && git_fs_path_contains_file(&buf, "gitdir") + && git_fs_path_contains_file(&buf, "HEAD"); + + git_str_dispose(&buf); + return error; +} + +int git_worktree_list(git_strarray *wts, git_repository *repo) +{ + git_vector worktrees = GIT_VECTOR_INIT; + git_str path = GIT_STR_INIT; + char *worktree; + size_t i, len; + int error; + + GIT_ASSERT_ARG(wts); + GIT_ASSERT_ARG(repo); + + wts->count = 0; + wts->strings = NULL; + + if ((error = git_str_joinpath(&path, repo->commondir, "worktrees/")) < 0) + goto exit; + if (!git_fs_path_exists(path.ptr) || git_fs_path_is_empty_dir(path.ptr)) + goto exit; + if ((error = git_fs_path_dirload(&worktrees, path.ptr, path.size, 0x0)) < 0) + goto exit; + + len = path.size; + + git_vector_foreach(&worktrees, i, worktree) { + git_str_truncate(&path, len); + git_str_puts(&path, worktree); + + if (!is_worktree_dir(path.ptr)) { + git_vector_remove(&worktrees, i); + git__free(worktree); + } + } + + wts->strings = (char **)git_vector_detach(&wts->count, NULL, &worktrees); + +exit: + git_str_dispose(&path); + + return error; +} + +char *git_worktree__read_link(const char *base, const char *file) +{ + git_str path = GIT_STR_INIT, buf = GIT_STR_INIT; + + GIT_ASSERT_ARG_WITH_RETVAL(base, NULL); + GIT_ASSERT_ARG_WITH_RETVAL(file, NULL); + + if (git_str_joinpath(&path, base, file) < 0) + goto err; + if (git_futils_readbuffer(&buf, path.ptr) < 0) + goto err; + git_str_dispose(&path); + + git_str_rtrim(&buf); + + if (!git_fs_path_is_relative(buf.ptr)) + return git_str_detach(&buf); + + if (git_str_sets(&path, base) < 0) + goto err; + if (git_fs_path_apply_relative(&path, buf.ptr) < 0) + goto err; + git_str_dispose(&buf); + + return git_str_detach(&path); + +err: + git_str_dispose(&buf); + git_str_dispose(&path); + + return NULL; +} + +static int write_wtfile(const char *base, const char *file, const git_str *buf) +{ + git_str path = GIT_STR_INIT; + int err; + + GIT_ASSERT_ARG(base); + GIT_ASSERT_ARG(file); + GIT_ASSERT_ARG(buf); + + if ((err = git_str_joinpath(&path, base, file)) < 0) + goto out; + + if ((err = git_futils_writebuffer(buf, path.ptr, O_CREAT|O_EXCL|O_WRONLY, 0644)) < 0) + goto out; + +out: + git_str_dispose(&path); + + return err; +} + +static int open_worktree_dir(git_worktree **out, const char *parent, const char *dir, const char *name) +{ + git_str gitdir = GIT_STR_INIT; + git_worktree *wt = NULL; + int error = 0; + + if (!is_worktree_dir(dir)) { + error = -1; + goto out; + } + + if ((error = git_path_validate_length(NULL, dir)) < 0) + goto out; + + if ((wt = git__calloc(1, sizeof(*wt))) == NULL) { + error = -1; + goto out; + } + + if ((wt->name = git__strdup(name)) == NULL || + (wt->commondir_path = git_worktree__read_link(dir, "commondir")) == NULL || + (wt->gitlink_path = git_worktree__read_link(dir, "gitdir")) == NULL || + (parent && (wt->parent_path = git__strdup(parent)) == NULL) || + (wt->worktree_path = git_fs_path_dirname(wt->gitlink_path)) == NULL) { + error = -1; + goto out; + } + + if ((error = git_fs_path_prettify_dir(&gitdir, dir, NULL)) < 0) + goto out; + wt->gitdir_path = git_str_detach(&gitdir); + + if ((error = git_worktree_is_locked(NULL, wt)) < 0) + goto out; + wt->locked = !!error; + error = 0; + + *out = wt; + +out: + if (error) + git_worktree_free(wt); + git_str_dispose(&gitdir); + + return error; +} + +int git_worktree_lookup(git_worktree **out, git_repository *repo, const char *name) +{ + git_str path = GIT_STR_INIT; + git_worktree *wt = NULL; + int error; + + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(name); + + *out = NULL; + + if ((error = git_str_join3(&path, '/', repo->commondir, "worktrees", name)) < 0) + goto out; + + if (!git_fs_path_isdir(path.ptr)) { + error = GIT_ENOTFOUND; + goto out; + } + + if ((error = (open_worktree_dir(out, git_repository_workdir(repo), path.ptr, name))) < 0) + goto out; + +out: + git_str_dispose(&path); + + if (error) + git_worktree_free(wt); + + return error; +} + +int git_worktree_open_from_repository(git_worktree **out, git_repository *repo) +{ + git_str parent = GIT_STR_INIT; + const char *gitdir, *commondir; + char *name = NULL; + int error = 0; + + if (!git_repository_is_worktree(repo)) { + git_error_set(GIT_ERROR_WORKTREE, "cannot open worktree of a non-worktree repo"); + error = -1; + goto out; + } + + gitdir = git_repository_path(repo); + commondir = git_repository_commondir(repo); + + if ((error = git_fs_path_prettify_dir(&parent, "..", commondir)) < 0) + goto out; + + /* The name is defined by the last component in '.git/worktree/%s' */ + name = git_fs_path_basename(gitdir); + + if ((error = open_worktree_dir(out, parent.ptr, gitdir, name)) < 0) + goto out; + +out: + git__free(name); + git_str_dispose(&parent); + + return error; +} + +void git_worktree_free(git_worktree *wt) +{ + if (!wt) + return; + + git__free(wt->commondir_path); + git__free(wt->worktree_path); + git__free(wt->gitlink_path); + git__free(wt->gitdir_path); + git__free(wt->parent_path); + git__free(wt->name); + git__free(wt); +} + +int git_worktree_validate(const git_worktree *wt) +{ + GIT_ASSERT_ARG(wt); + + if (!is_worktree_dir(wt->gitdir_path)) { + git_error_set(GIT_ERROR_WORKTREE, + "worktree gitdir ('%s') is not valid", + wt->gitlink_path); + return GIT_ERROR; + } + + if (wt->parent_path && !git_fs_path_exists(wt->parent_path)) { + git_error_set(GIT_ERROR_WORKTREE, + "worktree parent directory ('%s') does not exist ", + wt->parent_path); + return GIT_ERROR; + } + + if (!git_fs_path_exists(wt->commondir_path)) { + git_error_set(GIT_ERROR_WORKTREE, + "worktree common directory ('%s') does not exist ", + wt->commondir_path); + return GIT_ERROR; + } + + if (!git_fs_path_exists(wt->worktree_path)) { + git_error_set(GIT_ERROR_WORKTREE, + "worktree directory '%s' does not exist", + wt->worktree_path); + return GIT_ERROR; + } + + return 0; +} + +int git_worktree_add_options_init(git_worktree_add_options *opts, + unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE(opts, version, + git_worktree_add_options, GIT_WORKTREE_ADD_OPTIONS_INIT); + return 0; +} + +#ifndef GIT_DEPRECATE_HARD +int git_worktree_add_init_options(git_worktree_add_options *opts, + unsigned int version) +{ + return git_worktree_add_options_init(opts, version); +} +#endif + +int git_worktree_add(git_worktree **out, git_repository *repo, + const char *name, const char *worktree, + const git_worktree_add_options *opts) +{ + git_str gitdir = GIT_STR_INIT, wddir = GIT_STR_INIT, buf = GIT_STR_INIT; + git_reference *ref = NULL, *head = NULL; + git_commit *commit = NULL; + git_repository *wt = NULL; + git_checkout_options coopts; + git_worktree_add_options wtopts = GIT_WORKTREE_ADD_OPTIONS_INIT; + int err; + + GIT_ERROR_CHECK_VERSION( + opts, GIT_WORKTREE_ADD_OPTIONS_VERSION, "git_worktree_add_options"); + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(name); + GIT_ASSERT_ARG(worktree); + + *out = NULL; + + if (opts) + memcpy(&wtopts, opts, sizeof(wtopts)); + + memcpy(&coopts, &wtopts.checkout_options, sizeof(coopts)); + + if (wtopts.ref) { + if (!git_reference_is_branch(wtopts.ref)) { + git_error_set(GIT_ERROR_WORKTREE, "reference is not a branch"); + err = -1; + goto out; + } + + if ((err = git_reference_dup(&ref, wtopts.ref)) < 0) + goto out; + } else if (wtopts.checkout_existing && git_branch_lookup(&ref, repo, name, GIT_BRANCH_LOCAL) == 0) { + /* Do nothing */ + } else if ((err = git_repository_head(&head, repo)) < 0 || + (err = git_commit_lookup(&commit, repo, &head->target.oid)) < 0 || + (err = git_branch_create(&ref, repo, name, commit, false)) < 0) { + goto out; + } + + if (git_branch_is_checked_out(ref)) { + git_error_set(GIT_ERROR_WORKTREE, "reference %s is already checked out", + git_reference_name(ref)); + err = -1; + goto out; + } + + /* Create gitdir directory ".git/worktrees/" */ + if ((err = git_str_joinpath(&gitdir, repo->commondir, "worktrees")) < 0) + goto out; + if (!git_fs_path_exists(gitdir.ptr)) + if ((err = git_futils_mkdir(gitdir.ptr, 0755, GIT_MKDIR_EXCL)) < 0) + goto out; + if ((err = git_str_joinpath(&gitdir, gitdir.ptr, name)) < 0) + goto out; + if ((err = git_futils_mkdir(gitdir.ptr, 0755, GIT_MKDIR_EXCL)) < 0) + goto out; + if ((err = git_fs_path_prettify_dir(&gitdir, gitdir.ptr, NULL)) < 0) + goto out; + + /* Create worktree work dir */ + if ((err = git_futils_mkdir(worktree, 0755, GIT_MKDIR_EXCL)) < 0) + goto out; + if ((err = git_fs_path_prettify_dir(&wddir, worktree, NULL)) < 0) + goto out; + + if (wtopts.lock) { + int fd; + + if ((err = git_str_joinpath(&buf, gitdir.ptr, "locked")) < 0) + goto out; + + if ((fd = p_creat(buf.ptr, 0644)) < 0) { + err = fd; + goto out; + } + + p_close(fd); + git_str_clear(&buf); + } + + /* Create worktree .git file */ + if ((err = git_str_printf(&buf, "gitdir: %s\n", gitdir.ptr)) < 0) + goto out; + if ((err = write_wtfile(wddir.ptr, ".git", &buf)) < 0) + goto out; + + /* Create gitdir files */ + if ((err = git_fs_path_prettify_dir(&buf, repo->commondir, NULL) < 0) + || (err = git_str_putc(&buf, '\n')) < 0 + || (err = write_wtfile(gitdir.ptr, "commondir", &buf)) < 0) + goto out; + if ((err = git_str_joinpath(&buf, wddir.ptr, ".git")) < 0 + || (err = git_str_putc(&buf, '\n')) < 0 + || (err = write_wtfile(gitdir.ptr, "gitdir", &buf)) < 0) + goto out; + + /* Set worktree's HEAD */ + if ((err = git_repository_create_head(gitdir.ptr, git_reference_name(ref))) < 0) + goto out; + if ((err = git_repository_open(&wt, wddir.ptr)) < 0) + goto out; + + /* Checkout worktree's HEAD */ + if ((err = git_checkout_head(wt, &coopts)) < 0) + goto out; + + /* Load result */ + if ((err = git_worktree_lookup(out, repo, name)) < 0) + goto out; + +out: + git_str_dispose(&gitdir); + git_str_dispose(&wddir); + git_str_dispose(&buf); + git_reference_free(ref); + git_reference_free(head); + git_commit_free(commit); + git_repository_free(wt); + + return err; +} + +int git_worktree_lock(git_worktree *wt, const char *reason) +{ + git_str buf = GIT_STR_INIT, path = GIT_STR_INIT; + int error; + + GIT_ASSERT_ARG(wt); + + if ((error = git_worktree_is_locked(NULL, wt)) < 0) + goto out; + if (error) { + error = GIT_ELOCKED; + goto out; + } + + if ((error = git_str_joinpath(&path, wt->gitdir_path, "locked")) < 0) + goto out; + + if (reason) + git_str_attach_notowned(&buf, reason, strlen(reason)); + + if ((error = git_futils_writebuffer(&buf, path.ptr, O_CREAT|O_EXCL|O_WRONLY, 0644)) < 0) + goto out; + + wt->locked = 1; + +out: + git_str_dispose(&path); + + return error; +} + +int git_worktree_unlock(git_worktree *wt) +{ + git_str path = GIT_STR_INIT; + int error; + + GIT_ASSERT_ARG(wt); + + if ((error = git_worktree_is_locked(NULL, wt)) < 0) + return error; + if (!error) + return 1; + + if (git_str_joinpath(&path, wt->gitdir_path, "locked") < 0) + return -1; + + if (p_unlink(path.ptr) != 0) { + git_str_dispose(&path); + return -1; + } + + wt->locked = 0; + + git_str_dispose(&path); + + return 0; +} + +static int git_worktree__is_locked(git_str *reason, const git_worktree *wt) +{ + git_str path = GIT_STR_INIT; + int error, locked; + + GIT_ASSERT_ARG(wt); + + if (reason) + git_str_clear(reason); + + if ((error = git_str_joinpath(&path, wt->gitdir_path, "locked")) < 0) + goto out; + locked = git_fs_path_exists(path.ptr); + if (locked && reason && + (error = git_futils_readbuffer(reason, path.ptr)) < 0) + goto out; + + error = locked; +out: + git_str_dispose(&path); + + return error; +} + +int git_worktree_is_locked(git_buf *reason, const git_worktree *wt) +{ + git_str str = GIT_STR_INIT; + int error = 0; + + if (reason && (error = git_buf_tostr(&str, reason)) < 0) + return error; + + error = git_worktree__is_locked(reason ? &str : NULL, wt); + + if (error >= 0 && reason) { + if (git_buf_fromstr(reason, &str) < 0) + error = -1; + } + + git_str_dispose(&str); + return error; +} + +const char *git_worktree_name(const git_worktree *wt) +{ + GIT_ASSERT_ARG_WITH_RETVAL(wt, NULL); + return wt->name; +} + +const char *git_worktree_path(const git_worktree *wt) +{ + GIT_ASSERT_ARG_WITH_RETVAL(wt, NULL); + return wt->worktree_path; +} + +int git_worktree_prune_options_init( + git_worktree_prune_options *opts, + unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE(opts, version, + git_worktree_prune_options, GIT_WORKTREE_PRUNE_OPTIONS_INIT); + return 0; +} + +#ifndef GIT_DEPRECATE_HARD +int git_worktree_prune_init_options(git_worktree_prune_options *opts, + unsigned int version) +{ + return git_worktree_prune_options_init(opts, version); +} +#endif + +int git_worktree_is_prunable(git_worktree *wt, + git_worktree_prune_options *opts) +{ + git_worktree_prune_options popts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + git_str path = GIT_STR_INIT; + int ret = 0; + + GIT_ERROR_CHECK_VERSION( + opts, GIT_WORKTREE_PRUNE_OPTIONS_VERSION, + "git_worktree_prune_options"); + + if (opts) + memcpy(&popts, opts, sizeof(popts)); + + if ((popts.flags & GIT_WORKTREE_PRUNE_LOCKED) == 0) { + git_str reason = GIT_STR_INIT; + + if ((ret = git_worktree__is_locked(&reason, wt)) < 0) + goto out; + + if (ret) { + git_error_set(GIT_ERROR_WORKTREE, + "not pruning locked working tree: '%s'", + reason.size ? reason.ptr : "is locked"); + + git_str_dispose(&reason); + ret = 0; + goto out; + } + } + + if ((popts.flags & GIT_WORKTREE_PRUNE_VALID) == 0 && + git_worktree_validate(wt) == 0) { + git_error_set(GIT_ERROR_WORKTREE, "not pruning valid working tree"); + goto out; + } + + if ((ret = git_str_printf(&path, "%s/worktrees/%s", wt->commondir_path, wt->name) < 0)) + goto out; + + if (!git_fs_path_exists(path.ptr)) { + git_error_set(GIT_ERROR_WORKTREE, "worktree gitdir ('%s') does not exist", path.ptr); + goto out; + } + + ret = 1; + +out: + git_str_dispose(&path); + return ret; +} + +int git_worktree_prune(git_worktree *wt, + git_worktree_prune_options *opts) +{ + git_worktree_prune_options popts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + git_str path = GIT_STR_INIT; + char *wtpath; + int err; + + GIT_ERROR_CHECK_VERSION( + opts, GIT_WORKTREE_PRUNE_OPTIONS_VERSION, + "git_worktree_prune_options"); + + if (opts) + memcpy(&popts, opts, sizeof(popts)); + + if (!git_worktree_is_prunable(wt, &popts)) { + err = -1; + goto out; + } + + /* Delete gitdir in parent repository */ + if ((err = git_str_join3(&path, '/', wt->commondir_path, "worktrees", wt->name)) < 0) + goto out; + if (!git_fs_path_exists(path.ptr)) + { + git_error_set(GIT_ERROR_WORKTREE, "worktree gitdir '%s' does not exist", path.ptr); + err = -1; + goto out; + } + if ((err = git_futils_rmdir_r(path.ptr, NULL, GIT_RMDIR_REMOVE_FILES)) < 0) + goto out; + + /* Skip deletion of the actual working tree if it does + * not exist or deletion was not requested */ + if ((popts.flags & GIT_WORKTREE_PRUNE_WORKING_TREE) == 0 || + !git_fs_path_exists(wt->gitlink_path)) + { + goto out; + } + + if ((wtpath = git_fs_path_dirname(wt->gitlink_path)) == NULL) + goto out; + git_str_attach(&path, wtpath, 0); + if (!git_fs_path_exists(path.ptr)) + { + git_error_set(GIT_ERROR_WORKTREE, "working tree '%s' does not exist", path.ptr); + err = -1; + goto out; + } + if ((err = git_futils_rmdir_r(path.ptr, NULL, GIT_RMDIR_REMOVE_FILES)) < 0) + goto out; + +out: + git_str_dispose(&path); + + return err; +} diff --git a/vendor/libgit2/src/worktree.h b/vendor/libgit2/src/libgit2/worktree.h similarity index 100% rename from vendor/libgit2/src/worktree.h rename to vendor/libgit2/src/libgit2/worktree.h diff --git a/vendor/libgit2/src/merge.c b/vendor/libgit2/src/merge.c deleted file mode 100644 index 641b3263..00000000 --- a/vendor/libgit2/src/merge.c +++ /dev/null @@ -1,3435 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "merge.h" - -#include "posix.h" -#include "str.h" -#include "repository.h" -#include "revwalk.h" -#include "commit_list.h" -#include "fs_path.h" -#include "refs.h" -#include "object.h" -#include "iterator.h" -#include "refs.h" -#include "diff.h" -#include "diff_generate.h" -#include "diff_tform.h" -#include "checkout.h" -#include "tree.h" -#include "blob.h" -#include "oid.h" -#include "index.h" -#include "filebuf.h" -#include "config.h" -#include "oidarray.h" -#include "annotated_commit.h" -#include "commit.h" -#include "oidarray.h" -#include "merge_driver.h" -#include "oidmap.h" -#include "array.h" - -#include "git2/types.h" -#include "git2/repository.h" -#include "git2/object.h" -#include "git2/commit.h" -#include "git2/merge.h" -#include "git2/refs.h" -#include "git2/reset.h" -#include "git2/checkout.h" -#include "git2/signature.h" -#include "git2/config.h" -#include "git2/tree.h" -#include "git2/oidarray.h" -#include "git2/annotated_commit.h" -#include "git2/sys/index.h" -#include "git2/sys/hashsig.h" - -#define GIT_MERGE_INDEX_ENTRY_EXISTS(X) ((X).mode != 0) -#define GIT_MERGE_INDEX_ENTRY_ISFILE(X) S_ISREG((X).mode) - - -typedef enum { - TREE_IDX_ANCESTOR = 0, - TREE_IDX_OURS = 1, - TREE_IDX_THEIRS = 2 -} merge_tree_index_t; - -/* Tracks D/F conflicts */ -struct merge_diff_df_data { - const char *df_path; - const char *prev_path; - git_merge_diff *prev_conflict; -}; - -/* - * This acts as a negative cache entry marker. In case we've tried to calculate - * similarity metrics for a given blob already but `git_hashsig` determined - * that it's too small in order to have a meaningful hash signature, we will - * insert the address of this marker instead of `NULL`. Like this, we can - * easily check whether we have checked a gien entry already and skip doing the - * calculation again and again. - */ -static int cache_invalid_marker; - -/* Merge base computation */ - -static int merge_bases_many(git_commit_list **out, git_revwalk **walk_out, git_repository *repo, size_t length, const git_oid input_array[]) -{ - git_revwalk *walk = NULL; - git_vector list; - git_commit_list *result = NULL; - git_commit_list_node *commit; - int error = -1; - unsigned int i; - - if (length < 2) { - git_error_set(GIT_ERROR_INVALID, "at least two commits are required to find an ancestor"); - return -1; - } - - if (git_vector_init(&list, length - 1, NULL) < 0) - return -1; - - if (git_revwalk_new(&walk, repo) < 0) - goto on_error; - - for (i = 1; i < length; i++) { - commit = git_revwalk__commit_lookup(walk, &input_array[i]); - if (commit == NULL) - goto on_error; - - git_vector_insert(&list, commit); - } - - commit = git_revwalk__commit_lookup(walk, &input_array[0]); - if (commit == NULL) - goto on_error; - - if (git_merge__bases_many(&result, walk, commit, &list, 0) < 0) - goto on_error; - - if (!result) { - git_error_set(GIT_ERROR_MERGE, "no merge base found"); - error = GIT_ENOTFOUND; - goto on_error; - } - - *out = result; - *walk_out = walk; - - git_vector_free(&list); - return 0; - -on_error: - git_vector_free(&list); - git_revwalk_free(walk); - return error; -} - -int git_merge_base_many(git_oid *out, git_repository *repo, size_t length, const git_oid input_array[]) -{ - git_revwalk *walk; - git_commit_list *result = NULL; - int error = 0; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(input_array); - - if ((error = merge_bases_many(&result, &walk, repo, length, input_array)) < 0) - return error; - - git_oid_cpy(out, &result->item->oid); - - git_commit_list_free(&result); - git_revwalk_free(walk); - - return 0; -} - -int git_merge_bases_many(git_oidarray *out, git_repository *repo, size_t length, const git_oid input_array[]) -{ - git_revwalk *walk; - git_commit_list *list, *result = NULL; - int error = 0; - git_array_oid_t array; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(input_array); - - if ((error = merge_bases_many(&result, &walk, repo, length, input_array)) < 0) - return error; - - git_array_init(array); - - list = result; - while (list) { - git_oid *id = git_array_alloc(array); - if (id == NULL) { - error = -1; - goto cleanup; - } - - git_oid_cpy(id, &list->item->oid); - list = list->next; - } - - git_oidarray__from_array(out, &array); - -cleanup: - git_commit_list_free(&result); - git_revwalk_free(walk); - - return error; -} - -int git_merge_base_octopus(git_oid *out, git_repository *repo, size_t length, const git_oid input_array[]) -{ - git_oid result; - unsigned int i; - int error = -1; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(input_array); - - if (length < 2) { - git_error_set(GIT_ERROR_INVALID, "at least two commits are required to find an ancestor"); - return -1; - } - - result = input_array[0]; - for (i = 1; i < length; i++) { - error = git_merge_base(&result, repo, &result, &input_array[i]); - if (error < 0) - return error; - } - - *out = result; - - return 0; -} - -static int merge_bases(git_commit_list **out, git_revwalk **walk_out, git_repository *repo, const git_oid *one, const git_oid *two) -{ - git_revwalk *walk; - git_vector list; - git_commit_list *result = NULL; - git_commit_list_node *commit; - void *contents[1]; - - if (git_revwalk_new(&walk, repo) < 0) - return -1; - - commit = git_revwalk__commit_lookup(walk, two); - if (commit == NULL) - goto on_error; - - /* This is just one value, so we can do it on the stack */ - memset(&list, 0x0, sizeof(git_vector)); - contents[0] = commit; - list.length = 1; - list.contents = contents; - - commit = git_revwalk__commit_lookup(walk, one); - if (commit == NULL) - goto on_error; - - if (git_merge__bases_many(&result, walk, commit, &list, 0) < 0) - goto on_error; - - if (!result) { - git_revwalk_free(walk); - git_error_set(GIT_ERROR_MERGE, "no merge base found"); - return GIT_ENOTFOUND; - } - - *out = result; - *walk_out = walk; - - return 0; - -on_error: - git_revwalk_free(walk); - return -1; - -} - -int git_merge_base(git_oid *out, git_repository *repo, const git_oid *one, const git_oid *two) -{ - int error; - git_revwalk *walk; - git_commit_list *result; - - if ((error = merge_bases(&result, &walk, repo, one, two)) < 0) - return error; - - git_oid_cpy(out, &result->item->oid); - git_commit_list_free(&result); - git_revwalk_free(walk); - - return 0; -} - -int git_merge_bases(git_oidarray *out, git_repository *repo, const git_oid *one, const git_oid *two) -{ - int error; - git_revwalk *walk; - git_commit_list *result, *list; - git_array_oid_t array; - - git_array_init(array); - - if ((error = merge_bases(&result, &walk, repo, one, two)) < 0) - return error; - - list = result; - while (list) { - git_oid *id = git_array_alloc(array); - if (id == NULL) - goto on_error; - - git_oid_cpy(id, &list->item->oid); - list = list->next; - } - - git_oidarray__from_array(out, &array); - git_commit_list_free(&result); - git_revwalk_free(walk); - - return 0; - -on_error: - git_commit_list_free(&result); - git_revwalk_free(walk); - return -1; -} - -static int interesting(git_pqueue *list) -{ - size_t i; - - for (i = 0; i < git_pqueue_size(list); i++) { - git_commit_list_node *commit = git_pqueue_get(list, i); - if ((commit->flags & STALE) == 0) - return 1; - } - - return 0; -} - -static int clear_commit_marks_1(git_commit_list **plist, - git_commit_list_node *commit, unsigned int mark) -{ - while (commit) { - unsigned int i; - - if (!(mark & commit->flags)) - return 0; - - commit->flags &= ~mark; - - for (i = 1; i < commit->out_degree; i++) { - git_commit_list_node *p = commit->parents[i]; - if (git_commit_list_insert(p, plist) == NULL) - return -1; - } - - commit = commit->out_degree ? commit->parents[0] : NULL; - } - - return 0; -} - -static int clear_commit_marks_many(git_vector *commits, unsigned int mark) -{ - git_commit_list *list = NULL; - git_commit_list_node *c; - unsigned int i; - - git_vector_foreach(commits, i, c) { - if (git_commit_list_insert(c, &list) == NULL) - return -1; - } - - while (list) - if (clear_commit_marks_1(&list, git_commit_list_pop(&list), mark) < 0) - return -1; - return 0; -} - -static int clear_commit_marks(git_commit_list_node *commit, unsigned int mark) -{ - git_commit_list *list = NULL; - if (git_commit_list_insert(commit, &list) == NULL) - return -1; - while (list) - if (clear_commit_marks_1(&list, git_commit_list_pop(&list), mark) < 0) - return -1; - return 0; -} - -static int paint_down_to_common( - git_commit_list **out, - git_revwalk *walk, - git_commit_list_node *one, - git_vector *twos, - uint32_t minimum_generation) -{ - git_pqueue list; - git_commit_list *result = NULL; - git_commit_list_node *two; - - int error; - unsigned int i; - - if (git_pqueue_init(&list, 0, twos->length * 2, git_commit_list_generation_cmp) < 0) - return -1; - - one->flags |= PARENT1; - if (git_pqueue_insert(&list, one) < 0) - return -1; - - git_vector_foreach(twos, i, two) { - if (git_commit_list_parse(walk, two) < 0) - return -1; - - two->flags |= PARENT2; - if (git_pqueue_insert(&list, two) < 0) - return -1; - } - - /* as long as there are non-STALE commits */ - while (interesting(&list)) { - git_commit_list_node *commit = git_pqueue_pop(&list); - int flags; - - if (commit == NULL) - break; - - flags = commit->flags & (PARENT1 | PARENT2 | STALE); - if (flags == (PARENT1 | PARENT2)) { - if (!(commit->flags & RESULT)) { - commit->flags |= RESULT; - if (git_commit_list_insert(commit, &result) == NULL) - return -1; - } - /* we mark the parents of a merge stale */ - flags |= STALE; - } - - for (i = 0; i < commit->out_degree; i++) { - git_commit_list_node *p = commit->parents[i]; - if ((p->flags & flags) == flags) - continue; - if (p->generation < minimum_generation) - continue; - - if ((error = git_commit_list_parse(walk, p)) < 0) - return error; - - p->flags |= flags; - if (git_pqueue_insert(&list, p) < 0) - return -1; - } - } - - git_pqueue_free(&list); - *out = result; - return 0; -} - -static int remove_redundant(git_revwalk *walk, git_vector *commits, uint32_t minimum_generation) -{ - git_vector work = GIT_VECTOR_INIT; - unsigned char *redundant; - unsigned int *filled_index; - unsigned int i, j; - int error = 0; - - redundant = git__calloc(commits->length, 1); - GIT_ERROR_CHECK_ALLOC(redundant); - filled_index = git__calloc((commits->length - 1), sizeof(unsigned int)); - GIT_ERROR_CHECK_ALLOC(filled_index); - - for (i = 0; i < commits->length; ++i) { - if ((error = git_commit_list_parse(walk, commits->contents[i])) < 0) - goto done; - } - - for (i = 0; i < commits->length; ++i) { - git_commit_list *common = NULL; - git_commit_list_node *commit = commits->contents[i]; - - if (redundant[i]) - continue; - - git_vector_clear(&work); - - for (j = 0; j < commits->length; j++) { - if (i == j || redundant[j]) - continue; - - filled_index[work.length] = j; - if ((error = git_vector_insert(&work, commits->contents[j])) < 0) - goto done; - } - - error = paint_down_to_common(&common, walk, commit, &work, minimum_generation); - if (error < 0) - goto done; - - if (commit->flags & PARENT2) - redundant[i] = 1; - - for (j = 0; j < work.length; j++) { - git_commit_list_node *w = work.contents[j]; - if (w->flags & PARENT1) - redundant[filled_index[j]] = 1; - } - - git_commit_list_free(&common); - - if ((error = clear_commit_marks(commit, ALL_FLAGS)) < 0 || - (error = clear_commit_marks_many(&work, ALL_FLAGS)) < 0) - goto done; - } - - for (i = 0; i < commits->length; ++i) { - if (redundant[i]) - commits->contents[i] = NULL; - } - -done: - git__free(redundant); - git__free(filled_index); - git_vector_free(&work); - return error; -} - -int git_merge__bases_many( - git_commit_list **out, - git_revwalk *walk, - git_commit_list_node *one, - git_vector *twos, - uint32_t minimum_generation) -{ - int error; - unsigned int i; - git_commit_list_node *two; - git_commit_list *result = NULL, *tmp = NULL; - - /* If there's only the one commit, there can be no merge bases */ - if (twos->length == 0) { - *out = NULL; - return 0; - } - - /* if the commit is repeated, we have a our merge base already */ - git_vector_foreach(twos, i, two) { - if (one == two) - return git_commit_list_insert(one, out) ? 0 : -1; - } - - if (git_commit_list_parse(walk, one) < 0) - return -1; - - error = paint_down_to_common(&result, walk, one, twos, minimum_generation); - if (error < 0) - return error; - - /* filter out any stale commits in the results */ - tmp = result; - result = NULL; - - while (tmp) { - git_commit_list_node *c = git_commit_list_pop(&tmp); - if (!(c->flags & STALE)) - if (git_commit_list_insert_by_date(c, &result) == NULL) - return -1; - } - - /* - * more than one merge base -- see if there are redundant merge - * bases and remove them - */ - if (result && result->next) { - git_vector redundant = GIT_VECTOR_INIT; - - while (result) - git_vector_insert(&redundant, git_commit_list_pop(&result)); - - if ((error = clear_commit_marks(one, ALL_FLAGS)) < 0 || - (error = clear_commit_marks_many(twos, ALL_FLAGS)) < 0 || - (error = remove_redundant(walk, &redundant, minimum_generation)) < 0) { - git_vector_free(&redundant); - return error; - } - - git_vector_foreach(&redundant, i, two) { - if (two != NULL) - git_commit_list_insert_by_date(two, &result); - } - - git_vector_free(&redundant); - } - - *out = result; - return 0; -} - -int git_repository_mergehead_foreach( - git_repository *repo, - git_repository_mergehead_foreach_cb cb, - void *payload) -{ - git_str merge_head_path = GIT_STR_INIT, merge_head_file = GIT_STR_INIT; - char *buffer, *line; - size_t line_num = 1; - git_oid oid; - int error = 0; - - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(cb); - - if ((error = git_str_joinpath(&merge_head_path, repo->gitdir, - GIT_MERGE_HEAD_FILE)) < 0) - return error; - - if ((error = git_futils_readbuffer(&merge_head_file, - git_str_cstr(&merge_head_path))) < 0) - goto cleanup; - - buffer = merge_head_file.ptr; - - while ((line = git__strsep(&buffer, "\n")) != NULL) { - if (strlen(line) != GIT_OID_HEXSZ) { - git_error_set(GIT_ERROR_INVALID, "unable to parse OID - invalid length"); - error = -1; - goto cleanup; - } - - if ((error = git_oid_fromstr(&oid, line)) < 0) - goto cleanup; - - if ((error = cb(&oid, payload)) != 0) { - git_error_set_after_callback(error); - goto cleanup; - } - - ++line_num; - } - - if (*buffer) { - git_error_set(GIT_ERROR_MERGE, "no EOL at line %"PRIuZ, line_num); - error = -1; - goto cleanup; - } - -cleanup: - git_str_dispose(&merge_head_path); - git_str_dispose(&merge_head_file); - - return error; -} - -GIT_INLINE(int) index_entry_cmp(const git_index_entry *a, const git_index_entry *b) -{ - int value = 0; - - if (a->path == NULL) - return (b->path == NULL) ? 0 : 1; - - if ((value = a->mode - b->mode) == 0 && - (value = git_oid__cmp(&a->id, &b->id)) == 0) - value = strcmp(a->path, b->path); - - return value; -} - -/* Conflict resolution */ - -static int merge_conflict_resolve_trivial( - int *resolved, - git_merge_diff_list *diff_list, - const git_merge_diff *conflict) -{ - int ours_empty, theirs_empty; - int ours_changed, theirs_changed, ours_theirs_differ; - git_index_entry const *result = NULL; - int error = 0; - - GIT_ASSERT_ARG(resolved); - GIT_ASSERT_ARG(diff_list); - GIT_ASSERT_ARG(conflict); - - *resolved = 0; - - if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE || - conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) - return 0; - - if (conflict->our_status == GIT_DELTA_RENAMED || - conflict->their_status == GIT_DELTA_RENAMED) - return 0; - - ours_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry); - theirs_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry); - - ours_changed = (conflict->our_status != GIT_DELTA_UNMODIFIED); - theirs_changed = (conflict->their_status != GIT_DELTA_UNMODIFIED); - ours_theirs_differ = ours_changed && theirs_changed && - index_entry_cmp(&conflict->our_entry, &conflict->their_entry); - - /* - * Note: with only one ancestor, some cases are not distinct: - * - * 16: ancest:anc1/anc2, head:anc1, remote:anc2 = result:no merge - * 3: ancest:(empty)^, head:head, remote:(empty) = result:no merge - * 2: ancest:(empty)^, head:(empty), remote:remote = result:no merge - * - * Note that the two cases that take D/F conflicts into account - * specifically do not need to be explicitly tested, as D/F conflicts - * would fail the *empty* test: - * - * 3ALT: ancest:(empty)+, head:head, remote:*empty* = result:head - * 2ALT: ancest:(empty)+, head:*empty*, remote:remote = result:remote - * - * Note that many of these cases need not be explicitly tested, as - * they simply degrade to "all different" cases (eg, 11): - * - * 4: ancest:(empty)^, head:head, remote:remote = result:no merge - * 7: ancest:ancest+, head:(empty), remote:remote = result:no merge - * 9: ancest:ancest+, head:head, remote:(empty) = result:no merge - * 11: ancest:ancest+, head:head, remote:remote = result:no merge - */ - - /* 5ALT: ancest:*, head:head, remote:head = result:head */ - if (ours_changed && !ours_empty && !ours_theirs_differ) - result = &conflict->our_entry; - /* 6: ancest:ancest+, head:(empty), remote:(empty) = result:no merge */ - else if (ours_changed && ours_empty && theirs_empty) - *resolved = 0; - /* 8: ancest:ancest^, head:(empty), remote:ancest = result:no merge */ - else if (ours_empty && !theirs_changed) - *resolved = 0; - /* 10: ancest:ancest^, head:ancest, remote:(empty) = result:no merge */ - else if (!ours_changed && theirs_empty) - *resolved = 0; - /* 13: ancest:ancest+, head:head, remote:ancest = result:head */ - else if (ours_changed && !theirs_changed) - result = &conflict->our_entry; - /* 14: ancest:ancest+, head:ancest, remote:remote = result:remote */ - else if (!ours_changed && theirs_changed) - result = &conflict->their_entry; - else - *resolved = 0; - - if (result != NULL && - GIT_MERGE_INDEX_ENTRY_EXISTS(*result) && - (error = git_vector_insert(&diff_list->staged, (void *)result)) >= 0) - *resolved = 1; - - /* Note: trivial resolution does not update the REUC. */ - - return error; -} - -static int merge_conflict_resolve_one_removed( - int *resolved, - git_merge_diff_list *diff_list, - const git_merge_diff *conflict) -{ - int ours_empty, theirs_empty; - int ours_changed, theirs_changed; - int error = 0; - - GIT_ASSERT_ARG(resolved); - GIT_ASSERT_ARG(diff_list); - GIT_ASSERT_ARG(conflict); - - *resolved = 0; - - if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE || - conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) - return 0; - - ours_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry); - theirs_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry); - - ours_changed = (conflict->our_status != GIT_DELTA_UNMODIFIED); - theirs_changed = (conflict->their_status != GIT_DELTA_UNMODIFIED); - - /* Removed in both */ - if (ours_changed && ours_empty && theirs_empty) - *resolved = 1; - /* Removed in ours */ - else if (ours_empty && !theirs_changed) - *resolved = 1; - /* Removed in theirs */ - else if (!ours_changed && theirs_empty) - *resolved = 1; - - if (*resolved) - git_vector_insert(&diff_list->resolved, (git_merge_diff *)conflict); - - return error; -} - -static int merge_conflict_resolve_one_renamed( - int *resolved, - git_merge_diff_list *diff_list, - const git_merge_diff *conflict) -{ - int ours_renamed, theirs_renamed; - int ours_changed, theirs_changed; - git_index_entry *merged; - int error = 0; - - GIT_ASSERT_ARG(resolved); - GIT_ASSERT_ARG(diff_list); - GIT_ASSERT_ARG(conflict); - - *resolved = 0; - - if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) || - !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry)) - return 0; - - ours_renamed = (conflict->our_status == GIT_DELTA_RENAMED); - theirs_renamed = (conflict->their_status == GIT_DELTA_RENAMED); - - if (!ours_renamed && !theirs_renamed) - return 0; - - /* Reject one file in a 2->1 conflict */ - if (conflict->type == GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1 || - conflict->type == GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2 || - conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) - return 0; - - ours_changed = (git_oid__cmp(&conflict->ancestor_entry.id, &conflict->our_entry.id) != 0) || - (conflict->ancestor_entry.mode != conflict->our_entry.mode); - - theirs_changed = (git_oid__cmp(&conflict->ancestor_entry.id, &conflict->their_entry.id) != 0) || - (conflict->ancestor_entry.mode != conflict->their_entry.mode); - - /* if both are modified (and not to a common target) require a merge */ - if (ours_changed && theirs_changed && - git_oid__cmp(&conflict->our_entry.id, &conflict->their_entry.id) != 0) - return 0; - - if ((merged = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry))) == NULL) - return -1; - - if (ours_changed) - memcpy(merged, &conflict->our_entry, sizeof(git_index_entry)); - else - memcpy(merged, &conflict->their_entry, sizeof(git_index_entry)); - - if (ours_renamed) - merged->path = conflict->our_entry.path; - else - merged->path = conflict->their_entry.path; - - *resolved = 1; - - git_vector_insert(&diff_list->staged, merged); - git_vector_insert(&diff_list->resolved, (git_merge_diff *)conflict); - - return error; -} - -static bool merge_conflict_can_resolve_contents( - const git_merge_diff *conflict) -{ - if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) || - !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry)) - return false; - - /* Reject D/F conflicts */ - if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE) - return false; - - /* Reject submodules. */ - if (S_ISGITLINK(conflict->ancestor_entry.mode) || - S_ISGITLINK(conflict->our_entry.mode) || - S_ISGITLINK(conflict->their_entry.mode)) - return false; - - /* Reject link/file conflicts. */ - if ((S_ISLNK(conflict->ancestor_entry.mode) ^ - S_ISLNK(conflict->our_entry.mode)) || - (S_ISLNK(conflict->ancestor_entry.mode) ^ - S_ISLNK(conflict->their_entry.mode))) - return false; - - /* Reject name conflicts */ - if (conflict->type == GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1 || - conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) - return false; - - if ((conflict->our_status & GIT_DELTA_RENAMED) == GIT_DELTA_RENAMED && - (conflict->their_status & GIT_DELTA_RENAMED) == GIT_DELTA_RENAMED && - strcmp(conflict->ancestor_entry.path, conflict->their_entry.path) != 0) - return false; - - return true; -} - -static int merge_conflict_invoke_driver( - git_index_entry **out, - const char *name, - git_merge_driver *driver, - git_merge_diff_list *diff_list, - git_merge_driver_source *src) -{ - git_index_entry *result; - git_buf buf = {0}; - const char *path; - uint32_t mode; - git_odb *odb = NULL; - git_oid oid; - int error; - - *out = NULL; - - if ((error = driver->apply(driver, &path, &mode, &buf, name, src)) < 0 || - (error = git_repository_odb(&odb, src->repo)) < 0 || - (error = git_odb_write(&oid, odb, buf.ptr, buf.size, GIT_OBJECT_BLOB)) < 0) - goto done; - - result = git_pool_mallocz(&diff_list->pool, sizeof(git_index_entry)); - GIT_ERROR_CHECK_ALLOC(result); - - git_oid_cpy(&result->id, &oid); - result->mode = mode; - result->file_size = (uint32_t)buf.size; - - result->path = git_pool_strdup(&diff_list->pool, path); - GIT_ERROR_CHECK_ALLOC(result->path); - - *out = result; - -done: - git_buf_dispose(&buf); - git_odb_free(odb); - - return error; -} - -static int merge_conflict_resolve_contents( - int *resolved, - git_merge_diff_list *diff_list, - const git_merge_diff *conflict, - const git_merge_options *merge_opts, - const git_merge_file_options *file_opts) -{ - git_merge_driver_source source = {0}; - git_merge_file_result result = {0}; - git_merge_driver *driver; - git_merge_driver__builtin builtin = {{0}}; - git_index_entry *merge_result; - git_odb *odb = NULL; - const char *name; - bool fallback = false; - int error; - - GIT_ASSERT_ARG(resolved); - GIT_ASSERT_ARG(diff_list); - GIT_ASSERT_ARG(conflict); - - *resolved = 0; - - if (!merge_conflict_can_resolve_contents(conflict)) - return 0; - - source.repo = diff_list->repo; - source.default_driver = merge_opts->default_driver; - source.file_opts = file_opts; - source.ancestor = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) ? - &conflict->ancestor_entry : NULL; - source.ours = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ? - &conflict->our_entry : NULL; - source.theirs = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ? - &conflict->their_entry : NULL; - - if (file_opts->favor != GIT_MERGE_FILE_FAVOR_NORMAL) { - /* if the user requested a particular type of resolution (via the - * favor flag) then let that override the gitattributes and use - * the builtin driver. - */ - name = "text"; - builtin.base.apply = git_merge_driver__builtin_apply; - builtin.favor = file_opts->favor; - - driver = &builtin.base; - } else { - /* find the merge driver for this file */ - if ((error = git_merge_driver_for_source(&name, &driver, &source)) < 0) - goto done; - - if (driver == NULL) - fallback = true; - } - - if (driver) { - error = merge_conflict_invoke_driver(&merge_result, name, driver, - diff_list, &source); - - if (error == GIT_PASSTHROUGH) - fallback = true; - } - - if (fallback) { - error = merge_conflict_invoke_driver(&merge_result, "text", - &git_merge_driver__text.base, diff_list, &source); - } - - if (error < 0) { - if (error == GIT_EMERGECONFLICT) - error = 0; - - goto done; - } - - git_vector_insert(&diff_list->staged, merge_result); - git_vector_insert(&diff_list->resolved, (git_merge_diff *)conflict); - - *resolved = 1; - -done: - git_merge_file_result_free(&result); - git_odb_free(odb); - - return error; -} - -static int merge_conflict_resolve( - int *out, - git_merge_diff_list *diff_list, - const git_merge_diff *conflict, - const git_merge_options *merge_opts, - const git_merge_file_options *file_opts) -{ - int resolved = 0; - int error = 0; - - *out = 0; - - if ((error = merge_conflict_resolve_trivial( - &resolved, diff_list, conflict)) < 0) - goto done; - - if (!resolved && (error = merge_conflict_resolve_one_removed( - &resolved, diff_list, conflict)) < 0) - goto done; - - if (!resolved && (error = merge_conflict_resolve_one_renamed( - &resolved, diff_list, conflict)) < 0) - goto done; - - if (!resolved && (error = merge_conflict_resolve_contents( - &resolved, diff_list, conflict, merge_opts, file_opts)) < 0) - goto done; - - *out = resolved; - -done: - return error; -} - -/* Rename detection and coalescing */ - -struct merge_diff_similarity { - unsigned char similarity; - size_t other_idx; -}; - -static int index_entry_similarity_calc( - void **out, - git_repository *repo, - git_index_entry *entry, - const git_merge_options *opts) -{ - git_blob *blob; - git_diff_file diff_file = {{{0}}}; - git_object_size_t blobsize; - int error; - - if (*out || *out == &cache_invalid_marker) - return 0; - - *out = NULL; - - if ((error = git_blob_lookup(&blob, repo, &entry->id)) < 0) - return error; - - git_oid_cpy(&diff_file.id, &entry->id); - diff_file.path = entry->path; - diff_file.size = entry->file_size; - diff_file.mode = entry->mode; - diff_file.flags = 0; - - blobsize = git_blob_rawsize(blob); - - /* file too big for rename processing */ - if (!git__is_sizet(blobsize)) - return 0; - - error = opts->metric->buffer_signature(out, &diff_file, - git_blob_rawcontent(blob), (size_t)blobsize, - opts->metric->payload); - if (error == GIT_EBUFS) - *out = &cache_invalid_marker; - - git_blob_free(blob); - - return error; -} - -static int index_entry_similarity_inexact( - git_repository *repo, - git_index_entry *a, - size_t a_idx, - git_index_entry *b, - size_t b_idx, - void **cache, - const git_merge_options *opts) -{ - int score = 0; - int error = 0; - - if (!GIT_MODE_ISBLOB(a->mode) || !GIT_MODE_ISBLOB(b->mode)) - return 0; - - /* update signature cache if needed */ - if ((error = index_entry_similarity_calc(&cache[a_idx], repo, a, opts)) < 0 || - (error = index_entry_similarity_calc(&cache[b_idx], repo, b, opts)) < 0) - return error; - - /* some metrics may not wish to process this file (too big / too small) */ - if (cache[a_idx] == &cache_invalid_marker || cache[b_idx] == &cache_invalid_marker) - return 0; - - /* compare signatures */ - if (opts->metric->similarity(&score, cache[a_idx], cache[b_idx], opts->metric->payload) < 0) - return -1; - - /* clip score */ - if (score < 0) - score = 0; - else if (score > 100) - score = 100; - - return score; -} - -/* Tracks deletes by oid for merge_diff_mark_similarity_exact(). This is a -* non-shrinking queue where next_pos is the next position to dequeue. -*/ -typedef struct { - git_array_t(size_t) arr; - size_t next_pos; - size_t first_entry; -} deletes_by_oid_queue; - -static void deletes_by_oid_free(git_oidmap *map) { - deletes_by_oid_queue *queue; - - if (!map) - return; - - git_oidmap_foreach_value(map, queue, { - git_array_clear(queue->arr); - }); - git_oidmap_free(map); -} - -static int deletes_by_oid_enqueue(git_oidmap *map, git_pool *pool, const git_oid *id, size_t idx) -{ - deletes_by_oid_queue *queue; - size_t *array_entry; - - if ((queue = git_oidmap_get(map, id)) == NULL) { - queue = git_pool_malloc(pool, sizeof(deletes_by_oid_queue)); - GIT_ERROR_CHECK_ALLOC(queue); - - git_array_init(queue->arr); - queue->next_pos = 0; - queue->first_entry = idx; - - if (git_oidmap_set(map, id, queue) < 0) - return -1; - } else { - array_entry = git_array_alloc(queue->arr); - GIT_ERROR_CHECK_ALLOC(array_entry); - *array_entry = idx; - } - - return 0; -} - -static int deletes_by_oid_dequeue(size_t *idx, git_oidmap *map, const git_oid *id) -{ - deletes_by_oid_queue *queue; - size_t *array_entry; - - if ((queue = git_oidmap_get(map, id)) == NULL) - return GIT_ENOTFOUND; - - if (queue->next_pos == 0) { - *idx = queue->first_entry; - } else { - array_entry = git_array_get(queue->arr, queue->next_pos - 1); - if (array_entry == NULL) - return GIT_ENOTFOUND; - - *idx = *array_entry; - } - - queue->next_pos++; - return 0; -} - -static int merge_diff_mark_similarity_exact( - git_merge_diff_list *diff_list, - struct merge_diff_similarity *similarity_ours, - struct merge_diff_similarity *similarity_theirs) -{ - size_t i, j; - git_merge_diff *conflict_src, *conflict_tgt; - git_oidmap *ours_deletes_by_oid = NULL, *theirs_deletes_by_oid = NULL; - int error = 0; - - if (git_oidmap_new(&ours_deletes_by_oid) < 0 || - git_oidmap_new(&theirs_deletes_by_oid) < 0) { - error = -1; - goto done; - } - - /* Build a map of object ids to conflicts */ - git_vector_foreach(&diff_list->conflicts, i, conflict_src) { - /* Items can be the source of a rename iff they have an item in the - * ancestor slot and lack an item in the ours or theirs slot. */ - if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->ancestor_entry)) - continue; - - if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->our_entry)) { - error = deletes_by_oid_enqueue(ours_deletes_by_oid, &diff_list->pool, &conflict_src->ancestor_entry.id, i); - if (error < 0) - goto done; - } - - if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->their_entry)) { - error = deletes_by_oid_enqueue(theirs_deletes_by_oid, &diff_list->pool, &conflict_src->ancestor_entry.id, i); - if (error < 0) - goto done; - } - } - - git_vector_foreach(&diff_list->conflicts, j, conflict_tgt) { - if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->ancestor_entry)) - continue; - - if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->our_entry)) { - if (deletes_by_oid_dequeue(&i, ours_deletes_by_oid, &conflict_tgt->our_entry.id) == 0) { - similarity_ours[i].similarity = 100; - similarity_ours[i].other_idx = j; - - similarity_ours[j].similarity = 100; - similarity_ours[j].other_idx = i; - } - } - - if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->their_entry)) { - if (deletes_by_oid_dequeue(&i, theirs_deletes_by_oid, &conflict_tgt->their_entry.id) == 0) { - similarity_theirs[i].similarity = 100; - similarity_theirs[i].other_idx = j; - - similarity_theirs[j].similarity = 100; - similarity_theirs[j].other_idx = i; - } - } - } - -done: - deletes_by_oid_free(ours_deletes_by_oid); - deletes_by_oid_free(theirs_deletes_by_oid); - - return error; -} - -static int merge_diff_mark_similarity_inexact( - git_repository *repo, - git_merge_diff_list *diff_list, - struct merge_diff_similarity *similarity_ours, - struct merge_diff_similarity *similarity_theirs, - void **cache, - const git_merge_options *opts) -{ - size_t i, j; - git_merge_diff *conflict_src, *conflict_tgt; - int similarity; - - git_vector_foreach(&diff_list->conflicts, i, conflict_src) { - /* Items can be the source of a rename iff they have an item in the - * ancestor slot and lack an item in the ours or theirs slot. */ - if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->ancestor_entry) || - (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->our_entry) && - GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->their_entry))) - continue; - - git_vector_foreach(&diff_list->conflicts, j, conflict_tgt) { - size_t our_idx = diff_list->conflicts.length + j; - size_t their_idx = (diff_list->conflicts.length * 2) + j; - - if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->ancestor_entry)) - continue; - - if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->our_entry) && - !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->our_entry)) { - similarity = index_entry_similarity_inexact(repo, &conflict_src->ancestor_entry, i, &conflict_tgt->our_entry, our_idx, cache, opts); - - if (similarity == GIT_EBUFS) - continue; - else if (similarity < 0) - return similarity; - - if (similarity > similarity_ours[i].similarity && - similarity > similarity_ours[j].similarity) { - /* Clear previous best similarity */ - if (similarity_ours[i].similarity > 0) - similarity_ours[similarity_ours[i].other_idx].similarity = 0; - - if (similarity_ours[j].similarity > 0) - similarity_ours[similarity_ours[j].other_idx].similarity = 0; - - similarity_ours[i].similarity = similarity; - similarity_ours[i].other_idx = j; - - similarity_ours[j].similarity = similarity; - similarity_ours[j].other_idx = i; - } - } - - if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->their_entry) && - !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->their_entry)) { - similarity = index_entry_similarity_inexact(repo, &conflict_src->ancestor_entry, i, &conflict_tgt->their_entry, their_idx, cache, opts); - - if (similarity > similarity_theirs[i].similarity && - similarity > similarity_theirs[j].similarity) { - /* Clear previous best similarity */ - if (similarity_theirs[i].similarity > 0) - similarity_theirs[similarity_theirs[i].other_idx].similarity = 0; - - if (similarity_theirs[j].similarity > 0) - similarity_theirs[similarity_theirs[j].other_idx].similarity = 0; - - similarity_theirs[i].similarity = similarity; - similarity_theirs[i].other_idx = j; - - similarity_theirs[j].similarity = similarity; - similarity_theirs[j].other_idx = i; - } - } - } - } - - return 0; -} - -/* - * Rename conflicts: - * - * Ancestor Ours Theirs - * - * 0a A A A No rename - * b A A* A No rename (ours was rewritten) - * c A A A* No rename (theirs rewritten) - * 1a A A B[A] Rename or rename/edit - * b A B[A] A (automergeable) - * 2 A B[A] B[A] Both renamed (automergeable) - * 3a A B[A] Rename/delete - * b A B[A] (same) - * 4a A B[A] B Rename/add [B~ours B~theirs] - * b A B B[A] (same) - * 5 A B[A] C[A] Both renamed ("1 -> 2") - * 6 A C[A] Both renamed ("2 -> 1") - * B C[B] [C~ours C~theirs] (automergeable) - */ -static void merge_diff_mark_rename_conflict( - git_merge_diff_list *diff_list, - struct merge_diff_similarity *similarity_ours, - bool ours_renamed, - size_t ours_source_idx, - struct merge_diff_similarity *similarity_theirs, - bool theirs_renamed, - size_t theirs_source_idx, - git_merge_diff *target, - const git_merge_options *opts) -{ - git_merge_diff *ours_source = NULL, *theirs_source = NULL; - - if (ours_renamed) - ours_source = diff_list->conflicts.contents[ours_source_idx]; - - if (theirs_renamed) - theirs_source = diff_list->conflicts.contents[theirs_source_idx]; - - /* Detect 2->1 conflicts */ - if (ours_renamed && theirs_renamed) { - /* Both renamed to the same target name. */ - if (ours_source_idx == theirs_source_idx) - ours_source->type = GIT_MERGE_DIFF_BOTH_RENAMED; - else { - ours_source->type = GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1; - theirs_source->type = GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1; - } - } else if (ours_renamed) { - /* If our source was also renamed in theirs, this is a 1->2 */ - if (similarity_theirs[ours_source_idx].similarity >= opts->rename_threshold) - ours_source->type = GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2; - - else if (GIT_MERGE_INDEX_ENTRY_EXISTS(target->their_entry)) { - ours_source->type = GIT_MERGE_DIFF_RENAMED_ADDED; - target->type = GIT_MERGE_DIFF_RENAMED_ADDED; - } - - else if (!GIT_MERGE_INDEX_ENTRY_EXISTS(ours_source->their_entry)) - ours_source->type = GIT_MERGE_DIFF_RENAMED_DELETED; - - else if (ours_source->type == GIT_MERGE_DIFF_MODIFIED_DELETED) - ours_source->type = GIT_MERGE_DIFF_RENAMED_MODIFIED; - } else if (theirs_renamed) { - /* If their source was also renamed in ours, this is a 1->2 */ - if (similarity_ours[theirs_source_idx].similarity >= opts->rename_threshold) - theirs_source->type = GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2; - - else if (GIT_MERGE_INDEX_ENTRY_EXISTS(target->our_entry)) { - theirs_source->type = GIT_MERGE_DIFF_RENAMED_ADDED; - target->type = GIT_MERGE_DIFF_RENAMED_ADDED; - } - - else if (!GIT_MERGE_INDEX_ENTRY_EXISTS(theirs_source->our_entry)) - theirs_source->type = GIT_MERGE_DIFF_RENAMED_DELETED; - - else if (theirs_source->type == GIT_MERGE_DIFF_MODIFIED_DELETED) - theirs_source->type = GIT_MERGE_DIFF_RENAMED_MODIFIED; - } -} - -GIT_INLINE(void) merge_diff_coalesce_rename( - git_index_entry *source_entry, - git_delta_t *source_status, - git_index_entry *target_entry, - git_delta_t *target_status) -{ - /* Coalesce the rename target into the rename source. */ - memcpy(source_entry, target_entry, sizeof(git_index_entry)); - *source_status = GIT_DELTA_RENAMED; - - memset(target_entry, 0x0, sizeof(git_index_entry)); - *target_status = GIT_DELTA_UNMODIFIED; -} - -static void merge_diff_list_coalesce_renames( - git_merge_diff_list *diff_list, - struct merge_diff_similarity *similarity_ours, - struct merge_diff_similarity *similarity_theirs, - const git_merge_options *opts) -{ - size_t i; - bool ours_renamed = 0, theirs_renamed = 0; - size_t ours_source_idx = 0, theirs_source_idx = 0; - git_merge_diff *ours_source, *theirs_source, *target; - - for (i = 0; i < diff_list->conflicts.length; i++) { - target = diff_list->conflicts.contents[i]; - - ours_renamed = 0; - theirs_renamed = 0; - - if (GIT_MERGE_INDEX_ENTRY_EXISTS(target->our_entry) && - similarity_ours[i].similarity >= opts->rename_threshold) { - ours_source_idx = similarity_ours[i].other_idx; - - ours_source = diff_list->conflicts.contents[ours_source_idx]; - - merge_diff_coalesce_rename( - &ours_source->our_entry, - &ours_source->our_status, - &target->our_entry, - &target->our_status); - - similarity_ours[ours_source_idx].similarity = 0; - similarity_ours[i].similarity = 0; - - ours_renamed = 1; - } - - /* insufficient to determine direction */ - if (GIT_MERGE_INDEX_ENTRY_EXISTS(target->their_entry) && - similarity_theirs[i].similarity >= opts->rename_threshold) { - theirs_source_idx = similarity_theirs[i].other_idx; - - theirs_source = diff_list->conflicts.contents[theirs_source_idx]; - - merge_diff_coalesce_rename( - &theirs_source->their_entry, - &theirs_source->their_status, - &target->their_entry, - &target->their_status); - - similarity_theirs[theirs_source_idx].similarity = 0; - similarity_theirs[i].similarity = 0; - - theirs_renamed = 1; - } - - merge_diff_mark_rename_conflict(diff_list, - similarity_ours, ours_renamed, ours_source_idx, - similarity_theirs, theirs_renamed, theirs_source_idx, - target, opts); - } -} - -static int merge_diff_empty(const git_vector *conflicts, size_t idx, void *p) -{ - git_merge_diff *conflict = conflicts->contents[idx]; - - GIT_UNUSED(p); - - return (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) && - !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) && - !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry)); -} - -static void merge_diff_list_count_candidates( - git_merge_diff_list *diff_list, - size_t *src_count, - size_t *tgt_count) -{ - git_merge_diff *entry; - size_t i; - - *src_count = 0; - *tgt_count = 0; - - git_vector_foreach(&diff_list->conflicts, i, entry) { - if (GIT_MERGE_INDEX_ENTRY_EXISTS(entry->ancestor_entry) && - (!GIT_MERGE_INDEX_ENTRY_EXISTS(entry->our_entry) || - !GIT_MERGE_INDEX_ENTRY_EXISTS(entry->their_entry))) - (*src_count)++; - else if (!GIT_MERGE_INDEX_ENTRY_EXISTS(entry->ancestor_entry)) - (*tgt_count)++; - } -} - -int git_merge_diff_list__find_renames( - git_repository *repo, - git_merge_diff_list *diff_list, - const git_merge_options *opts) -{ - struct merge_diff_similarity *similarity_ours, *similarity_theirs; - void **cache = NULL; - size_t cache_size = 0; - size_t src_count, tgt_count, i; - int error = 0; - - GIT_ASSERT_ARG(diff_list); - GIT_ASSERT_ARG(opts); - - if ((opts->flags & GIT_MERGE_FIND_RENAMES) == 0 || - !diff_list->conflicts.length) - return 0; - - similarity_ours = git__calloc(diff_list->conflicts.length, - sizeof(struct merge_diff_similarity)); - GIT_ERROR_CHECK_ALLOC(similarity_ours); - - similarity_theirs = git__calloc(diff_list->conflicts.length, - sizeof(struct merge_diff_similarity)); - GIT_ERROR_CHECK_ALLOC(similarity_theirs); - - /* Calculate similarity between items that were deleted from the ancestor - * and added in the other branch. - */ - if ((error = merge_diff_mark_similarity_exact(diff_list, similarity_ours, similarity_theirs)) < 0) - goto done; - - if (opts->rename_threshold < 100 && diff_list->conflicts.length <= opts->target_limit) { - GIT_ERROR_CHECK_ALLOC_MULTIPLY(&cache_size, diff_list->conflicts.length, 3); - cache = git__calloc(cache_size, sizeof(void *)); - GIT_ERROR_CHECK_ALLOC(cache); - - merge_diff_list_count_candidates(diff_list, &src_count, &tgt_count); - - if (src_count > opts->target_limit || tgt_count > opts->target_limit) { - /* TODO: report! */ - } else { - if ((error = merge_diff_mark_similarity_inexact( - repo, diff_list, similarity_ours, similarity_theirs, cache, opts)) < 0) - goto done; - } - } - - /* For entries that are appropriately similar, merge the new name's entry - * into the old name. - */ - merge_diff_list_coalesce_renames(diff_list, similarity_ours, similarity_theirs, opts); - - /* And remove any entries that were merged and are now empty. */ - git_vector_remove_matching(&diff_list->conflicts, merge_diff_empty, NULL); - -done: - if (cache != NULL) { - for (i = 0; i < cache_size; ++i) { - if (cache[i] != NULL && cache[i] != &cache_invalid_marker) - opts->metric->free_signature(cache[i], opts->metric->payload); - } - - git__free(cache); - } - - git__free(similarity_ours); - git__free(similarity_theirs); - - return error; -} - -/* Directory/file conflict handling */ - -GIT_INLINE(const char *) merge_diff_path( - const git_merge_diff *conflict) -{ - if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry)) - return conflict->ancestor_entry.path; - else if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry)) - return conflict->our_entry.path; - else if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry)) - return conflict->their_entry.path; - - return NULL; -} - -GIT_INLINE(bool) merge_diff_any_side_added_or_modified( - const git_merge_diff *conflict) -{ - if (conflict->our_status == GIT_DELTA_ADDED || - conflict->our_status == GIT_DELTA_MODIFIED || - conflict->their_status == GIT_DELTA_ADDED || - conflict->their_status == GIT_DELTA_MODIFIED) - return true; - - return false; -} - -GIT_INLINE(bool) path_is_prefixed(const char *parent, const char *child) -{ - size_t child_len = strlen(child); - size_t parent_len = strlen(parent); - - if (child_len < parent_len || - strncmp(parent, child, parent_len) != 0) - return 0; - - return (child[parent_len] == '/'); -} - -GIT_INLINE(int) merge_diff_detect_df_conflict( - struct merge_diff_df_data *df_data, - git_merge_diff *conflict) -{ - const char *cur_path = merge_diff_path(conflict); - - /* Determine if this is a D/F conflict or the child of one */ - if (df_data->df_path && - path_is_prefixed(df_data->df_path, cur_path)) - conflict->type = GIT_MERGE_DIFF_DF_CHILD; - else if(df_data->df_path) - df_data->df_path = NULL; - else if (df_data->prev_path && - merge_diff_any_side_added_or_modified(df_data->prev_conflict) && - merge_diff_any_side_added_or_modified(conflict) && - path_is_prefixed(df_data->prev_path, cur_path)) { - conflict->type = GIT_MERGE_DIFF_DF_CHILD; - - df_data->prev_conflict->type = GIT_MERGE_DIFF_DIRECTORY_FILE; - df_data->df_path = df_data->prev_path; - } - - df_data->prev_path = cur_path; - df_data->prev_conflict = conflict; - - return 0; -} - -/* Conflict handling */ - -GIT_INLINE(int) merge_diff_detect_type( - git_merge_diff *conflict) -{ - if (conflict->our_status == GIT_DELTA_ADDED && - conflict->their_status == GIT_DELTA_ADDED) - conflict->type = GIT_MERGE_DIFF_BOTH_ADDED; - else if (conflict->our_status == GIT_DELTA_MODIFIED && - conflict->their_status == GIT_DELTA_MODIFIED) - conflict->type = GIT_MERGE_DIFF_BOTH_MODIFIED; - else if (conflict->our_status == GIT_DELTA_DELETED && - conflict->their_status == GIT_DELTA_DELETED) - conflict->type = GIT_MERGE_DIFF_BOTH_DELETED; - else if (conflict->our_status == GIT_DELTA_MODIFIED && - conflict->their_status == GIT_DELTA_DELETED) - conflict->type = GIT_MERGE_DIFF_MODIFIED_DELETED; - else if (conflict->our_status == GIT_DELTA_DELETED && - conflict->their_status == GIT_DELTA_MODIFIED) - conflict->type = GIT_MERGE_DIFF_MODIFIED_DELETED; - else - conflict->type = GIT_MERGE_DIFF_NONE; - - return 0; -} - -GIT_INLINE(int) index_entry_dup_pool( - git_index_entry *out, - git_pool *pool, - const git_index_entry *src) -{ - if (src != NULL) { - memcpy(out, src, sizeof(git_index_entry)); - if ((out->path = git_pool_strdup(pool, src->path)) == NULL) - return -1; - } - - return 0; -} - -GIT_INLINE(int) merge_delta_type_from_index_entries( - const git_index_entry *ancestor, - const git_index_entry *other) -{ - if (ancestor == NULL && other == NULL) - return GIT_DELTA_UNMODIFIED; - else if (ancestor == NULL && other != NULL) - return GIT_DELTA_ADDED; - else if (ancestor != NULL && other == NULL) - return GIT_DELTA_DELETED; - else if (S_ISDIR(ancestor->mode) ^ S_ISDIR(other->mode)) - return GIT_DELTA_TYPECHANGE; - else if(S_ISLNK(ancestor->mode) ^ S_ISLNK(other->mode)) - return GIT_DELTA_TYPECHANGE; - else if (git_oid__cmp(&ancestor->id, &other->id) || - ancestor->mode != other->mode) - return GIT_DELTA_MODIFIED; - - return GIT_DELTA_UNMODIFIED; -} - -static git_merge_diff *merge_diff_from_index_entries( - git_merge_diff_list *diff_list, - const git_index_entry **entries) -{ - git_merge_diff *conflict; - git_pool *pool = &diff_list->pool; - - if ((conflict = git_pool_mallocz(pool, sizeof(git_merge_diff))) == NULL) - return NULL; - - if (index_entry_dup_pool(&conflict->ancestor_entry, pool, entries[TREE_IDX_ANCESTOR]) < 0 || - index_entry_dup_pool(&conflict->our_entry, pool, entries[TREE_IDX_OURS]) < 0 || - index_entry_dup_pool(&conflict->their_entry, pool, entries[TREE_IDX_THEIRS]) < 0) - return NULL; - - conflict->our_status = merge_delta_type_from_index_entries( - entries[TREE_IDX_ANCESTOR], entries[TREE_IDX_OURS]); - conflict->their_status = merge_delta_type_from_index_entries( - entries[TREE_IDX_ANCESTOR], entries[TREE_IDX_THEIRS]); - - return conflict; -} - -/* Merge trees */ - -static int merge_diff_list_insert_conflict( - git_merge_diff_list *diff_list, - struct merge_diff_df_data *merge_df_data, - const git_index_entry *tree_items[3]) -{ - git_merge_diff *conflict; - - if ((conflict = merge_diff_from_index_entries(diff_list, tree_items)) == NULL || - merge_diff_detect_type(conflict) < 0 || - merge_diff_detect_df_conflict(merge_df_data, conflict) < 0 || - git_vector_insert(&diff_list->conflicts, conflict) < 0) - return -1; - - return 0; -} - -static int merge_diff_list_insert_unmodified( - git_merge_diff_list *diff_list, - const git_index_entry *tree_items[3]) -{ - int error = 0; - git_index_entry *entry; - - entry = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry)); - GIT_ERROR_CHECK_ALLOC(entry); - - if ((error = index_entry_dup_pool(entry, &diff_list->pool, tree_items[0])) >= 0) - error = git_vector_insert(&diff_list->staged, entry); - - return error; -} - -struct merge_diff_find_data { - git_merge_diff_list *diff_list; - struct merge_diff_df_data df_data; -}; - -static int queue_difference(const git_index_entry **entries, void *data) -{ - struct merge_diff_find_data *find_data = data; - bool item_modified = false; - size_t i; - - if (!entries[0] || !entries[1] || !entries[2]) { - item_modified = true; - } else { - for (i = 1; i < 3; i++) { - if (index_entry_cmp(entries[0], entries[i]) != 0) { - item_modified = true; - break; - } - } - } - - return item_modified ? - merge_diff_list_insert_conflict( - find_data->diff_list, &find_data->df_data, entries) : - merge_diff_list_insert_unmodified(find_data->diff_list, entries); -} - -int git_merge_diff_list__find_differences( - git_merge_diff_list *diff_list, - git_iterator *ancestor_iter, - git_iterator *our_iter, - git_iterator *their_iter) -{ - git_iterator *iterators[3] = { ancestor_iter, our_iter, their_iter }; - struct merge_diff_find_data find_data = { diff_list }; - - return git_iterator_walk(iterators, 3, queue_difference, &find_data); -} - -git_merge_diff_list *git_merge_diff_list__alloc(git_repository *repo) -{ - git_merge_diff_list *diff_list = git__calloc(1, sizeof(git_merge_diff_list)); - - if (diff_list == NULL) - return NULL; - - diff_list->repo = repo; - - - if (git_pool_init(&diff_list->pool, 1) < 0 || - git_vector_init(&diff_list->staged, 0, NULL) < 0 || - git_vector_init(&diff_list->conflicts, 0, NULL) < 0 || - git_vector_init(&diff_list->resolved, 0, NULL) < 0) { - git_merge_diff_list__free(diff_list); - return NULL; - } - - return diff_list; -} - -void git_merge_diff_list__free(git_merge_diff_list *diff_list) -{ - if (!diff_list) - return; - - git_vector_free(&diff_list->staged); - git_vector_free(&diff_list->conflicts); - git_vector_free(&diff_list->resolved); - git_pool_clear(&diff_list->pool); - git__free(diff_list); -} - -static int merge_normalize_opts( - git_repository *repo, - git_merge_options *opts, - const git_merge_options *given) -{ - git_config *cfg = NULL; - git_config_entry *entry = NULL; - int error = 0; - - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(opts); - - if ((error = git_repository_config__weakptr(&cfg, repo)) < 0) - return error; - - if (given != NULL) { - memcpy(opts, given, sizeof(git_merge_options)); - } else { - git_merge_options init = GIT_MERGE_OPTIONS_INIT; - memcpy(opts, &init, sizeof(init)); - } - - if ((opts->flags & GIT_MERGE_FIND_RENAMES) && !opts->rename_threshold) - opts->rename_threshold = GIT_MERGE_DEFAULT_RENAME_THRESHOLD; - - if (given && given->default_driver) { - opts->default_driver = git__strdup(given->default_driver); - GIT_ERROR_CHECK_ALLOC(opts->default_driver); - } else { - error = git_config_get_entry(&entry, cfg, "merge.default"); - - if (error == 0) { - opts->default_driver = git__strdup(entry->value); - GIT_ERROR_CHECK_ALLOC(opts->default_driver); - } else if (error == GIT_ENOTFOUND) { - error = 0; - } else { - goto done; - } - } - - if (!opts->target_limit) { - int limit = git_config__get_int_force(cfg, "merge.renamelimit", 0); - - if (!limit) - limit = git_config__get_int_force(cfg, "diff.renamelimit", 0); - - opts->target_limit = (limit <= 0) ? - GIT_MERGE_DEFAULT_TARGET_LIMIT : (unsigned int)limit; - } - - /* assign the internal metric with whitespace flag as payload */ - if (!opts->metric) { - opts->metric = git__malloc(sizeof(git_diff_similarity_metric)); - GIT_ERROR_CHECK_ALLOC(opts->metric); - - opts->metric->file_signature = git_diff_find_similar__hashsig_for_file; - opts->metric->buffer_signature = git_diff_find_similar__hashsig_for_buf; - opts->metric->free_signature = git_diff_find_similar__hashsig_free; - opts->metric->similarity = git_diff_find_similar__calc_similarity; - opts->metric->payload = (void *)GIT_HASHSIG_SMART_WHITESPACE; - } - -done: - git_config_entry_free(entry); - return error; -} - - -static int merge_index_insert_reuc( - git_index *index, - size_t idx, - const git_index_entry *entry) -{ - const git_index_reuc_entry *reuc; - int mode[3] = { 0, 0, 0 }; - git_oid const *oid[3] = { NULL, NULL, NULL }; - size_t i; - - if (!GIT_MERGE_INDEX_ENTRY_EXISTS(*entry)) - return 0; - - if ((reuc = git_index_reuc_get_bypath(index, entry->path)) != NULL) { - for (i = 0; i < 3; i++) { - mode[i] = reuc->mode[i]; - oid[i] = &reuc->oid[i]; - } - } - - mode[idx] = entry->mode; - oid[idx] = &entry->id; - - return git_index_reuc_add(index, entry->path, - mode[0], oid[0], mode[1], oid[1], mode[2], oid[2]); -} - -static int index_update_reuc(git_index *index, git_merge_diff_list *diff_list) -{ - int error; - size_t i; - git_merge_diff *conflict; - - /* Add each entry in the resolved conflict to the REUC independently, since - * the paths may differ due to renames. */ - git_vector_foreach(&diff_list->resolved, i, conflict) { - const git_index_entry *ancestor = - GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) ? - &conflict->ancestor_entry : NULL; - - const git_index_entry *ours = - GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ? - &conflict->our_entry : NULL; - - const git_index_entry *theirs = - GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ? - &conflict->their_entry : NULL; - - if (ancestor != NULL && - (error = merge_index_insert_reuc(index, TREE_IDX_ANCESTOR, ancestor)) < 0) - return error; - - if (ours != NULL && - (error = merge_index_insert_reuc(index, TREE_IDX_OURS, ours)) < 0) - return error; - - if (theirs != NULL && - (error = merge_index_insert_reuc(index, TREE_IDX_THEIRS, theirs)) < 0) - return error; - } - - return 0; -} - -static int index_from_diff_list(git_index **out, - git_merge_diff_list *diff_list, bool skip_reuc) -{ - git_index *index; - size_t i; - git_merge_diff *conflict; - int error = 0; - - *out = NULL; - - if ((error = git_index_new(&index)) < 0) - return error; - - if ((error = git_index__fill(index, &diff_list->staged)) < 0) - goto on_error; - - git_vector_foreach(&diff_list->conflicts, i, conflict) { - const git_index_entry *ancestor = - GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) ? - &conflict->ancestor_entry : NULL; - - const git_index_entry *ours = - GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ? - &conflict->our_entry : NULL; - - const git_index_entry *theirs = - GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ? - &conflict->their_entry : NULL; - - if ((error = git_index_conflict_add(index, ancestor, ours, theirs)) < 0) - goto on_error; - } - - /* Add each rename entry to the rename portion of the index. */ - git_vector_foreach(&diff_list->conflicts, i, conflict) { - const char *ancestor_path, *our_path, *their_path; - - if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry)) - continue; - - ancestor_path = conflict->ancestor_entry.path; - - our_path = - GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ? - conflict->our_entry.path : NULL; - - their_path = - GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ? - conflict->their_entry.path : NULL; - - if ((our_path && strcmp(ancestor_path, our_path) != 0) || - (their_path && strcmp(ancestor_path, their_path) != 0)) { - if ((error = git_index_name_add(index, ancestor_path, our_path, their_path)) < 0) - goto on_error; - } - } - - if (!skip_reuc) { - if ((error = index_update_reuc(index, diff_list)) < 0) - goto on_error; - } - - *out = index; - return 0; - -on_error: - git_index_free(index); - return error; -} - -static git_iterator *iterator_given_or_empty(git_iterator **empty, git_iterator *given) -{ - git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT; - - if (given) - return given; - - opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE; - - if (git_iterator_for_nothing(empty, &opts) < 0) - return NULL; - - return *empty; -} - -int git_merge__iterators( - git_index **out, - git_repository *repo, - git_iterator *ancestor_iter, - git_iterator *our_iter, - git_iterator *theirs_iter, - const git_merge_options *given_opts) -{ - git_iterator *empty_ancestor = NULL, - *empty_ours = NULL, - *empty_theirs = NULL; - git_merge_diff_list *diff_list; - git_merge_options opts; - git_merge_file_options file_opts = GIT_MERGE_FILE_OPTIONS_INIT; - git_merge_diff *conflict; - git_vector changes; - size_t i; - int error = 0; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(repo); - - *out = NULL; - - GIT_ERROR_CHECK_VERSION( - given_opts, GIT_MERGE_OPTIONS_VERSION, "git_merge_options"); - - if ((error = merge_normalize_opts(repo, &opts, given_opts)) < 0) - return error; - - file_opts.favor = opts.file_favor; - file_opts.flags = opts.file_flags; - - /* use the git-inspired labels when virtual base building */ - if (opts.flags & GIT_MERGE_VIRTUAL_BASE) { - file_opts.ancestor_label = "merged common ancestors"; - file_opts.our_label = "Temporary merge branch 1"; - file_opts.their_label = "Temporary merge branch 2"; - file_opts.flags |= GIT_MERGE_FILE_ACCEPT_CONFLICTS; - file_opts.marker_size = GIT_MERGE_CONFLICT_MARKER_SIZE + 2; - } - - diff_list = git_merge_diff_list__alloc(repo); - GIT_ERROR_CHECK_ALLOC(diff_list); - - ancestor_iter = iterator_given_or_empty(&empty_ancestor, ancestor_iter); - our_iter = iterator_given_or_empty(&empty_ours, our_iter); - theirs_iter = iterator_given_or_empty(&empty_theirs, theirs_iter); - - if ((error = git_merge_diff_list__find_differences( - diff_list, ancestor_iter, our_iter, theirs_iter)) < 0 || - (error = git_merge_diff_list__find_renames(repo, diff_list, &opts)) < 0) - goto done; - - memcpy(&changes, &diff_list->conflicts, sizeof(git_vector)); - git_vector_clear(&diff_list->conflicts); - - git_vector_foreach(&changes, i, conflict) { - int resolved = 0; - - if ((error = merge_conflict_resolve( - &resolved, diff_list, conflict, &opts, &file_opts)) < 0) - goto done; - - if (!resolved) { - if ((opts.flags & GIT_MERGE_FAIL_ON_CONFLICT)) { - git_error_set(GIT_ERROR_MERGE, "merge conflicts exist"); - error = GIT_EMERGECONFLICT; - goto done; - } - - git_vector_insert(&diff_list->conflicts, conflict); - } - } - - error = index_from_diff_list(out, diff_list, - (opts.flags & GIT_MERGE_SKIP_REUC)); - -done: - if (!given_opts || !given_opts->metric) - git__free(opts.metric); - - git__free((char *)opts.default_driver); - - git_merge_diff_list__free(diff_list); - git_iterator_free(empty_ancestor); - git_iterator_free(empty_ours); - git_iterator_free(empty_theirs); - - return error; -} - -int git_merge_trees( - git_index **out, - git_repository *repo, - const git_tree *ancestor_tree, - const git_tree *our_tree, - const git_tree *their_tree, - const git_merge_options *merge_opts) -{ - git_iterator *ancestor_iter = NULL, *our_iter = NULL, *their_iter = NULL; - git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT; - int error; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(repo); - - /* if one side is treesame to the ancestor, take the other side */ - if (ancestor_tree && merge_opts && (merge_opts->flags & GIT_MERGE_SKIP_REUC)) { - const git_tree *result = NULL; - const git_oid *ancestor_tree_id = git_tree_id(ancestor_tree); - - if (our_tree && !git_oid_cmp(ancestor_tree_id, git_tree_id(our_tree))) - result = their_tree; - else if (their_tree && !git_oid_cmp(ancestor_tree_id, git_tree_id(their_tree))) - result = our_tree; - - if (result) { - if ((error = git_index_new(out)) == 0) - error = git_index_read_tree(*out, result); - - return error; - } - } - - iter_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE; - - if ((error = git_iterator_for_tree( - &ancestor_iter, (git_tree *)ancestor_tree, &iter_opts)) < 0 || - (error = git_iterator_for_tree( - &our_iter, (git_tree *)our_tree, &iter_opts)) < 0 || - (error = git_iterator_for_tree( - &their_iter, (git_tree *)their_tree, &iter_opts)) < 0) - goto done; - - error = git_merge__iterators( - out, repo, ancestor_iter, our_iter, their_iter, merge_opts); - -done: - git_iterator_free(ancestor_iter); - git_iterator_free(our_iter); - git_iterator_free(their_iter); - - return error; -} - -static int merge_annotated_commits( - git_index **index_out, - git_annotated_commit **base_out, - git_repository *repo, - git_annotated_commit *our_commit, - git_annotated_commit *their_commit, - size_t recursion_level, - const git_merge_options *opts); - -GIT_INLINE(int) insert_head_ids( - git_array_oid_t *ids, - const git_annotated_commit *annotated_commit) -{ - git_oid *id; - size_t i; - - if (annotated_commit->type == GIT_ANNOTATED_COMMIT_REAL) { - id = git_array_alloc(*ids); - GIT_ERROR_CHECK_ALLOC(id); - - git_oid_cpy(id, git_commit_id(annotated_commit->commit)); - } else { - for (i = 0; i < annotated_commit->parents.size; i++) { - id = git_array_alloc(*ids); - GIT_ERROR_CHECK_ALLOC(id); - - git_oid_cpy(id, &annotated_commit->parents.ptr[i]); - } - } - - return 0; -} - -static int create_virtual_base( - git_annotated_commit **out, - git_repository *repo, - git_annotated_commit *one, - git_annotated_commit *two, - const git_merge_options *opts, - size_t recursion_level) -{ - git_annotated_commit *result = NULL; - git_index *index = NULL; - git_merge_options virtual_opts = GIT_MERGE_OPTIONS_INIT; - - /* Conflicts in the merge base creation do not propagate to conflicts - * in the result; the conflicted base will act as the common ancestor. - */ - if (opts) - memcpy(&virtual_opts, opts, sizeof(git_merge_options)); - - virtual_opts.flags &= ~GIT_MERGE_FAIL_ON_CONFLICT; - virtual_opts.flags |= GIT_MERGE_VIRTUAL_BASE; - - if ((merge_annotated_commits(&index, NULL, repo, one, two, - recursion_level + 1, &virtual_opts)) < 0) - return -1; - - result = git__calloc(1, sizeof(git_annotated_commit)); - GIT_ERROR_CHECK_ALLOC(result); - result->type = GIT_ANNOTATED_COMMIT_VIRTUAL; - result->index = index; - - if (insert_head_ids(&result->parents, one) < 0 || - insert_head_ids(&result->parents, two) < 0) { - git_annotated_commit_free(result); - return -1; - } - - *out = result; - return 0; -} - -static int compute_base( - git_annotated_commit **out, - git_repository *repo, - const git_annotated_commit *one, - const git_annotated_commit *two, - const git_merge_options *given_opts, - size_t recursion_level) -{ - git_array_oid_t head_ids = GIT_ARRAY_INIT; - git_oidarray bases = {0}; - git_annotated_commit *base = NULL, *other = NULL, *new_base = NULL; - git_merge_options opts = GIT_MERGE_OPTIONS_INIT; - size_t i, base_count; - int error; - - *out = NULL; - - if (given_opts) - memcpy(&opts, given_opts, sizeof(git_merge_options)); - - /* With more than two commits, merge_bases_many finds the base of - * the first commit and a hypothetical merge of the others. Since - * "one" may itself be a virtual commit, which insert_head_ids - * substitutes multiple ancestors for, it needs to be added - * after "two" which is always a single real commit. - */ - if ((error = insert_head_ids(&head_ids, two)) < 0 || - (error = insert_head_ids(&head_ids, one)) < 0 || - (error = git_merge_bases_many(&bases, repo, - head_ids.size, head_ids.ptr)) < 0) - goto done; - - base_count = (opts.flags & GIT_MERGE_NO_RECURSIVE) ? 0 : bases.count; - - if (base_count) - git_oidarray__reverse(&bases); - - if ((error = git_annotated_commit_lookup(&base, repo, &bases.ids[0])) < 0) - goto done; - - for (i = 1; i < base_count; i++) { - recursion_level++; - - if (opts.recursion_limit && recursion_level > opts.recursion_limit) - break; - - if ((error = git_annotated_commit_lookup(&other, repo, - &bases.ids[i])) < 0 || - (error = create_virtual_base(&new_base, repo, base, other, &opts, - recursion_level)) < 0) - goto done; - - git_annotated_commit_free(base); - git_annotated_commit_free(other); - - base = new_base; - new_base = NULL; - other = NULL; - } - -done: - if (error == 0) - *out = base; - else - git_annotated_commit_free(base); - - git_annotated_commit_free(other); - git_annotated_commit_free(new_base); - git_oidarray_dispose(&bases); - git_array_clear(head_ids); - return error; -} - -static int iterator_for_annotated_commit( - git_iterator **out, - git_annotated_commit *commit) -{ - git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT; - int error; - - opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE; - - if (commit == NULL) { - error = git_iterator_for_nothing(out, &opts); - } else if (commit->type == GIT_ANNOTATED_COMMIT_VIRTUAL) { - error = git_iterator_for_index(out, git_index_owner(commit->index), commit->index, &opts); - } else { - if (!commit->tree && - (error = git_commit_tree(&commit->tree, commit->commit)) < 0) - goto done; - - error = git_iterator_for_tree(out, commit->tree, &opts); - } - -done: - return error; -} - -static int merge_annotated_commits( - git_index **index_out, - git_annotated_commit **base_out, - git_repository *repo, - git_annotated_commit *ours, - git_annotated_commit *theirs, - size_t recursion_level, - const git_merge_options *opts) -{ - git_annotated_commit *base = NULL; - git_iterator *base_iter = NULL, *our_iter = NULL, *their_iter = NULL; - int error; - - if ((error = compute_base(&base, repo, ours, theirs, opts, - recursion_level)) < 0) { - - if (error != GIT_ENOTFOUND) - goto done; - - git_error_clear(); - } - - if ((error = iterator_for_annotated_commit(&base_iter, base)) < 0 || - (error = iterator_for_annotated_commit(&our_iter, ours)) < 0 || - (error = iterator_for_annotated_commit(&their_iter, theirs)) < 0 || - (error = git_merge__iterators(index_out, repo, base_iter, our_iter, - their_iter, opts)) < 0) - goto done; - - if (base_out) { - *base_out = base; - base = NULL; - } - -done: - git_annotated_commit_free(base); - git_iterator_free(base_iter); - git_iterator_free(our_iter); - git_iterator_free(their_iter); - return error; -} - - -int git_merge_commits( - git_index **out, - git_repository *repo, - const git_commit *our_commit, - const git_commit *their_commit, - const git_merge_options *opts) -{ - git_annotated_commit *ours = NULL, *theirs = NULL, *base = NULL; - int error = 0; - - if ((error = git_annotated_commit_from_commit(&ours, (git_commit *)our_commit)) < 0 || - (error = git_annotated_commit_from_commit(&theirs, (git_commit *)their_commit)) < 0) - goto done; - - error = merge_annotated_commits(out, &base, repo, ours, theirs, 0, opts); - -done: - git_annotated_commit_free(ours); - git_annotated_commit_free(theirs); - git_annotated_commit_free(base); - return error; -} - -/* Merge setup / cleanup */ - -static int write_merge_head( - git_repository *repo, - const git_annotated_commit *heads[], - size_t heads_len) -{ - git_filebuf file = GIT_FILEBUF_INIT; - git_str file_path = GIT_STR_INIT; - size_t i; - int error = 0; - - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(heads); - - if ((error = git_str_joinpath(&file_path, repo->gitdir, GIT_MERGE_HEAD_FILE)) < 0 || - (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) < 0) - goto cleanup; - - for (i = 0; i < heads_len; i++) { - if ((error = git_filebuf_printf(&file, "%s\n", heads[i]->id_str)) < 0) - goto cleanup; - } - - error = git_filebuf_commit(&file); - -cleanup: - if (error < 0) - git_filebuf_cleanup(&file); - - git_str_dispose(&file_path); - - return error; -} - -static int write_merge_mode(git_repository *repo) -{ - git_filebuf file = GIT_FILEBUF_INIT; - git_str file_path = GIT_STR_INIT; - int error = 0; - - GIT_ASSERT_ARG(repo); - - if ((error = git_str_joinpath(&file_path, repo->gitdir, GIT_MERGE_MODE_FILE)) < 0 || - (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) < 0) - goto cleanup; - - if ((error = git_filebuf_write(&file, "no-ff", 5)) < 0) - goto cleanup; - - error = git_filebuf_commit(&file); - -cleanup: - if (error < 0) - git_filebuf_cleanup(&file); - - git_str_dispose(&file_path); - - return error; -} - -struct merge_msg_entry { - const git_annotated_commit *merge_head; - bool written; -}; - -static int msg_entry_is_branch( - const struct merge_msg_entry *entry, - git_vector *entries) -{ - GIT_UNUSED(entries); - - return (entry->written == 0 && - entry->merge_head->remote_url == NULL && - entry->merge_head->ref_name != NULL && - git__strncmp(GIT_REFS_HEADS_DIR, entry->merge_head->ref_name, strlen(GIT_REFS_HEADS_DIR)) == 0); -} - -static int msg_entry_is_tracking( - const struct merge_msg_entry *entry, - git_vector *entries) -{ - GIT_UNUSED(entries); - - return (entry->written == 0 && - entry->merge_head->remote_url == NULL && - entry->merge_head->ref_name != NULL && - git__strncmp(GIT_REFS_REMOTES_DIR, entry->merge_head->ref_name, strlen(GIT_REFS_REMOTES_DIR)) == 0); -} - -static int msg_entry_is_tag( - const struct merge_msg_entry *entry, - git_vector *entries) -{ - GIT_UNUSED(entries); - - return (entry->written == 0 && - entry->merge_head->remote_url == NULL && - entry->merge_head->ref_name != NULL && - git__strncmp(GIT_REFS_TAGS_DIR, entry->merge_head->ref_name, strlen(GIT_REFS_TAGS_DIR)) == 0); -} - -static int msg_entry_is_remote( - const struct merge_msg_entry *entry, - git_vector *entries) -{ - if (entry->written == 0 && - entry->merge_head->remote_url != NULL && - entry->merge_head->ref_name != NULL && - git__strncmp(GIT_REFS_HEADS_DIR, entry->merge_head->ref_name, strlen(GIT_REFS_HEADS_DIR)) == 0) - { - struct merge_msg_entry *existing; - - /* Match only branches from the same remote */ - if (entries->length == 0) - return 1; - - existing = git_vector_get(entries, 0); - - return (git__strcmp(existing->merge_head->remote_url, - entry->merge_head->remote_url) == 0); - } - - return 0; -} - -static int msg_entry_is_oid( - const struct merge_msg_entry *merge_msg_entry) -{ - return (merge_msg_entry->written == 0 && - merge_msg_entry->merge_head->ref_name == NULL && - merge_msg_entry->merge_head->remote_url == NULL); -} - -static int merge_msg_entry_written( - const struct merge_msg_entry *merge_msg_entry) -{ - return (merge_msg_entry->written == 1); -} - -static int merge_msg_entries( - git_vector *v, - const struct merge_msg_entry *entries, - size_t len, - int (*match)(const struct merge_msg_entry *entry, git_vector *entries)) -{ - size_t i; - int matches, total = 0; - - git_vector_clear(v); - - for (i = 0; i < len; i++) { - if ((matches = match(&entries[i], v)) < 0) - return matches; - else if (!matches) - continue; - - git_vector_insert(v, (struct merge_msg_entry *)&entries[i]); - total++; - } - - return total; -} - -static int merge_msg_write_entries( - git_filebuf *file, - git_vector *entries, - const char *item_name, - const char *item_plural_name, - size_t ref_name_skip, - const char *source, - char sep) -{ - struct merge_msg_entry *entry; - size_t i; - int error = 0; - - if (entries->length == 0) - return 0; - - if (sep && (error = git_filebuf_printf(file, "%c ", sep)) < 0) - goto done; - - if ((error = git_filebuf_printf(file, "%s ", - (entries->length == 1) ? item_name : item_plural_name)) < 0) - goto done; - - git_vector_foreach(entries, i, entry) { - if (i > 0 && - (error = git_filebuf_printf(file, "%s", (i == entries->length - 1) ? " and " : ", ")) < 0) - goto done; - - if ((error = git_filebuf_printf(file, "'%s'", entry->merge_head->ref_name + ref_name_skip)) < 0) - goto done; - - entry->written = 1; - } - - if (source) - error = git_filebuf_printf(file, " of %s", source); - -done: - return error; -} - -static int merge_msg_write_branches( - git_filebuf *file, - git_vector *entries, - char sep) -{ - return merge_msg_write_entries(file, entries, - "branch", "branches", strlen(GIT_REFS_HEADS_DIR), NULL, sep); -} - -static int merge_msg_write_tracking( - git_filebuf *file, - git_vector *entries, - char sep) -{ - return merge_msg_write_entries(file, entries, - "remote-tracking branch", "remote-tracking branches", 0, NULL, sep); -} - -static int merge_msg_write_tags( - git_filebuf *file, - git_vector *entries, - char sep) -{ - return merge_msg_write_entries(file, entries, - "tag", "tags", strlen(GIT_REFS_TAGS_DIR), NULL, sep); -} - -static int merge_msg_write_remotes( - git_filebuf *file, - git_vector *entries, - char sep) -{ - const char *source; - - if (entries->length == 0) - return 0; - - source = ((struct merge_msg_entry *)entries->contents[0])->merge_head->remote_url; - - return merge_msg_write_entries(file, entries, - "branch", "branches", strlen(GIT_REFS_HEADS_DIR), source, sep); -} - -static int write_merge_msg( - git_repository *repo, - const git_annotated_commit *heads[], - size_t heads_len) -{ - git_filebuf file = GIT_FILEBUF_INIT; - git_str file_path = GIT_STR_INIT; - struct merge_msg_entry *entries; - git_vector matching = GIT_VECTOR_INIT; - size_t i; - char sep = 0; - int error = 0; - - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(heads); - - entries = git__calloc(heads_len, sizeof(struct merge_msg_entry)); - GIT_ERROR_CHECK_ALLOC(entries); - - if (git_vector_init(&matching, heads_len, NULL) < 0) { - git__free(entries); - return -1; - } - - for (i = 0; i < heads_len; i++) - entries[i].merge_head = heads[i]; - - if ((error = git_str_joinpath(&file_path, repo->gitdir, GIT_MERGE_MSG_FILE)) < 0 || - (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) < 0 || - (error = git_filebuf_write(&file, "Merge ", 6)) < 0) - goto cleanup; - - /* - * This is to emulate the format of MERGE_MSG by core git. - * - * Core git will write all the commits specified by OID, in the order - * provided, until the first named branch or tag is reached, at which - * point all branches will be written in the order provided, then all - * tags, then all remote tracking branches and finally all commits that - * were specified by OID that were not already written. - * - * Yes. Really. - */ - for (i = 0; i < heads_len; i++) { - if (!msg_entry_is_oid(&entries[i])) - break; - - if ((error = git_filebuf_printf(&file, - "%scommit '%s'", (i > 0) ? "; " : "", - entries[i].merge_head->id_str)) < 0) - goto cleanup; - - entries[i].written = 1; - } - - if (i) - sep = ';'; - - if ((error = merge_msg_entries(&matching, entries, heads_len, msg_entry_is_branch)) < 0 || - (error = merge_msg_write_branches(&file, &matching, sep)) < 0) - goto cleanup; - - if (matching.length) - sep =','; - - if ((error = merge_msg_entries(&matching, entries, heads_len, msg_entry_is_tracking)) < 0 || - (error = merge_msg_write_tracking(&file, &matching, sep)) < 0) - goto cleanup; - - if (matching.length) - sep =','; - - if ((error = merge_msg_entries(&matching, entries, heads_len, msg_entry_is_tag)) < 0 || - (error = merge_msg_write_tags(&file, &matching, sep)) < 0) - goto cleanup; - - if (matching.length) - sep =','; - - /* We should never be called with multiple remote branches, but handle - * it in case we are... */ - while ((error = merge_msg_entries(&matching, entries, heads_len, msg_entry_is_remote)) > 0) { - if ((error = merge_msg_write_remotes(&file, &matching, sep)) < 0) - goto cleanup; - - if (matching.length) - sep =','; - } - - if (error < 0) - goto cleanup; - - for (i = 0; i < heads_len; i++) { - if (merge_msg_entry_written(&entries[i])) - continue; - - if ((error = git_filebuf_printf(&file, "; commit '%s'", - entries[i].merge_head->id_str)) < 0) - goto cleanup; - } - - if ((error = git_filebuf_printf(&file, "\n")) < 0 || - (error = git_filebuf_commit(&file)) < 0) - goto cleanup; - -cleanup: - if (error < 0) - git_filebuf_cleanup(&file); - - git_str_dispose(&file_path); - - git_vector_free(&matching); - git__free(entries); - - return error; -} - -int git_merge__setup( - git_repository *repo, - const git_annotated_commit *our_head, - const git_annotated_commit *heads[], - size_t heads_len) -{ - int error = 0; - - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(our_head); - GIT_ASSERT_ARG(heads); - - if ((error = git_repository__set_orig_head(repo, git_annotated_commit_id(our_head))) == 0 && - (error = write_merge_head(repo, heads, heads_len)) == 0 && - (error = write_merge_mode(repo)) == 0) { - error = write_merge_msg(repo, heads, heads_len); - } - - return error; -} - -/* Merge branches */ - -static int merge_ancestor_head( - git_annotated_commit **ancestor_head, - git_repository *repo, - const git_annotated_commit *our_head, - const git_annotated_commit **their_heads, - size_t their_heads_len) -{ - git_oid *oids, ancestor_oid; - size_t i, alloc_len; - int error = 0; - - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(our_head); - GIT_ASSERT_ARG(their_heads); - - GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, their_heads_len, 1); - oids = git__calloc(alloc_len, sizeof(git_oid)); - GIT_ERROR_CHECK_ALLOC(oids); - - git_oid_cpy(&oids[0], git_commit_id(our_head->commit)); - - for (i = 0; i < their_heads_len; i++) - git_oid_cpy(&oids[i + 1], git_annotated_commit_id(their_heads[i])); - - if ((error = git_merge_base_many(&ancestor_oid, repo, their_heads_len + 1, oids)) < 0) - goto on_error; - - error = git_annotated_commit_lookup(ancestor_head, repo, &ancestor_oid); - -on_error: - git__free(oids); - return error; -} - -static const char *merge_their_label(const char *branchname) -{ - const char *slash; - - if ((slash = strrchr(branchname, '/')) == NULL) - return branchname; - - if (*(slash+1) == '\0') - return "theirs"; - - return slash+1; -} - -static int merge_normalize_checkout_opts( - git_checkout_options *out, - git_repository *repo, - const git_checkout_options *given_checkout_opts, - unsigned int checkout_strategy, - git_annotated_commit *ancestor, - const git_annotated_commit *our_head, - const git_annotated_commit **their_heads, - size_t their_heads_len) -{ - git_checkout_options default_checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; - int error = 0; - - GIT_UNUSED(repo); - - if (given_checkout_opts != NULL) - memcpy(out, given_checkout_opts, sizeof(git_checkout_options)); - else - memcpy(out, &default_checkout_opts, sizeof(git_checkout_options)); - - out->checkout_strategy = checkout_strategy; - - if (!out->ancestor_label) { - if (ancestor && ancestor->type == GIT_ANNOTATED_COMMIT_REAL) - out->ancestor_label = git_commit_summary(ancestor->commit); - else if (ancestor) - out->ancestor_label = "merged common ancestors"; - else - out->ancestor_label = "empty base"; - } - - if (!out->our_label) { - if (our_head && our_head->ref_name) - out->our_label = our_head->ref_name; - else - out->our_label = "ours"; - } - - if (!out->their_label) { - if (their_heads_len == 1 && their_heads[0]->ref_name) - out->their_label = merge_their_label(their_heads[0]->ref_name); - else if (their_heads_len == 1) - out->their_label = their_heads[0]->id_str; - else - out->their_label = "theirs"; - } - - return error; -} - -static int merge_check_index(size_t *conflicts, git_repository *repo, git_index *index_new, git_vector *merged_paths) -{ - git_tree *head_tree = NULL; - git_index *index_repo = NULL; - git_iterator *iter_repo = NULL, *iter_new = NULL; - git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT; - git_diff *staged_diff_list = NULL, *index_diff_list = NULL; - git_diff_delta *delta; - git_diff_options opts = GIT_DIFF_OPTIONS_INIT; - git_vector staged_paths = GIT_VECTOR_INIT; - size_t i; - int error = 0; - - GIT_UNUSED(merged_paths); - - *conflicts = 0; - - /* No staged changes may exist unless the change staged is identical to - * the result of the merge. This allows one to apply to merge manually, - * then run merge. Any other staged change would be overwritten by - * a reset merge. - */ - if ((error = git_repository_head_tree(&head_tree, repo)) < 0 || - (error = git_repository_index(&index_repo, repo)) < 0 || - (error = git_diff_tree_to_index(&staged_diff_list, repo, head_tree, index_repo, &opts)) < 0) - goto done; - - if (staged_diff_list->deltas.length == 0) - goto done; - - git_vector_foreach(&staged_diff_list->deltas, i, delta) { - if ((error = git_vector_insert(&staged_paths, (char *)delta->new_file.path)) < 0) - goto done; - } - - iter_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE; - iter_opts.pathlist.strings = (char **)staged_paths.contents; - iter_opts.pathlist.count = staged_paths.length; - - if ((error = git_iterator_for_index(&iter_repo, repo, index_repo, &iter_opts)) < 0 || - (error = git_iterator_for_index(&iter_new, repo, index_new, &iter_opts)) < 0 || - (error = git_diff__from_iterators(&index_diff_list, repo, iter_repo, iter_new, &opts)) < 0) - goto done; - - *conflicts = index_diff_list->deltas.length; - -done: - git_tree_free(head_tree); - git_index_free(index_repo); - git_iterator_free(iter_repo); - git_iterator_free(iter_new); - git_diff_free(staged_diff_list); - git_diff_free(index_diff_list); - git_vector_free(&staged_paths); - - return error; -} - -static int merge_check_workdir(size_t *conflicts, git_repository *repo, git_index *index_new, git_vector *merged_paths) -{ - git_diff *wd_diff_list = NULL; - git_diff_options opts = GIT_DIFF_OPTIONS_INIT; - int error = 0; - - GIT_UNUSED(index_new); - - *conflicts = 0; - - /* We need to have merged at least 1 file for the possibility to exist to - * have conflicts with the workdir. Passing 0 as the pathspec count parameter - * will consider all files in the working directory, that is, we may detect - * a conflict if there were untracked files in the workdir prior to starting - * the merge. This typically happens when cherry-picking a commit whose - * changes have already been applied. - */ - if (merged_paths->length == 0) - return 0; - - opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED; - - /* Workdir changes may exist iff they do not conflict with changes that - * will be applied by the merge (including conflicts). Ensure that there - * are no changes in the workdir to these paths. - */ - opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH; - opts.pathspec.count = merged_paths->length; - opts.pathspec.strings = (char **)merged_paths->contents; - opts.ignore_submodules = GIT_SUBMODULE_IGNORE_ALL; - - if ((error = git_diff_index_to_workdir(&wd_diff_list, repo, NULL, &opts)) < 0) - goto done; - - *conflicts = wd_diff_list->deltas.length; - -done: - git_diff_free(wd_diff_list); - - return error; -} - -int git_merge__check_result(git_repository *repo, git_index *index_new) -{ - git_tree *head_tree = NULL; - git_iterator *iter_head = NULL, *iter_new = NULL; - git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT; - git_diff *merged_list = NULL; - git_diff_options opts = GIT_DIFF_OPTIONS_INIT; - git_diff_delta *delta; - git_vector paths = GIT_VECTOR_INIT; - size_t i, index_conflicts = 0, wd_conflicts = 0, conflicts; - const git_index_entry *e; - int error = 0; - - iter_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE; - - if ((error = git_repository_head_tree(&head_tree, repo)) < 0 || - (error = git_iterator_for_tree(&iter_head, head_tree, &iter_opts)) < 0 || - (error = git_iterator_for_index(&iter_new, repo, index_new, &iter_opts)) < 0 || - (error = git_diff__from_iterators(&merged_list, repo, iter_head, iter_new, &opts)) < 0) - goto done; - - git_vector_foreach(&merged_list->deltas, i, delta) { - if ((error = git_vector_insert(&paths, (char *)delta->new_file.path)) < 0) - goto done; - } - - for (i = 0; i < git_index_entrycount(index_new); i++) { - e = git_index_get_byindex(index_new, i); - - if (git_index_entry_is_conflict(e) && - (git_vector_last(&paths) == NULL || - strcmp(git_vector_last(&paths), e->path) != 0)) { - - if ((error = git_vector_insert(&paths, (char *)e->path)) < 0) - goto done; - } - } - - /* Make sure the index and workdir state do not prevent merging */ - if ((error = merge_check_index(&index_conflicts, repo, index_new, &paths)) < 0 || - (error = merge_check_workdir(&wd_conflicts, repo, index_new, &paths)) < 0) - goto done; - - if ((conflicts = index_conflicts + wd_conflicts) > 0) { - git_error_set(GIT_ERROR_MERGE, "%" PRIuZ " uncommitted change%s would be overwritten by merge", - conflicts, (conflicts != 1) ? "s" : ""); - error = GIT_ECONFLICT; - } - -done: - git_vector_free(&paths); - git_tree_free(head_tree); - git_iterator_free(iter_head); - git_iterator_free(iter_new); - git_diff_free(merged_list); - - return error; -} - -int git_merge__append_conflicts_to_merge_msg( - git_repository *repo, - git_index *index) -{ - git_filebuf file = GIT_FILEBUF_INIT; - git_str file_path = GIT_STR_INIT; - const char *last = NULL; - size_t i; - int error; - - if (!git_index_has_conflicts(index)) - return 0; - - if ((error = git_str_joinpath(&file_path, repo->gitdir, GIT_MERGE_MSG_FILE)) < 0 || - (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_APPEND, GIT_MERGE_FILE_MODE)) < 0) - goto cleanup; - - git_filebuf_printf(&file, "\n#Conflicts:\n"); - - for (i = 0; i < git_index_entrycount(index); i++) { - const git_index_entry *e = git_index_get_byindex(index, i); - - if (!git_index_entry_is_conflict(e)) - continue; - - if (last == NULL || strcmp(e->path, last) != 0) - git_filebuf_printf(&file, "#\t%s\n", e->path); - - last = e->path; - } - - error = git_filebuf_commit(&file); - -cleanup: - if (error < 0) - git_filebuf_cleanup(&file); - - git_str_dispose(&file_path); - - return error; -} - -static int merge_state_cleanup(git_repository *repo) -{ - const char *state_files[] = { - GIT_MERGE_HEAD_FILE, - GIT_MERGE_MODE_FILE, - GIT_MERGE_MSG_FILE, - }; - - return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files)); -} - -static int merge_heads( - git_annotated_commit **ancestor_head_out, - git_annotated_commit **our_head_out, - git_repository *repo, - git_reference *our_ref, - const git_annotated_commit **their_heads, - size_t their_heads_len) -{ - git_annotated_commit *ancestor_head = NULL, *our_head = NULL; - int error = 0; - - *ancestor_head_out = NULL; - *our_head_out = NULL; - - if ((error = git_annotated_commit_from_ref(&our_head, repo, our_ref)) < 0) - goto done; - - if ((error = merge_ancestor_head(&ancestor_head, repo, our_head, their_heads, their_heads_len)) < 0) { - if (error != GIT_ENOTFOUND) - goto done; - - git_error_clear(); - error = 0; - } - - *ancestor_head_out = ancestor_head; - *our_head_out = our_head; - -done: - if (error < 0) { - git_annotated_commit_free(ancestor_head); - git_annotated_commit_free(our_head); - } - - return error; -} - -static int merge_preference(git_merge_preference_t *out, git_repository *repo) -{ - git_config *config; - const char *value; - int bool_value, error = 0; - - *out = GIT_MERGE_PREFERENCE_NONE; - - if ((error = git_repository_config_snapshot(&config, repo)) < 0) - goto done; - - if ((error = git_config_get_string(&value, config, "merge.ff")) < 0) { - if (error == GIT_ENOTFOUND) { - git_error_clear(); - error = 0; - } - - goto done; - } - - if (git_config_parse_bool(&bool_value, value) == 0) { - if (!bool_value) - *out |= GIT_MERGE_PREFERENCE_NO_FASTFORWARD; - } else { - if (strcasecmp(value, "only") == 0) - *out |= GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY; - } - -done: - git_config_free(config); - return error; -} - -int git_merge_analysis_for_ref( - git_merge_analysis_t *analysis_out, - git_merge_preference_t *preference_out, - git_repository *repo, - git_reference *our_ref, - const git_annotated_commit **their_heads, - size_t their_heads_len) -{ - git_annotated_commit *ancestor_head = NULL, *our_head = NULL; - int error = 0; - bool unborn; - - GIT_ASSERT_ARG(analysis_out); - GIT_ASSERT_ARG(preference_out); - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(their_heads && their_heads_len > 0); - - if (their_heads_len != 1) { - git_error_set(GIT_ERROR_MERGE, "can only merge a single branch"); - error = -1; - goto done; - } - - *analysis_out = GIT_MERGE_ANALYSIS_NONE; - - if ((error = merge_preference(preference_out, repo)) < 0) - goto done; - - if ((error = git_reference__is_unborn_head(&unborn, our_ref, repo)) < 0) - goto done; - - if (unborn) { - *analysis_out |= GIT_MERGE_ANALYSIS_FASTFORWARD | GIT_MERGE_ANALYSIS_UNBORN; - error = 0; - goto done; - } - - if ((error = merge_heads(&ancestor_head, &our_head, repo, our_ref, their_heads, their_heads_len)) < 0) - goto done; - - /* We're up-to-date if we're trying to merge our own common ancestor. */ - if (ancestor_head && git_oid_equal( - git_annotated_commit_id(ancestor_head), git_annotated_commit_id(their_heads[0]))) - *analysis_out |= GIT_MERGE_ANALYSIS_UP_TO_DATE; - - /* We're fastforwardable if we're our own common ancestor. */ - else if (ancestor_head && git_oid_equal( - git_annotated_commit_id(ancestor_head), git_annotated_commit_id(our_head))) - *analysis_out |= GIT_MERGE_ANALYSIS_FASTFORWARD | GIT_MERGE_ANALYSIS_NORMAL; - - /* Otherwise, just a normal merge is possible. */ - else - *analysis_out |= GIT_MERGE_ANALYSIS_NORMAL; - -done: - git_annotated_commit_free(ancestor_head); - git_annotated_commit_free(our_head); - return error; -} - -int git_merge_analysis( - git_merge_analysis_t *analysis_out, - git_merge_preference_t *preference_out, - git_repository *repo, - const git_annotated_commit **their_heads, - size_t their_heads_len) -{ - git_reference *head_ref = NULL; - int error = 0; - - if ((error = git_reference_lookup(&head_ref, repo, GIT_HEAD_FILE)) < 0) { - git_error_set(GIT_ERROR_MERGE, "failed to lookup HEAD reference"); - return error; - } - - error = git_merge_analysis_for_ref(analysis_out, preference_out, repo, head_ref, their_heads, their_heads_len); - - git_reference_free(head_ref); - - return error; -} - -int git_merge( - git_repository *repo, - const git_annotated_commit **their_heads, - size_t their_heads_len, - const git_merge_options *merge_opts, - const git_checkout_options *given_checkout_opts) -{ - git_reference *our_ref = NULL; - git_checkout_options checkout_opts; - git_annotated_commit *our_head = NULL, *base = NULL; - git_index *repo_index = NULL, *index = NULL; - git_indexwriter indexwriter = GIT_INDEXWRITER_INIT; - unsigned int checkout_strategy; - int error = 0; - - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(their_heads && their_heads_len > 0); - - if (their_heads_len != 1) { - git_error_set(GIT_ERROR_MERGE, "can only merge a single branch"); - return -1; - } - - if ((error = git_repository__ensure_not_bare(repo, "merge")) < 0) - goto done; - - checkout_strategy = given_checkout_opts ? - given_checkout_opts->checkout_strategy : - GIT_CHECKOUT_SAFE; - - if ((error = git_indexwriter_init_for_operation(&indexwriter, repo, - &checkout_strategy)) < 0) - goto done; - - if ((error = git_repository_index(&repo_index, repo) < 0) || - (error = git_index_read(repo_index, 0) < 0)) - goto done; - - /* Write the merge setup files to the repository. */ - if ((error = git_annotated_commit_from_head(&our_head, repo)) < 0 || - (error = git_merge__setup(repo, our_head, their_heads, - their_heads_len)) < 0) - goto done; - - /* TODO: octopus */ - - if ((error = merge_annotated_commits(&index, &base, repo, our_head, - (git_annotated_commit *)their_heads[0], 0, merge_opts)) < 0 || - (error = git_merge__check_result(repo, index)) < 0 || - (error = git_merge__append_conflicts_to_merge_msg(repo, index)) < 0) - goto done; - - /* check out the merge results */ - - if ((error = merge_normalize_checkout_opts(&checkout_opts, repo, - given_checkout_opts, checkout_strategy, - base, our_head, their_heads, their_heads_len)) < 0 || - (error = git_checkout_index(repo, index, &checkout_opts)) < 0) - goto done; - - error = git_indexwriter_commit(&indexwriter); - -done: - if (error < 0) - merge_state_cleanup(repo); - - git_indexwriter_cleanup(&indexwriter); - git_index_free(index); - git_annotated_commit_free(our_head); - git_annotated_commit_free(base); - git_reference_free(our_ref); - git_index_free(repo_index); - - return error; -} - -int git_merge_options_init(git_merge_options *opts, unsigned int version) -{ - GIT_INIT_STRUCTURE_FROM_TEMPLATE( - opts, version, git_merge_options, GIT_MERGE_OPTIONS_INIT); - return 0; -} - -#ifndef GIT_DEPRECATE_HARD -int git_merge_init_options(git_merge_options *opts, unsigned int version) -{ - return git_merge_options_init(opts, version); -} -#endif - -int git_merge_file_input_init(git_merge_file_input *input, unsigned int version) -{ - GIT_INIT_STRUCTURE_FROM_TEMPLATE( - input, version, git_merge_file_input, GIT_MERGE_FILE_INPUT_INIT); - return 0; -} - -#ifndef GIT_DEPRECATE_HARD -int git_merge_file_init_input(git_merge_file_input *input, unsigned int version) -{ - return git_merge_file_input_init(input, version); -} -#endif - -int git_merge_file_options_init( - git_merge_file_options *opts, unsigned int version) -{ - GIT_INIT_STRUCTURE_FROM_TEMPLATE( - opts, version, git_merge_file_options, GIT_MERGE_FILE_OPTIONS_INIT); - return 0; -} - -#ifndef GIT_DEPRECATE_HARD -int git_merge_file_init_options( - git_merge_file_options *opts, unsigned int version) -{ - return git_merge_file_options_init(opts, version); -} -#endif diff --git a/vendor/libgit2/src/midx.c b/vendor/libgit2/src/midx.c deleted file mode 100644 index 0092601f..00000000 --- a/vendor/libgit2/src/midx.c +++ /dev/null @@ -1,901 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "midx.h" - -#include "array.h" -#include "buf.h" -#include "filebuf.h" -#include "futils.h" -#include "hash.h" -#include "odb.h" -#include "pack.h" -#include "fs_path.h" -#include "repository.h" -#include "str.h" - -#define MIDX_SIGNATURE 0x4d494458 /* "MIDX" */ -#define MIDX_VERSION 1 -#define MIDX_OBJECT_ID_VERSION 1 -struct git_midx_header { - uint32_t signature; - uint8_t version; - uint8_t object_id_version; - uint8_t chunks; - uint8_t base_midx_files; - uint32_t packfiles; -}; - -#define MIDX_PACKFILE_NAMES_ID 0x504e414d /* "PNAM" */ -#define MIDX_OID_FANOUT_ID 0x4f494446 /* "OIDF" */ -#define MIDX_OID_LOOKUP_ID 0x4f49444c /* "OIDL" */ -#define MIDX_OBJECT_OFFSETS_ID 0x4f4f4646 /* "OOFF" */ -#define MIDX_OBJECT_LARGE_OFFSETS_ID 0x4c4f4646 /* "LOFF" */ - -struct git_midx_chunk { - off64_t offset; - size_t length; -}; - -typedef int (*midx_write_cb)(const char *buf, size_t size, void *cb_data); - -static int midx_error(const char *message) -{ - git_error_set(GIT_ERROR_ODB, "invalid multi-pack-index file - %s", message); - return -1; -} - -static int midx_parse_packfile_names( - git_midx_file *idx, - const unsigned char *data, - uint32_t packfiles, - struct git_midx_chunk *chunk) -{ - int error; - uint32_t i; - char *packfile_name = (char *)(data + chunk->offset); - size_t chunk_size = chunk->length, len; - if (chunk->offset == 0) - return midx_error("missing Packfile Names chunk"); - if (chunk->length == 0) - return midx_error("empty Packfile Names chunk"); - if ((error = git_vector_init(&idx->packfile_names, packfiles, git__strcmp_cb)) < 0) - return error; - for (i = 0; i < packfiles; ++i) { - len = p_strnlen(packfile_name, chunk_size); - if (len == 0) - return midx_error("empty packfile name"); - if (len + 1 > chunk_size) - return midx_error("unterminated packfile name"); - git_vector_insert(&idx->packfile_names, packfile_name); - if (i && strcmp(git_vector_get(&idx->packfile_names, i - 1), packfile_name) >= 0) - return midx_error("packfile names are not sorted"); - if (strlen(packfile_name) <= strlen(".idx") || git__suffixcmp(packfile_name, ".idx") != 0) - return midx_error("non-.idx packfile name"); - if (strchr(packfile_name, '/') != NULL || strchr(packfile_name, '\\') != NULL) - return midx_error("non-local packfile"); - packfile_name += len + 1; - chunk_size -= len + 1; - } - return 0; -} - -static int midx_parse_oid_fanout( - git_midx_file *idx, - const unsigned char *data, - struct git_midx_chunk *chunk_oid_fanout) -{ - uint32_t i, nr; - if (chunk_oid_fanout->offset == 0) - return midx_error("missing OID Fanout chunk"); - if (chunk_oid_fanout->length == 0) - return midx_error("empty OID Fanout chunk"); - if (chunk_oid_fanout->length != 256 * 4) - return midx_error("OID Fanout chunk has wrong length"); - - idx->oid_fanout = (const uint32_t *)(data + chunk_oid_fanout->offset); - nr = 0; - for (i = 0; i < 256; ++i) { - uint32_t n = ntohl(idx->oid_fanout[i]); - if (n < nr) - return midx_error("index is non-monotonic"); - nr = n; - } - idx->num_objects = nr; - return 0; -} - -static int midx_parse_oid_lookup( - git_midx_file *idx, - const unsigned char *data, - struct git_midx_chunk *chunk_oid_lookup) -{ - uint32_t i; - git_oid *oid, *prev_oid, zero_oid = {{0}}; - - if (chunk_oid_lookup->offset == 0) - return midx_error("missing OID Lookup chunk"); - if (chunk_oid_lookup->length == 0) - return midx_error("empty OID Lookup chunk"); - if (chunk_oid_lookup->length != idx->num_objects * GIT_OID_RAWSZ) - return midx_error("OID Lookup chunk has wrong length"); - - idx->oid_lookup = oid = (git_oid *)(data + chunk_oid_lookup->offset); - prev_oid = &zero_oid; - for (i = 0; i < idx->num_objects; ++i, ++oid) { - if (git_oid_cmp(prev_oid, oid) >= 0) - return midx_error("OID Lookup index is non-monotonic"); - prev_oid = oid; - } - - return 0; -} - -static int midx_parse_object_offsets( - git_midx_file *idx, - const unsigned char *data, - struct git_midx_chunk *chunk_object_offsets) -{ - if (chunk_object_offsets->offset == 0) - return midx_error("missing Object Offsets chunk"); - if (chunk_object_offsets->length == 0) - return midx_error("empty Object Offsets chunk"); - if (chunk_object_offsets->length != idx->num_objects * 8) - return midx_error("Object Offsets chunk has wrong length"); - - idx->object_offsets = data + chunk_object_offsets->offset; - - return 0; -} - -static int midx_parse_object_large_offsets( - git_midx_file *idx, - const unsigned char *data, - struct git_midx_chunk *chunk_object_large_offsets) -{ - if (chunk_object_large_offsets->length == 0) - return 0; - if (chunk_object_large_offsets->length % 8 != 0) - return midx_error("malformed Object Large Offsets chunk"); - - idx->object_large_offsets = data + chunk_object_large_offsets->offset; - idx->num_object_large_offsets = chunk_object_large_offsets->length / 8; - - return 0; -} - -int git_midx_parse( - git_midx_file *idx, - const unsigned char *data, - size_t size) -{ - struct git_midx_header *hdr; - const unsigned char *chunk_hdr; - struct git_midx_chunk *last_chunk; - uint32_t i; - off64_t last_chunk_offset, chunk_offset, trailer_offset; - size_t checksum_size; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; - int error; - struct git_midx_chunk chunk_packfile_names = {0}, - chunk_oid_fanout = {0}, - chunk_oid_lookup = {0}, - chunk_object_offsets = {0}, - chunk_object_large_offsets = {0}; - - GIT_ASSERT_ARG(idx); - - if (size < sizeof(struct git_midx_header) + GIT_OID_RAWSZ) - return midx_error("multi-pack index is too short"); - - hdr = ((struct git_midx_header *)data); - - if (hdr->signature != htonl(MIDX_SIGNATURE) || - hdr->version != MIDX_VERSION || - hdr->object_id_version != MIDX_OBJECT_ID_VERSION) { - return midx_error("unsupported multi-pack index version"); - } - if (hdr->chunks == 0) - return midx_error("no chunks in multi-pack index"); - - /* - * The very first chunk's offset should be after the header, all the chunk - * headers, and a special zero chunk. - */ - last_chunk_offset = - sizeof(struct git_midx_header) + - (1 + hdr->chunks) * 12; - - checksum_size = GIT_HASH_SHA1_SIZE; - trailer_offset = size - checksum_size; - - if (trailer_offset < last_chunk_offset) - return midx_error("wrong index size"); - memcpy(idx->checksum, data + trailer_offset, checksum_size); - - if (git_hash_buf(checksum, data, (size_t)trailer_offset, GIT_HASH_ALGORITHM_SHA1) < 0) - return midx_error("could not calculate signature"); - if (memcmp(checksum, idx->checksum, checksum_size) != 0) - return midx_error("index signature mismatch"); - - chunk_hdr = data + sizeof(struct git_midx_header); - last_chunk = NULL; - for (i = 0; i < hdr->chunks; ++i, chunk_hdr += 12) { - uint32_t chunk_id = ntohl(*((uint32_t *)(chunk_hdr + 0))); - uint64_t high_offset = ((uint64_t)ntohl(*((uint32_t *)(chunk_hdr + 4)))) & 0xffffffffu; - uint64_t low_offset = ((uint64_t)ntohl(*((uint32_t *)(chunk_hdr + 8)))) & 0xffffffffu; - - if (high_offset >= INT32_MAX) - return midx_error("chunk offset out of range"); - chunk_offset = (off64_t)(high_offset << 32 | low_offset); - if (chunk_offset < last_chunk_offset) - return midx_error("chunks are non-monotonic"); - if (chunk_offset >= trailer_offset) - return midx_error("chunks extend beyond the trailer"); - if (last_chunk != NULL) - last_chunk->length = (size_t)(chunk_offset - last_chunk_offset); - last_chunk_offset = chunk_offset; - - switch (chunk_id) { - case MIDX_PACKFILE_NAMES_ID: - chunk_packfile_names.offset = last_chunk_offset; - last_chunk = &chunk_packfile_names; - break; - - case MIDX_OID_FANOUT_ID: - chunk_oid_fanout.offset = last_chunk_offset; - last_chunk = &chunk_oid_fanout; - break; - - case MIDX_OID_LOOKUP_ID: - chunk_oid_lookup.offset = last_chunk_offset; - last_chunk = &chunk_oid_lookup; - break; - - case MIDX_OBJECT_OFFSETS_ID: - chunk_object_offsets.offset = last_chunk_offset; - last_chunk = &chunk_object_offsets; - break; - - case MIDX_OBJECT_LARGE_OFFSETS_ID: - chunk_object_large_offsets.offset = last_chunk_offset; - last_chunk = &chunk_object_large_offsets; - break; - - default: - return midx_error("unrecognized chunk ID"); - } - } - last_chunk->length = (size_t)(trailer_offset - last_chunk_offset); - - error = midx_parse_packfile_names( - idx, data, ntohl(hdr->packfiles), &chunk_packfile_names); - if (error < 0) - return error; - error = midx_parse_oid_fanout(idx, data, &chunk_oid_fanout); - if (error < 0) - return error; - error = midx_parse_oid_lookup(idx, data, &chunk_oid_lookup); - if (error < 0) - return error; - error = midx_parse_object_offsets(idx, data, &chunk_object_offsets); - if (error < 0) - return error; - error = midx_parse_object_large_offsets(idx, data, &chunk_object_large_offsets); - if (error < 0) - return error; - - return 0; -} - -int git_midx_open( - git_midx_file **idx_out, - const char *path) -{ - git_midx_file *idx; - git_file fd = -1; - size_t idx_size; - struct stat st; - int error; - - /* TODO: properly open the file without access time using O_NOATIME */ - fd = git_futils_open_ro(path); - if (fd < 0) - return fd; - - if (p_fstat(fd, &st) < 0) { - p_close(fd); - git_error_set(GIT_ERROR_ODB, "multi-pack-index file not found - '%s'", path); - return -1; - } - - if (!S_ISREG(st.st_mode) || !git__is_sizet(st.st_size)) { - p_close(fd); - git_error_set(GIT_ERROR_ODB, "invalid pack index '%s'", path); - return -1; - } - idx_size = (size_t)st.st_size; - - idx = git__calloc(1, sizeof(git_midx_file)); - GIT_ERROR_CHECK_ALLOC(idx); - - error = git_str_sets(&idx->filename, path); - if (error < 0) - return error; - - error = git_futils_mmap_ro(&idx->index_map, fd, 0, idx_size); - p_close(fd); - if (error < 0) { - git_midx_free(idx); - return error; - } - - if ((error = git_midx_parse(idx, idx->index_map.data, idx_size)) < 0) { - git_midx_free(idx); - return error; - } - - *idx_out = idx; - return 0; -} - -bool git_midx_needs_refresh( - const git_midx_file *idx, - const char *path) -{ - git_file fd = -1; - struct stat st; - ssize_t bytes_read; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; - size_t checksum_size; - - /* TODO: properly open the file without access time using O_NOATIME */ - fd = git_futils_open_ro(path); - if (fd < 0) - return true; - - if (p_fstat(fd, &st) < 0) { - p_close(fd); - return true; - } - - if (!S_ISREG(st.st_mode) || - !git__is_sizet(st.st_size) || - (size_t)st.st_size != idx->index_map.len) { - p_close(fd); - return true; - } - - checksum_size = GIT_HASH_SHA1_SIZE; - bytes_read = p_pread(fd, checksum, checksum_size, st.st_size - GIT_OID_RAWSZ); - p_close(fd); - - if (bytes_read != (ssize_t)checksum_size) - return true; - - return (memcmp(checksum, idx->checksum, checksum_size) != 0); -} - -int git_midx_entry_find( - git_midx_entry *e, - git_midx_file *idx, - const git_oid *short_oid, - size_t len) -{ - int pos, found = 0; - size_t pack_index; - uint32_t hi, lo; - const git_oid *current = NULL; - const unsigned char *object_offset; - off64_t offset; - - GIT_ASSERT_ARG(idx); - - hi = ntohl(idx->oid_fanout[(int)short_oid->id[0]]); - lo = ((short_oid->id[0] == 0x0) ? 0 : ntohl(idx->oid_fanout[(int)short_oid->id[0] - 1])); - - pos = git_pack__lookup_sha1(idx->oid_lookup, GIT_OID_RAWSZ, lo, hi, short_oid->id); - - if (pos >= 0) { - /* An object matching exactly the oid was found */ - found = 1; - current = idx->oid_lookup + pos; - } else { - /* No object was found */ - /* pos refers to the object with the "closest" oid to short_oid */ - pos = -1 - pos; - if (pos < (int)idx->num_objects) { - current = idx->oid_lookup + pos; - - if (!git_oid_ncmp(short_oid, current, len)) - found = 1; - } - } - - if (found && len != GIT_OID_HEXSZ && pos + 1 < (int)idx->num_objects) { - /* Check for ambiguousity */ - const git_oid *next = current + 1; - - if (!git_oid_ncmp(short_oid, next, len)) { - found = 2; - } - } - - if (!found) - return git_odb__error_notfound("failed to find offset for multi-pack index entry", short_oid, len); - if (found > 1) - return git_odb__error_ambiguous("found multiple offsets for multi-pack index entry"); - - object_offset = idx->object_offsets + pos * 8; - offset = ntohl(*((uint32_t *)(object_offset + 4))); - if (offset & 0x80000000) { - uint32_t object_large_offsets_pos = offset & 0x7fffffff; - const unsigned char *object_large_offsets_index = idx->object_large_offsets; - - /* Make sure we're not being sent out of bounds */ - if (object_large_offsets_pos >= idx->num_object_large_offsets) - return git_odb__error_notfound("invalid index into the object large offsets table", short_oid, len); - - object_large_offsets_index += 8 * object_large_offsets_pos; - - offset = (((uint64_t)ntohl(*((uint32_t *)(object_large_offsets_index + 0)))) << 32) | - ntohl(*((uint32_t *)(object_large_offsets_index + 4))); - } - pack_index = ntohl(*((uint32_t *)(object_offset + 0))); - if (pack_index >= git_vector_length(&idx->packfile_names)) - return midx_error("invalid index into the packfile names table"); - e->pack_index = pack_index; - e->offset = offset; - git_oid_cpy(&e->sha1, current); - return 0; -} - -int git_midx_foreach_entry( - git_midx_file *idx, - git_odb_foreach_cb cb, - void *data) -{ - size_t i; - int error; - - GIT_ASSERT_ARG(idx); - - for (i = 0; i < idx->num_objects; ++i) { - if ((error = cb(&idx->oid_lookup[i], data)) != 0) - return git_error_set_after_callback(error); - } - - return error; -} - -int git_midx_close(git_midx_file *idx) -{ - GIT_ASSERT_ARG(idx); - - if (idx->index_map.data) - git_futils_mmap_free(&idx->index_map); - - git_vector_free(&idx->packfile_names); - - return 0; -} - -void git_midx_free(git_midx_file *idx) -{ - if (!idx) - return; - - git_str_dispose(&idx->filename); - git_midx_close(idx); - git__free(idx); -} - -static int packfile__cmp(const void *a_, const void *b_) -{ - const struct git_pack_file *a = a_; - const struct git_pack_file *b = b_; - - return strcmp(a->pack_name, b->pack_name); -} - -int git_midx_writer_new( - git_midx_writer **out, - const char *pack_dir) -{ - git_midx_writer *w = git__calloc(1, sizeof(git_midx_writer)); - GIT_ERROR_CHECK_ALLOC(w); - - if (git_str_sets(&w->pack_dir, pack_dir) < 0) { - git__free(w); - return -1; - } - git_fs_path_squash_slashes(&w->pack_dir); - - if (git_vector_init(&w->packs, 0, packfile__cmp) < 0) { - git_str_dispose(&w->pack_dir); - git__free(w); - return -1; - } - - *out = w; - return 0; -} - -void git_midx_writer_free(git_midx_writer *w) -{ - struct git_pack_file *p; - size_t i; - - if (!w) - return; - - git_vector_foreach (&w->packs, i, p) - git_mwindow_put_pack(p); - git_vector_free(&w->packs); - git_str_dispose(&w->pack_dir); - git__free(w); -} - -int git_midx_writer_add( - git_midx_writer *w, - const char *idx_path) -{ - git_str idx_path_buf = GIT_STR_INIT; - int error; - struct git_pack_file *p; - - error = git_fs_path_prettify(&idx_path_buf, idx_path, git_str_cstr(&w->pack_dir)); - if (error < 0) - return error; - - error = git_mwindow_get_pack(&p, git_str_cstr(&idx_path_buf)); - git_str_dispose(&idx_path_buf); - if (error < 0) - return error; - - error = git_vector_insert(&w->packs, p); - if (error < 0) { - git_mwindow_put_pack(p); - return error; - } - - return 0; -} - -typedef git_array_t(git_midx_entry) object_entry_array_t; - -struct object_entry_cb_state { - uint32_t pack_index; - object_entry_array_t *object_entries_array; -}; - -static int object_entry__cb(const git_oid *oid, off64_t offset, void *data) -{ - struct object_entry_cb_state *state = (struct object_entry_cb_state *)data; - - git_midx_entry *entry = git_array_alloc(*state->object_entries_array); - GIT_ERROR_CHECK_ALLOC(entry); - - git_oid_cpy(&entry->sha1, oid); - entry->offset = offset; - entry->pack_index = state->pack_index; - - return 0; -} - -static int object_entry__cmp(const void *a_, const void *b_) -{ - const git_midx_entry *a = (const git_midx_entry *)a_; - const git_midx_entry *b = (const git_midx_entry *)b_; - - return git_oid_cmp(&a->sha1, &b->sha1); -} - -static int write_offset(off64_t offset, midx_write_cb write_cb, void *cb_data) -{ - int error; - uint32_t word; - - word = htonl((uint32_t)((offset >> 32) & 0xffffffffu)); - error = write_cb((const char *)&word, sizeof(word), cb_data); - if (error < 0) - return error; - word = htonl((uint32_t)((offset >> 0) & 0xffffffffu)); - error = write_cb((const char *)&word, sizeof(word), cb_data); - if (error < 0) - return error; - - return 0; -} - -static int write_chunk_header(int chunk_id, off64_t offset, midx_write_cb write_cb, void *cb_data) -{ - uint32_t word = htonl(chunk_id); - int error = write_cb((const char *)&word, sizeof(word), cb_data); - if (error < 0) - return error; - return write_offset(offset, write_cb, cb_data); - - return 0; -} - -static int midx_write_buf(const char *buf, size_t size, void *data) -{ - git_str *b = (git_str *)data; - return git_str_put(b, buf, size); -} - -struct midx_write_hash_context { - midx_write_cb write_cb; - void *cb_data; - git_hash_ctx *ctx; -}; - -static int midx_write_hash(const char *buf, size_t size, void *data) -{ - struct midx_write_hash_context *ctx = (struct midx_write_hash_context *)data; - int error; - - error = git_hash_update(ctx->ctx, buf, size); - if (error < 0) - return error; - - return ctx->write_cb(buf, size, ctx->cb_data); -} - -static int midx_write( - git_midx_writer *w, - midx_write_cb write_cb, - void *cb_data) -{ - int error = 0; - size_t i; - struct git_pack_file *p; - struct git_midx_header hdr = {0}; - uint32_t oid_fanout_count; - uint32_t object_large_offsets_count; - uint32_t oid_fanout[256]; - off64_t offset; - git_str packfile_names = GIT_STR_INIT, - oid_lookup = GIT_STR_INIT, - object_offsets = GIT_STR_INIT, - object_large_offsets = GIT_STR_INIT; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; - size_t checksum_size; - git_midx_entry *entry; - object_entry_array_t object_entries_array = GIT_ARRAY_INIT; - git_vector object_entries = GIT_VECTOR_INIT; - git_hash_ctx ctx; - struct midx_write_hash_context hash_cb_data = {0}; - - hdr.signature = htonl(MIDX_SIGNATURE); - hdr.version = MIDX_VERSION; - hdr.object_id_version = MIDX_OBJECT_ID_VERSION; - hdr.base_midx_files = 0; - - hash_cb_data.write_cb = write_cb; - hash_cb_data.cb_data = cb_data; - hash_cb_data.ctx = &ctx; - - checksum_size = GIT_HASH_SHA1_SIZE; - error = git_hash_ctx_init(&ctx, GIT_HASH_ALGORITHM_SHA1); - if (error < 0) - return error; - cb_data = &hash_cb_data; - write_cb = midx_write_hash; - - git_vector_sort(&w->packs); - git_vector_foreach (&w->packs, i, p) { - git_str relative_index = GIT_STR_INIT; - struct object_entry_cb_state state = {0}; - size_t path_len; - - state.pack_index = (uint32_t)i; - state.object_entries_array = &object_entries_array; - - error = git_str_sets(&relative_index, p->pack_name); - if (error < 0) - goto cleanup; - error = git_fs_path_make_relative(&relative_index, git_str_cstr(&w->pack_dir)); - if (error < 0) { - git_str_dispose(&relative_index); - goto cleanup; - } - path_len = git_str_len(&relative_index); - if (path_len <= strlen(".pack") || git__suffixcmp(git_str_cstr(&relative_index), ".pack") != 0) { - git_str_dispose(&relative_index); - git_error_set(GIT_ERROR_INVALID, "invalid packfile name: '%s'", p->pack_name); - error = -1; - goto cleanup; - } - path_len -= strlen(".pack"); - - git_str_put(&packfile_names, git_str_cstr(&relative_index), path_len); - git_str_puts(&packfile_names, ".idx"); - git_str_putc(&packfile_names, '\0'); - git_str_dispose(&relative_index); - - error = git_pack_foreach_entry_offset(p, object_entry__cb, &state); - if (error < 0) - goto cleanup; - } - - /* Sort the object entries. */ - error = git_vector_init(&object_entries, git_array_size(object_entries_array), object_entry__cmp); - if (error < 0) - goto cleanup; - git_array_foreach (object_entries_array, i, entry) { - if ((error = git_vector_set(NULL, &object_entries, i, entry)) < 0) - goto cleanup; - } - git_vector_set_sorted(&object_entries, 0); - git_vector_sort(&object_entries); - git_vector_uniq(&object_entries, NULL); - - /* Pad the packfile names so it is a multiple of four. */ - while (git_str_len(&packfile_names) & 3) - git_str_putc(&packfile_names, '\0'); - - /* Fill the OID Fanout table. */ - oid_fanout_count = 0; - for (i = 0; i < 256; i++) { - while (oid_fanout_count < git_vector_length(&object_entries) && - ((const git_midx_entry *)git_vector_get(&object_entries, oid_fanout_count))->sha1.id[0] <= i) - ++oid_fanout_count; - oid_fanout[i] = htonl(oid_fanout_count); - } - - /* Fill the OID Lookup table. */ - git_vector_foreach (&object_entries, i, entry) { - error = git_str_put(&oid_lookup, (const char *)&entry->sha1, sizeof(entry->sha1)); - if (error < 0) - goto cleanup; - } - - /* Fill the Object Offsets and Object Large Offsets tables. */ - object_large_offsets_count = 0; - git_vector_foreach (&object_entries, i, entry) { - uint32_t word; - - word = htonl((uint32_t)entry->pack_index); - error = git_str_put(&object_offsets, (const char *)&word, sizeof(word)); - if (error < 0) - goto cleanup; - if (entry->offset >= 0x80000000l) { - word = htonl(0x80000000u | object_large_offsets_count++); - if ((error = write_offset(entry->offset, midx_write_buf, &object_large_offsets)) < 0) - goto cleanup; - } else { - word = htonl((uint32_t)entry->offset & 0x7fffffffu); - } - - error = git_str_put(&object_offsets, (const char *)&word, sizeof(word)); - if (error < 0) - goto cleanup; - } - - /* Write the header. */ - hdr.packfiles = htonl((uint32_t)git_vector_length(&w->packs)); - hdr.chunks = 4; - if (git_str_len(&object_large_offsets) > 0) - hdr.chunks++; - error = write_cb((const char *)&hdr, sizeof(hdr), cb_data); - if (error < 0) - goto cleanup; - - /* Write the chunk headers. */ - offset = sizeof(hdr) + (hdr.chunks + 1) * 12; - error = write_chunk_header(MIDX_PACKFILE_NAMES_ID, offset, write_cb, cb_data); - if (error < 0) - goto cleanup; - offset += git_str_len(&packfile_names); - error = write_chunk_header(MIDX_OID_FANOUT_ID, offset, write_cb, cb_data); - if (error < 0) - goto cleanup; - offset += sizeof(oid_fanout); - error = write_chunk_header(MIDX_OID_LOOKUP_ID, offset, write_cb, cb_data); - if (error < 0) - goto cleanup; - offset += git_str_len(&oid_lookup); - error = write_chunk_header(MIDX_OBJECT_OFFSETS_ID, offset, write_cb, cb_data); - if (error < 0) - goto cleanup; - offset += git_str_len(&object_offsets); - if (git_str_len(&object_large_offsets) > 0) { - error = write_chunk_header(MIDX_OBJECT_LARGE_OFFSETS_ID, offset, write_cb, cb_data); - if (error < 0) - goto cleanup; - offset += git_str_len(&object_large_offsets); - } - error = write_chunk_header(0, offset, write_cb, cb_data); - if (error < 0) - goto cleanup; - - /* Write all the chunks. */ - error = write_cb(git_str_cstr(&packfile_names), git_str_len(&packfile_names), cb_data); - if (error < 0) - goto cleanup; - error = write_cb((const char *)oid_fanout, sizeof(oid_fanout), cb_data); - if (error < 0) - goto cleanup; - error = write_cb(git_str_cstr(&oid_lookup), git_str_len(&oid_lookup), cb_data); - if (error < 0) - goto cleanup; - error = write_cb(git_str_cstr(&object_offsets), git_str_len(&object_offsets), cb_data); - if (error < 0) - goto cleanup; - error = write_cb(git_str_cstr(&object_large_offsets), git_str_len(&object_large_offsets), cb_data); - if (error < 0) - goto cleanup; - - /* Finalize the checksum and write the trailer. */ - error = git_hash_final(checksum, &ctx); - if (error < 0) - goto cleanup; - error = write_cb((char *)checksum, checksum_size, cb_data); - if (error < 0) - goto cleanup; - -cleanup: - git_array_clear(object_entries_array); - git_vector_free(&object_entries); - git_str_dispose(&packfile_names); - git_str_dispose(&oid_lookup); - git_str_dispose(&object_offsets); - git_str_dispose(&object_large_offsets); - git_hash_ctx_cleanup(&ctx); - return error; -} - -static int midx_write_filebuf(const char *buf, size_t size, void *data) -{ - git_filebuf *f = (git_filebuf *)data; - return git_filebuf_write(f, buf, size); -} - -int git_midx_writer_commit( - git_midx_writer *w) -{ - int error; - int filebuf_flags = GIT_FILEBUF_DO_NOT_BUFFER; - git_str midx_path = GIT_STR_INIT; - git_filebuf output = GIT_FILEBUF_INIT; - - error = git_str_joinpath(&midx_path, git_str_cstr(&w->pack_dir), "multi-pack-index"); - if (error < 0) - return error; - - if (git_repository__fsync_gitdir) - filebuf_flags |= GIT_FILEBUF_FSYNC; - error = git_filebuf_open(&output, git_str_cstr(&midx_path), filebuf_flags, 0644); - git_str_dispose(&midx_path); - if (error < 0) - return error; - - error = midx_write(w, midx_write_filebuf, &output); - if (error < 0) { - git_filebuf_cleanup(&output); - return error; - } - - return git_filebuf_commit(&output); -} - -int git_midx_writer_dump( - git_buf *midx, - git_midx_writer *w) -{ - git_str str = GIT_STR_INIT; - int error; - - if ((error = git_buf_tostr(&str, midx)) < 0 || - (error = midx_write(w, midx_write_buf, &str)) == 0) - error = git_buf_fromstr(midx, &str); - - git_str_dispose(&str); - return error; -} diff --git a/vendor/libgit2/src/net.c b/vendor/libgit2/src/net.c deleted file mode 100644 index a76fd1d7..00000000 --- a/vendor/libgit2/src/net.c +++ /dev/null @@ -1,750 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "net.h" -#include "netops.h" - -#include - -#include "posix.h" -#include "str.h" -#include "http_parser.h" -#include "runtime.h" - -#define DEFAULT_PORT_HTTP "80" -#define DEFAULT_PORT_HTTPS "443" -#define DEFAULT_PORT_GIT "9418" -#define DEFAULT_PORT_SSH "22" - -bool git_net_str_is_url(const char *str) -{ - const char *c; - - for (c = str; *c; c++) { - if (*c == ':' && *(c+1) == '/' && *(c+2) == '/') - return true; - - if ((*c < 'a' || *c > 'z') && - (*c < 'A' || *c > 'Z') && - (*c < '0' || *c > '9') && - (*c != '+' && *c != '-' && *c != '.')) - break; - } - - return false; -} - -static const char *default_port_for_scheme(const char *scheme) -{ - if (strcmp(scheme, "http") == 0) - return DEFAULT_PORT_HTTP; - else if (strcmp(scheme, "https") == 0) - return DEFAULT_PORT_HTTPS; - else if (strcmp(scheme, "git") == 0) - return DEFAULT_PORT_GIT; - else if (strcmp(scheme, "ssh") == 0 || - strcmp(scheme, "ssh+git") == 0 || - strcmp(scheme, "git+ssh") == 0) - return DEFAULT_PORT_SSH; - - return NULL; -} - -int git_net_url_dup(git_net_url *out, git_net_url *in) -{ - if (in->scheme) { - out->scheme = git__strdup(in->scheme); - GIT_ERROR_CHECK_ALLOC(out->scheme); - } - - if (in->host) { - out->host = git__strdup(in->host); - GIT_ERROR_CHECK_ALLOC(out->host); - } - - if (in->port) { - out->port = git__strdup(in->port); - GIT_ERROR_CHECK_ALLOC(out->port); - } - - if (in->path) { - out->path = git__strdup(in->path); - GIT_ERROR_CHECK_ALLOC(out->path); - } - - if (in->query) { - out->query = git__strdup(in->query); - GIT_ERROR_CHECK_ALLOC(out->query); - } - - if (in->username) { - out->username = git__strdup(in->username); - GIT_ERROR_CHECK_ALLOC(out->username); - } - - if (in->password) { - out->password = git__strdup(in->password); - GIT_ERROR_CHECK_ALLOC(out->password); - } - - return 0; -} - -int git_net_url_parse(git_net_url *url, const char *given) -{ - struct http_parser_url u = {0}; - bool has_scheme, has_host, has_port, has_path, has_query, has_userinfo; - git_str scheme = GIT_STR_INIT, - host = GIT_STR_INIT, - port = GIT_STR_INIT, - path = GIT_STR_INIT, - username = GIT_STR_INIT, - password = GIT_STR_INIT, - query = GIT_STR_INIT; - int error = GIT_EINVALIDSPEC; - - if (http_parser_parse_url(given, strlen(given), false, &u)) { - git_error_set(GIT_ERROR_NET, "malformed URL '%s'", given); - goto done; - } - - has_scheme = !!(u.field_set & (1 << UF_SCHEMA)); - has_host = !!(u.field_set & (1 << UF_HOST)); - has_port = !!(u.field_set & (1 << UF_PORT)); - has_path = !!(u.field_set & (1 << UF_PATH)); - has_query = !!(u.field_set & (1 << UF_QUERY)); - has_userinfo = !!(u.field_set & (1 << UF_USERINFO)); - - if (has_scheme) { - const char *url_scheme = given + u.field_data[UF_SCHEMA].off; - size_t url_scheme_len = u.field_data[UF_SCHEMA].len; - git_str_put(&scheme, url_scheme, url_scheme_len); - git__strntolower(scheme.ptr, scheme.size); - } else { - git_error_set(GIT_ERROR_NET, "malformed URL '%s'", given); - goto done; - } - - if (has_host) { - const char *url_host = given + u.field_data[UF_HOST].off; - size_t url_host_len = u.field_data[UF_HOST].len; - git_str_decode_percent(&host, url_host, url_host_len); - } - - if (has_port) { - const char *url_port = given + u.field_data[UF_PORT].off; - size_t url_port_len = u.field_data[UF_PORT].len; - git_str_put(&port, url_port, url_port_len); - } else { - const char *default_port = default_port_for_scheme(scheme.ptr); - - if (default_port == NULL) { - git_error_set(GIT_ERROR_NET, "unknown scheme for URL '%s'", given); - goto done; - } - - git_str_puts(&port, default_port); - } - - if (has_path) { - const char *url_path = given + u.field_data[UF_PATH].off; - size_t url_path_len = u.field_data[UF_PATH].len; - git_str_put(&path, url_path, url_path_len); - } else { - git_str_puts(&path, "/"); - } - - if (has_query) { - const char *url_query = given + u.field_data[UF_QUERY].off; - size_t url_query_len = u.field_data[UF_QUERY].len; - git_str_decode_percent(&query, url_query, url_query_len); - } - - if (has_userinfo) { - const char *url_userinfo = given + u.field_data[UF_USERINFO].off; - size_t url_userinfo_len = u.field_data[UF_USERINFO].len; - const char *colon = memchr(url_userinfo, ':', url_userinfo_len); - - if (colon) { - const char *url_username = url_userinfo; - size_t url_username_len = colon - url_userinfo; - const char *url_password = colon + 1; - size_t url_password_len = url_userinfo_len - (url_username_len + 1); - - git_str_decode_percent(&username, url_username, url_username_len); - git_str_decode_percent(&password, url_password, url_password_len); - } else { - git_str_decode_percent(&username, url_userinfo, url_userinfo_len); - } - } - - if (git_str_oom(&scheme) || - git_str_oom(&host) || - git_str_oom(&port) || - git_str_oom(&path) || - git_str_oom(&query) || - git_str_oom(&username) || - git_str_oom(&password)) - return -1; - - url->scheme = git_str_detach(&scheme); - url->host = git_str_detach(&host); - url->port = git_str_detach(&port); - url->path = git_str_detach(&path); - url->query = git_str_detach(&query); - url->username = git_str_detach(&username); - url->password = git_str_detach(&password); - - error = 0; - -done: - git_str_dispose(&scheme); - git_str_dispose(&host); - git_str_dispose(&port); - git_str_dispose(&path); - git_str_dispose(&query); - git_str_dispose(&username); - git_str_dispose(&password); - return error; -} - -static int scp_invalid(const char *message) -{ - git_error_set(GIT_ERROR_NET, "invalid scp-style path: %s", message); - return GIT_EINVALIDSPEC; -} - -static bool is_ipv6(const char *str) -{ - const char *c; - size_t colons = 0; - - if (*str++ != '[') - return false; - - for (c = str; *c; c++) { - if (*c == ':') - colons++; - - if (*c == ']') - return (colons > 1); - - if (*c != ':' && - (*c < '0' || *c > '9') && - (*c < 'a' || *c > 'f') && - (*c < 'A' || *c > 'F')) - return false; - } - - return false; -} - -static bool has_at(const char *str) -{ - const char *c; - - for (c = str; *c; c++) { - if (*c == '@') - return true; - - if (*c == ':') - break; - } - - return false; -} - -int git_net_url_parse_scp(git_net_url *url, const char *given) -{ - const char *default_port = default_port_for_scheme("ssh"); - const char *c, *user, *host, *port, *path = NULL; - size_t user_len = 0, host_len = 0, port_len = 0; - unsigned short bracket = 0; - - enum { - NONE, - USER, - HOST_START, HOST, HOST_END, - IPV6, IPV6_END, - PORT_START, PORT, PORT_END, - PATH_START - } state = NONE; - - memset(url, 0, sizeof(git_net_url)); - - for (c = given; *c && !path; c++) { - switch (state) { - case NONE: - switch (*c) { - case '@': - return scp_invalid("unexpected '@'"); - case ':': - return scp_invalid("unexpected ':'"); - case '[': - if (is_ipv6(c)) { - state = IPV6; - host = c; - } else if (bracket++ > 1) { - return scp_invalid("unexpected '['"); - } - break; - default: - if (has_at(c)) { - state = USER; - user = c; - } else { - state = HOST; - host = c; - } - break; - } - break; - - case USER: - if (*c == '@') { - user_len = (c - user); - state = HOST_START; - } - break; - - case HOST_START: - state = (*c == '[') ? IPV6 : HOST; - host = c; - break; - - case HOST: - if (*c == ':') { - host_len = (c - host); - state = bracket ? PORT_START : PATH_START; - } else if (*c == ']') { - if (bracket-- == 0) - return scp_invalid("unexpected ']'"); - - host_len = (c - host); - state = HOST_END; - } - break; - - case HOST_END: - if (*c != ':') - return scp_invalid("unexpected character after hostname"); - state = PATH_START; - break; - - case IPV6: - if (*c == ']') - state = IPV6_END; - break; - - case IPV6_END: - if (*c != ':') - return scp_invalid("unexpected character after ipv6 address"); - - host_len = (c - host); - state = bracket ? PORT_START : PATH_START; - break; - - case PORT_START: - port = c; - state = PORT; - break; - - case PORT: - if (*c == ']') { - if (bracket-- == 0) - return scp_invalid("unexpected ']'"); - - port_len = c - port; - state = PORT_END; - } - break; - - case PORT_END: - if (*c != ':') - return scp_invalid("unexpected character after ipv6 address"); - - state = PATH_START; - break; - - case PATH_START: - path = c; - break; - - default: - GIT_ASSERT("unhandled state"); - } - } - - if (!path) - return scp_invalid("path is required"); - - GIT_ERROR_CHECK_ALLOC(url->scheme = git__strdup("ssh")); - - if (user_len) - GIT_ERROR_CHECK_ALLOC(url->username = git__strndup(user, user_len)); - - GIT_ASSERT(host_len); - GIT_ERROR_CHECK_ALLOC(url->host = git__strndup(host, host_len)); - - if (port_len) - GIT_ERROR_CHECK_ALLOC(url->port = git__strndup(port, port_len)); - else - GIT_ERROR_CHECK_ALLOC(url->port = git__strdup(default_port)); - - GIT_ASSERT(path); - GIT_ERROR_CHECK_ALLOC(url->path = git__strdup(path)); - - return 0; -} - -int git_net_url_joinpath( - git_net_url *out, - git_net_url *one, - const char *two) -{ - git_str path = GIT_STR_INIT; - const char *query; - size_t one_len, two_len; - - git_net_url_dispose(out); - - if ((query = strchr(two, '?')) != NULL) { - two_len = query - two; - - if (*(++query) != '\0') { - out->query = git__strdup(query); - GIT_ERROR_CHECK_ALLOC(out->query); - } - } else { - two_len = strlen(two); - } - - /* Strip all trailing `/`s from the first path */ - one_len = one->path ? strlen(one->path) : 0; - while (one_len && one->path[one_len - 1] == '/') - one_len--; - - /* Strip all leading `/`s from the second path */ - while (*two == '/') { - two++; - two_len--; - } - - git_str_put(&path, one->path, one_len); - git_str_putc(&path, '/'); - git_str_put(&path, two, two_len); - - if (git_str_oom(&path)) - return -1; - - out->path = git_str_detach(&path); - - if (one->scheme) { - out->scheme = git__strdup(one->scheme); - GIT_ERROR_CHECK_ALLOC(out->scheme); - } - - if (one->host) { - out->host = git__strdup(one->host); - GIT_ERROR_CHECK_ALLOC(out->host); - } - - if (one->port) { - out->port = git__strdup(one->port); - GIT_ERROR_CHECK_ALLOC(out->port); - } - - if (one->username) { - out->username = git__strdup(one->username); - GIT_ERROR_CHECK_ALLOC(out->username); - } - - if (one->password) { - out->password = git__strdup(one->password); - GIT_ERROR_CHECK_ALLOC(out->password); - } - - return 0; -} - -/* - * Some servers strip the query parameters from the Location header - * when sending a redirect. Others leave it in place. - * Check for both, starting with the stripped case first, - * since it appears to be more common. - */ -static void remove_service_suffix( - git_net_url *url, - const char *service_suffix) -{ - const char *service_query = strchr(service_suffix, '?'); - size_t full_suffix_len = strlen(service_suffix); - size_t suffix_len = service_query ? - (size_t)(service_query - service_suffix) : full_suffix_len; - size_t path_len = strlen(url->path); - ssize_t truncate = -1; - - /* - * Check for a redirect without query parameters, - * like "/newloc/info/refs"' - */ - if (suffix_len && path_len >= suffix_len) { - size_t suffix_offset = path_len - suffix_len; - - if (git__strncmp(url->path + suffix_offset, service_suffix, suffix_len) == 0 && - (!service_query || git__strcmp(url->query, service_query + 1) == 0)) { - truncate = suffix_offset; - } - } - - /* - * If we haven't already found where to truncate to remove the - * suffix, check for a redirect with query parameters, like - * "/newloc/info/refs?service=git-upload-pack" - */ - if (truncate < 0 && git__suffixcmp(url->path, service_suffix) == 0) - truncate = path_len - full_suffix_len; - - /* Ensure we leave a minimum of '/' as the path */ - if (truncate == 0) - truncate++; - - if (truncate > 0) { - url->path[truncate] = '\0'; - - git__free(url->query); - url->query = NULL; - } -} - -int git_net_url_apply_redirect( - git_net_url *url, - const char *redirect_location, - bool allow_offsite, - const char *service_suffix) -{ - git_net_url tmp = GIT_NET_URL_INIT; - int error = 0; - - GIT_ASSERT(url); - GIT_ASSERT(redirect_location); - - if (redirect_location[0] == '/') { - git__free(url->path); - - if ((url->path = git__strdup(redirect_location)) == NULL) { - error = -1; - goto done; - } - } else { - git_net_url *original = url; - - if ((error = git_net_url_parse(&tmp, redirect_location)) < 0) - goto done; - - /* Validate that this is a legal redirection */ - - if (original->scheme && - strcmp(original->scheme, tmp.scheme) != 0 && - strcmp(tmp.scheme, "https") != 0) { - git_error_set(GIT_ERROR_NET, "cannot redirect from '%s' to '%s'", - original->scheme, tmp.scheme); - - error = -1; - goto done; - } - - if (original->host && - !allow_offsite && - git__strcasecmp(original->host, tmp.host) != 0) { - git_error_set(GIT_ERROR_NET, "cannot redirect from '%s' to '%s'", - original->host, tmp.host); - - error = -1; - goto done; - } - - git_net_url_swap(url, &tmp); - } - - /* Remove the service suffix if it was given to us */ - if (service_suffix) - remove_service_suffix(url, service_suffix); - -done: - git_net_url_dispose(&tmp); - return error; -} - -bool git_net_url_valid(git_net_url *url) -{ - return (url->host && url->port && url->path); -} - -bool git_net_url_is_default_port(git_net_url *url) -{ - const char *default_port; - - if ((default_port = default_port_for_scheme(url->scheme)) != NULL) - return (strcmp(url->port, default_port) == 0); - else - return false; -} - -bool git_net_url_is_ipv6(git_net_url *url) -{ - return (strchr(url->host, ':') != NULL); -} - -void git_net_url_swap(git_net_url *a, git_net_url *b) -{ - git_net_url tmp = GIT_NET_URL_INIT; - - memcpy(&tmp, a, sizeof(git_net_url)); - memcpy(a, b, sizeof(git_net_url)); - memcpy(b, &tmp, sizeof(git_net_url)); -} - -int git_net_url_fmt(git_str *buf, git_net_url *url) -{ - GIT_ASSERT_ARG(url); - GIT_ASSERT_ARG(url->scheme); - GIT_ASSERT_ARG(url->host); - - git_str_puts(buf, url->scheme); - git_str_puts(buf, "://"); - - if (url->username) { - git_str_puts(buf, url->username); - - if (url->password) { - git_str_puts(buf, ":"); - git_str_puts(buf, url->password); - } - - git_str_putc(buf, '@'); - } - - git_str_puts(buf, url->host); - - if (url->port && !git_net_url_is_default_port(url)) { - git_str_putc(buf, ':'); - git_str_puts(buf, url->port); - } - - git_str_puts(buf, url->path ? url->path : "/"); - - if (url->query) { - git_str_putc(buf, '?'); - git_str_puts(buf, url->query); - } - - return git_str_oom(buf) ? -1 : 0; -} - -int git_net_url_fmt_path(git_str *buf, git_net_url *url) -{ - git_str_puts(buf, url->path ? url->path : "/"); - - if (url->query) { - git_str_putc(buf, '?'); - git_str_puts(buf, url->query); - } - - return git_str_oom(buf) ? -1 : 0; -} - -static bool matches_pattern( - git_net_url *url, - const char *pattern, - size_t pattern_len) -{ - const char *domain, *port = NULL, *colon; - size_t host_len, domain_len, port_len = 0, wildcard = 0; - - GIT_UNUSED(url); - GIT_UNUSED(pattern); - - if (!pattern_len) - return false; - else if (pattern_len == 1 && pattern[0] == '*') - return true; - else if (pattern_len > 1 && pattern[0] == '*' && pattern[1] == '.') - wildcard = 2; - else if (pattern[0] == '.') - wildcard = 1; - - domain = pattern + wildcard; - domain_len = pattern_len - wildcard; - - if ((colon = memchr(domain, ':', domain_len)) != NULL) { - domain_len = colon - domain; - port = colon + 1; - port_len = pattern_len - wildcard - domain_len - 1; - } - - /* A pattern's port *must* match if it's specified */ - if (port_len && git__strlcmp(url->port, port, port_len) != 0) - return false; - - /* No wildcard? Host must match exactly. */ - if (!wildcard) - return !git__strlcmp(url->host, domain, domain_len); - - /* Wildcard: ensure there's (at least) a suffix match */ - if ((host_len = strlen(url->host)) < domain_len || - memcmp(url->host + (host_len - domain_len), domain, domain_len)) - return false; - - /* The pattern is *.domain and the host is simply domain */ - if (host_len == domain_len) - return true; - - /* The pattern is *.domain and the host is foo.domain */ - return (url->host[host_len - domain_len - 1] == '.'); -} - -bool git_net_url_matches_pattern(git_net_url *url, const char *pattern) -{ - return matches_pattern(url, pattern, strlen(pattern)); -} - -bool git_net_url_matches_pattern_list( - git_net_url *url, - const char *pattern_list) -{ - const char *pattern, *pattern_end, *sep; - - for (pattern = pattern_list; - pattern && *pattern; - pattern = sep ? sep + 1 : NULL) { - sep = strchr(pattern, ','); - pattern_end = sep ? sep : strchr(pattern, '\0'); - - if (matches_pattern(url, pattern, (pattern_end - pattern))) - return true; - } - - return false; -} - -void git_net_url_dispose(git_net_url *url) -{ - if (url->username) - git__memzero(url->username, strlen(url->username)); - - if (url->password) - git__memzero(url->password, strlen(url->password)); - - git__free(url->scheme); url->scheme = NULL; - git__free(url->host); url->host = NULL; - git__free(url->port); url->port = NULL; - git__free(url->path); url->path = NULL; - git__free(url->query); url->query = NULL; - git__free(url->username); url->username = NULL; - git__free(url->password); url->password = NULL; -} diff --git a/vendor/libgit2/src/net.h b/vendor/libgit2/src/net.h deleted file mode 100644 index 499315e6..00000000 --- a/vendor/libgit2/src/net.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_net_h__ -#define INCLUDE_net_h__ - -#include "common.h" - -typedef struct git_net_url { - char *scheme; - char *host; - char *port; - char *path; - char *query; - char *username; - char *password; -} git_net_url; - -#define GIT_NET_URL_INIT { NULL } - -/** Is a given string a url? */ -extern bool git_net_str_is_url(const char *str); - -/** Duplicate a URL */ -extern int git_net_url_dup(git_net_url *out, git_net_url *in); - -/** Parses a string containing a URL into a structure. */ -extern int git_net_url_parse(git_net_url *url, const char *str); - -/** Parses a string containing an SCP style path into a URL structure. */ -extern int git_net_url_parse_scp(git_net_url *url, const char *str); - -/** Appends a path and/or query string to the given URL */ -extern int git_net_url_joinpath( - git_net_url *out, - git_net_url *in, - const char *path); - -/** Ensures that a URL is minimally valid (contains a host, port and path) */ -extern bool git_net_url_valid(git_net_url *url); - -/** Returns true if the URL is on the default port. */ -extern bool git_net_url_is_default_port(git_net_url *url); - -/** Returns true if the host portion of the URL is an ipv6 address. */ -extern bool git_net_url_is_ipv6(git_net_url *url); - -/* Applies a redirect to the URL with a git-aware service suffix. */ -extern int git_net_url_apply_redirect( - git_net_url *url, - const char *redirect_location, - bool allow_offsite, - const char *service_suffix); - -/** Swaps the contents of one URL for another. */ -extern void git_net_url_swap(git_net_url *a, git_net_url *b); - -/** Places the URL into the given buffer. */ -extern int git_net_url_fmt(git_str *out, git_net_url *url); - -/** Place the path and query string into the given buffer. */ -extern int git_net_url_fmt_path(git_str *buf, git_net_url *url); - -/** Determines if the url matches given pattern or pattern list */ -extern bool git_net_url_matches_pattern( - git_net_url *url, - const char *pattern); -extern bool git_net_url_matches_pattern_list( - git_net_url *url, - const char *pattern_list); - -/** Disposes the contents of the structure. */ -extern void git_net_url_dispose(git_net_url *url); - -#endif diff --git a/vendor/libgit2/src/netops.c b/vendor/libgit2/src/netops.c deleted file mode 100644 index 0a27365b..00000000 --- a/vendor/libgit2/src/netops.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "netops.h" - -#include -#include "git2/errors.h" - -#include "posix.h" -#include "str.h" -#include "http_parser.h" -#include "runtime.h" - -int gitno_recv(gitno_buffer *buf) -{ - return buf->recv(buf); -} - -void gitno_buffer_setup_callback( - gitno_buffer *buf, - char *data, - size_t len, - int (*recv)(gitno_buffer *buf), void *cb_data) -{ - memset(data, 0x0, len); - buf->data = data; - buf->len = len; - buf->offset = 0; - buf->recv = recv; - buf->cb_data = cb_data; -} - -static int recv_stream(gitno_buffer *buf) -{ - git_stream *io = (git_stream *) buf->cb_data; - size_t readlen = buf->len - buf->offset; - ssize_t ret; - - readlen = min(readlen, INT_MAX); - - ret = git_stream_read(io, buf->data + buf->offset, (int)readlen); - if (ret < 0) - return -1; - - buf->offset += ret; - return (int)ret; -} - -void gitno_buffer_setup_fromstream(git_stream *st, gitno_buffer *buf, char *data, size_t len) -{ - memset(data, 0x0, len); - buf->data = data; - buf->len = len; - buf->offset = 0; - buf->recv = recv_stream; - buf->cb_data = st; -} - -/* Consume up to ptr and move the rest of the buffer to the beginning */ -int gitno_consume(gitno_buffer *buf, const char *ptr) -{ - size_t consumed; - - GIT_ASSERT(ptr - buf->data >= 0); - GIT_ASSERT(ptr - buf->data <= (int) buf->len); - - consumed = ptr - buf->data; - - memmove(buf->data, ptr, buf->offset - consumed); - memset(buf->data + buf->offset, 0x0, buf->len - buf->offset); - buf->offset -= consumed; - - return 0; -} - -/* Consume const bytes and move the rest of the buffer to the beginning */ -void gitno_consume_n(gitno_buffer *buf, size_t cons) -{ - memmove(buf->data, buf->data + cons, buf->len - buf->offset); - memset(buf->data + cons, 0x0, buf->len - buf->offset); - buf->offset -= cons; -} - -/* Match host names according to RFC 2818 rules */ -int gitno__match_host(const char *pattern, const char *host) -{ - for (;;) { - char c = git__tolower(*pattern++); - - if (c == '\0') - return *host ? -1 : 0; - - if (c == '*') { - c = *pattern; - /* '*' at the end matches everything left */ - if (c == '\0') - return 0; - - /* - * We've found a pattern, so move towards the next matching - * char. The '.' is handled specially because wildcards aren't - * allowed to cross subdomains. - */ - - while(*host) { - char h = git__tolower(*host); - if (c == h) - return gitno__match_host(pattern, host++); - if (h == '.') - return gitno__match_host(pattern, host); - host++; - } - return -1; - } - - if (c != git__tolower(*host++)) - return -1; - } - - return -1; -} diff --git a/vendor/libgit2/src/netops.h b/vendor/libgit2/src/netops.h deleted file mode 100644 index 56f96853..00000000 --- a/vendor/libgit2/src/netops.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_netops_h__ -#define INCLUDE_netops_h__ - -#include "common.h" - -#include "posix.h" -#include "stream.h" -#include "net.h" - -#ifdef GIT_OPENSSL -# include "streams/openssl.h" -#endif - -typedef struct gitno_ssl { -#ifdef GIT_OPENSSL - SSL *ssl; -#else - size_t dummy; -#endif -} gitno_ssl; - -/* Represents a socket that may or may not be using SSL */ -typedef struct gitno_socket { - GIT_SOCKET socket; - gitno_ssl ssl; -} gitno_socket; - -typedef struct gitno_buffer { - char *data; - size_t len; - size_t offset; - int (*recv)(struct gitno_buffer *buffer); - void *cb_data; -} gitno_buffer; - -/* Flags to gitno_connect */ -enum { - /* Attempt to create an SSL connection. */ - GITNO_CONNECT_SSL = 1 -}; - -/** - * Check if the name in a cert matches the wanted hostname - * - * Check if a pattern from a certificate matches the hostname we - * wanted to connect to according to RFC2818 rules (which specifies - * HTTP over TLS). Mainly, an asterisk matches anything, but is - * limited to a single url component. - * - * Note that this does not set an error message. It expects the user - * to provide the message for the user. - */ -int gitno__match_host(const char *pattern, const char *host); - -void gitno_buffer_setup_fromstream(git_stream *st, gitno_buffer *buf, char *data, size_t len); -void gitno_buffer_setup_callback(gitno_buffer *buf, char *data, size_t len, int (*recv)(gitno_buffer *buf), void *cb_data); -int gitno_recv(gitno_buffer *buf); - -int gitno_consume(gitno_buffer *buf, const char *ptr); -void gitno_consume_n(gitno_buffer *buf, size_t cons); - -#endif diff --git a/vendor/libgit2/src/notes.c b/vendor/libgit2/src/notes.c deleted file mode 100644 index d1a2b0f6..00000000 --- a/vendor/libgit2/src/notes.c +++ /dev/null @@ -1,809 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "notes.h" - -#include "buf.h" -#include "refs.h" -#include "config.h" -#include "iterator.h" -#include "signature.h" -#include "blob.h" - -static int note_error_notfound(void) -{ - git_error_set(GIT_ERROR_INVALID, "note could not be found"); - return GIT_ENOTFOUND; -} - -static int find_subtree_in_current_level( - git_tree **out, - git_repository *repo, - git_tree *parent, - const char *annotated_object_sha, - int fanout) -{ - size_t i; - const git_tree_entry *entry; - - *out = NULL; - - if (parent == NULL) - return note_error_notfound(); - - for (i = 0; i < git_tree_entrycount(parent); i++) { - entry = git_tree_entry_byindex(parent, i); - - if (!git__ishex(git_tree_entry_name(entry))) - continue; - - if (S_ISDIR(git_tree_entry_filemode(entry)) - && strlen(git_tree_entry_name(entry)) == 2 - && !strncmp(git_tree_entry_name(entry), annotated_object_sha + fanout, 2)) - return git_tree_lookup(out, repo, git_tree_entry_id(entry)); - - /* Not a DIR, so do we have an already existing blob? */ - if (!strcmp(git_tree_entry_name(entry), annotated_object_sha + fanout)) - return GIT_EEXISTS; - } - - return note_error_notfound(); -} - -static int find_subtree_r(git_tree **out, git_tree *root, - git_repository *repo, const char *target, int *fanout) -{ - int error; - git_tree *subtree = NULL; - - *out = NULL; - - error = find_subtree_in_current_level(&subtree, repo, root, target, *fanout); - if (error == GIT_EEXISTS) - return git_tree_lookup(out, repo, git_tree_id(root)); - - if (error < 0) - return error; - - *fanout += 2; - error = find_subtree_r(out, subtree, repo, target, fanout); - git_tree_free(subtree); - - return error; -} - -static int find_blob(git_oid *blob, git_tree *tree, const char *target) -{ - size_t i; - const git_tree_entry *entry; - - for (i=0; iid, note_oid); - - if (git_signature_dup(¬e->author, git_commit_author(commit)) < 0 || - git_signature_dup(¬e->committer, git_commit_committer(commit)) < 0) - return -1; - - blobsize = git_blob_rawsize(blob); - GIT_ERROR_CHECK_BLOBSIZE(blobsize); - - note->message = git__strndup(git_blob_rawcontent(blob), (size_t)blobsize); - GIT_ERROR_CHECK_ALLOC(note->message); - - *out = note; - return 0; -} - -static int note_lookup( - git_note **out, - git_repository *repo, - git_commit *commit, - git_tree *tree, - const char *target) -{ - int error, fanout = 0; - git_oid oid; - git_blob *blob = NULL; - git_note *note = NULL; - git_tree *subtree = NULL; - - if ((error = find_subtree_r(&subtree, tree, repo, target, &fanout)) < 0) - goto cleanup; - - if ((error = find_blob(&oid, subtree, target + fanout)) < 0) - goto cleanup; - - if ((error = git_blob_lookup(&blob, repo, &oid)) < 0) - goto cleanup; - - if ((error = note_new(¬e, &oid, commit, blob)) < 0) - goto cleanup; - - *out = note; - -cleanup: - git_tree_free(subtree); - git_blob_free(blob); - return error; -} - -static int note_remove( - git_oid *notes_commit_out, - git_repository *repo, - const git_signature *author, const git_signature *committer, - const char *notes_ref, git_tree *tree, - const char *target, git_commit **parents) -{ - int error; - git_tree *tree_after_removal = NULL; - git_oid oid; - - if ((error = manipulate_note_in_tree_r( - &tree_after_removal, repo, tree, NULL, target, 0, - remove_note_in_tree_eexists_cb, remove_note_in_tree_enotfound_cb)) < 0) - goto cleanup; - - error = git_commit_create(&oid, repo, notes_ref, author, committer, - NULL, GIT_NOTES_DEFAULT_MSG_RM, - tree_after_removal, - *parents == NULL ? 0 : 1, - (const git_commit **) parents); - - if (error < 0) - goto cleanup; - - if (notes_commit_out) - git_oid_cpy(notes_commit_out, &oid); - -cleanup: - git_tree_free(tree_after_removal); - return error; -} - -static int note_get_default_ref(git_str *out, git_repository *repo) -{ - git_config *cfg; - int error; - - if ((error = git_repository_config__weakptr(&cfg, repo)) < 0) - return error; - - error = git_config__get_string_buf(out, cfg, "core.notesref"); - - if (error == GIT_ENOTFOUND) - error = git_str_puts(out, GIT_NOTES_DEFAULT_REF); - - return error; -} - -static int normalize_namespace(git_str *out, git_repository *repo, const char *notes_ref) -{ - if (notes_ref) - return git_str_puts(out, notes_ref); - - return note_get_default_ref(out, repo); -} - -static int retrieve_note_commit( - git_commit **commit_out, - git_str *notes_ref_out, - git_repository *repo, - const char *notes_ref) -{ - int error; - git_oid oid; - - if ((error = normalize_namespace(notes_ref_out, repo, notes_ref)) < 0) - return error; - - if ((error = git_reference_name_to_id(&oid, repo, notes_ref_out->ptr)) < 0) - return error; - - if (git_commit_lookup(commit_out, repo, &oid) < 0) - return error; - - return 0; -} - -int git_note_commit_read( - git_note **out, - git_repository *repo, - git_commit *notes_commit, - const git_oid *oid) -{ - int error; - git_tree *tree = NULL; - char target[GIT_OID_HEXSZ + 1]; - - git_oid_tostr(target, sizeof(target), oid); - - if ((error = git_commit_tree(&tree, notes_commit)) < 0) - goto cleanup; - - error = note_lookup(out, repo, notes_commit, tree, target); - -cleanup: - git_tree_free(tree); - return error; -} - -int git_note_read(git_note **out, git_repository *repo, - const char *notes_ref_in, const git_oid *oid) -{ - int error; - git_str notes_ref = GIT_STR_INIT; - git_commit *commit = NULL; - - error = retrieve_note_commit(&commit, ¬es_ref, repo, notes_ref_in); - - if (error < 0) - goto cleanup; - - error = git_note_commit_read(out, repo, commit, oid); - -cleanup: - git_str_dispose(¬es_ref); - git_commit_free(commit); - return error; -} - -int git_note_commit_create( - git_oid *notes_commit_out, - git_oid *notes_blob_out, - git_repository *repo, - git_commit *parent, - const git_signature *author, - const git_signature *committer, - const git_oid *oid, - const char *note, - int allow_note_overwrite) -{ - int error; - git_tree *tree = NULL; - char target[GIT_OID_HEXSZ + 1]; - - git_oid_tostr(target, sizeof(target), oid); - - if (parent != NULL && (error = git_commit_tree(&tree, parent)) < 0) - goto cleanup; - - error = note_write(notes_commit_out, notes_blob_out, repo, author, - committer, NULL, note, tree, target, &parent, allow_note_overwrite); - - if (error < 0) - goto cleanup; - -cleanup: - git_tree_free(tree); - return error; -} - -int git_note_create( - git_oid *out, - git_repository *repo, - const char *notes_ref_in, - const git_signature *author, - const git_signature *committer, - const git_oid *oid, - const char *note, - int allow_note_overwrite) -{ - int error; - git_str notes_ref = GIT_STR_INIT; - git_commit *existing_notes_commit = NULL; - git_reference *ref = NULL; - git_oid notes_blob_oid, notes_commit_oid; - - error = retrieve_note_commit(&existing_notes_commit, ¬es_ref, - repo, notes_ref_in); - - if (error < 0 && error != GIT_ENOTFOUND) - goto cleanup; - - error = git_note_commit_create(¬es_commit_oid, - ¬es_blob_oid, - repo, existing_notes_commit, author, - committer, oid, note, - allow_note_overwrite); - if (error < 0) - goto cleanup; - - error = git_reference_create(&ref, repo, notes_ref.ptr, - ¬es_commit_oid, 1, NULL); - - if (out != NULL) - git_oid_cpy(out, ¬es_blob_oid); - -cleanup: - git_str_dispose(¬es_ref); - git_commit_free(existing_notes_commit); - git_reference_free(ref); - return error; -} - -int git_note_commit_remove( - git_oid *notes_commit_out, - git_repository *repo, - git_commit *notes_commit, - const git_signature *author, - const git_signature *committer, - const git_oid *oid) -{ - int error; - git_tree *tree = NULL; - char target[GIT_OID_HEXSZ + 1]; - - git_oid_tostr(target, sizeof(target), oid); - - if ((error = git_commit_tree(&tree, notes_commit)) < 0) - goto cleanup; - - error = note_remove(notes_commit_out, - repo, author, committer, NULL, tree, target, ¬es_commit); - -cleanup: - git_tree_free(tree); - return error; -} - -int git_note_remove(git_repository *repo, const char *notes_ref_in, - const git_signature *author, const git_signature *committer, - const git_oid *oid) -{ - int error; - git_str notes_ref_target = GIT_STR_INIT; - git_commit *existing_notes_commit = NULL; - git_oid new_notes_commit; - git_reference *notes_ref = NULL; - - error = retrieve_note_commit(&existing_notes_commit, ¬es_ref_target, - repo, notes_ref_in); - - if (error < 0) - goto cleanup; - - error = git_note_commit_remove(&new_notes_commit, repo, - existing_notes_commit, author, committer, oid); - if (error < 0) - goto cleanup; - - error = git_reference_create(¬es_ref, repo, notes_ref_target.ptr, - &new_notes_commit, 1, NULL); - -cleanup: - git_str_dispose(¬es_ref_target); - git_reference_free(notes_ref); - git_commit_free(existing_notes_commit); - return error; -} - -int git_note_default_ref(git_buf *out, git_repository *repo) -{ - GIT_BUF_WRAP_PRIVATE(out, note_get_default_ref, repo); -} - -const git_signature *git_note_committer(const git_note *note) -{ - GIT_ASSERT_ARG_WITH_RETVAL(note, NULL); - return note->committer; -} - -const git_signature *git_note_author(const git_note *note) -{ - GIT_ASSERT_ARG_WITH_RETVAL(note, NULL); - return note->author; -} - -const char *git_note_message(const git_note *note) -{ - GIT_ASSERT_ARG_WITH_RETVAL(note, NULL); - return note->message; -} - -const git_oid *git_note_id(const git_note *note) -{ - GIT_ASSERT_ARG_WITH_RETVAL(note, NULL); - return ¬e->id; -} - -void git_note_free(git_note *note) -{ - if (note == NULL) - return; - - git_signature_free(note->committer); - git_signature_free(note->author); - git__free(note->message); - git__free(note); -} - -static int process_entry_path( - const char *entry_path, - git_oid *annotated_object_id) -{ - int error = 0; - size_t i = 0, j = 0, len; - git_str buf = GIT_STR_INIT; - - if ((error = git_str_puts(&buf, entry_path)) < 0) - goto cleanup; - - len = git_str_len(&buf); - - while (i < len) { - if (buf.ptr[i] == '/') { - i++; - continue; - } - - if (git__fromhex(buf.ptr[i]) < 0) { - /* This is not a note entry */ - goto cleanup; - } - - if (i != j) - buf.ptr[j] = buf.ptr[i]; - - i++; - j++; - } - - buf.ptr[j] = '\0'; - buf.size = j; - - if (j != GIT_OID_HEXSZ) { - /* This is not a note entry */ - goto cleanup; - } - - error = git_oid_fromstr(annotated_object_id, buf.ptr); - -cleanup: - git_str_dispose(&buf); - return error; -} - -int git_note_foreach( - git_repository *repo, - const char *notes_ref, - git_note_foreach_cb note_cb, - void *payload) -{ - int error; - git_note_iterator *iter = NULL; - git_oid note_id, annotated_id; - - if ((error = git_note_iterator_new(&iter, repo, notes_ref)) < 0) - return error; - - while (!(error = git_note_next(¬e_id, &annotated_id, iter))) { - if ((error = note_cb(¬e_id, &annotated_id, payload)) != 0) { - git_error_set_after_callback(error); - break; - } - } - - if (error == GIT_ITEROVER) - error = 0; - - git_note_iterator_free(iter); - return error; -} - -void git_note_iterator_free(git_note_iterator *it) -{ - if (it == NULL) - return; - - git_iterator_free(it); -} - -int git_note_commit_iterator_new( - git_note_iterator **it, - git_commit *notes_commit) -{ - int error; - git_tree *tree; - - if ((error = git_commit_tree(&tree, notes_commit)) < 0) - goto cleanup; - - if ((error = git_iterator_for_tree(it, tree, NULL)) < 0) - git_iterator_free(*it); - -cleanup: - git_tree_free(tree); - - return error; -} - -int git_note_iterator_new( - git_note_iterator **it, - git_repository *repo, - const char *notes_ref_in) -{ - int error; - git_commit *commit = NULL; - git_str notes_ref = GIT_STR_INIT; - - error = retrieve_note_commit(&commit, ¬es_ref, repo, notes_ref_in); - if (error < 0) - goto cleanup; - - error = git_note_commit_iterator_new(it, commit); - -cleanup: - git_str_dispose(¬es_ref); - git_commit_free(commit); - - return error; -} - -int git_note_next( - git_oid *note_id, - git_oid *annotated_id, - git_note_iterator *it) -{ - int error; - const git_index_entry *item; - - if ((error = git_iterator_current(&item, it)) < 0) - return error; - - git_oid_cpy(note_id, &item->id); - - if ((error = process_entry_path(item->path, annotated_id)) < 0) - return error; - - if ((error = git_iterator_advance(NULL, it)) < 0 && error != GIT_ITEROVER) - return error; - - return 0; -} diff --git a/vendor/libgit2/src/oid.c b/vendor/libgit2/src/oid.c deleted file mode 100644 index 19061e89..00000000 --- a/vendor/libgit2/src/oid.c +++ /dev/null @@ -1,463 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "oid.h" - -#include "git2/oid.h" -#include "repository.h" -#include "threadstate.h" -#include -#include - -const git_oid git_oid__empty_blob_sha1 = - {{ 0xe6, 0x9d, 0xe2, 0x9b, 0xb2, 0xd1, 0xd6, 0x43, 0x4b, 0x8b, - 0x29, 0xae, 0x77, 0x5a, 0xd8, 0xc2, 0xe4, 0x8c, 0x53, 0x91 }}; -const git_oid git_oid__empty_tree_sha1 = - {{ 0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60, - 0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04 }}; - -static char to_hex[] = "0123456789abcdef"; - -static int oid_error_invalid(const char *msg) -{ - git_error_set(GIT_ERROR_INVALID, "unable to parse OID - %s", msg); - return -1; -} - -int git_oid_fromstrn(git_oid *out, const char *str, size_t length) -{ - size_t p; - int v; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(str); - - if (!length) - return oid_error_invalid("too short"); - - if (length > GIT_OID_HEXSZ) - return oid_error_invalid("too long"); - - memset(out->id, 0, GIT_OID_RAWSZ); - - for (p = 0; p < length; p++) { - v = git__fromhex(str[p]); - if (v < 0) - return oid_error_invalid("contains invalid characters"); - - out->id[p / 2] |= (unsigned char)(v << (p % 2 ? 0 : 4)); - } - - return 0; -} - -int git_oid_fromstrp(git_oid *out, const char *str) -{ - return git_oid_fromstrn(out, str, strlen(str)); -} - -int git_oid_fromstr(git_oid *out, const char *str) -{ - return git_oid_fromstrn(out, str, GIT_OID_HEXSZ); -} - -GIT_INLINE(char) *fmt_one(char *str, unsigned int val) -{ - *str++ = to_hex[val >> 4]; - *str++ = to_hex[val & 0xf]; - return str; -} - -int git_oid_nfmt(char *str, size_t n, const git_oid *oid) -{ - size_t i, max_i; - - if (!oid) { - memset(str, 0, n); - return 0; - } - if (n > GIT_OID_HEXSZ) { - memset(&str[GIT_OID_HEXSZ], 0, n - GIT_OID_HEXSZ); - n = GIT_OID_HEXSZ; - } - - max_i = n / 2; - - for (i = 0; i < max_i; i++) - str = fmt_one(str, oid->id[i]); - - if (n & 1) - *str++ = to_hex[oid->id[i] >> 4]; - - return 0; -} - -int git_oid_fmt(char *str, const git_oid *oid) -{ - return git_oid_nfmt(str, GIT_OID_HEXSZ, oid); -} - -int git_oid_pathfmt(char *str, const git_oid *oid) -{ - size_t i; - - str = fmt_one(str, oid->id[0]); - *str++ = '/'; - for (i = 1; i < sizeof(oid->id); i++) - str = fmt_one(str, oid->id[i]); - - return 0; -} - -char *git_oid_tostr_s(const git_oid *oid) -{ - char *str = GIT_THREADSTATE->oid_fmt; - git_oid_nfmt(str, GIT_OID_HEXSZ + 1, oid); - return str; -} - -char *git_oid_allocfmt(const git_oid *oid) -{ - char *str = git__malloc(GIT_OID_HEXSZ + 1); - if (!str) - return NULL; - git_oid_nfmt(str, GIT_OID_HEXSZ + 1, oid); - return str; -} - -char *git_oid_tostr(char *out, size_t n, const git_oid *oid) -{ - if (!out || n == 0) - return ""; - - if (n > GIT_OID_HEXSZ + 1) - n = GIT_OID_HEXSZ + 1; - - git_oid_nfmt(out, n - 1, oid); /* allow room for terminating NUL */ - out[n - 1] = '\0'; - - return out; -} - -int git_oid__parse( - git_oid *oid, const char **buffer_out, - const char *buffer_end, const char *header) -{ - const size_t sha_len = GIT_OID_HEXSZ; - const size_t header_len = strlen(header); - - const char *buffer = *buffer_out; - - if (buffer + (header_len + sha_len + 1) > buffer_end) - return -1; - - if (memcmp(buffer, header, header_len) != 0) - return -1; - - if (buffer[header_len + sha_len] != '\n') - return -1; - - if (git_oid_fromstr(oid, buffer + header_len) < 0) - return -1; - - *buffer_out = buffer + (header_len + sha_len + 1); - - return 0; -} - -void git_oid__writebuf(git_str *buf, const char *header, const git_oid *oid) -{ - char hex_oid[GIT_OID_HEXSZ]; - - git_oid_fmt(hex_oid, oid); - git_str_puts(buf, header); - git_str_put(buf, hex_oid, GIT_OID_HEXSZ); - git_str_putc(buf, '\n'); -} - -int git_oid_fromraw(git_oid *out, const unsigned char *raw) -{ - memcpy(out->id, raw, sizeof(out->id)); - return 0; -} - -int git_oid_cpy(git_oid *out, const git_oid *src) -{ - memcpy(out->id, src->id, sizeof(out->id)); - return 0; -} - -int git_oid_cmp(const git_oid *a, const git_oid *b) -{ - return git_oid__cmp(a, b); -} - -int git_oid_equal(const git_oid *a, const git_oid *b) -{ - return (git_oid__cmp(a, b) == 0); -} - -int git_oid_ncmp(const git_oid *oid_a, const git_oid *oid_b, size_t len) -{ - const unsigned char *a = oid_a->id; - const unsigned char *b = oid_b->id; - - if (len > GIT_OID_HEXSZ) - len = GIT_OID_HEXSZ; - - while (len > 1) { - if (*a != *b) - return 1; - a++; - b++; - len -= 2; - }; - - if (len) - if ((*a ^ *b) & 0xf0) - return 1; - - return 0; -} - -int git_oid_strcmp(const git_oid *oid_a, const char *str) -{ - const unsigned char *a; - unsigned char strval; - int hexval; - - for (a = oid_a->id; *str && (a - oid_a->id) < GIT_OID_RAWSZ; ++a) { - if ((hexval = git__fromhex(*str++)) < 0) - return -1; - strval = (unsigned char)(hexval << 4); - if (*str) { - if ((hexval = git__fromhex(*str++)) < 0) - return -1; - strval |= hexval; - } - if (*a != strval) - return (*a - strval); - } - - return 0; -} - -int git_oid_streq(const git_oid *oid_a, const char *str) -{ - return git_oid_strcmp(oid_a, str) == 0 ? 0 : -1; -} - -int git_oid_is_zero(const git_oid *oid_a) -{ - const unsigned char *a = oid_a->id; - unsigned int i; - for (i = 0; i < GIT_OID_RAWSZ; ++i, ++a) - if (*a != 0) - return 0; - return 1; -} - -#ifndef GIT_DEPRECATE_HARD -int git_oid_iszero(const git_oid *oid_a) -{ - return git_oid_is_zero(oid_a); -} -#endif - -typedef short node_index; - -typedef union { - const char *tail; - node_index children[16]; -} trie_node; - -struct git_oid_shorten { - trie_node *nodes; - size_t node_count, size; - int min_length, full; -}; - -static int resize_trie(git_oid_shorten *self, size_t new_size) -{ - self->nodes = git__reallocarray(self->nodes, new_size, sizeof(trie_node)); - GIT_ERROR_CHECK_ALLOC(self->nodes); - - if (new_size > self->size) { - memset(&self->nodes[self->size], 0x0, (new_size - self->size) * sizeof(trie_node)); - } - - self->size = new_size; - return 0; -} - -static trie_node *push_leaf(git_oid_shorten *os, node_index idx, int push_at, const char *oid) -{ - trie_node *node, *leaf; - node_index idx_leaf; - - if (os->node_count >= os->size) { - if (resize_trie(os, os->size * 2) < 0) - return NULL; - } - - idx_leaf = (node_index)os->node_count++; - - if (os->node_count == SHRT_MAX) { - os->full = 1; - return NULL; - } - - node = &os->nodes[idx]; - node->children[push_at] = -idx_leaf; - - leaf = &os->nodes[idx_leaf]; - leaf->tail = oid; - - return node; -} - -git_oid_shorten *git_oid_shorten_new(size_t min_length) -{ - git_oid_shorten *os; - - GIT_ASSERT_ARG_WITH_RETVAL((size_t)((int)min_length) == min_length, NULL); - - os = git__calloc(1, sizeof(git_oid_shorten)); - if (os == NULL) - return NULL; - - if (resize_trie(os, 16) < 0) { - git__free(os); - return NULL; - } - - os->node_count = 1; - os->min_length = (int)min_length; - - return os; -} - -void git_oid_shorten_free(git_oid_shorten *os) -{ - if (os == NULL) - return; - - git__free(os->nodes); - git__free(os); -} - - -/* - * What wizardry is this? - * - * This is just a memory-optimized trie: basically a very fancy - * 16-ary tree, which is used to store the prefixes of the OID - * strings. - * - * Read more: http://en.wikipedia.org/wiki/Trie - * - * Magic that happens in this method: - * - * - Each node in the trie is an union, so it can work both as - * a normal node, or as a leaf. - * - * - Each normal node points to 16 children (one for each possible - * character in the oid). This is *not* stored in an array of - * pointers, because in a 64-bit arch this would be sucking - * 16*sizeof(void*) = 128 bytes of memory per node, which is - * insane. What we do is store Node Indexes, and use these indexes - * to look up each node in the om->index array. These indexes are - * signed shorts, so this limits the amount of unique OIDs that - * fit in the structure to about 20000 (assuming a more or less uniform - * distribution). - * - * - All the nodes in om->index array are stored contiguously in - * memory, and each of them is 32 bytes, so we fit 2x nodes per - * cache line. Convenient for speed. - * - * - To differentiate the leafs from the normal nodes, we store all - * the indexes towards a leaf as a negative index (indexes to normal - * nodes are positives). When we find that one of the children for - * a node has a negative value, that means it's going to be a leaf. - * This reduces the amount of indexes we have by two, but also reduces - * the size of each node by 1-4 bytes (the amount we would need to - * add a `is_leaf` field): this is good because it allows the nodes - * to fit cleanly in cache lines. - * - * - Once we reach an empty children, instead of continuing to insert - * new nodes for each remaining character of the OID, we store a pointer - * to the tail in the leaf; if the leaf is reached again, we turn it - * into a normal node and use the tail to create a new leaf. - * - * This is a pretty good balance between performance and memory usage. - */ -int git_oid_shorten_add(git_oid_shorten *os, const char *text_oid) -{ - int i; - bool is_leaf; - node_index idx; - - if (os->full) { - git_error_set(GIT_ERROR_INVALID, "unable to shorten OID - OID set full"); - return -1; - } - - if (text_oid == NULL) - return os->min_length; - - idx = 0; - is_leaf = false; - - for (i = 0; i < GIT_OID_HEXSZ; ++i) { - int c = git__fromhex(text_oid[i]); - trie_node *node; - - if (c == -1) { - git_error_set(GIT_ERROR_INVALID, "unable to shorten OID - invalid hex value"); - return -1; - } - - node = &os->nodes[idx]; - - if (is_leaf) { - const char *tail; - - tail = node->tail; - node->tail = NULL; - - node = push_leaf(os, idx, git__fromhex(tail[0]), &tail[1]); - if (node == NULL) { - if (os->full) - git_error_set(GIT_ERROR_INVALID, "unable to shorten OID - OID set full"); - return -1; - } - } - - if (node->children[c] == 0) { - if (push_leaf(os, idx, c, &text_oid[i + 1]) == NULL) { - if (os->full) - git_error_set(GIT_ERROR_INVALID, "unable to shorten OID - OID set full"); - return -1; - } - break; - } - - idx = node->children[c]; - is_leaf = false; - - if (idx < 0) { - node->children[c] = idx = -idx; - is_leaf = true; - } - } - - if (++i > os->min_length) - os->min_length = i; - - return os->min_length; -} - diff --git a/vendor/libgit2/src/oid.h b/vendor/libgit2/src/oid.h deleted file mode 100644 index 5baec33e..00000000 --- a/vendor/libgit2/src/oid.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_oid_h__ -#define INCLUDE_oid_h__ - -#include "common.h" - -#include "git2/oid.h" - -extern const git_oid git_oid__empty_blob_sha1; -extern const git_oid git_oid__empty_tree_sha1; - -/** - * Format a git_oid into a newly allocated c-string. - * - * The c-string is owned by the caller and needs to be manually freed. - * - * @param id the oid structure to format - * @return the c-string; NULL if memory is exhausted. Caller must - * deallocate the string with git__free(). - */ -char *git_oid_allocfmt(const git_oid *id); - -GIT_INLINE(int) git_oid__hashcmp(const unsigned char *sha1, const unsigned char *sha2) -{ - return memcmp(sha1, sha2, GIT_OID_RAWSZ); -} - -/* - * Compare two oid structures. - * - * @param a first oid structure. - * @param b second oid structure. - * @return <0, 0, >0 if a < b, a == b, a > b. - */ -GIT_INLINE(int) git_oid__cmp(const git_oid *a, const git_oid *b) -{ - return git_oid__hashcmp(a->id, b->id); -} - -GIT_INLINE(void) git_oid__cpy_prefix( - git_oid *out, const git_oid *id, size_t len) -{ - memcpy(&out->id, id->id, (len + 1) / 2); - - if (len & 1) - out->id[len / 2] &= 0xF0; -} - -GIT_INLINE(bool) git_oid__is_hexstr(const char *str) -{ - size_t i; - - for (i = 0; str[i] != '\0'; i++) { - if (git__fromhex(str[i]) < 0) - return false; - } - - return (i == GIT_OID_HEXSZ); -} - -#endif diff --git a/vendor/libgit2/src/oidarray.c b/vendor/libgit2/src/oidarray.c deleted file mode 100644 index 583017c4..00000000 --- a/vendor/libgit2/src/oidarray.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "oidarray.h" - -#include "git2/oidarray.h" -#include "array.h" - -void git_oidarray_dispose(git_oidarray *arr) -{ - git__free(arr->ids); -} - -void git_oidarray__from_array(git_oidarray *arr, git_array_oid_t *array) -{ - arr->count = array->size; - arr->ids = array->ptr; -} - -void git_oidarray__reverse(git_oidarray *arr) -{ - size_t i; - git_oid tmp; - - for (i = 0; i < arr->count / 2; i++) { - git_oid_cpy(&tmp, &arr->ids[i]); - git_oid_cpy(&arr->ids[i], &arr->ids[(arr->count-1)-i]); - git_oid_cpy(&arr->ids[(arr->count-1)-i], &tmp); - } -} - -#ifndef GIT_DEPRECATE_HARD - -void git_oidarray_free(git_oidarray *arr) -{ - git_oidarray_dispose(arr); -} - -#endif diff --git a/vendor/libgit2/src/oidarray.h b/vendor/libgit2/src/oidarray.h deleted file mode 100644 index eed3a109..00000000 --- a/vendor/libgit2/src/oidarray.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_oidarray_h__ -#define INCLUDE_oidarray_h__ - -#include "common.h" - -#include "git2/oidarray.h" -#include "array.h" - -typedef git_array_t(git_oid) git_array_oid_t; - -extern void git_oidarray__reverse(git_oidarray *arr); -extern void git_oidarray__from_array(git_oidarray *arr, git_array_oid_t *array); - -#endif diff --git a/vendor/libgit2/src/oidmap.c b/vendor/libgit2/src/oidmap.c deleted file mode 100644 index 0ae8bf33..00000000 --- a/vendor/libgit2/src/oidmap.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "oidmap.h" - -#define kmalloc git__malloc -#define kcalloc git__calloc -#define krealloc git__realloc -#define kreallocarray git__reallocarray -#define kfree git__free -#include "khash.h" - -__KHASH_TYPE(oid, const git_oid *, void *) - -GIT_INLINE(khint_t) git_oidmap_hash(const git_oid *oid) -{ - khint_t h; - memcpy(&h, oid, sizeof(khint_t)); - return h; -} - -__KHASH_IMPL(oid, static kh_inline, const git_oid *, void *, 1, git_oidmap_hash, git_oid_equal) - -int git_oidmap_new(git_oidmap **out) -{ - *out = kh_init(oid); - GIT_ERROR_CHECK_ALLOC(*out); - - return 0; -} - -void git_oidmap_free(git_oidmap *map) -{ - kh_destroy(oid, map); -} - -void git_oidmap_clear(git_oidmap *map) -{ - kh_clear(oid, map); -} - -size_t git_oidmap_size(git_oidmap *map) -{ - return kh_size(map); -} - -void *git_oidmap_get(git_oidmap *map, const git_oid *key) -{ - size_t idx = kh_get(oid, map, key); - if (idx == kh_end(map) || !kh_exist(map, idx)) - return NULL; - return kh_val(map, idx); -} - -int git_oidmap_set(git_oidmap *map, const git_oid *key, void *value) -{ - size_t idx; - int rval; - - idx = kh_put(oid, map, key, &rval); - if (rval < 0) - return -1; - - if (rval == 0) - kh_key(map, idx) = key; - - kh_val(map, idx) = value; - - return 0; -} - -int git_oidmap_delete(git_oidmap *map, const git_oid *key) -{ - khiter_t idx = kh_get(oid, map, key); - if (idx == kh_end(map)) - return GIT_ENOTFOUND; - kh_del(oid, map, idx); - return 0; -} - -int git_oidmap_exists(git_oidmap *map, const git_oid *key) -{ - return kh_get(oid, map, key) != kh_end(map); -} - -int git_oidmap_iterate(void **value, git_oidmap *map, size_t *iter, const git_oid **key) -{ - size_t i = *iter; - - while (i < map->n_buckets && !kh_exist(map, i)) - i++; - - if (i >= map->n_buckets) - return GIT_ITEROVER; - - if (key) - *key = kh_key(map, i); - if (value) - *value = kh_value(map, i); - *iter = ++i; - - return 0; -} diff --git a/vendor/libgit2/src/parse.c b/vendor/libgit2/src/parse.c deleted file mode 100644 index 0a10758b..00000000 --- a/vendor/libgit2/src/parse.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#include "parse.h" - -int git_parse_ctx_init(git_parse_ctx *ctx, const char *content, size_t content_len) -{ - if (content && content_len) { - ctx->content = content; - ctx->content_len = content_len; - } else { - ctx->content = ""; - ctx->content_len = 0; - } - - ctx->remain = ctx->content; - ctx->remain_len = ctx->content_len; - ctx->line = ctx->remain; - ctx->line_len = git__linenlen(ctx->line, ctx->remain_len); - ctx->line_num = 1; - - return 0; -} - -void git_parse_ctx_clear(git_parse_ctx *ctx) -{ - memset(ctx, 0, sizeof(*ctx)); - ctx->content = ""; -} - -void git_parse_advance_line(git_parse_ctx *ctx) -{ - ctx->line += ctx->line_len; - ctx->remain_len -= ctx->line_len; - ctx->line_len = git__linenlen(ctx->line, ctx->remain_len); - ctx->line_num++; -} - -void git_parse_advance_chars(git_parse_ctx *ctx, size_t char_cnt) -{ - ctx->line += char_cnt; - ctx->remain_len -= char_cnt; - ctx->line_len -= char_cnt; -} - -int git_parse_advance_expected( - git_parse_ctx *ctx, - const char *expected, - size_t expected_len) -{ - if (ctx->line_len < expected_len) - return -1; - - if (memcmp(ctx->line, expected, expected_len) != 0) - return -1; - - git_parse_advance_chars(ctx, expected_len); - return 0; -} - -int git_parse_advance_ws(git_parse_ctx *ctx) -{ - int ret = -1; - - while (ctx->line_len > 0 && - ctx->line[0] != '\n' && - git__isspace(ctx->line[0])) { - ctx->line++; - ctx->line_len--; - ctx->remain_len--; - ret = 0; - } - - return ret; -} - -int git_parse_advance_nl(git_parse_ctx *ctx) -{ - if (ctx->line_len != 1 || ctx->line[0] != '\n') - return -1; - - git_parse_advance_line(ctx); - return 0; -} - -int git_parse_advance_digit(int64_t *out, git_parse_ctx *ctx, int base) -{ - const char *end; - int ret; - - if (ctx->line_len < 1 || !git__isdigit(ctx->line[0])) - return -1; - - if ((ret = git__strntol64(out, ctx->line, ctx->line_len, &end, base)) < 0) - return -1; - - git_parse_advance_chars(ctx, (end - ctx->line)); - return 0; -} - -int git_parse_advance_oid(git_oid *out, git_parse_ctx *ctx) -{ - if (ctx->line_len < GIT_OID_HEXSZ) - return -1; - if ((git_oid_fromstrn(out, ctx->line, GIT_OID_HEXSZ)) < 0) - return -1; - git_parse_advance_chars(ctx, GIT_OID_HEXSZ); - return 0; -} - -int git_parse_peek(char *out, git_parse_ctx *ctx, int flags) -{ - size_t remain = ctx->line_len; - const char *ptr = ctx->line; - - while (remain) { - char c = *ptr; - - if ((flags & GIT_PARSE_PEEK_SKIP_WHITESPACE) && - git__isspace(c)) { - remain--; - ptr++; - continue; - } - - *out = c; - return 0; - } - - return -1; -} diff --git a/vendor/libgit2/src/path.c b/vendor/libgit2/src/path.c deleted file mode 100644 index 05a3dc2c..00000000 --- a/vendor/libgit2/src/path.c +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "path.h" - -#include "repository.h" -#include "fs_path.h" - -typedef struct { - git_repository *repo; - uint16_t file_mode; - unsigned int flags; -} repository_path_validate_data; - -static int32_t next_hfs_char(const char **in, size_t *len) -{ - while (*len) { - uint32_t codepoint; - int cp_len = git_utf8_iterate(&codepoint, *in, *len); - if (cp_len < 0) - return -1; - - (*in) += cp_len; - (*len) -= cp_len; - - /* these code points are ignored completely */ - switch (codepoint) { - case 0x200c: /* ZERO WIDTH NON-JOINER */ - case 0x200d: /* ZERO WIDTH JOINER */ - case 0x200e: /* LEFT-TO-RIGHT MARK */ - case 0x200f: /* RIGHT-TO-LEFT MARK */ - case 0x202a: /* LEFT-TO-RIGHT EMBEDDING */ - case 0x202b: /* RIGHT-TO-LEFT EMBEDDING */ - case 0x202c: /* POP DIRECTIONAL FORMATTING */ - case 0x202d: /* LEFT-TO-RIGHT OVERRIDE */ - case 0x202e: /* RIGHT-TO-LEFT OVERRIDE */ - case 0x206a: /* INHIBIT SYMMETRIC SWAPPING */ - case 0x206b: /* ACTIVATE SYMMETRIC SWAPPING */ - case 0x206c: /* INHIBIT ARABIC FORM SHAPING */ - case 0x206d: /* ACTIVATE ARABIC FORM SHAPING */ - case 0x206e: /* NATIONAL DIGIT SHAPES */ - case 0x206f: /* NOMINAL DIGIT SHAPES */ - case 0xfeff: /* ZERO WIDTH NO-BREAK SPACE */ - continue; - } - - /* fold into lowercase -- this will only fold characters in - * the ASCII range, which is perfectly fine, because the - * git folder name can only be composed of ascii characters - */ - return git__tolower((int)codepoint); - } - return 0; /* NULL byte -- end of string */ -} - -static bool validate_dotgit_hfs_generic( - const char *path, - size_t len, - const char *needle, - size_t needle_len) -{ - size_t i; - char c; - - if (next_hfs_char(&path, &len) != '.') - return true; - - for (i = 0; i < needle_len; i++) { - c = next_hfs_char(&path, &len); - if (c != needle[i]) - return true; - } - - if (next_hfs_char(&path, &len) != '\0') - return true; - - return false; -} - -static bool validate_dotgit_hfs(const char *path, size_t len) -{ - return validate_dotgit_hfs_generic(path, len, "git", CONST_STRLEN("git")); -} - -GIT_INLINE(bool) validate_dotgit_ntfs( - git_repository *repo, - const char *path, - size_t len) -{ - git_str *reserved = git_repository__reserved_names_win32; - size_t reserved_len = git_repository__reserved_names_win32_len; - size_t start = 0, i; - - if (repo) - git_repository__reserved_names(&reserved, &reserved_len, repo, true); - - for (i = 0; i < reserved_len; i++) { - git_str *r = &reserved[i]; - - if (len >= r->size && - strncasecmp(path, r->ptr, r->size) == 0) { - start = r->size; - break; - } - } - - if (!start) - return true; - - /* - * Reject paths that start with Windows-style directory separators - * (".git\") or NTFS alternate streams (".git:") and could be used - * to write to the ".git" directory on Windows platforms. - */ - if (path[start] == '\\' || path[start] == ':') - return false; - - /* Reject paths like '.git ' or '.git.' */ - for (i = start; i < len; i++) { - if (path[i] != ' ' && path[i] != '.') - return true; - } - - return false; -} - -/* - * Windows paths that end with spaces and/or dots are elided to the - * path without them for backward compatibility. That is to say - * that opening file "foo ", "foo." or even "foo . . ." will all - * map to a filename of "foo". This function identifies spaces and - * dots at the end of a filename, whether the proper end of the - * filename (end of string) or a colon (which would indicate a - * Windows alternate data stream.) - */ -GIT_INLINE(bool) ntfs_end_of_filename(const char *path) -{ - const char *c = path; - - for (;; c++) { - if (*c == '\0' || *c == ':') - return true; - if (*c != ' ' && *c != '.') - return false; - } - - return true; -} - -GIT_INLINE(bool) validate_dotgit_ntfs_generic( - const char *name, - size_t len, - const char *dotgit_name, - size_t dotgit_len, - const char *shortname_pfix) -{ - int i, saw_tilde; - - if (name[0] == '.' && len >= dotgit_len && - !strncasecmp(name + 1, dotgit_name, dotgit_len)) { - return !ntfs_end_of_filename(name + dotgit_len + 1); - } - - /* Detect the basic NTFS shortname with the first six chars */ - if (!strncasecmp(name, dotgit_name, 6) && name[6] == '~' && - name[7] >= '1' && name[7] <= '4') - return !ntfs_end_of_filename(name + 8); - - /* Catch fallback names */ - for (i = 0, saw_tilde = 0; i < 8; i++) { - if (name[i] == '\0') { - return true; - } else if (saw_tilde) { - if (name[i] < '0' || name[i] > '9') - return true; - } else if (name[i] == '~') { - if (name[i+1] < '1' || name[i+1] > '9') - return true; - saw_tilde = 1; - } else if (i >= 6) { - return true; - } else if ((unsigned char)name[i] > 127) { - return true; - } else if (git__tolower(name[i]) != shortname_pfix[i]) { - return true; - } - } - - return !ntfs_end_of_filename(name + i); -} - -/* - * Return the length of the common prefix between str and prefix, comparing them - * case-insensitively (must be ASCII to match). - */ -GIT_INLINE(size_t) common_prefix_icase(const char *str, size_t len, const char *prefix) -{ - size_t count = 0; - - while (len > 0 && tolower(*str) == tolower(*prefix)) { - count++; - str++; - prefix++; - len--; - } - - return count; -} - -static bool validate_repo_component( - const char *component, - size_t len, - void *payload) -{ - repository_path_validate_data *data = (repository_path_validate_data *)payload; - - if (data->flags & GIT_PATH_REJECT_DOT_GIT_HFS) { - if (!validate_dotgit_hfs(component, len)) - return false; - - if (S_ISLNK(data->file_mode) && - git_path_is_gitfile(component, len, GIT_PATH_GITFILE_GITMODULES, GIT_PATH_FS_HFS)) - return false; - } - - if (data->flags & GIT_PATH_REJECT_DOT_GIT_NTFS) { - if (!validate_dotgit_ntfs(data->repo, component, len)) - return false; - - if (S_ISLNK(data->file_mode) && - git_path_is_gitfile(component, len, GIT_PATH_GITFILE_GITMODULES, GIT_PATH_FS_NTFS)) - return false; - } - - /* don't bother rerunning the `.git` test if we ran the HFS or NTFS - * specific tests, they would have already rejected `.git`. - */ - if ((data->flags & GIT_PATH_REJECT_DOT_GIT_HFS) == 0 && - (data->flags & GIT_PATH_REJECT_DOT_GIT_NTFS) == 0 && - (data->flags & GIT_PATH_REJECT_DOT_GIT_LITERAL)) { - if (len >= 4 && - component[0] == '.' && - (component[1] == 'g' || component[1] == 'G') && - (component[2] == 'i' || component[2] == 'I') && - (component[3] == 't' || component[3] == 'T')) { - if (len == 4) - return false; - - if (S_ISLNK(data->file_mode) && - common_prefix_icase(component, len, ".gitmodules") == len) - return false; - } - } - - return true; -} - -GIT_INLINE(unsigned int) dotgit_flags( - git_repository *repo, - unsigned int flags) -{ - int protectHFS = 0, protectNTFS = 1; - int error = 0; - - flags |= GIT_PATH_REJECT_DOT_GIT_LITERAL; - -#ifdef __APPLE__ - protectHFS = 1; -#endif - - if (repo && !protectHFS) - error = git_repository__configmap_lookup(&protectHFS, repo, GIT_CONFIGMAP_PROTECTHFS); - if (!error && protectHFS) - flags |= GIT_PATH_REJECT_DOT_GIT_HFS; - - if (repo) - error = git_repository__configmap_lookup(&protectNTFS, repo, GIT_CONFIGMAP_PROTECTNTFS); - if (!error && protectNTFS) - flags |= GIT_PATH_REJECT_DOT_GIT_NTFS; - - return flags; -} - -GIT_INLINE(unsigned int) length_flags( - git_repository *repo, - unsigned int flags) -{ -#ifdef GIT_WIN32 - int allow = 0; - - if (repo && - git_repository__configmap_lookup(&allow, repo, GIT_CONFIGMAP_LONGPATHS) < 0) - allow = 0; - - if (allow) - flags &= ~GIT_FS_PATH_REJECT_LONG_PATHS; - -#else - GIT_UNUSED(repo); - flags &= ~GIT_FS_PATH_REJECT_LONG_PATHS; -#endif - - return flags; -} - -bool git_path_str_is_valid( - git_repository *repo, - const git_str *path, - uint16_t file_mode, - unsigned int flags) -{ - repository_path_validate_data data = {0}; - - /* Upgrade the ".git" checks based on platform */ - if ((flags & GIT_PATH_REJECT_DOT_GIT)) - flags = dotgit_flags(repo, flags); - - /* Update the length checks based on platform */ - if ((flags & GIT_FS_PATH_REJECT_LONG_PATHS)) - flags = length_flags(repo, flags); - - data.repo = repo; - data.file_mode = file_mode; - data.flags = flags; - - return git_fs_path_str_is_valid_ext(path, flags, NULL, validate_repo_component, NULL, &data); -} - -static const struct { - const char *file; - const char *hash; - size_t filelen; -} gitfiles[] = { - { "gitignore", "gi250a", CONST_STRLEN("gitignore") }, - { "gitmodules", "gi7eba", CONST_STRLEN("gitmodules") }, - { "gitattributes", "gi7d29", CONST_STRLEN("gitattributes") } -}; - -extern int git_path_is_gitfile( - const char *path, - size_t pathlen, - git_path_gitfile gitfile, - git_path_fs fs) -{ - const char *file, *hash; - size_t filelen; - - if (!(gitfile >= GIT_PATH_GITFILE_GITIGNORE && gitfile < ARRAY_SIZE(gitfiles))) { - git_error_set(GIT_ERROR_OS, "invalid gitfile for path validation"); - return -1; - } - - file = gitfiles[gitfile].file; - filelen = gitfiles[gitfile].filelen; - hash = gitfiles[gitfile].hash; - - switch (fs) { - case GIT_PATH_FS_GENERIC: - return !validate_dotgit_ntfs_generic(path, pathlen, file, filelen, hash) || - !validate_dotgit_hfs_generic(path, pathlen, file, filelen); - case GIT_PATH_FS_NTFS: - return !validate_dotgit_ntfs_generic(path, pathlen, file, filelen, hash); - case GIT_PATH_FS_HFS: - return !validate_dotgit_hfs_generic(path, pathlen, file, filelen); - default: - git_error_set(GIT_ERROR_OS, "invalid filesystem for path validation"); - return -1; - } -} - diff --git a/vendor/libgit2/src/posix.c b/vendor/libgit2/src/posix.c deleted file mode 100644 index b1f85dc9..00000000 --- a/vendor/libgit2/src/posix.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "posix.h" - -#include "fs_path.h" -#include -#include - -size_t p_fsync__cnt = 0; - -#ifndef GIT_WIN32 - -#ifdef NO_ADDRINFO - -int p_getaddrinfo( - const char *host, - const char *port, - struct addrinfo *hints, - struct addrinfo **info) -{ - struct addrinfo *ainfo, *ai; - int p = 0; - - GIT_UNUSED(hints); - - if ((ainfo = git__malloc(sizeof(struct addrinfo))) == NULL) - return -1; - - if ((ainfo->ai_hostent = gethostbyname(host)) == NULL) { - git__free(ainfo); - return -2; - } - - ainfo->ai_servent = getservbyname(port, 0); - - if (ainfo->ai_servent) - ainfo->ai_port = ainfo->ai_servent->s_port; - else - ainfo->ai_port = htons(atol(port)); - - memcpy(&ainfo->ai_addr_in.sin_addr, - ainfo->ai_hostent->h_addr_list[0], - ainfo->ai_hostent->h_length); - - ainfo->ai_protocol = 0; - ainfo->ai_socktype = hints->ai_socktype; - ainfo->ai_family = ainfo->ai_hostent->h_addrtype; - ainfo->ai_addr_in.sin_family = ainfo->ai_family; - ainfo->ai_addr_in.sin_port = ainfo->ai_port; - ainfo->ai_addr = (struct addrinfo *)&ainfo->ai_addr_in; - ainfo->ai_addrlen = sizeof(struct sockaddr_in); - - *info = ainfo; - - if (ainfo->ai_hostent->h_addr_list[1] == NULL) { - ainfo->ai_next = NULL; - return 0; - } - - ai = ainfo; - - for (p = 1; ainfo->ai_hostent->h_addr_list[p] != NULL; p++) { - if (!(ai->ai_next = git__malloc(sizeof(struct addrinfo)))) { - p_freeaddrinfo(ainfo); - return -1; - } - memcpy(ai->ai_next, ainfo, sizeof(struct addrinfo)); - memcpy(&ai->ai_next->ai_addr_in.sin_addr, - ainfo->ai_hostent->h_addr_list[p], - ainfo->ai_hostent->h_length); - ai->ai_next->ai_addr = (struct addrinfo *)&ai->ai_next->ai_addr_in; - ai = ai->ai_next; - } - - ai->ai_next = NULL; - return 0; -} - -void p_freeaddrinfo(struct addrinfo *info) -{ - struct addrinfo *p, *next; - - p = info; - - while(p != NULL) { - next = p->ai_next; - git__free(p); - p = next; - } -} - -const char *p_gai_strerror(int ret) -{ - switch(ret) { - case -1: return "Out of memory"; break; - case -2: return "Address lookup failed"; break; - default: return "Unknown error"; break; - } -} - -#endif /* NO_ADDRINFO */ - -int p_open(const char *path, volatile int flags, ...) -{ - mode_t mode = 0; - - #ifdef GIT_DEBUG_STRICT_OPEN - if (strstr(path, "//") != NULL) { - errno = EACCES; - return -1; - } - #endif - - if (flags & O_CREAT) { - va_list arg_list; - - va_start(arg_list, flags); - mode = (mode_t)va_arg(arg_list, int); - va_end(arg_list); - } - - return open(path, flags | O_BINARY | O_CLOEXEC, mode); -} - -int p_creat(const char *path, mode_t mode) -{ - return open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC, mode); -} - -int p_getcwd(char *buffer_out, size_t size) -{ - char *cwd_buffer; - - GIT_ASSERT_ARG(buffer_out); - GIT_ASSERT_ARG(size > 0); - - cwd_buffer = getcwd(buffer_out, size); - - if (cwd_buffer == NULL) - return -1; - - git_fs_path_mkposix(buffer_out); - git_fs_path_string_to_dir(buffer_out, size); /* append trailing slash */ - - return 0; -} - -int p_rename(const char *from, const char *to) -{ - if (!link(from, to)) { - p_unlink(from); - return 0; - } - - if (!rename(from, to)) - return 0; - - return -1; -} - -#endif /* GIT_WIN32 */ - -ssize_t p_read(git_file fd, void *buf, size_t cnt) -{ - char *b = buf; - - if (!git__is_ssizet(cnt)) { -#ifdef GIT_WIN32 - SetLastError(ERROR_INVALID_PARAMETER); -#endif - errno = EINVAL; - return -1; - } - - while (cnt) { - ssize_t r; -#ifdef GIT_WIN32 - r = read(fd, b, cnt > INT_MAX ? INT_MAX : (unsigned int)cnt); -#else - r = read(fd, b, cnt); -#endif - if (r < 0) { - if (errno == EINTR || errno == EAGAIN) - continue; - return -1; - } - if (!r) - break; - cnt -= r; - b += r; - } - return (b - (char *)buf); -} - -int p_write(git_file fd, const void *buf, size_t cnt) -{ - const char *b = buf; - - while (cnt) { - ssize_t r; -#ifdef GIT_WIN32 - GIT_ASSERT((size_t)((unsigned int)cnt) == cnt); - r = write(fd, b, (unsigned int)cnt); -#else - r = write(fd, b, cnt); -#endif - if (r < 0) { - if (errno == EINTR || GIT_ISBLOCKED(errno)) - continue; - return -1; - } - if (!r) { - errno = EPIPE; - return -1; - } - cnt -= r; - b += r; - } - return 0; -} - -#ifdef NO_MMAP - -#include "map.h" - -int git__page_size(size_t *page_size) -{ - /* dummy; here we don't need any alignment anyway */ - *page_size = 4096; - return 0; -} - -int git__mmap_alignment(size_t *alignment) -{ - /* dummy; here we don't need any alignment anyway */ - *alignment = 4096; - return 0; -} - - -int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset) -{ - const char *ptr; - size_t remaining_len; - - GIT_MMAP_VALIDATE(out, len, prot, flags); - - /* writes cannot be emulated without handling pagefaults since write happens by - * writing to mapped memory */ - if (prot & GIT_PROT_WRITE) { - git_error_set(GIT_ERROR_OS, "trying to map %s-writeable", - ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED) ? "shared": "private"); - return -1; - } - - if (!git__is_ssizet(len)) { - errno = EINVAL; - return -1; - } - - out->len = 0; - out->data = git__malloc(len); - GIT_ERROR_CHECK_ALLOC(out->data); - - remaining_len = len; - ptr = (const char *)out->data; - while (remaining_len > 0) { - ssize_t nb; - HANDLE_EINTR(nb, p_pread(fd, (void *)ptr, remaining_len, offset)); - if (nb <= 0) { - git_error_set(GIT_ERROR_OS, "mmap emulation failed"); - git__free(out->data); - out->data = NULL; - return -1; - } - - ptr += nb; - offset += nb; - remaining_len -= nb; - } - - out->len = len; - return 0; -} - -int p_munmap(git_map *map) -{ - GIT_ASSERT_ARG(map); - git__free(map->data); - - /* Initializing will help debug use-after-free */ - map->len = 0; - map->data = NULL; - - return 0; -} - -#endif diff --git a/vendor/libgit2/src/posix.h b/vendor/libgit2/src/posix.h deleted file mode 100644 index e6f60307..00000000 --- a/vendor/libgit2/src/posix.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_posix_h__ -#define INCLUDE_posix_h__ - -#include "common.h" - -#include -#include -#include - -/* stat: file mode type testing macros */ -#ifndef S_IFGITLINK -#define S_IFGITLINK 0160000 -#define S_ISGITLINK(m) (((m) & S_IFMT) == S_IFGITLINK) -#endif - -#ifndef S_IFLNK -#define S_IFLNK 0120000 -#undef _S_IFLNK -#define _S_IFLNK S_IFLNK -#endif - -#ifndef S_IWUSR -#define S_IWUSR 00200 -#endif - -#ifndef S_IXUSR -#define S_IXUSR 00100 -#endif - -#ifndef S_ISLNK -#define S_ISLNK(m) (((m) & _S_IFMT) == _S_IFLNK) -#endif - -#ifndef S_ISDIR -#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR) -#endif - -#ifndef S_ISREG -#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG) -#endif - -#ifndef S_ISFIFO -#define S_ISFIFO(m) (((m) & _S_IFMT) == _S_IFIFO) -#endif - -/* if S_ISGID is not defined, then don't try to set it */ -#ifndef S_ISGID -#define S_ISGID 0 -#endif - -#ifndef O_BINARY -#define O_BINARY 0 -#endif -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#endif -#ifndef SOCK_CLOEXEC -#define SOCK_CLOEXEC 0 -#endif - -/* access() mode parameter #defines */ -#ifndef F_OK -#define F_OK 0 /* existence check */ -#endif -#ifndef W_OK -#define W_OK 2 /* write mode check */ -#endif -#ifndef R_OK -#define R_OK 4 /* read mode check */ -#endif - -/* Determine whether an errno value indicates that a read or write failed - * because the descriptor is blocked. - */ -#if defined(EWOULDBLOCK) -#define GIT_ISBLOCKED(e) ((e) == EAGAIN || (e) == EWOULDBLOCK) -#else -#define GIT_ISBLOCKED(e) ((e) == EAGAIN) -#endif - -/* define some standard errnos that the runtime may be missing. for example, - * mingw lacks EAFNOSUPPORT. */ -#ifndef EAFNOSUPPORT -#define EAFNOSUPPORT (INT_MAX-1) -#endif - -/* Compiler independent macro to handle signal interrpted system calls */ -#define HANDLE_EINTR(result, x) do { \ - result = (x); \ - } while (result == -1 && errno == EINTR); - - -/* Provide a 64-bit size for offsets. */ - -#if defined(_MSC_VER) -typedef __int64 off64_t; -#elif defined(__HAIKU__) -typedef __haiku_std_int64 off64_t; -#elif defined(__APPLE__) -typedef __int64_t off64_t; -#else -typedef int64_t off64_t; -#endif - -typedef int git_file; - -/** - * Standard POSIX Methods - * - * All the methods starting with the `p_` prefix are - * direct ports of the standard POSIX methods. - * - * Some of the methods are slightly wrapped to provide - * saner defaults. Some of these methods are emulated - * in Windows platforms. - * - * Use your manpages to check the docs on these. - */ - -extern ssize_t p_read(git_file fd, void *buf, size_t cnt); -extern int p_write(git_file fd, const void *buf, size_t cnt); - -extern ssize_t p_pread(int fd, void *data, size_t size, off64_t offset); -extern ssize_t p_pwrite(int fd, const void *data, size_t size, off64_t offset); - -#define p_close(fd) close(fd) -#define p_umask(m) umask(m) - -extern int p_open(const char *path, int flags, ...); -extern int p_creat(const char *path, mode_t mode); -extern int p_getcwd(char *buffer_out, size_t size); -extern int p_rename(const char *from, const char *to); - -extern int git__page_size(size_t *page_size); -extern int git__mmap_alignment(size_t *page_size); - -/* The number of times `p_fsync` has been called. Note that this is for - * test code only; it it not necessarily thread-safe and should not be - * relied upon in production. - */ -extern size_t p_fsync__cnt; - -/** - * Platform-dependent methods - */ -#ifdef GIT_WIN32 -# include "win32/posix.h" -#else -# include "unix/posix.h" -#endif - -#include "strnlen.h" - -#ifdef NO_READDIR_R -GIT_INLINE(int) p_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) -{ - GIT_UNUSED(entry); - *result = readdir(dirp); - return 0; -} -#else /* NO_READDIR_R */ -# define p_readdir_r(d,e,r) readdir_r(d,e,r) -#endif - -#ifdef NO_ADDRINFO -# include -struct addrinfo { - struct hostent *ai_hostent; - struct servent *ai_servent; - struct sockaddr_in ai_addr_in; - struct sockaddr *ai_addr; - size_t ai_addrlen; - int ai_family; - int ai_socktype; - int ai_protocol; - long ai_port; - struct addrinfo *ai_next; -}; - -extern int p_getaddrinfo(const char *host, const char *port, - struct addrinfo *hints, struct addrinfo **info); -extern void p_freeaddrinfo(struct addrinfo *info); -extern const char *p_gai_strerror(int ret); -#else -# define p_getaddrinfo(a, b, c, d) getaddrinfo(a, b, c, d) -# define p_freeaddrinfo(a) freeaddrinfo(a) -# define p_gai_strerror(c) gai_strerror(c) -#endif /* NO_ADDRINFO */ - -#endif diff --git a/vendor/libgit2/src/push.c b/vendor/libgit2/src/push.c deleted file mode 100644 index da8aebad..00000000 --- a/vendor/libgit2/src/push.c +++ /dev/null @@ -1,558 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "push.h" - -#include "git2.h" - -#include "pack.h" -#include "pack-objects.h" -#include "remote.h" -#include "vector.h" -#include "tree.h" - -static int push_spec_rref_cmp(const void *a, const void *b) -{ - const push_spec *push_spec_a = a, *push_spec_b = b; - - return strcmp(push_spec_a->refspec.dst, push_spec_b->refspec.dst); -} - -static int push_status_ref_cmp(const void *a, const void *b) -{ - const push_status *push_status_a = a, *push_status_b = b; - - return strcmp(push_status_a->ref, push_status_b->ref); -} - -int git_push_new(git_push **out, git_remote *remote, const git_push_options *opts) -{ - git_push *p; - - *out = NULL; - - GIT_ERROR_CHECK_VERSION(opts, GIT_PUSH_OPTIONS_VERSION, "git_push_options"); - - p = git__calloc(1, sizeof(*p)); - GIT_ERROR_CHECK_ALLOC(p); - - p->repo = remote->repo; - p->remote = remote; - p->report_status = 1; - p->pb_parallelism = opts ? opts->pb_parallelism : 1; - - if (opts) { - GIT_ERROR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks"); - memcpy(&p->callbacks, &opts->callbacks, sizeof(git_remote_callbacks)); - } - - if (git_vector_init(&p->specs, 0, push_spec_rref_cmp) < 0) { - git__free(p); - return -1; - } - - if (git_vector_init(&p->status, 0, push_status_ref_cmp) < 0) { - git_vector_free(&p->specs); - git__free(p); - return -1; - } - - if (git_vector_init(&p->updates, 0, NULL) < 0) { - git_vector_free(&p->status); - git_vector_free(&p->specs); - git__free(p); - return -1; - } - - *out = p; - return 0; -} - -static void free_refspec(push_spec *spec) -{ - if (spec == NULL) - return; - - git_refspec__dispose(&spec->refspec); - git__free(spec); -} - -static int check_rref(char *ref) -{ - if (git__prefixcmp(ref, "refs/")) { - git_error_set(GIT_ERROR_INVALID, "not a valid reference '%s'", ref); - return -1; - } - - return 0; -} - -static int check_lref(git_push *push, char *ref) -{ - /* lref must be resolvable to an existing object */ - git_object *obj; - int error = git_revparse_single(&obj, push->repo, ref); - git_object_free(obj); - - if (!error) - return 0; - - if (error == GIT_ENOTFOUND) - git_error_set(GIT_ERROR_REFERENCE, - "src refspec '%s' does not match any existing object", ref); - else - git_error_set(GIT_ERROR_INVALID, "not a valid reference '%s'", ref); - return -1; -} - -static int parse_refspec(git_push *push, push_spec **spec, const char *str) -{ - push_spec *s; - - *spec = NULL; - - s = git__calloc(1, sizeof(*s)); - GIT_ERROR_CHECK_ALLOC(s); - - if (git_refspec__parse(&s->refspec, str, false) < 0) { - git_error_set(GIT_ERROR_INVALID, "invalid refspec %s", str); - goto on_error; - } - - if (s->refspec.src && s->refspec.src[0] != '\0' && - check_lref(push, s->refspec.src) < 0) { - goto on_error; - } - - if (check_rref(s->refspec.dst) < 0) - goto on_error; - - *spec = s; - return 0; - -on_error: - free_refspec(s); - return -1; -} - -int git_push_add_refspec(git_push *push, const char *refspec) -{ - push_spec *spec; - - if (parse_refspec(push, &spec, refspec) < 0 || - git_vector_insert(&push->specs, spec) < 0) - return -1; - - return 0; -} - -int git_push_update_tips(git_push *push, const git_remote_callbacks *callbacks) -{ - git_str remote_ref_name = GIT_STR_INIT; - size_t i, j; - git_refspec *fetch_spec; - push_spec *push_spec = NULL; - git_reference *remote_ref; - push_status *status; - int error = 0; - - git_vector_foreach(&push->status, i, status) { - int fire_callback = 1; - - /* Skip unsuccessful updates which have non-empty messages */ - if (status->msg) - continue; - - /* Find the corresponding remote ref */ - fetch_spec = git_remote__matching_refspec(push->remote, status->ref); - if (!fetch_spec) - continue; - - /* Clear the buffer which can be dirty from previous iteration */ - git_str_clear(&remote_ref_name); - - if ((error = git_refspec__transform(&remote_ref_name, fetch_spec, status->ref)) < 0) - goto on_error; - - /* Find matching push ref spec */ - git_vector_foreach(&push->specs, j, push_spec) { - if (!strcmp(push_spec->refspec.dst, status->ref)) - break; - } - - /* Could not find the corresponding push ref spec for this push update */ - if (j == push->specs.length) - continue; - - /* Update the remote ref */ - if (git_oid_is_zero(&push_spec->loid)) { - error = git_reference_lookup(&remote_ref, push->remote->repo, git_str_cstr(&remote_ref_name)); - - if (error >= 0) { - error = git_reference_delete(remote_ref); - git_reference_free(remote_ref); - } - } else { - error = git_reference_create(NULL, push->remote->repo, - git_str_cstr(&remote_ref_name), &push_spec->loid, 1, - "update by push"); - } - - if (error < 0) { - if (error != GIT_ENOTFOUND) - goto on_error; - - git_error_clear(); - fire_callback = 0; - } - - if (fire_callback && callbacks && callbacks->update_tips) { - error = callbacks->update_tips(git_str_cstr(&remote_ref_name), - &push_spec->roid, &push_spec->loid, callbacks->payload); - - if (error < 0) - goto on_error; - } - } - - error = 0; - -on_error: - git_str_dispose(&remote_ref_name); - return error; -} - -/** - * Insert all tags until we find a non-tag object, which is returned - * in `out`. - */ -static int enqueue_tag(git_object **out, git_push *push, git_oid *id) -{ - git_object *obj = NULL, *target = NULL; - int error; - - if ((error = git_object_lookup(&obj, push->repo, id, GIT_OBJECT_TAG)) < 0) - return error; - - while (git_object_type(obj) == GIT_OBJECT_TAG) { - if ((error = git_packbuilder_insert(push->pb, git_object_id(obj), NULL)) < 0) - break; - - if ((error = git_tag_target(&target, (git_tag *) obj)) < 0) - break; - - git_object_free(obj); - obj = target; - } - - if (error < 0) - git_object_free(obj); - else - *out = obj; - - return error; -} - -static int queue_objects(git_push *push) -{ - git_remote_head *head; - push_spec *spec; - git_revwalk *rw; - unsigned int i; - int error = -1; - - if (git_revwalk_new(&rw, push->repo) < 0) - return -1; - - git_revwalk_sorting(rw, GIT_SORT_TIME); - - git_vector_foreach(&push->specs, i, spec) { - git_object_t type; - size_t size; - - if (git_oid_is_zero(&spec->loid)) - /* - * Delete reference on remote side; - * nothing to do here. - */ - continue; - - if (git_oid_equal(&spec->loid, &spec->roid)) - continue; /* up-to-date */ - - if ((error = git_odb_read_header(&size, &type, push->repo->_odb, &spec->loid)) < 0) - goto on_error; - - if (type == GIT_OBJECT_TAG) { - git_object *target; - - if ((error = enqueue_tag(&target, push, &spec->loid)) < 0) - goto on_error; - - if (git_object_type(target) == GIT_OBJECT_COMMIT) { - if ((error = git_revwalk_push(rw, git_object_id(target))) < 0) { - git_object_free(target); - goto on_error; - } - } else { - if ((error = git_packbuilder_insert( - push->pb, git_object_id(target), NULL)) < 0) { - git_object_free(target); - goto on_error; - } - } - git_object_free(target); - } else if ((error = git_revwalk_push(rw, &spec->loid)) < 0) - goto on_error; - - if (!spec->refspec.force) { - git_oid base; - - if (git_oid_is_zero(&spec->roid)) - continue; - - if (!git_odb_exists(push->repo->_odb, &spec->roid)) { - git_error_set(GIT_ERROR_REFERENCE, - "cannot push because a reference that you are trying to update on the remote contains commits that are not present locally."); - error = GIT_ENONFASTFORWARD; - goto on_error; - } - - error = git_merge_base(&base, push->repo, - &spec->loid, &spec->roid); - - if (error == GIT_ENOTFOUND || - (!error && !git_oid_equal(&base, &spec->roid))) { - git_error_set(GIT_ERROR_REFERENCE, - "cannot push non-fastforwardable reference"); - error = GIT_ENONFASTFORWARD; - goto on_error; - } - - if (error < 0) - goto on_error; - } - } - - git_vector_foreach(&push->remote->refs, i, head) { - if (git_oid_is_zero(&head->oid)) - continue; - - if ((error = git_revwalk_hide(rw, &head->oid)) < 0 && - error != GIT_ENOTFOUND && error != GIT_EINVALIDSPEC && error != GIT_EPEEL) - goto on_error; - } - - error = git_packbuilder_insert_walk(push->pb, rw); - -on_error: - git_revwalk_free(rw); - return error; -} - -static int add_update(git_push *push, push_spec *spec) -{ - git_push_update *u = git__calloc(1, sizeof(git_push_update)); - GIT_ERROR_CHECK_ALLOC(u); - - u->src_refname = git__strdup(spec->refspec.src); - GIT_ERROR_CHECK_ALLOC(u->src_refname); - - u->dst_refname = git__strdup(spec->refspec.dst); - GIT_ERROR_CHECK_ALLOC(u->dst_refname); - - git_oid_cpy(&u->src, &spec->roid); - git_oid_cpy(&u->dst, &spec->loid); - - return git_vector_insert(&push->updates, u); -} - -static int calculate_work(git_push *push) -{ - git_remote_head *head; - push_spec *spec; - unsigned int i, j; - - /* Update local and remote oids*/ - - git_vector_foreach(&push->specs, i, spec) { - if (spec->refspec.src && spec->refspec.src[0]!= '\0') { - /* This is a create or update. Local ref must exist. */ - if (git_reference_name_to_id( - &spec->loid, push->repo, spec->refspec.src) < 0) { - git_error_set(GIT_ERROR_REFERENCE, "no such reference '%s'", spec->refspec.src); - return -1; - } - } - - /* Remote ref may or may not (e.g. during create) already exist. */ - git_vector_foreach(&push->remote->refs, j, head) { - if (!strcmp(spec->refspec.dst, head->name)) { - git_oid_cpy(&spec->roid, &head->oid); - break; - } - } - - if (add_update(push, spec) < 0) - return -1; - } - - return 0; -} - -static int do_push(git_push *push) -{ - int error = 0; - git_transport *transport = push->remote->transport; - git_remote_callbacks *callbacks = &push->callbacks; - - if (!transport->push) { - git_error_set(GIT_ERROR_NET, "remote transport doesn't support push"); - error = -1; - goto on_error; - } - - /* - * A pack-file MUST be sent if either create or update command - * is used, even if the server already has all the necessary - * objects. In this case the client MUST send an empty pack-file. - */ - - if ((error = git_packbuilder_new(&push->pb, push->repo)) < 0) - goto on_error; - - git_packbuilder_set_threads(push->pb, push->pb_parallelism); - - if (callbacks && callbacks->pack_progress) - if ((error = git_packbuilder_set_callbacks(push->pb, callbacks->pack_progress, callbacks->payload)) < 0) - goto on_error; - - if ((error = calculate_work(push)) < 0) - goto on_error; - - if (callbacks && callbacks->push_negotiation && - (error = callbacks->push_negotiation((const git_push_update **) push->updates.contents, - push->updates.length, callbacks->payload)) < 0) - goto on_error; - - if ((error = queue_objects(push)) < 0 || - (error = transport->push(transport, push)) < 0) - goto on_error; - -on_error: - git_packbuilder_free(push->pb); - return error; -} - -static int filter_refs(git_remote *remote) -{ - const git_remote_head **heads; - size_t heads_len, i; - - git_vector_clear(&remote->refs); - - if (git_remote_ls(&heads, &heads_len, remote) < 0) - return -1; - - for (i = 0; i < heads_len; i++) { - if (git_vector_insert(&remote->refs, (void *)heads[i]) < 0) - return -1; - } - - return 0; -} - -int git_push_finish(git_push *push) -{ - int error; - - if (!git_remote_connected(push->remote)) { - git_error_set(GIT_ERROR_NET, "remote is disconnected"); - return -1; - } - - if ((error = filter_refs(push->remote)) < 0 || - (error = do_push(push)) < 0) - return error; - - if (!push->unpack_ok) { - error = -1; - git_error_set(GIT_ERROR_NET, "unpacking the sent packfile failed on the remote"); - } - - return error; -} - -int git_push_status_foreach(git_push *push, - int (*cb)(const char *ref, const char *msg, void *data), - void *data) -{ - push_status *status; - unsigned int i; - - git_vector_foreach(&push->status, i, status) { - int error = cb(status->ref, status->msg, data); - if (error) - return git_error_set_after_callback(error); - } - - return 0; -} - -void git_push_status_free(push_status *status) -{ - if (status == NULL) - return; - - git__free(status->msg); - git__free(status->ref); - git__free(status); -} - -void git_push_free(git_push *push) -{ - push_spec *spec; - push_status *status; - git_push_update *update; - unsigned int i; - - if (push == NULL) - return; - - git_vector_foreach(&push->specs, i, spec) { - free_refspec(spec); - } - git_vector_free(&push->specs); - - git_vector_foreach(&push->status, i, status) { - git_push_status_free(status); - } - git_vector_free(&push->status); - - git_vector_foreach(&push->updates, i, update) { - git__free(update->src_refname); - git__free(update->dst_refname); - git__free(update); - } - git_vector_free(&push->updates); - - git__free(push); -} - -int git_push_options_init(git_push_options *opts, unsigned int version) -{ - GIT_INIT_STRUCTURE_FROM_TEMPLATE( - opts, version, git_push_options, GIT_PUSH_OPTIONS_INIT); - return 0; -} - -#ifndef GIT_DEPRECATE_HARD -int git_push_init_options(git_push_options *opts, unsigned int version) -{ - return git_push_options_init(opts, version); -} -#endif diff --git a/vendor/libgit2/src/reflog.c b/vendor/libgit2/src/reflog.c deleted file mode 100644 index 1e9c0d4f..00000000 --- a/vendor/libgit2/src/reflog.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "reflog.h" - -#include "repository.h" -#include "filebuf.h" -#include "signature.h" -#include "refdb.h" - -#include "git2/sys/refdb_backend.h" -#include "git2/sys/reflog.h" - -void git_reflog_entry__free(git_reflog_entry *entry) -{ - git_signature_free(entry->committer); - - git__free(entry->msg); - git__free(entry); -} - -void git_reflog_free(git_reflog *reflog) -{ - size_t i; - git_reflog_entry *entry; - - if (reflog == NULL) - return; - - if (reflog->db) - GIT_REFCOUNT_DEC(reflog->db, git_refdb__free); - - for (i=0; i < reflog->entries.length; i++) { - entry = git_vector_get(&reflog->entries, i); - - git_reflog_entry__free(entry); - } - - git_vector_free(&reflog->entries); - git__free(reflog->ref_name); - git__free(reflog); -} - -int git_reflog_read(git_reflog **reflog, git_repository *repo, const char *name) -{ - git_refdb *refdb; - int error; - - GIT_ASSERT_ARG(reflog); - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(name); - - if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) - return error; - - return git_refdb_reflog_read(reflog, refdb, name); -} - -int git_reflog_write(git_reflog *reflog) -{ - git_refdb *db; - - GIT_ASSERT_ARG(reflog); - GIT_ASSERT_ARG(reflog->db); - - db = reflog->db; - return db->backend->reflog_write(db->backend, reflog); -} - -int git_reflog_append(git_reflog *reflog, const git_oid *new_oid, const git_signature *committer, const char *msg) -{ - const git_reflog_entry *previous; - git_reflog_entry *entry; - - GIT_ASSERT_ARG(reflog); - GIT_ASSERT_ARG(new_oid); - GIT_ASSERT_ARG(committer); - - entry = git__calloc(1, sizeof(git_reflog_entry)); - GIT_ERROR_CHECK_ALLOC(entry); - - if ((git_signature_dup(&entry->committer, committer)) < 0) - goto cleanup; - - if (msg != NULL) { - size_t i, msglen = strlen(msg); - - if ((entry->msg = git__strndup(msg, msglen)) == NULL) - goto cleanup; - - /* - * Replace all newlines with spaces, except for - * the final trailing newline. - */ - for (i = 0; i < msglen; i++) - if (entry->msg[i] == '\n') - entry->msg[i] = ' '; - } - - previous = git_reflog_entry_byindex(reflog, 0); - - if (previous == NULL) - git_oid_fromstr(&entry->oid_old, GIT_OID_HEX_ZERO); - else - git_oid_cpy(&entry->oid_old, &previous->oid_cur); - - git_oid_cpy(&entry->oid_cur, new_oid); - - if (git_vector_insert(&reflog->entries, entry) < 0) - goto cleanup; - - return 0; - -cleanup: - git_reflog_entry__free(entry); - return -1; -} - -int git_reflog_rename(git_repository *repo, const char *old_name, const char *new_name) -{ - git_refdb *refdb; - int error; - - if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) - return -1; - - return refdb->backend->reflog_rename(refdb->backend, old_name, new_name); -} - -int git_reflog_delete(git_repository *repo, const char *name) -{ - git_refdb *refdb; - int error; - - if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) - return -1; - - return refdb->backend->reflog_delete(refdb->backend, name); -} - -size_t git_reflog_entrycount(git_reflog *reflog) -{ - GIT_ASSERT_ARG_WITH_RETVAL(reflog, 0); - return reflog->entries.length; -} - -const git_reflog_entry *git_reflog_entry_byindex(const git_reflog *reflog, size_t idx) -{ - GIT_ASSERT_ARG_WITH_RETVAL(reflog, NULL); - - if (idx >= reflog->entries.length) - return NULL; - - return git_vector_get( - &reflog->entries, reflog_inverse_index(idx, reflog->entries.length)); -} - -const git_oid *git_reflog_entry_id_old(const git_reflog_entry *entry) -{ - GIT_ASSERT_ARG_WITH_RETVAL(entry, NULL); - return &entry->oid_old; -} - -const git_oid *git_reflog_entry_id_new(const git_reflog_entry *entry) -{ - GIT_ASSERT_ARG_WITH_RETVAL(entry, NULL); - return &entry->oid_cur; -} - -const git_signature *git_reflog_entry_committer(const git_reflog_entry *entry) -{ - GIT_ASSERT_ARG_WITH_RETVAL(entry, NULL); - return entry->committer; -} - -const char *git_reflog_entry_message(const git_reflog_entry *entry) -{ - GIT_ASSERT_ARG_WITH_RETVAL(entry, NULL); - return entry->msg; -} - -int git_reflog_drop(git_reflog *reflog, size_t idx, int rewrite_previous_entry) -{ - size_t entrycount; - git_reflog_entry *entry, *previous; - - entrycount = git_reflog_entrycount(reflog); - - entry = (git_reflog_entry *)git_reflog_entry_byindex(reflog, idx); - - if (entry == NULL) { - git_error_set(GIT_ERROR_REFERENCE, "no reflog entry at index %"PRIuZ, idx); - return GIT_ENOTFOUND; - } - - git_reflog_entry__free(entry); - - if (git_vector_remove( - &reflog->entries, reflog_inverse_index(idx, entrycount)) < 0) - return -1; - - if (!rewrite_previous_entry) - return 0; - - /* No need to rewrite anything when removing the most recent entry */ - if (idx == 0) - return 0; - - /* Have the latest entry just been dropped? */ - if (entrycount == 1) - return 0; - - entry = (git_reflog_entry *)git_reflog_entry_byindex(reflog, idx - 1); - - /* If the oldest entry has just been removed... */ - if (idx == entrycount - 1) { - /* ...clear the oid_old member of the "new" oldest entry */ - if (git_oid_fromstr(&entry->oid_old, GIT_OID_HEX_ZERO) < 0) - return -1; - - return 0; - } - - previous = (git_reflog_entry *)git_reflog_entry_byindex(reflog, idx); - git_oid_cpy(&entry->oid_old, &previous->oid_cur); - - return 0; -} diff --git a/vendor/libgit2/src/refs.c b/vendor/libgit2/src/refs.c deleted file mode 100644 index 5c875b95..00000000 --- a/vendor/libgit2/src/refs.c +++ /dev/null @@ -1,1395 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "refs.h" - -#include "hash.h" -#include "repository.h" -#include "futils.h" -#include "filebuf.h" -#include "pack.h" -#include "reflog.h" -#include "refdb.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -bool git_reference__enable_symbolic_ref_target_validation = true; - -enum { - GIT_PACKREF_HAS_PEEL = 1, - GIT_PACKREF_WAS_LOOSE = 2 -}; - -static git_reference *alloc_ref(const char *name) -{ - git_reference *ref = NULL; - size_t namelen = strlen(name), reflen; - - if (!GIT_ADD_SIZET_OVERFLOW(&reflen, sizeof(git_reference), namelen) && - !GIT_ADD_SIZET_OVERFLOW(&reflen, reflen, 1) && - (ref = git__calloc(1, reflen)) != NULL) - memcpy(ref->name, name, namelen + 1); - - return ref; -} - -git_reference *git_reference__alloc_symbolic( - const char *name, const char *target) -{ - git_reference *ref; - - GIT_ASSERT_ARG_WITH_RETVAL(name, NULL); - GIT_ASSERT_ARG_WITH_RETVAL(target, NULL); - - ref = alloc_ref(name); - if (!ref) - return NULL; - - ref->type = GIT_REFERENCE_SYMBOLIC; - - if ((ref->target.symbolic = git__strdup(target)) == NULL) { - git__free(ref); - return NULL; - } - - return ref; -} - -git_reference *git_reference__alloc( - const char *name, - const git_oid *oid, - const git_oid *peel) -{ - git_reference *ref; - - GIT_ASSERT_ARG_WITH_RETVAL(name, NULL); - GIT_ASSERT_ARG_WITH_RETVAL(oid, NULL); - - ref = alloc_ref(name); - if (!ref) - return NULL; - - ref->type = GIT_REFERENCE_DIRECT; - git_oid_cpy(&ref->target.oid, oid); - - if (peel != NULL) - git_oid_cpy(&ref->peel, peel); - - return ref; -} - -git_reference *git_reference__realloc( - git_reference **ptr_to_ref, const char *name) -{ - size_t namelen, reflen; - git_reference *rewrite = NULL; - - GIT_ASSERT_ARG_WITH_RETVAL(ptr_to_ref, NULL); - GIT_ASSERT_ARG_WITH_RETVAL(name, NULL); - - namelen = strlen(name); - - if (!GIT_ADD_SIZET_OVERFLOW(&reflen, sizeof(git_reference), namelen) && - !GIT_ADD_SIZET_OVERFLOW(&reflen, reflen, 1) && - (rewrite = git__realloc(*ptr_to_ref, reflen)) != NULL) - memcpy(rewrite->name, name, namelen + 1); - - *ptr_to_ref = NULL; - - return rewrite; -} - -int git_reference_dup(git_reference **dest, git_reference *source) -{ - if (source->type == GIT_REFERENCE_SYMBOLIC) - *dest = git_reference__alloc_symbolic(source->name, source->target.symbolic); - else - *dest = git_reference__alloc(source->name, &source->target.oid, &source->peel); - - GIT_ERROR_CHECK_ALLOC(*dest); - - (*dest)->db = source->db; - GIT_REFCOUNT_INC((*dest)->db); - - return 0; -} - -void git_reference_free(git_reference *reference) -{ - if (reference == NULL) - return; - - if (reference->type == GIT_REFERENCE_SYMBOLIC) - git__free(reference->target.symbolic); - - if (reference->db) - GIT_REFCOUNT_DEC(reference->db, git_refdb__free); - - git__free(reference); -} - -int git_reference_delete(git_reference *ref) -{ - const git_oid *old_id = NULL; - const char *old_target = NULL; - - if (!strcmp(ref->name, "HEAD")) { - git_error_set(GIT_ERROR_REFERENCE, "cannot delete HEAD"); - return GIT_ERROR; - } - - if (ref->type == GIT_REFERENCE_DIRECT) - old_id = &ref->target.oid; - else - old_target = ref->target.symbolic; - - return git_refdb_delete(ref->db, ref->name, old_id, old_target); -} - -int git_reference_remove(git_repository *repo, const char *name) -{ - git_refdb *db; - int error; - - if ((error = git_repository_refdb__weakptr(&db, repo)) < 0) - return error; - - return git_refdb_delete(db, name, NULL, NULL); -} - -int git_reference_lookup(git_reference **ref_out, - git_repository *repo, const char *name) -{ - return git_reference_lookup_resolved(ref_out, repo, name, 0); -} - -int git_reference_name_to_id( - git_oid *out, git_repository *repo, const char *name) -{ - int error; - git_reference *ref; - - if ((error = git_reference_lookup_resolved(&ref, repo, name, -1)) < 0) - return error; - - git_oid_cpy(out, git_reference_target(ref)); - git_reference_free(ref); - return 0; -} - -static int reference_normalize_for_repo( - git_refname_t out, - git_repository *repo, - const char *name, - bool validate) -{ - int precompose; - unsigned int flags = GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL; - - if (!git_repository__configmap_lookup(&precompose, repo, GIT_CONFIGMAP_PRECOMPOSE) && - precompose) - flags |= GIT_REFERENCE_FORMAT__PRECOMPOSE_UNICODE; - - if (!validate) - flags |= GIT_REFERENCE_FORMAT__VALIDATION_DISABLE; - - return git_reference_normalize_name(out, GIT_REFNAME_MAX, name, flags); -} - -int git_reference_lookup_resolved( - git_reference **ref_out, - git_repository *repo, - const char *name, - int max_nesting) -{ - git_refname_t normalized; - git_refdb *refdb; - int error = 0; - - GIT_ASSERT_ARG(ref_out); - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(name); - - if ((error = reference_normalize_for_repo(normalized, repo, name, true)) < 0 || - (error = git_repository_refdb__weakptr(&refdb, repo)) < 0 || - (error = git_refdb_resolve(ref_out, refdb, normalized, max_nesting)) < 0) - return error; - - /* - * The resolved reference may be a symbolic reference in case its - * target doesn't exist. If the user asked us to resolve (e.g. - * `max_nesting != 0`), then we need to return an error in case we got - * a symbolic reference back. - */ - if (max_nesting && git_reference_type(*ref_out) == GIT_REFERENCE_SYMBOLIC) { - git_reference_free(*ref_out); - *ref_out = NULL; - return GIT_ENOTFOUND; - } - - return 0; -} - -int git_reference_dwim(git_reference **out, git_repository *repo, const char *refname) -{ - int error = 0, i, valid; - bool fallbackmode = true, foundvalid = false; - git_reference *ref; - git_str refnamebuf = GIT_STR_INIT, name = GIT_STR_INIT; - - static const char *formatters[] = { - "%s", - GIT_REFS_DIR "%s", - GIT_REFS_TAGS_DIR "%s", - GIT_REFS_HEADS_DIR "%s", - GIT_REFS_REMOTES_DIR "%s", - GIT_REFS_REMOTES_DIR "%s/" GIT_HEAD_FILE, - NULL - }; - - if (*refname) - git_str_puts(&name, refname); - else { - git_str_puts(&name, GIT_HEAD_FILE); - fallbackmode = false; - } - - for (i = 0; formatters[i] && (fallbackmode || i == 0); i++) { - - git_str_clear(&refnamebuf); - - if ((error = git_str_printf(&refnamebuf, formatters[i], git_str_cstr(&name))) < 0 || - (error = git_reference_name_is_valid(&valid, git_str_cstr(&refnamebuf))) < 0) - goto cleanup; - - if (!valid) { - error = GIT_EINVALIDSPEC; - continue; - } - foundvalid = true; - - error = git_reference_lookup_resolved(&ref, repo, git_str_cstr(&refnamebuf), -1); - - if (!error) { - *out = ref; - error = 0; - goto cleanup; - } - - if (error != GIT_ENOTFOUND) - goto cleanup; - } - -cleanup: - if (error && !foundvalid) { - /* never found a valid reference name */ - git_error_set(GIT_ERROR_REFERENCE, - "could not use '%s' as valid reference name", git_str_cstr(&name)); - } - - if (error == GIT_ENOTFOUND) - git_error_set(GIT_ERROR_REFERENCE, "no reference found for shorthand '%s'", refname); - - git_str_dispose(&name); - git_str_dispose(&refnamebuf); - return error; -} - -/** - * Getters - */ -git_reference_t git_reference_type(const git_reference *ref) -{ - GIT_ASSERT_ARG(ref); - return ref->type; -} - -const char *git_reference_name(const git_reference *ref) -{ - GIT_ASSERT_ARG_WITH_RETVAL(ref, NULL); - return ref->name; -} - -git_repository *git_reference_owner(const git_reference *ref) -{ - GIT_ASSERT_ARG_WITH_RETVAL(ref, NULL); - return ref->db->repo; -} - -const git_oid *git_reference_target(const git_reference *ref) -{ - GIT_ASSERT_ARG_WITH_RETVAL(ref, NULL); - - if (ref->type != GIT_REFERENCE_DIRECT) - return NULL; - - return &ref->target.oid; -} - -const git_oid *git_reference_target_peel(const git_reference *ref) -{ - GIT_ASSERT_ARG_WITH_RETVAL(ref, NULL); - - if (ref->type != GIT_REFERENCE_DIRECT || git_oid_is_zero(&ref->peel)) - return NULL; - - return &ref->peel; -} - -const char *git_reference_symbolic_target(const git_reference *ref) -{ - GIT_ASSERT_ARG_WITH_RETVAL(ref, NULL); - - if (ref->type != GIT_REFERENCE_SYMBOLIC) - return NULL; - - return ref->target.symbolic; -} - -static int reference__create( - git_reference **ref_out, - git_repository *repo, - const char *name, - const git_oid *oid, - const char *symbolic, - int force, - const git_signature *signature, - const char *log_message, - const git_oid *old_id, - const char *old_target) -{ - git_refname_t normalized; - git_refdb *refdb; - git_reference *ref = NULL; - int error = 0; - - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(name); - GIT_ASSERT_ARG(symbolic || signature); - - if (ref_out) - *ref_out = NULL; - - error = reference_normalize_for_repo(normalized, repo, name, true); - if (error < 0) - return error; - - error = git_repository_refdb__weakptr(&refdb, repo); - if (error < 0) - return error; - - if (oid != NULL) { - GIT_ASSERT(symbolic == NULL); - - if (!git_object__is_valid(repo, oid, GIT_OBJECT_ANY)) { - git_error_set(GIT_ERROR_REFERENCE, - "target OID for the reference doesn't exist on the repository"); - return -1; - } - - ref = git_reference__alloc(normalized, oid, NULL); - } else { - git_refname_t normalized_target; - - error = reference_normalize_for_repo(normalized_target, repo, - symbolic, git_reference__enable_symbolic_ref_target_validation); - - if (error < 0) - return error; - - ref = git_reference__alloc_symbolic(normalized, normalized_target); - } - - GIT_ERROR_CHECK_ALLOC(ref); - - if ((error = git_refdb_write(refdb, ref, force, signature, log_message, old_id, old_target)) < 0) { - git_reference_free(ref); - return error; - } - - if (ref_out == NULL) - git_reference_free(ref); - else - *ref_out = ref; - - return 0; -} - -static int refs_configured_ident(git_signature **out, const git_repository *repo) -{ - if (repo->ident_name && repo->ident_email) - return git_signature_now(out, repo->ident_name, repo->ident_email); - - /* if not configured let us fall-through to the next method */ - return -1; -} - -int git_reference__log_signature(git_signature **out, git_repository *repo) -{ - int error; - git_signature *who; - - if(((error = refs_configured_ident(&who, repo)) < 0) && - ((error = git_signature_default(&who, repo)) < 0) && - ((error = git_signature_now(&who, "unknown", "unknown")) < 0)) - return error; - - *out = who; - return 0; -} - -int git_reference_create_matching( - git_reference **ref_out, - git_repository *repo, - const char *name, - const git_oid *id, - int force, - const git_oid *old_id, - const char *log_message) - -{ - int error; - git_signature *who = NULL; - - GIT_ASSERT_ARG(id); - - if ((error = git_reference__log_signature(&who, repo)) < 0) - return error; - - error = reference__create( - ref_out, repo, name, id, NULL, force, who, log_message, old_id, NULL); - - git_signature_free(who); - return error; -} - -int git_reference_create( - git_reference **ref_out, - git_repository *repo, - const char *name, - const git_oid *id, - int force, - const char *log_message) -{ - return git_reference_create_matching(ref_out, repo, name, id, force, NULL, log_message); -} - -int git_reference_symbolic_create_matching( - git_reference **ref_out, - git_repository *repo, - const char *name, - const char *target, - int force, - const char *old_target, - const char *log_message) -{ - int error; - git_signature *who = NULL; - - GIT_ASSERT_ARG(target); - - if ((error = git_reference__log_signature(&who, repo)) < 0) - return error; - - error = reference__create( - ref_out, repo, name, NULL, target, force, who, log_message, NULL, old_target); - - git_signature_free(who); - return error; -} - -int git_reference_symbolic_create( - git_reference **ref_out, - git_repository *repo, - const char *name, - const char *target, - int force, - const char *log_message) -{ - return git_reference_symbolic_create_matching(ref_out, repo, name, target, force, NULL, log_message); -} - -static int ensure_is_an_updatable_direct_reference(git_reference *ref) -{ - if (ref->type == GIT_REFERENCE_DIRECT) - return 0; - - git_error_set(GIT_ERROR_REFERENCE, "cannot set OID on symbolic reference"); - return -1; -} - -int git_reference_set_target( - git_reference **out, - git_reference *ref, - const git_oid *id, - const char *log_message) -{ - int error; - git_repository *repo; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(ref); - GIT_ASSERT_ARG(id); - - repo = ref->db->repo; - - if ((error = ensure_is_an_updatable_direct_reference(ref)) < 0) - return error; - - return git_reference_create_matching(out, repo, ref->name, id, 1, &ref->target.oid, log_message); -} - -static int ensure_is_an_updatable_symbolic_reference(git_reference *ref) -{ - if (ref->type == GIT_REFERENCE_SYMBOLIC) - return 0; - - git_error_set(GIT_ERROR_REFERENCE, "cannot set symbolic target on a direct reference"); - return -1; -} - -int git_reference_symbolic_set_target( - git_reference **out, - git_reference *ref, - const char *target, - const char *log_message) -{ - int error; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(ref); - GIT_ASSERT_ARG(target); - - if ((error = ensure_is_an_updatable_symbolic_reference(ref)) < 0) - return error; - - return git_reference_symbolic_create_matching( - out, ref->db->repo, ref->name, target, 1, ref->target.symbolic, log_message); -} - -typedef struct { - const char *old_name; - git_refname_t new_name; -} refs_update_head_payload; - -static int refs_update_head(git_repository *worktree, void *_payload) -{ - refs_update_head_payload *payload = (refs_update_head_payload *)_payload; - git_reference *head = NULL, *updated = NULL; - int error; - - if ((error = git_reference_lookup(&head, worktree, GIT_HEAD_FILE)) < 0) - goto out; - - if (git_reference_type(head) != GIT_REFERENCE_SYMBOLIC || - git__strcmp(git_reference_symbolic_target(head), payload->old_name) != 0) - goto out; - - /* Update HEAD if it was pointing to the reference being renamed */ - if ((error = git_reference_symbolic_set_target(&updated, head, payload->new_name, NULL)) < 0) { - git_error_set(GIT_ERROR_REFERENCE, "failed to update HEAD after renaming reference"); - goto out; - } - -out: - git_reference_free(updated); - git_reference_free(head); - return error; -} - -int git_reference_rename( - git_reference **out, - git_reference *ref, - const char *new_name, - int force, - const char *log_message) -{ - refs_update_head_payload payload; - git_signature *signature = NULL; - git_repository *repo; - int error; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(ref); - - repo = git_reference_owner(ref); - - if ((error = git_reference__log_signature(&signature, repo)) < 0 || - (error = reference_normalize_for_repo(payload.new_name, repo, new_name, true)) < 0 || - (error = git_refdb_rename(out, ref->db, ref->name, payload.new_name, force, signature, log_message)) < 0) - goto out; - - payload.old_name = ref->name; - - /* We may have to update any HEAD that was pointing to the renamed reference. */ - if ((error = git_repository_foreach_worktree(repo, refs_update_head, &payload)) < 0) - goto out; - -out: - git_signature_free(signature); - return error; -} - -int git_reference_resolve(git_reference **ref_out, const git_reference *ref) -{ - switch (git_reference_type(ref)) { - case GIT_REFERENCE_DIRECT: - return git_reference_lookup(ref_out, ref->db->repo, ref->name); - - case GIT_REFERENCE_SYMBOLIC: - return git_reference_lookup_resolved(ref_out, ref->db->repo, ref->target.symbolic, -1); - - default: - git_error_set(GIT_ERROR_REFERENCE, "invalid reference"); - return -1; - } -} - -int git_reference_foreach( - git_repository *repo, - git_reference_foreach_cb callback, - void *payload) -{ - git_reference_iterator *iter; - git_reference *ref; - int error; - - if ((error = git_reference_iterator_new(&iter, repo)) < 0) - return error; - - while (!(error = git_reference_next(&ref, iter))) { - if ((error = callback(ref, payload)) != 0) { - git_error_set_after_callback(error); - break; - } - } - - if (error == GIT_ITEROVER) - error = 0; - - git_reference_iterator_free(iter); - return error; -} - -int git_reference_foreach_name( - git_repository *repo, - git_reference_foreach_name_cb callback, - void *payload) -{ - git_reference_iterator *iter; - const char *refname; - int error; - - if ((error = git_reference_iterator_new(&iter, repo)) < 0) - return error; - - while (!(error = git_reference_next_name(&refname, iter))) { - if ((error = callback(refname, payload)) != 0) { - git_error_set_after_callback(error); - break; - } - } - - if (error == GIT_ITEROVER) - error = 0; - - git_reference_iterator_free(iter); - return error; -} - -int git_reference_foreach_glob( - git_repository *repo, - const char *glob, - git_reference_foreach_name_cb callback, - void *payload) -{ - git_reference_iterator *iter; - const char *refname; - int error; - - if ((error = git_reference_iterator_glob_new(&iter, repo, glob)) < 0) - return error; - - while (!(error = git_reference_next_name(&refname, iter))) { - if ((error = callback(refname, payload)) != 0) { - git_error_set_after_callback(error); - break; - } - } - - if (error == GIT_ITEROVER) - error = 0; - - git_reference_iterator_free(iter); - return error; -} - -int git_reference_iterator_new(git_reference_iterator **out, git_repository *repo) -{ - git_refdb *refdb; - - if (git_repository_refdb__weakptr(&refdb, repo) < 0) - return -1; - - return git_refdb_iterator(out, refdb, NULL); -} - -int git_reference_iterator_glob_new( - git_reference_iterator **out, git_repository *repo, const char *glob) -{ - git_refdb *refdb; - - if (git_repository_refdb__weakptr(&refdb, repo) < 0) - return -1; - - return git_refdb_iterator(out, refdb, glob); -} - -int git_reference_next(git_reference **out, git_reference_iterator *iter) -{ - return git_refdb_iterator_next(out, iter); -} - -int git_reference_next_name(const char **out, git_reference_iterator *iter) -{ - return git_refdb_iterator_next_name(out, iter); -} - -void git_reference_iterator_free(git_reference_iterator *iter) -{ - if (iter == NULL) - return; - - git_refdb_iterator_free(iter); -} - -static int cb__reflist_add(const char *ref, void *data) -{ - char *name = git__strdup(ref); - GIT_ERROR_CHECK_ALLOC(name); - return git_vector_insert((git_vector *)data, name); -} - -int git_reference_list( - git_strarray *array, - git_repository *repo) -{ - git_vector ref_list; - - GIT_ASSERT_ARG(array); - GIT_ASSERT_ARG(repo); - - array->strings = NULL; - array->count = 0; - - if (git_vector_init(&ref_list, 8, NULL) < 0) - return -1; - - if (git_reference_foreach_name( - repo, &cb__reflist_add, (void *)&ref_list) < 0) { - git_vector_free(&ref_list); - return -1; - } - - array->strings = (char **)git_vector_detach(&array->count, NULL, &ref_list); - - return 0; -} - -static int is_valid_ref_char(char ch) -{ - if ((unsigned) ch <= ' ') - return 0; - - switch (ch) { - case '~': - case '^': - case ':': - case '\\': - case '?': - case '[': - return 0; - default: - return 1; - } -} - -static int ensure_segment_validity(const char *name, char may_contain_glob) -{ - const char *current = name; - char prev = '\0'; - const int lock_len = (int)strlen(GIT_FILELOCK_EXTENSION); - int segment_len; - - if (*current == '.') - return -1; /* Refname starts with "." */ - - for (current = name; ; current++) { - if (*current == '\0' || *current == '/') - break; - - if (!is_valid_ref_char(*current)) - return -1; /* Illegal character in refname */ - - if (prev == '.' && *current == '.') - return -1; /* Refname contains ".." */ - - if (prev == '@' && *current == '{') - return -1; /* Refname contains "@{" */ - - if (*current == '*') { - if (!may_contain_glob) - return -1; - may_contain_glob = 0; - } - - prev = *current; - } - - segment_len = (int)(current - name); - - /* A refname component can not end with ".lock" */ - if (segment_len >= lock_len && - !memcmp(current - lock_len, GIT_FILELOCK_EXTENSION, lock_len)) - return -1; - - return segment_len; -} - -static bool is_all_caps_and_underscore(const char *name, size_t len) -{ - size_t i; - char c; - - GIT_ASSERT_ARG(name); - GIT_ASSERT_ARG(len > 0); - - for (i = 0; i < len; i++) - { - c = name[i]; - if ((c < 'A' || c > 'Z') && c != '_') - return false; - } - - if (*name == '_' || name[len - 1] == '_') - return false; - - return true; -} - -/* Inspired from https://github.com/git/git/blob/f06d47e7e0d9db709ee204ed13a8a7486149f494/refs.c#L36-100 */ -int git_reference__normalize_name( - git_str *buf, - const char *name, - unsigned int flags) -{ - const char *current; - int segment_len, segments_count = 0, error = GIT_EINVALIDSPEC; - unsigned int process_flags; - bool normalize = (buf != NULL); - bool validate = (flags & GIT_REFERENCE_FORMAT__VALIDATION_DISABLE) == 0; - -#ifdef GIT_USE_ICONV - git_fs_path_iconv_t ic = GIT_PATH_ICONV_INIT; -#endif - - GIT_ASSERT_ARG(name); - - process_flags = flags; - current = (char *)name; - - if (validate && *current == '/') - goto cleanup; - - if (normalize) - git_str_clear(buf); - -#ifdef GIT_USE_ICONV - if ((flags & GIT_REFERENCE_FORMAT__PRECOMPOSE_UNICODE) != 0) { - size_t namelen = strlen(current); - if ((error = git_fs_path_iconv_init_precompose(&ic)) < 0 || - (error = git_fs_path_iconv(&ic, ¤t, &namelen)) < 0) - goto cleanup; - error = GIT_EINVALIDSPEC; - } -#endif - - if (!validate) { - git_str_sets(buf, current); - - error = git_str_oom(buf) ? -1 : 0; - goto cleanup; - } - - while (true) { - char may_contain_glob = process_flags & GIT_REFERENCE_FORMAT_REFSPEC_PATTERN; - - segment_len = ensure_segment_validity(current, may_contain_glob); - if (segment_len < 0) - goto cleanup; - - if (segment_len > 0) { - /* - * There may only be one glob in a pattern, thus we reset - * the pattern-flag in case the current segment has one. - */ - if (memchr(current, '*', segment_len)) - process_flags &= ~GIT_REFERENCE_FORMAT_REFSPEC_PATTERN; - - if (normalize) { - size_t cur_len = git_str_len(buf); - - git_str_joinpath(buf, git_str_cstr(buf), current); - git_str_truncate(buf, - cur_len + segment_len + (segments_count ? 1 : 0)); - - if (git_str_oom(buf)) { - error = -1; - goto cleanup; - } - } - - segments_count++; - } - - /* No empty segment is allowed when not normalizing */ - if (segment_len == 0 && !normalize) - goto cleanup; - - if (current[segment_len] == '\0') - break; - - current += segment_len + 1; - } - - /* A refname can not be empty */ - if (segment_len == 0 && segments_count == 0) - goto cleanup; - - /* A refname can not end with "." */ - if (current[segment_len - 1] == '.') - goto cleanup; - - /* A refname can not end with "/" */ - if (current[segment_len - 1] == '/') - goto cleanup; - - if ((segments_count == 1 ) && !(flags & GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL)) - goto cleanup; - - if ((segments_count == 1 ) && - !(flags & GIT_REFERENCE_FORMAT_REFSPEC_SHORTHAND) && - !(is_all_caps_and_underscore(name, (size_t)segment_len) || - ((flags & GIT_REFERENCE_FORMAT_REFSPEC_PATTERN) && !strcmp("*", name)))) - goto cleanup; - - if ((segments_count > 1) - && (is_all_caps_and_underscore(name, strchr(name, '/') - name))) - goto cleanup; - - error = 0; - -cleanup: - if (error == GIT_EINVALIDSPEC) - git_error_set( - GIT_ERROR_REFERENCE, - "the given reference name '%s' is not valid", name); - - if (error && normalize) - git_str_dispose(buf); - -#ifdef GIT_USE_ICONV - git_fs_path_iconv_clear(&ic); -#endif - - return error; -} - -int git_reference_normalize_name( - char *buffer_out, - size_t buffer_size, - const char *name, - unsigned int flags) -{ - git_str buf = GIT_STR_INIT; - int error; - - if ((error = git_reference__normalize_name(&buf, name, flags)) < 0) - goto cleanup; - - if (git_str_len(&buf) > buffer_size - 1) { - git_error_set( - GIT_ERROR_REFERENCE, - "the provided buffer is too short to hold the normalization of '%s'", name); - error = GIT_EBUFS; - goto cleanup; - } - - if ((error = git_str_copy_cstr(buffer_out, buffer_size, &buf)) < 0) - goto cleanup; - - error = 0; - -cleanup: - git_str_dispose(&buf); - return error; -} - -#define GIT_REFERENCE_TYPEMASK (GIT_REFERENCE_DIRECT | GIT_REFERENCE_SYMBOLIC) - -int git_reference_cmp( - const git_reference *ref1, - const git_reference *ref2) -{ - git_reference_t type1, type2; - - GIT_ASSERT_ARG(ref1); - GIT_ASSERT_ARG(ref2); - - type1 = git_reference_type(ref1); - type2 = git_reference_type(ref2); - - /* let's put symbolic refs before OIDs */ - if (type1 != type2) - return (type1 == GIT_REFERENCE_SYMBOLIC) ? -1 : 1; - - if (type1 == GIT_REFERENCE_SYMBOLIC) - return strcmp(ref1->target.symbolic, ref2->target.symbolic); - - return git_oid__cmp(&ref1->target.oid, &ref2->target.oid); -} - -/* - * Starting with the reference given by `ref_name`, follows symbolic - * references until a direct reference is found and updated the OID - * on that direct reference to `oid`. - */ -int git_reference__update_terminal( - git_repository *repo, - const char *ref_name, - const git_oid *oid, - const git_signature *sig, - const char *log_message) -{ - git_reference *ref = NULL, *ref2 = NULL; - git_signature *who = NULL; - git_refdb *refdb = NULL; - const git_signature *to_use; - int error = 0; - - if (!sig && (error = git_reference__log_signature(&who, repo)) < 0) - goto out; - - to_use = sig ? sig : who; - - if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) - goto out; - - if ((error = git_refdb_resolve(&ref, refdb, ref_name, -1)) < 0) { - if (error == GIT_ENOTFOUND) { - git_error_clear(); - error = reference__create(&ref2, repo, ref_name, oid, NULL, 0, to_use, - log_message, NULL, NULL); - } - goto out; - } - - /* In case the resolved reference is symbolic, then it's a dangling symref. */ - if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) { - error = reference__create(&ref2, repo, ref->target.symbolic, oid, NULL, 0, to_use, - log_message, NULL, NULL); - } else { - error = reference__create(&ref2, repo, ref->name, oid, NULL, 1, to_use, - log_message, &ref->target.oid, NULL); - } - -out: - git_reference_free(ref2); - git_reference_free(ref); - git_signature_free(who); - return error; -} - -static const char *commit_type(const git_commit *commit) -{ - unsigned int count = git_commit_parentcount(commit); - - if (count >= 2) - return " (merge)"; - else if (count == 0) - return " (initial)"; - else - return ""; -} - -int git_reference__update_for_commit( - git_repository *repo, - git_reference *ref, - const char *ref_name, - const git_oid *id, - const char *operation) -{ - git_reference *ref_new = NULL; - git_commit *commit = NULL; - git_str reflog_msg = GIT_STR_INIT; - const git_signature *who; - int error; - - if ((error = git_commit_lookup(&commit, repo, id)) < 0 || - (error = git_str_printf(&reflog_msg, "%s%s: %s", - operation ? operation : "commit", - commit_type(commit), - git_commit_summary(commit))) < 0) - goto done; - - who = git_commit_committer(commit); - - if (ref) { - if ((error = ensure_is_an_updatable_direct_reference(ref)) < 0) - return error; - - error = reference__create(&ref_new, repo, ref->name, id, NULL, 1, who, - git_str_cstr(&reflog_msg), &ref->target.oid, NULL); - } - else - error = git_reference__update_terminal( - repo, ref_name, id, who, git_str_cstr(&reflog_msg)); - -done: - git_reference_free(ref_new); - git_str_dispose(&reflog_msg); - git_commit_free(commit); - return error; -} - -int git_reference_has_log(git_repository *repo, const char *refname) -{ - int error; - git_refdb *refdb; - - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(refname); - - if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) - return error; - - return git_refdb_has_log(refdb, refname); -} - -int git_reference_ensure_log(git_repository *repo, const char *refname) -{ - int error; - git_refdb *refdb; - - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(refname); - - if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) - return error; - - return git_refdb_ensure_log(refdb, refname); -} - -int git_reference__is_branch(const char *ref_name) -{ - return git__prefixcmp(ref_name, GIT_REFS_HEADS_DIR) == 0; -} - -int git_reference_is_branch(const git_reference *ref) -{ - GIT_ASSERT_ARG(ref); - return git_reference__is_branch(ref->name); -} - -int git_reference__is_remote(const char *ref_name) -{ - return git__prefixcmp(ref_name, GIT_REFS_REMOTES_DIR) == 0; -} - -int git_reference_is_remote(const git_reference *ref) -{ - GIT_ASSERT_ARG(ref); - return git_reference__is_remote(ref->name); -} - -int git_reference__is_tag(const char *ref_name) -{ - return git__prefixcmp(ref_name, GIT_REFS_TAGS_DIR) == 0; -} - -int git_reference_is_tag(const git_reference *ref) -{ - GIT_ASSERT_ARG(ref); - return git_reference__is_tag(ref->name); -} - -int git_reference__is_note(const char *ref_name) -{ - return git__prefixcmp(ref_name, GIT_REFS_NOTES_DIR) == 0; -} - -int git_reference_is_note(const git_reference *ref) -{ - GIT_ASSERT_ARG(ref); - return git_reference__is_note(ref->name); -} - -static int peel_error(int error, const git_reference *ref, const char *msg) -{ - git_error_set( - GIT_ERROR_INVALID, - "the reference '%s' cannot be peeled - %s", git_reference_name(ref), msg); - return error; -} - -int git_reference_peel( - git_object **peeled, - const git_reference *ref, - git_object_t target_type) -{ - const git_reference *resolved = NULL; - git_reference *allocated = NULL; - git_object *target = NULL; - int error; - - GIT_ASSERT_ARG(ref); - - if (ref->type == GIT_REFERENCE_DIRECT) { - resolved = ref; - } else { - if ((error = git_reference_resolve(&allocated, ref)) < 0) - return peel_error(error, ref, "Cannot resolve reference"); - - resolved = allocated; - } - - /* - * If we try to peel an object to a tag, we cannot use - * the fully peeled object, as that will always resolve - * to a commit. So we only want to use the peeled value - * if it is not zero and the target is not a tag. - */ - if (target_type != GIT_OBJECT_TAG && !git_oid_is_zero(&resolved->peel)) { - error = git_object_lookup(&target, - git_reference_owner(ref), &resolved->peel, GIT_OBJECT_ANY); - } else { - error = git_object_lookup(&target, - git_reference_owner(ref), &resolved->target.oid, GIT_OBJECT_ANY); - } - - if (error < 0) { - peel_error(error, ref, "Cannot retrieve reference target"); - goto cleanup; - } - - if (target_type == GIT_OBJECT_ANY && git_object_type(target) != GIT_OBJECT_TAG) - error = git_object_dup(peeled, target); - else - error = git_object_peel(peeled, target, target_type); - -cleanup: - git_object_free(target); - git_reference_free(allocated); - - return error; -} - -int git_reference__name_is_valid( - int *valid, - const char *refname, - unsigned int flags) -{ - int error; - - GIT_ASSERT(valid && refname); - - *valid = 0; - - error = git_reference__normalize_name(NULL, refname, flags); - - if (!error) - *valid = 1; - else if (error == GIT_EINVALIDSPEC) - error = 0; - - return error; -} - -int git_reference_name_is_valid(int *valid, const char *refname) -{ - return git_reference__name_is_valid(valid, refname, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL); -} - -const char *git_reference__shorthand(const char *name) -{ - if (!git__prefixcmp(name, GIT_REFS_HEADS_DIR)) - return name + strlen(GIT_REFS_HEADS_DIR); - else if (!git__prefixcmp(name, GIT_REFS_TAGS_DIR)) - return name + strlen(GIT_REFS_TAGS_DIR); - else if (!git__prefixcmp(name, GIT_REFS_REMOTES_DIR)) - return name + strlen(GIT_REFS_REMOTES_DIR); - else if (!git__prefixcmp(name, GIT_REFS_DIR)) - return name + strlen(GIT_REFS_DIR); - - /* No shorthands are available, so just return the name. */ - return name; -} - -const char *git_reference_shorthand(const git_reference *ref) -{ - return git_reference__shorthand(ref->name); -} - -int git_reference__is_unborn_head(bool *unborn, const git_reference *ref, git_repository *repo) -{ - int error; - git_reference *tmp_ref; - - GIT_ASSERT_ARG(unborn); - GIT_ASSERT_ARG(ref); - GIT_ASSERT_ARG(repo); - - if (ref->type == GIT_REFERENCE_DIRECT) { - *unborn = 0; - return 0; - } - - error = git_reference_lookup_resolved(&tmp_ref, repo, ref->name, -1); - git_reference_free(tmp_ref); - - if (error != 0 && error != GIT_ENOTFOUND) - return error; - else if (error == GIT_ENOTFOUND && git__strcmp(ref->name, GIT_HEAD_FILE) == 0) - *unborn = true; - else - *unborn = false; - - return 0; -} - -/* Deprecated functions */ - -#ifndef GIT_DEPRECATE_HARD - -int git_reference_is_valid_name(const char *refname) -{ - int valid = 0; - - git_reference__name_is_valid(&valid, refname, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL); - - return valid; -} - -#endif diff --git a/vendor/libgit2/src/regexp.c b/vendor/libgit2/src/regexp.c deleted file mode 100644 index 2569dea0..00000000 --- a/vendor/libgit2/src/regexp.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "regexp.h" - -#if defined(GIT_REGEX_BUILTIN) || defined(GIT_REGEX_PCRE) - -int git_regexp_compile(git_regexp *r, const char *pattern, int flags) -{ - int erroffset, cflags = 0; - const char *error = NULL; - - if (flags & GIT_REGEXP_ICASE) - cflags |= PCRE_CASELESS; - - if ((*r = pcre_compile(pattern, cflags, &error, &erroffset, NULL)) == NULL) { - git_error_set_str(GIT_ERROR_REGEX, error); - return GIT_EINVALIDSPEC; - } - - return 0; -} - -void git_regexp_dispose(git_regexp *r) -{ - pcre_free(*r); - *r = NULL; -} - -int git_regexp_match(const git_regexp *r, const char *string) -{ - int error; - if ((error = pcre_exec(*r, NULL, string, (int) strlen(string), 0, 0, NULL, 0)) < 0) - return (error == PCRE_ERROR_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC; - return 0; -} - -int git_regexp_search(const git_regexp *r, const char *string, size_t nmatches, git_regmatch *matches) -{ - int static_ovec[9] = {0}, *ovec; - int error; - size_t i; - - /* The ovec array always needs to be a multiple of three */ - if (nmatches <= ARRAY_SIZE(static_ovec) / 3) - ovec = static_ovec; - else - ovec = git__calloc(nmatches * 3, sizeof(*ovec)); - GIT_ERROR_CHECK_ALLOC(ovec); - - if ((error = pcre_exec(*r, NULL, string, (int) strlen(string), 0, 0, ovec, (int) nmatches * 3)) < 0) - goto out; - - if (error == 0) - error = (int) nmatches; - - for (i = 0; i < (unsigned int) error; i++) { - matches[i].start = (ovec[i * 2] < 0) ? -1 : ovec[i * 2]; - matches[i].end = (ovec[i * 2 + 1] < 0) ? -1 : ovec[i * 2 + 1]; - } - for (i = (unsigned int) error; i < nmatches; i++) - matches[i].start = matches[i].end = -1; - -out: - if (nmatches > ARRAY_SIZE(static_ovec) / 3) - git__free(ovec); - if (error < 0) - return (error == PCRE_ERROR_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC; - return 0; -} - -#elif defined(GIT_REGEX_PCRE2) - -int git_regexp_compile(git_regexp *r, const char *pattern, int flags) -{ - unsigned char errmsg[1024]; - PCRE2_SIZE erroff; - int error, cflags = 0; - - if (flags & GIT_REGEXP_ICASE) - cflags |= PCRE2_CASELESS; - - if ((*r = pcre2_compile((const unsigned char *) pattern, PCRE2_ZERO_TERMINATED, - cflags, &error, &erroff, NULL)) == NULL) { - pcre2_get_error_message(error, errmsg, sizeof(errmsg)); - git_error_set_str(GIT_ERROR_REGEX, (char *) errmsg); - return GIT_EINVALIDSPEC; - } - - return 0; -} - -void git_regexp_dispose(git_regexp *r) -{ - pcre2_code_free(*r); - *r = NULL; -} - -int git_regexp_match(const git_regexp *r, const char *string) -{ - pcre2_match_data *data; - int error; - - data = pcre2_match_data_create(1, NULL); - GIT_ERROR_CHECK_ALLOC(data); - - if ((error = pcre2_match(*r, (const unsigned char *) string, strlen(string), - 0, 0, data, NULL)) < 0) - return (error == PCRE2_ERROR_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC; - - pcre2_match_data_free(data); - return 0; -} - -int git_regexp_search(const git_regexp *r, const char *string, size_t nmatches, git_regmatch *matches) -{ - pcre2_match_data *data = NULL; - PCRE2_SIZE *ovec; - int error; - size_t i; - - if ((data = pcre2_match_data_create(nmatches, NULL)) == NULL) { - git_error_set_oom(); - goto out; - } - - if ((error = pcre2_match(*r, (const unsigned char *) string, strlen(string), - 0, 0, data, NULL)) < 0) - goto out; - - if (error == 0 || (unsigned int) error > nmatches) - error = nmatches; - ovec = pcre2_get_ovector_pointer(data); - - for (i = 0; i < (unsigned int) error; i++) { - matches[i].start = (ovec[i * 2] == PCRE2_UNSET) ? -1 : (ssize_t) ovec[i * 2]; - matches[i].end = (ovec[i * 2 + 1] == PCRE2_UNSET) ? -1 : (ssize_t) ovec[i * 2 + 1]; - } - for (i = (unsigned int) error; i < nmatches; i++) - matches[i].start = matches[i].end = -1; - -out: - pcre2_match_data_free(data); - if (error < 0) - return (error == PCRE2_ERROR_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC; - return 0; -} - -#elif defined(GIT_REGEX_REGCOMP) || defined(GIT_REGEX_REGCOMP_L) - -#if defined(GIT_REGEX_REGCOMP_L) -# include -#endif - -int git_regexp_compile(git_regexp *r, const char *pattern, int flags) -{ - int cflags = REG_EXTENDED, error; - char errmsg[1024]; - - if (flags & GIT_REGEXP_ICASE) - cflags |= REG_ICASE; - -# if defined(GIT_REGEX_REGCOMP) - if ((error = regcomp(r, pattern, cflags)) != 0) -# else - if ((error = regcomp_l(r, pattern, cflags, (locale_t) 0)) != 0) -# endif - { - regerror(error, r, errmsg, sizeof(errmsg)); - git_error_set_str(GIT_ERROR_REGEX, errmsg); - return GIT_EINVALIDSPEC; - } - - return 0; -} - -void git_regexp_dispose(git_regexp *r) -{ - regfree(r); -} - -int git_regexp_match(const git_regexp *r, const char *string) -{ - int error; - if ((error = regexec(r, string, 0, NULL, 0)) != 0) - return (error == REG_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC; - return 0; -} - -int git_regexp_search(const git_regexp *r, const char *string, size_t nmatches, git_regmatch *matches) -{ - regmatch_t static_m[3], *m; - int error; - size_t i; - - if (nmatches <= ARRAY_SIZE(static_m)) - m = static_m; - else - m = git__calloc(nmatches, sizeof(*m)); - - if ((error = regexec(r, string, nmatches, m, 0)) != 0) - goto out; - - for (i = 0; i < nmatches; i++) { - matches[i].start = (m[i].rm_so < 0) ? -1 : m[i].rm_so; - matches[i].end = (m[i].rm_eo < 0) ? -1 : m[i].rm_eo; - } - -out: - if (nmatches > ARRAY_SIZE(static_m)) - git__free(m); - if (error) - return (error == REG_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC; - return 0; -} - -#endif diff --git a/vendor/libgit2/src/remote.h b/vendor/libgit2/src/remote.h deleted file mode 100644 index ea9c7d17..00000000 --- a/vendor/libgit2/src/remote.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_remote_h__ -#define INCLUDE_remote_h__ - -#include "common.h" - -#include "git2/remote.h" -#include "git2/transport.h" -#include "git2/sys/transport.h" - -#include "refspec.h" -#include "vector.h" -#include "net.h" - -#define GIT_REMOTE_ORIGIN "origin" - -struct git_remote { - char *name; - char *url; - char *pushurl; - git_vector refs; - git_vector refspecs; - git_vector active_refspecs; - git_vector passive_refspecs; - git_vector local_heads; - git_transport *transport; - git_repository *repo; - git_push *push; - git_indexer_progress stats; - unsigned int need_pack; - git_remote_autotag_option_t download_tags; - int prune_refs; - int passed_refspecs; -}; - -int git_remote__urlfordirection(git_str *url_out, struct git_remote *remote, int direction, const git_remote_callbacks *callbacks); -int git_remote__http_proxy(char **out, git_remote *remote, git_net_url *url); - -git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname); -git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname); - -int git_remote__default_branch(git_str *out, git_remote *remote); - -int git_remote_connect_options_dup( - git_remote_connect_options *dst, - const git_remote_connect_options *src); -int git_remote_connect_options_normalize( - git_remote_connect_options *dst, - git_repository *repo, - const git_remote_connect_options *src); -void git_remote_connect_options_dispose(git_remote_connect_options *opts); - -int git_remote_capabilities(unsigned int *out, git_remote *remote); - -#endif diff --git a/vendor/libgit2/src/repository.c b/vendor/libgit2/src/repository.c deleted file mode 100644 index 6119c1c7..00000000 --- a/vendor/libgit2/src/repository.c +++ /dev/null @@ -1,3334 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "repository.h" - -#include - -#include "git2/object.h" -#include "git2/sys/repository.h" - -#include "buf.h" -#include "common.h" -#include "commit.h" -#include "tag.h" -#include "blob.h" -#include "futils.h" -#include "sysdir.h" -#include "filebuf.h" -#include "index.h" -#include "config.h" -#include "refs.h" -#include "filter.h" -#include "odb.h" -#include "refdb.h" -#include "remote.h" -#include "merge.h" -#include "diff_driver.h" -#include "annotated_commit.h" -#include "submodule.h" -#include "worktree.h" -#include "path.h" -#include "strmap.h" - -#ifdef GIT_WIN32 -# include "win32/w32_util.h" -#endif - -bool git_repository__validate_ownership = true; -bool git_repository__fsync_gitdir = false; - -static const struct { - git_repository_item_t parent; - git_repository_item_t fallback; - const char *name; - bool directory; -} items[] = { - { GIT_REPOSITORY_ITEM_GITDIR, GIT_REPOSITORY_ITEM__LAST, NULL, true }, - { GIT_REPOSITORY_ITEM_WORKDIR, GIT_REPOSITORY_ITEM__LAST, NULL, true }, - { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM__LAST, NULL, true }, - { GIT_REPOSITORY_ITEM_GITDIR, GIT_REPOSITORY_ITEM__LAST, "index", false }, - { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "objects", true }, - { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "refs", true }, - { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "packed-refs", false }, - { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "remotes", true }, - { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "config", false }, - { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "info", true }, - { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "hooks", true }, - { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "logs", true }, - { GIT_REPOSITORY_ITEM_GITDIR, GIT_REPOSITORY_ITEM__LAST, "modules", true }, - { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "worktrees", true } -}; - -static int check_repositoryformatversion(int *version, git_config *config); -static int check_extensions(git_config *config, int version); -static int load_global_config(git_config **config); - -#define GIT_COMMONDIR_FILE "commondir" -#define GIT_GITDIR_FILE "gitdir" - -#define GIT_FILE_CONTENT_PREFIX "gitdir:" - -#define GIT_BRANCH_DEFAULT "master" - -#define GIT_REPO_VERSION 0 -#define GIT_REPO_MAX_VERSION 1 - -git_str git_repository__reserved_names_win32[] = { - { DOT_GIT, 0, CONST_STRLEN(DOT_GIT) }, - { GIT_DIR_SHORTNAME, 0, CONST_STRLEN(GIT_DIR_SHORTNAME) } -}; -size_t git_repository__reserved_names_win32_len = 2; - -git_str git_repository__reserved_names_posix[] = { - { DOT_GIT, 0, CONST_STRLEN(DOT_GIT) }, -}; -size_t git_repository__reserved_names_posix_len = 1; - -static void set_odb(git_repository *repo, git_odb *odb) -{ - if (odb) { - GIT_REFCOUNT_OWN(odb, repo); - GIT_REFCOUNT_INC(odb); - } - - if ((odb = git_atomic_swap(repo->_odb, odb)) != NULL) { - GIT_REFCOUNT_OWN(odb, NULL); - git_odb_free(odb); - } -} - -static void set_refdb(git_repository *repo, git_refdb *refdb) -{ - if (refdb) { - GIT_REFCOUNT_OWN(refdb, repo); - GIT_REFCOUNT_INC(refdb); - } - - if ((refdb = git_atomic_swap(repo->_refdb, refdb)) != NULL) { - GIT_REFCOUNT_OWN(refdb, NULL); - git_refdb_free(refdb); - } -} - -static void set_config(git_repository *repo, git_config *config) -{ - if (config) { - GIT_REFCOUNT_OWN(config, repo); - GIT_REFCOUNT_INC(config); - } - - if ((config = git_atomic_swap(repo->_config, config)) != NULL) { - GIT_REFCOUNT_OWN(config, NULL); - git_config_free(config); - } - - git_repository__configmap_lookup_cache_clear(repo); -} - -static void set_index(git_repository *repo, git_index *index) -{ - if (index) { - GIT_REFCOUNT_OWN(index, repo); - GIT_REFCOUNT_INC(index); - } - - if ((index = git_atomic_swap(repo->_index, index)) != NULL) { - GIT_REFCOUNT_OWN(index, NULL); - git_index_free(index); - } -} - -int git_repository__cleanup(git_repository *repo) -{ - GIT_ASSERT_ARG(repo); - - git_repository_submodule_cache_clear(repo); - git_cache_clear(&repo->objects); - git_attr_cache_flush(repo); - - set_config(repo, NULL); - set_index(repo, NULL); - set_odb(repo, NULL); - set_refdb(repo, NULL); - - return 0; -} - -void git_repository_free(git_repository *repo) -{ - size_t i; - - if (repo == NULL) - return; - - git_repository__cleanup(repo); - - git_cache_dispose(&repo->objects); - - git_diff_driver_registry_free(repo->diff_drivers); - repo->diff_drivers = NULL; - - for (i = 0; i < repo->reserved_names.size; i++) - git_str_dispose(git_array_get(repo->reserved_names, i)); - git_array_clear(repo->reserved_names); - - git__free(repo->gitlink); - git__free(repo->gitdir); - git__free(repo->commondir); - git__free(repo->workdir); - git__free(repo->namespace); - git__free(repo->ident_name); - git__free(repo->ident_email); - - git__memzero(repo, sizeof(*repo)); - git__free(repo); -} - -/* Check if we have a separate commondir (e.g. we have a worktree) */ -static int lookup_commondir(bool *separate, git_str *commondir, git_str *repository_path) -{ - git_str common_link = GIT_STR_INIT; - int error; - - /* - * If there's no commondir file, the repository path is the - * common path, but it needs a trailing slash. - */ - if (!git_fs_path_contains_file(repository_path, GIT_COMMONDIR_FILE)) { - if ((error = git_str_set(commondir, repository_path->ptr, repository_path->size)) == 0) - error = git_fs_path_to_dir(commondir); - - *separate = false; - goto done; - } - - *separate = true; - - if ((error = git_str_joinpath(&common_link, repository_path->ptr, GIT_COMMONDIR_FILE)) < 0 || - (error = git_futils_readbuffer(&common_link, common_link.ptr)) < 0) - goto done; - - git_str_rtrim(&common_link); - if (git_fs_path_is_relative(common_link.ptr)) { - if ((error = git_str_joinpath(commondir, repository_path->ptr, common_link.ptr)) < 0) - goto done; - } else { - git_str_swap(commondir, &common_link); - } - - git_str_dispose(&common_link); - - /* Make sure the commondir path always has a trailing slash */ - error = git_fs_path_prettify_dir(commondir, commondir->ptr, NULL); - -done: - return error; -} - -GIT_INLINE(int) validate_repo_path(git_str *path) -{ - /* - * The longest static path in a repository (or commondir) is the - * packed refs file. (Loose refs may be longer since they - * include the reference name, but will be validated when the - * path is constructed.) - */ - static size_t suffix_len = - CONST_STRLEN("objects/pack/pack-.pack.lock") + - GIT_OID_HEXSZ; - - return git_fs_path_validate_str_length_with_suffix( - path, suffix_len); -} - -/* - * Git repository open methods - * - * Open a repository object from its path - */ -static int is_valid_repository_path(bool *out, git_str *repository_path, git_str *common_path) -{ - bool separate_commondir = false; - int error; - - *out = false; - - if ((error = lookup_commondir(&separate_commondir, common_path, repository_path)) < 0) - return error; - - /* Ensure HEAD file exists */ - if (git_fs_path_contains_file(repository_path, GIT_HEAD_FILE) == false) - return 0; - - /* Check files in common dir */ - if (git_fs_path_contains_dir(common_path, GIT_OBJECTS_DIR) == false) - return 0; - if (git_fs_path_contains_dir(common_path, GIT_REFS_DIR) == false) - return 0; - - /* Ensure the repo (and commondir) are valid paths */ - if ((error = validate_repo_path(common_path)) < 0 || - (separate_commondir && - (error = validate_repo_path(repository_path)) < 0)) - return error; - - *out = true; - return 0; -} - -static git_repository *repository_alloc(void) -{ - git_repository *repo = git__calloc(1, sizeof(git_repository)); - - if (repo == NULL || - git_cache_init(&repo->objects) < 0) - goto on_error; - - git_array_init_to_size(repo->reserved_names, 4); - if (!repo->reserved_names.ptr) - goto on_error; - - /* set all the entries in the configmap cache to `unset` */ - git_repository__configmap_lookup_cache_clear(repo); - - return repo; - -on_error: - if (repo) - git_cache_dispose(&repo->objects); - - git__free(repo); - return NULL; -} - -int git_repository_new(git_repository **out) -{ - git_repository *repo; - - *out = repo = repository_alloc(); - GIT_ERROR_CHECK_ALLOC(repo); - - repo->is_bare = 1; - repo->is_worktree = 0; - - return 0; -} - -static int load_config_data(git_repository *repo, const git_config *config) -{ - int is_bare; - - int err = git_config_get_bool(&is_bare, config, "core.bare"); - if (err < 0 && err != GIT_ENOTFOUND) - return err; - - /* Try to figure out if it's bare, default to non-bare if it's not set */ - if (err != GIT_ENOTFOUND) - repo->is_bare = is_bare && !repo->is_worktree; - else - repo->is_bare = 0; - - return 0; -} - -static int load_workdir(git_repository *repo, git_config *config, git_str *parent_path) -{ - int error; - git_config_entry *ce; - git_str worktree = GIT_STR_INIT; - git_str path = GIT_STR_INIT; - - if (repo->is_bare) - return 0; - - if ((error = git_config__lookup_entry( - &ce, config, "core.worktree", false)) < 0) - return error; - - if (repo->is_worktree) { - char *gitlink = git_worktree__read_link(repo->gitdir, GIT_GITDIR_FILE); - if (!gitlink) { - error = -1; - goto cleanup; - } - - git_str_attach(&worktree, gitlink, 0); - - if ((git_fs_path_dirname_r(&worktree, worktree.ptr)) < 0 || - git_fs_path_to_dir(&worktree) < 0) { - error = -1; - goto cleanup; - } - - repo->workdir = git_str_detach(&worktree); - } - else if (ce && ce->value) { - if ((error = git_fs_path_prettify_dir( - &worktree, ce->value, repo->gitdir)) < 0) - goto cleanup; - - repo->workdir = git_str_detach(&worktree); - } - else if (parent_path && git_fs_path_isdir(parent_path->ptr)) - repo->workdir = git_str_detach(parent_path); - else { - if (git_fs_path_dirname_r(&worktree, repo->gitdir) < 0 || - git_fs_path_to_dir(&worktree) < 0) { - error = -1; - goto cleanup; - } - - repo->workdir = git_str_detach(&worktree); - } - - GIT_ERROR_CHECK_ALLOC(repo->workdir); -cleanup: - git_str_dispose(&path); - git_config_entry_free(ce); - return error; -} - -/* - * This function returns furthest offset into path where a ceiling dir - * is found, so we can stop processing the path at that point. - * - * Note: converting this to use git_strs instead of GIT_PATH_MAX buffers on - * the stack could remove directories name limits, but at the cost of doing - * repeated malloc/frees inside the loop below, so let's not do it now. - */ -static size_t find_ceiling_dir_offset( - const char *path, - const char *ceiling_directories) -{ - char buf[GIT_PATH_MAX + 1]; - char buf2[GIT_PATH_MAX + 1]; - const char *ceil, *sep; - size_t len, max_len = 0, min_len; - - GIT_ASSERT_ARG(path); - - min_len = (size_t)(git_fs_path_root(path) + 1); - - if (ceiling_directories == NULL || min_len == 0) - return min_len; - - for (sep = ceil = ceiling_directories; *sep; ceil = sep + 1) { - for (sep = ceil; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++); - len = sep - ceil; - - if (len == 0 || len >= sizeof(buf) || git_fs_path_root(ceil) == -1) - continue; - - strncpy(buf, ceil, len); - buf[len] = '\0'; - - if (p_realpath(buf, buf2) == NULL) - continue; - - len = strlen(buf2); - if (len > 0 && buf2[len-1] == '/') - buf[--len] = '\0'; - - if (!strncmp(path, buf2, len) && - (path[len] == '/' || !path[len]) && - len > max_len) - { - max_len = len; - } - } - - return (max_len <= min_len ? min_len : max_len); -} - -/* - * Read the contents of `file_path` and set `path_out` to the repo dir that - * it points to. Before calling, set `path_out` to the base directory that - * should be used if the contents of `file_path` are a relative path. - */ -static int read_gitfile(git_str *path_out, const char *file_path) -{ - int error = 0; - git_str file = GIT_STR_INIT; - size_t prefix_len = strlen(GIT_FILE_CONTENT_PREFIX); - - GIT_ASSERT_ARG(path_out); - GIT_ASSERT_ARG(file_path); - - if (git_futils_readbuffer(&file, file_path) < 0) - return -1; - - git_str_rtrim(&file); - /* apparently on Windows, some people use backslashes in paths */ - git_fs_path_mkposix(file.ptr); - - if (git_str_len(&file) <= prefix_len || - memcmp(git_str_cstr(&file), GIT_FILE_CONTENT_PREFIX, prefix_len) != 0) - { - git_error_set(GIT_ERROR_REPOSITORY, - "the `.git` file at '%s' is malformed", file_path); - error = -1; - } - else if ((error = git_fs_path_dirname_r(path_out, file_path)) >= 0) { - const char *gitlink = git_str_cstr(&file) + prefix_len; - while (*gitlink && git__isspace(*gitlink)) gitlink++; - - error = git_fs_path_prettify_dir( - path_out, gitlink, git_str_cstr(path_out)); - } - - git_str_dispose(&file); - return error; -} - -typedef struct { - const char *repo_path; - git_str tmp; - bool is_safe; -} validate_ownership_data; - -static int validate_ownership_cb(const git_config_entry *entry, void *payload) -{ - validate_ownership_data *data = payload; - - if (strcmp(entry->value, "") == 0) - data->is_safe = false; - - if (git_fs_path_prettify_dir(&data->tmp, entry->value, NULL) == 0 && - strcmp(data->tmp.ptr, data->repo_path) == 0) - data->is_safe = true; - - return 0; -} - -static int validate_ownership(const char *repo_path) -{ - git_config *config = NULL; - validate_ownership_data data = { repo_path, GIT_STR_INIT, false }; - bool is_safe; - int error; - - if ((error = git_fs_path_owner_is_current_user(&is_safe, repo_path)) < 0) { - if (error == GIT_ENOTFOUND) - error = 0; - - goto done; - } - - if (is_safe) { - error = 0; - goto done; - } - - if (load_global_config(&config) == 0) { - error = git_config_get_multivar_foreach(config, "safe.directory", NULL, validate_ownership_cb, &data); - - if (!error && data.is_safe) - goto done; - } - - git_error_set(GIT_ERROR_CONFIG, - "repository path '%s' is not owned by current user", - repo_path); - error = GIT_EOWNER; - -done: - git_config_free(config); - git_str_dispose(&data.tmp); - return error; -} - -static int find_repo( - git_str *gitdir_path, - git_str *workdir_path, - git_str *gitlink_path, - git_str *commondir_path, - const char *start_path, - uint32_t flags, - const char *ceiling_dirs) -{ - git_str path = GIT_STR_INIT; - git_str repo_link = GIT_STR_INIT; - git_str common_link = GIT_STR_INIT; - struct stat st; - dev_t initial_device = 0; - int min_iterations; - bool in_dot_git, is_valid; - size_t ceiling_offset = 0; - int error; - - git_str_clear(gitdir_path); - - error = git_fs_path_prettify(&path, start_path, NULL); - if (error < 0) - return error; - - /* in_dot_git toggles each loop: - * /a/b/c/.git, /a/b/c, /a/b/.git, /a/b, /a/.git, /a - * With GIT_REPOSITORY_OPEN_BARE or GIT_REPOSITORY_OPEN_NO_DOTGIT, we - * assume we started with /a/b/c.git and don't append .git the first - * time through. - * min_iterations indicates the number of iterations left before going - * further counts as a search. */ - if (flags & (GIT_REPOSITORY_OPEN_BARE | GIT_REPOSITORY_OPEN_NO_DOTGIT)) { - in_dot_git = true; - min_iterations = 1; - } else { - in_dot_git = false; - min_iterations = 2; - } - - for (;;) { - if (!(flags & GIT_REPOSITORY_OPEN_NO_DOTGIT)) { - if (!in_dot_git) { - if ((error = git_str_joinpath(&path, path.ptr, DOT_GIT)) < 0) - goto out; - } - in_dot_git = !in_dot_git; - } - - if (p_stat(path.ptr, &st) == 0) { - /* check that we have not crossed device boundaries */ - if (initial_device == 0) - initial_device = st.st_dev; - else if (st.st_dev != initial_device && - !(flags & GIT_REPOSITORY_OPEN_CROSS_FS)) - break; - - if (S_ISDIR(st.st_mode)) { - if ((error = is_valid_repository_path(&is_valid, &path, &common_link)) < 0) - goto out; - - if (is_valid) { - if ((error = git_fs_path_to_dir(&path)) < 0 || - (error = git_str_set(gitdir_path, path.ptr, path.size)) < 0) - goto out; - - if (gitlink_path) - if ((error = git_str_attach(gitlink_path, git_worktree__read_link(path.ptr, GIT_GITDIR_FILE), 0)) < 0) - goto out; - if (commondir_path) - git_str_swap(&common_link, commondir_path); - - break; - } - } else if (S_ISREG(st.st_mode) && git__suffixcmp(path.ptr, "/" DOT_GIT) == 0) { - if ((error = read_gitfile(&repo_link, path.ptr)) < 0 || - (error = is_valid_repository_path(&is_valid, &repo_link, &common_link)) < 0) - goto out; - - if (is_valid) { - git_str_swap(gitdir_path, &repo_link); - - if (gitlink_path) - if ((error = git_str_put(gitlink_path, path.ptr, path.size)) < 0) - goto out; - if (commondir_path) - git_str_swap(&common_link, commondir_path); - } - break; - } - } - - /* Move up one directory. If we're in_dot_git, we'll search the - * parent itself next. If we're !in_dot_git, we'll search .git - * in the parent directory next (added at the top of the loop). */ - if ((error = git_fs_path_dirname_r(&path, path.ptr)) < 0) - goto out; - - /* Once we've checked the directory (and .git if applicable), - * find the ceiling for a search. */ - if (min_iterations && (--min_iterations == 0)) - ceiling_offset = find_ceiling_dir_offset(path.ptr, ceiling_dirs); - - /* Check if we should stop searching here. */ - if (min_iterations == 0 && - (path.ptr[ceiling_offset] == 0 || (flags & GIT_REPOSITORY_OPEN_NO_SEARCH))) - break; - } - - if (workdir_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) { - if (!git_str_len(gitdir_path)) - git_str_clear(workdir_path); - else if ((error = git_fs_path_dirname_r(workdir_path, path.ptr)) < 0 || - (error = git_fs_path_to_dir(workdir_path)) < 0) - goto out; - } - - /* If we didn't find the repository, and we don't have any other error - * to report, report that. */ - if (!git_str_len(gitdir_path)) { - git_error_set(GIT_ERROR_REPOSITORY, "could not find repository from '%s'", start_path); - error = GIT_ENOTFOUND; - goto out; - } - -out: - git_str_dispose(&path); - git_str_dispose(&repo_link); - git_str_dispose(&common_link); - return error; -} - -int git_repository_open_bare( - git_repository **repo_ptr, - const char *bare_path) -{ - git_str path = GIT_STR_INIT, common_path = GIT_STR_INIT; - git_repository *repo = NULL; - bool is_valid; - int error; - - if ((error = git_fs_path_prettify_dir(&path, bare_path, NULL)) < 0 || - (error = is_valid_repository_path(&is_valid, &path, &common_path)) < 0) - return error; - - if (!is_valid) { - git_str_dispose(&path); - git_str_dispose(&common_path); - git_error_set(GIT_ERROR_REPOSITORY, "path is not a repository: %s", bare_path); - return GIT_ENOTFOUND; - } - - repo = repository_alloc(); - GIT_ERROR_CHECK_ALLOC(repo); - - repo->gitdir = git_str_detach(&path); - GIT_ERROR_CHECK_ALLOC(repo->gitdir); - repo->commondir = git_str_detach(&common_path); - GIT_ERROR_CHECK_ALLOC(repo->commondir); - - /* of course we're bare! */ - repo->is_bare = 1; - repo->is_worktree = 0; - repo->workdir = NULL; - - *repo_ptr = repo; - return 0; -} - -static int _git_repository_open_ext_from_env( - git_repository **out, - const char *start_path) -{ - git_repository *repo = NULL; - git_index *index = NULL; - git_odb *odb = NULL; - git_str dir_buf = GIT_STR_INIT; - git_str ceiling_dirs_buf = GIT_STR_INIT; - git_str across_fs_buf = GIT_STR_INIT; - git_str index_file_buf = GIT_STR_INIT; - git_str namespace_buf = GIT_STR_INIT; - git_str object_dir_buf = GIT_STR_INIT; - git_str alts_buf = GIT_STR_INIT; - git_str work_tree_buf = GIT_STR_INIT; - git_str common_dir_buf = GIT_STR_INIT; - const char *ceiling_dirs = NULL; - unsigned flags = 0; - int error; - - if (!start_path) { - error = git__getenv(&dir_buf, "GIT_DIR"); - if (error == GIT_ENOTFOUND) { - git_error_clear(); - start_path = "."; - } else if (error < 0) - goto error; - else { - start_path = git_str_cstr(&dir_buf); - flags |= GIT_REPOSITORY_OPEN_NO_SEARCH; - flags |= GIT_REPOSITORY_OPEN_NO_DOTGIT; - } - } - - error = git__getenv(&ceiling_dirs_buf, "GIT_CEILING_DIRECTORIES"); - if (error == GIT_ENOTFOUND) - git_error_clear(); - else if (error < 0) - goto error; - else - ceiling_dirs = git_str_cstr(&ceiling_dirs_buf); - - error = git__getenv(&across_fs_buf, "GIT_DISCOVERY_ACROSS_FILESYSTEM"); - if (error == GIT_ENOTFOUND) - git_error_clear(); - else if (error < 0) - goto error; - else { - int across_fs = 0; - error = git_config_parse_bool(&across_fs, git_str_cstr(&across_fs_buf)); - if (error < 0) - goto error; - if (across_fs) - flags |= GIT_REPOSITORY_OPEN_CROSS_FS; - } - - error = git__getenv(&index_file_buf, "GIT_INDEX_FILE"); - if (error == GIT_ENOTFOUND) - git_error_clear(); - else if (error < 0) - goto error; - else { - error = git_index_open(&index, git_str_cstr(&index_file_buf)); - if (error < 0) - goto error; - } - - error = git__getenv(&namespace_buf, "GIT_NAMESPACE"); - if (error == GIT_ENOTFOUND) - git_error_clear(); - else if (error < 0) - goto error; - - error = git__getenv(&object_dir_buf, "GIT_OBJECT_DIRECTORY"); - if (error == GIT_ENOTFOUND) - git_error_clear(); - else if (error < 0) - goto error; - else { - error = git_odb_open(&odb, git_str_cstr(&object_dir_buf)); - if (error < 0) - goto error; - } - - error = git__getenv(&work_tree_buf, "GIT_WORK_TREE"); - if (error == GIT_ENOTFOUND) - git_error_clear(); - else if (error < 0) - goto error; - else { - git_error_set(GIT_ERROR_INVALID, "GIT_WORK_TREE unimplemented"); - error = GIT_ERROR; - goto error; - } - - error = git__getenv(&work_tree_buf, "GIT_COMMON_DIR"); - if (error == GIT_ENOTFOUND) - git_error_clear(); - else if (error < 0) - goto error; - else { - git_error_set(GIT_ERROR_INVALID, "GIT_COMMON_DIR unimplemented"); - error = GIT_ERROR; - goto error; - } - - error = git_repository_open_ext(&repo, start_path, flags, ceiling_dirs); - if (error < 0) - goto error; - - if (odb) - git_repository_set_odb(repo, odb); - - error = git__getenv(&alts_buf, "GIT_ALTERNATE_OBJECT_DIRECTORIES"); - if (error == GIT_ENOTFOUND) { - git_error_clear(); - error = 0; - } else if (error < 0) - goto error; - else { - const char *end; - char *alt, *sep; - if (!odb) { - error = git_repository_odb(&odb, repo); - if (error < 0) - goto error; - } - - end = git_str_cstr(&alts_buf) + git_str_len(&alts_buf); - for (sep = alt = alts_buf.ptr; sep != end; alt = sep+1) { - for (sep = alt; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++) - ; - if (*sep) - *sep = '\0'; - error = git_odb_add_disk_alternate(odb, alt); - if (error < 0) - goto error; - } - } - - if (git_str_len(&namespace_buf)) { - error = git_repository_set_namespace(repo, git_str_cstr(&namespace_buf)); - if (error < 0) - goto error; - } - - git_repository_set_index(repo, index); - - if (out) { - *out = repo; - goto success; - } -error: - git_repository_free(repo); -success: - git_odb_free(odb); - git_index_free(index); - git_str_dispose(&common_dir_buf); - git_str_dispose(&work_tree_buf); - git_str_dispose(&alts_buf); - git_str_dispose(&object_dir_buf); - git_str_dispose(&namespace_buf); - git_str_dispose(&index_file_buf); - git_str_dispose(&across_fs_buf); - git_str_dispose(&ceiling_dirs_buf); - git_str_dispose(&dir_buf); - return error; -} - -static int repo_is_worktree(unsigned *out, const git_repository *repo) -{ - git_str gitdir_link = GIT_STR_INIT; - int error; - - /* Worktrees cannot have the same commondir and gitdir */ - if (repo->commondir && repo->gitdir - && !strcmp(repo->commondir, repo->gitdir)) { - *out = 0; - return 0; - } - - if ((error = git_str_joinpath(&gitdir_link, repo->gitdir, "gitdir")) < 0) - return -1; - - /* A 'gitdir' file inside a git directory is currently - * only used when the repository is a working tree. */ - *out = !!git_fs_path_exists(gitdir_link.ptr); - - git_str_dispose(&gitdir_link); - return error; -} - -int git_repository_open_ext( - git_repository **repo_ptr, - const char *start_path, - unsigned int flags, - const char *ceiling_dirs) -{ - int error; - unsigned is_worktree; - git_str gitdir = GIT_STR_INIT, workdir = GIT_STR_INIT, - gitlink = GIT_STR_INIT, commondir = GIT_STR_INIT; - git_repository *repo = NULL; - git_config *config = NULL; - const char *validation_path; - int version = 0; - - if (flags & GIT_REPOSITORY_OPEN_FROM_ENV) - return _git_repository_open_ext_from_env(repo_ptr, start_path); - - if (repo_ptr) - *repo_ptr = NULL; - - error = find_repo( - &gitdir, &workdir, &gitlink, &commondir, start_path, flags, ceiling_dirs); - - if (error < 0 || !repo_ptr) - goto cleanup; - - repo = repository_alloc(); - GIT_ERROR_CHECK_ALLOC(repo); - - repo->gitdir = git_str_detach(&gitdir); - GIT_ERROR_CHECK_ALLOC(repo->gitdir); - - if (gitlink.size) { - repo->gitlink = git_str_detach(&gitlink); - GIT_ERROR_CHECK_ALLOC(repo->gitlink); - } - if (commondir.size) { - repo->commondir = git_str_detach(&commondir); - GIT_ERROR_CHECK_ALLOC(repo->commondir); - } - - if ((error = repo_is_worktree(&is_worktree, repo)) < 0) - goto cleanup; - repo->is_worktree = is_worktree; - - /* - * We'd like to have the config, but git doesn't particularly - * care if it's not there, so we need to deal with that. - */ - - error = git_repository_config_snapshot(&config, repo); - if (error < 0 && error != GIT_ENOTFOUND) - goto cleanup; - - if (config && (error = check_repositoryformatversion(&version, config)) < 0) - goto cleanup; - - if ((error = check_extensions(config, version)) < 0) - goto cleanup; - - if ((flags & GIT_REPOSITORY_OPEN_BARE) != 0) { - repo->is_bare = 1; - } else { - if (config && - ((error = load_config_data(repo, config)) < 0 || - (error = load_workdir(repo, config, &workdir)) < 0)) - goto cleanup; - } - - /* - * Ensure that the git directory is owned by the current user. - */ - validation_path = repo->is_bare ? repo->gitdir : repo->workdir; - - if (git_repository__validate_ownership && - (error = validate_ownership(validation_path)) < 0) - goto cleanup; - -cleanup: - git_str_dispose(&gitdir); - git_str_dispose(&workdir); - git_str_dispose(&gitlink); - git_str_dispose(&commondir); - git_config_free(config); - - if (error < 0) - git_repository_free(repo); - else if (repo_ptr) - *repo_ptr = repo; - - return error; -} - -int git_repository_open(git_repository **repo_out, const char *path) -{ - return git_repository_open_ext( - repo_out, path, GIT_REPOSITORY_OPEN_NO_SEARCH, NULL); -} - -int git_repository_open_from_worktree(git_repository **repo_out, git_worktree *wt) -{ - git_str path = GIT_STR_INIT; - git_repository *repo = NULL; - size_t len; - int err; - - GIT_ASSERT_ARG(repo_out); - GIT_ASSERT_ARG(wt); - - *repo_out = NULL; - len = strlen(wt->gitlink_path); - - if (len <= 4 || strcasecmp(wt->gitlink_path + len - 4, ".git")) { - err = -1; - goto out; - } - - if ((err = git_str_set(&path, wt->gitlink_path, len - 4)) < 0) - goto out; - - if ((err = git_repository_open(&repo, path.ptr)) < 0) - goto out; - - *repo_out = repo; - -out: - git_str_dispose(&path); - - return err; -} - -int git_repository_wrap_odb(git_repository **repo_out, git_odb *odb) -{ - git_repository *repo; - - repo = repository_alloc(); - GIT_ERROR_CHECK_ALLOC(repo); - - git_repository_set_odb(repo, odb); - *repo_out = repo; - - return 0; -} - -int git_repository_discover( - git_buf *out, - const char *start_path, - int across_fs, - const char *ceiling_dirs) -{ - uint32_t flags = across_fs ? GIT_REPOSITORY_OPEN_CROSS_FS : 0; - - GIT_ASSERT_ARG(start_path); - - GIT_BUF_WRAP_PRIVATE(out, find_repo, NULL, NULL, NULL, start_path, flags, ceiling_dirs); -} - -static int load_config( - git_config **out, - git_repository *repo, - const char *global_config_path, - const char *xdg_config_path, - const char *system_config_path, - const char *programdata_path) -{ - int error; - git_str config_path = GIT_STR_INIT; - git_config *cfg = NULL; - - GIT_ASSERT_ARG(out); - - if ((error = git_config_new(&cfg)) < 0) - return error; - - if (repo) { - if ((error = git_repository__item_path(&config_path, repo, GIT_REPOSITORY_ITEM_CONFIG)) == 0) - error = git_config_add_file_ondisk(cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, repo, 0); - - if (error && error != GIT_ENOTFOUND) - goto on_error; - - git_str_dispose(&config_path); - } - - if (global_config_path != NULL && - (error = git_config_add_file_ondisk( - cfg, global_config_path, GIT_CONFIG_LEVEL_GLOBAL, repo, 0)) < 0 && - error != GIT_ENOTFOUND) - goto on_error; - - if (xdg_config_path != NULL && - (error = git_config_add_file_ondisk( - cfg, xdg_config_path, GIT_CONFIG_LEVEL_XDG, repo, 0)) < 0 && - error != GIT_ENOTFOUND) - goto on_error; - - if (system_config_path != NULL && - (error = git_config_add_file_ondisk( - cfg, system_config_path, GIT_CONFIG_LEVEL_SYSTEM, repo, 0)) < 0 && - error != GIT_ENOTFOUND) - goto on_error; - - if (programdata_path != NULL && - (error = git_config_add_file_ondisk( - cfg, programdata_path, GIT_CONFIG_LEVEL_PROGRAMDATA, repo, 0)) < 0 && - error != GIT_ENOTFOUND) - goto on_error; - - git_error_clear(); /* clear any lingering ENOTFOUND errors */ - - *out = cfg; - return 0; - -on_error: - git_str_dispose(&config_path); - git_config_free(cfg); - *out = NULL; - return error; -} - -static const char *path_unless_empty(git_str *buf) -{ - return git_str_len(buf) > 0 ? git_str_cstr(buf) : NULL; -} - -int git_repository_config__weakptr(git_config **out, git_repository *repo) -{ - int error = 0; - - if (repo->_config == NULL) { - git_str global_buf = GIT_STR_INIT; - git_str xdg_buf = GIT_STR_INIT; - git_str system_buf = GIT_STR_INIT; - git_str programdata_buf = GIT_STR_INIT; - git_config *config; - - git_config__find_global(&global_buf); - git_config__find_xdg(&xdg_buf); - git_config__find_system(&system_buf); - git_config__find_programdata(&programdata_buf); - - /* If there is no global file, open a backend for it anyway */ - if (git_str_len(&global_buf) == 0) - git_config__global_location(&global_buf); - - error = load_config( - &config, repo, - path_unless_empty(&global_buf), - path_unless_empty(&xdg_buf), - path_unless_empty(&system_buf), - path_unless_empty(&programdata_buf)); - if (!error) { - GIT_REFCOUNT_OWN(config, repo); - - if (git_atomic_compare_and_swap(&repo->_config, NULL, config) != NULL) { - GIT_REFCOUNT_OWN(config, NULL); - git_config_free(config); - } - } - - git_str_dispose(&global_buf); - git_str_dispose(&xdg_buf); - git_str_dispose(&system_buf); - git_str_dispose(&programdata_buf); - } - - *out = repo->_config; - return error; -} - -int git_repository_config(git_config **out, git_repository *repo) -{ - if (git_repository_config__weakptr(out, repo) < 0) - return -1; - - GIT_REFCOUNT_INC(*out); - return 0; -} - -int git_repository_config_snapshot(git_config **out, git_repository *repo) -{ - int error; - git_config *weak; - - if ((error = git_repository_config__weakptr(&weak, repo)) < 0) - return error; - - return git_config_snapshot(out, weak); -} - -int git_repository_set_config(git_repository *repo, git_config *config) -{ - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(config); - - set_config(repo, config); - return 0; -} - -int git_repository_odb__weakptr(git_odb **out, git_repository *repo) -{ - int error = 0; - - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(out); - - *out = git_atomic_load(repo->_odb); - if (*out == NULL) { - git_str odb_path = GIT_STR_INIT; - git_odb *odb; - - if ((error = git_repository__item_path(&odb_path, repo, - GIT_REPOSITORY_ITEM_OBJECTS)) < 0 || - (error = git_odb_new(&odb)) < 0) - return error; - - GIT_REFCOUNT_OWN(odb, repo); - - if ((error = git_odb__set_caps(odb, GIT_ODB_CAP_FROM_OWNER)) < 0 || - (error = git_odb__add_default_backends(odb, odb_path.ptr, 0, 0)) < 0) { - git_odb_free(odb); - return error; - } - - if (git_atomic_compare_and_swap(&repo->_odb, NULL, odb) != NULL) { - GIT_REFCOUNT_OWN(odb, NULL); - git_odb_free(odb); - } - - git_str_dispose(&odb_path); - *out = git_atomic_load(repo->_odb); - } - - return error; -} - -int git_repository_odb(git_odb **out, git_repository *repo) -{ - if (git_repository_odb__weakptr(out, repo) < 0) - return -1; - - GIT_REFCOUNT_INC(*out); - return 0; -} - -int git_repository_set_odb(git_repository *repo, git_odb *odb) -{ - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(odb); - - set_odb(repo, odb); - return 0; -} - -int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo) -{ - int error = 0; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(repo); - - if (repo->_refdb == NULL) { - git_refdb *refdb; - - error = git_refdb_open(&refdb, repo); - if (!error) { - GIT_REFCOUNT_OWN(refdb, repo); - - if (git_atomic_compare_and_swap(&repo->_refdb, NULL, refdb) != NULL) { - GIT_REFCOUNT_OWN(refdb, NULL); - git_refdb_free(refdb); - } - } - } - - *out = repo->_refdb; - return error; -} - -int git_repository_refdb(git_refdb **out, git_repository *repo) -{ - if (git_repository_refdb__weakptr(out, repo) < 0) - return -1; - - GIT_REFCOUNT_INC(*out); - return 0; -} - -int git_repository_set_refdb(git_repository *repo, git_refdb *refdb) -{ - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(refdb); - - set_refdb(repo, refdb); - return 0; -} - -int git_repository_index__weakptr(git_index **out, git_repository *repo) -{ - int error = 0; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(repo); - - if (repo->_index == NULL) { - git_str index_path = GIT_STR_INIT; - git_index *index; - - if ((error = git_str_joinpath(&index_path, repo->gitdir, GIT_INDEX_FILE)) < 0) - return error; - - error = git_index_open(&index, index_path.ptr); - if (!error) { - GIT_REFCOUNT_OWN(index, repo); - - if (git_atomic_compare_and_swap(&repo->_index, NULL, index) != NULL) { - GIT_REFCOUNT_OWN(index, NULL); - git_index_free(index); - } - - error = git_index_set_caps(repo->_index, - GIT_INDEX_CAPABILITY_FROM_OWNER); - } - - git_str_dispose(&index_path); - } - - *out = repo->_index; - return error; -} - -int git_repository_index(git_index **out, git_repository *repo) -{ - if (git_repository_index__weakptr(out, repo) < 0) - return -1; - - GIT_REFCOUNT_INC(*out); - return 0; -} - -int git_repository_set_index(git_repository *repo, git_index *index) -{ - GIT_ASSERT_ARG(repo); - set_index(repo, index); - return 0; -} - -int git_repository_set_namespace(git_repository *repo, const char *namespace) -{ - git__free(repo->namespace); - - if (namespace == NULL) { - repo->namespace = NULL; - return 0; - } - - return (repo->namespace = git__strdup(namespace)) ? 0 : -1; -} - -const char *git_repository_get_namespace(git_repository *repo) -{ - return repo->namespace; -} - -#ifdef GIT_WIN32 -static int reserved_names_add8dot3(git_repository *repo, const char *path) -{ - char *name = git_win32_path_8dot3_name(path); - const char *def = GIT_DIR_SHORTNAME; - const char *def_dot_git = DOT_GIT; - size_t name_len, def_len = CONST_STRLEN(GIT_DIR_SHORTNAME); - size_t def_dot_git_len = CONST_STRLEN(DOT_GIT); - git_str *buf; - - if (!name) - return 0; - - name_len = strlen(name); - - if ((name_len == def_len && memcmp(name, def, def_len) == 0) || - (name_len == def_dot_git_len && memcmp(name, def_dot_git, def_dot_git_len) == 0)) { - git__free(name); - return 0; - } - - if ((buf = git_array_alloc(repo->reserved_names)) == NULL) - return -1; - - git_str_attach(buf, name, name_len); - return true; -} - -bool git_repository__reserved_names( - git_str **out, size_t *outlen, git_repository *repo, bool include_ntfs) -{ - GIT_UNUSED(include_ntfs); - - if (repo->reserved_names.size == 0) { - git_str *buf; - size_t i; - - /* Add the static defaults */ - for (i = 0; i < git_repository__reserved_names_win32_len; i++) { - if ((buf = git_array_alloc(repo->reserved_names)) == NULL) - goto on_error; - - buf->ptr = git_repository__reserved_names_win32[i].ptr; - buf->size = git_repository__reserved_names_win32[i].size; - } - - /* Try to add any repo-specific reserved names - the gitlink file - * within a submodule or the repository (if the repository directory - * is beneath the workdir). These are typically `.git`, but should - * be protected in case they are not. Note, repo and workdir paths - * are always prettified to end in `/`, so a prefixcmp is safe. - */ - if (!repo->is_bare) { - int (*prefixcmp)(const char *, const char *); - int error, ignorecase; - - error = git_repository__configmap_lookup( - &ignorecase, repo, GIT_CONFIGMAP_IGNORECASE); - prefixcmp = (error || ignorecase) ? git__prefixcmp_icase : - git__prefixcmp; - - if (repo->gitlink && - reserved_names_add8dot3(repo, repo->gitlink) < 0) - goto on_error; - - if (repo->gitdir && - prefixcmp(repo->gitdir, repo->workdir) == 0 && - reserved_names_add8dot3(repo, repo->gitdir) < 0) - goto on_error; - } - } - - *out = repo->reserved_names.ptr; - *outlen = repo->reserved_names.size; - - return true; - - /* Always give good defaults, even on OOM */ -on_error: - *out = git_repository__reserved_names_win32; - *outlen = git_repository__reserved_names_win32_len; - - return false; -} -#else -bool git_repository__reserved_names( - git_str **out, size_t *outlen, git_repository *repo, bool include_ntfs) -{ - GIT_UNUSED(repo); - - if (include_ntfs) { - *out = git_repository__reserved_names_win32; - *outlen = git_repository__reserved_names_win32_len; - } else { - *out = git_repository__reserved_names_posix; - *outlen = git_repository__reserved_names_posix_len; - } - - return true; -} -#endif - -static int check_repositoryformatversion(int *version, git_config *config) -{ - int error; - - error = git_config_get_int32(version, config, "core.repositoryformatversion"); - /* git ignores this if the config variable isn't there */ - if (error == GIT_ENOTFOUND) - return 0; - - if (error < 0) - return -1; - - if (GIT_REPO_MAX_VERSION < *version) { - git_error_set(GIT_ERROR_REPOSITORY, - "unsupported repository version %d; only versions up to %d are supported", - *version, GIT_REPO_MAX_VERSION); - return -1; - } - - return 0; -} - -static const char *builtin_extensions[] = { - "noop" -}; - -static git_vector user_extensions = GIT_VECTOR_INIT; - -static int check_valid_extension(const git_config_entry *entry, void *payload) -{ - git_str cfg = GIT_STR_INIT; - bool reject; - const char *extension; - size_t i; - int error = 0; - - GIT_UNUSED(payload); - - git_vector_foreach (&user_extensions, i, extension) { - git_str_clear(&cfg); - - /* - * Users can specify that they don't want to support an - * extension with a '!' prefix. - */ - if ((reject = (extension[0] == '!')) == true) - extension = &extension[1]; - - if ((error = git_str_printf(&cfg, "extensions.%s", extension)) < 0) - goto done; - - if (strcmp(entry->name, cfg.ptr) == 0) { - if (reject) - goto fail; - - goto done; - } - } - - for (i = 0; i < ARRAY_SIZE(builtin_extensions); i++) { - extension = builtin_extensions[i]; - - if ((error = git_str_printf(&cfg, "extensions.%s", extension)) < 0) - goto done; - - if (strcmp(entry->name, cfg.ptr) == 0) - goto done; - } - -fail: - git_error_set(GIT_ERROR_REPOSITORY, "unsupported extension name %s", entry->name); - error = -1; - -done: - git_str_dispose(&cfg); - return error; -} - -static int check_extensions(git_config *config, int version) -{ - if (version < 1) - return 0; - - return git_config_foreach_match(config, "^extensions\\.", check_valid_extension, NULL); -} - -int git_repository__extensions(char ***out, size_t *out_len) -{ - git_vector extensions; - const char *builtin, *user; - char *extension; - size_t i, j; - - if (git_vector_init(&extensions, 8, NULL) < 0) - return -1; - - for (i = 0; i < ARRAY_SIZE(builtin_extensions); i++) { - bool match = false; - - builtin = builtin_extensions[i]; - - git_vector_foreach (&user_extensions, j, user) { - if (user[0] == '!' && strcmp(builtin, &user[1]) == 0) { - match = true; - break; - } - } - - if (match) - continue; - - if ((extension = git__strdup(builtin)) == NULL || - git_vector_insert(&extensions, extension) < 0) - return -1; - } - - git_vector_foreach (&user_extensions, i, user) { - if (user[0] == '!') - continue; - - if ((extension = git__strdup(user)) == NULL || - git_vector_insert(&extensions, extension) < 0) - return -1; - } - - *out = (char **)git_vector_detach(out_len, NULL, &extensions); - return 0; -} - -int git_repository__set_extensions(const char **extensions, size_t len) -{ - char *extension; - size_t i; - - git_repository__free_extensions(); - - for (i = 0; i < len; i++) { - if ((extension = git__strdup(extensions[i])) == NULL || - git_vector_insert(&user_extensions, extension) < 0) - return -1; - } - - return 0; -} - -void git_repository__free_extensions(void) -{ - git_vector_free_deep(&user_extensions); -} - -int git_repository_create_head(const char *git_dir, const char *ref_name) -{ - git_str ref_path = GIT_STR_INIT; - git_filebuf ref = GIT_FILEBUF_INIT; - const char *fmt; - int error; - - if ((error = git_str_joinpath(&ref_path, git_dir, GIT_HEAD_FILE)) < 0 || - (error = git_filebuf_open(&ref, ref_path.ptr, 0, GIT_REFS_FILE_MODE)) < 0) - goto out; - - if (git__prefixcmp(ref_name, GIT_REFS_DIR) == 0) - fmt = "ref: %s\n"; - else - fmt = "ref: " GIT_REFS_HEADS_DIR "%s\n"; - - if ((error = git_filebuf_printf(&ref, fmt, ref_name)) < 0 || - (error = git_filebuf_commit(&ref)) < 0) - goto out; - -out: - git_str_dispose(&ref_path); - git_filebuf_cleanup(&ref); - return error; -} - -static bool is_chmod_supported(const char *file_path) -{ - struct stat st1, st2; - - if (p_stat(file_path, &st1) < 0) - return false; - - if (p_chmod(file_path, st1.st_mode ^ S_IXUSR) < 0) - return false; - - if (p_stat(file_path, &st2) < 0) - return false; - - return (st1.st_mode != st2.st_mode); -} - -static bool is_filesystem_case_insensitive(const char *gitdir_path) -{ - git_str path = GIT_STR_INIT; - int is_insensitive = -1; - - if (!git_str_joinpath(&path, gitdir_path, "CoNfIg")) - is_insensitive = git_fs_path_exists(git_str_cstr(&path)); - - git_str_dispose(&path); - return is_insensitive; -} - -/* - * Return a configuration object with only the global and system - * configurations; no repository-level configuration. - */ -static int load_global_config(git_config **config) -{ - git_str global_buf = GIT_STR_INIT; - git_str xdg_buf = GIT_STR_INIT; - git_str system_buf = GIT_STR_INIT; - git_str programdata_buf = GIT_STR_INIT; - int error; - - git_config__find_global(&global_buf); - git_config__find_xdg(&xdg_buf); - git_config__find_system(&system_buf); - git_config__find_programdata(&programdata_buf); - - error = load_config(config, NULL, - path_unless_empty(&global_buf), - path_unless_empty(&xdg_buf), - path_unless_empty(&system_buf), - path_unless_empty(&programdata_buf)); - - git_str_dispose(&global_buf); - git_str_dispose(&xdg_buf); - git_str_dispose(&system_buf); - git_str_dispose(&programdata_buf); - - return error; -} - -static bool are_symlinks_supported(const char *wd_path) -{ - git_config *config = NULL; - int symlinks = 0; - - /* - * To emulate Git for Windows, symlinks on Windows must be explicitly - * opted-in. We examine the system configuration for a core.symlinks - * set to true. If found, we then examine the filesystem to see if - * symlinks are _actually_ supported by the current user. If that is - * _not_ set, then we do not test or enable symlink support. - */ -#ifdef GIT_WIN32 - if (load_global_config(&config) < 0 || - git_config_get_bool(&symlinks, config, "core.symlinks") < 0 || - !symlinks) - goto done; -#endif - - if (!(symlinks = git_fs_path_supports_symlinks(wd_path))) - goto done; - -done: - git_config_free(config); - return symlinks != 0; -} - -static int create_empty_file(const char *path, mode_t mode) -{ - int fd; - - if ((fd = p_creat(path, mode)) < 0) { - git_error_set(GIT_ERROR_OS, "error while creating '%s'", path); - return -1; - } - - if (p_close(fd) < 0) { - git_error_set(GIT_ERROR_OS, "error while closing '%s'", path); - return -1; - } - - return 0; -} - -static int repo_local_config( - git_config **out, - git_str *config_dir, - git_repository *repo, - const char *repo_dir) -{ - int error = 0; - git_config *parent; - const char *cfg_path; - - if (git_str_joinpath(config_dir, repo_dir, GIT_CONFIG_FILENAME_INREPO) < 0) - return -1; - cfg_path = git_str_cstr(config_dir); - - /* make LOCAL config if missing */ - if (!git_fs_path_isfile(cfg_path) && - (error = create_empty_file(cfg_path, GIT_CONFIG_FILE_MODE)) < 0) - return error; - - /* if no repo, just open that file directly */ - if (!repo) - return git_config_open_ondisk(out, cfg_path); - - /* otherwise, open parent config and get that level */ - if ((error = git_repository_config__weakptr(&parent, repo)) < 0) - return error; - - if (git_config_open_level(out, parent, GIT_CONFIG_LEVEL_LOCAL) < 0) { - git_error_clear(); - - if (!(error = git_config_add_file_ondisk( - parent, cfg_path, GIT_CONFIG_LEVEL_LOCAL, repo, false))) - error = git_config_open_level(out, parent, GIT_CONFIG_LEVEL_LOCAL); - } - - git_config_free(parent); - - return error; -} - -static int repo_init_fs_configs( - git_config *cfg, - const char *cfg_path, - const char *repo_dir, - const char *work_dir, - bool update_ignorecase) -{ - int error = 0; - - if (!work_dir) - work_dir = repo_dir; - - if ((error = git_config_set_bool( - cfg, "core.filemode", is_chmod_supported(cfg_path))) < 0) - return error; - - if (!are_symlinks_supported(work_dir)) { - if ((error = git_config_set_bool(cfg, "core.symlinks", false)) < 0) - return error; - } else if (git_config_delete_entry(cfg, "core.symlinks") < 0) - git_error_clear(); - - if (update_ignorecase) { - if (is_filesystem_case_insensitive(repo_dir)) { - if ((error = git_config_set_bool(cfg, "core.ignorecase", true)) < 0) - return error; - } else if (git_config_delete_entry(cfg, "core.ignorecase") < 0) - git_error_clear(); - } - -#ifdef GIT_USE_ICONV - if ((error = git_config_set_bool( - cfg, "core.precomposeunicode", - git_fs_path_does_decompose_unicode(work_dir))) < 0) - return error; - /* on non-iconv platforms, don't even set core.precomposeunicode */ -#endif - - return 0; -} - -static int repo_init_config( - const char *repo_dir, - const char *work_dir, - uint32_t flags, - uint32_t mode) -{ - int error = 0; - git_str cfg_path = GIT_STR_INIT, worktree_path = GIT_STR_INIT; - git_config *config = NULL; - bool is_bare = ((flags & GIT_REPOSITORY_INIT_BARE) != 0); - bool is_reinit = ((flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0); - int version = 0; - - if ((error = repo_local_config(&config, &cfg_path, NULL, repo_dir)) < 0) - goto cleanup; - - if (is_reinit && (error = check_repositoryformatversion(&version, config)) < 0) - goto cleanup; - - if ((error = check_extensions(config, version)) < 0) - goto cleanup; - -#define SET_REPO_CONFIG(TYPE, NAME, VAL) do { \ - if ((error = git_config_set_##TYPE(config, NAME, VAL)) < 0) \ - goto cleanup; } while (0) - - SET_REPO_CONFIG(bool, "core.bare", is_bare); - SET_REPO_CONFIG(int32, "core.repositoryformatversion", GIT_REPO_VERSION); - - if ((error = repo_init_fs_configs( - config, cfg_path.ptr, repo_dir, work_dir, !is_reinit)) < 0) - goto cleanup; - - if (!is_bare) { - SET_REPO_CONFIG(bool, "core.logallrefupdates", true); - - if (!(flags & GIT_REPOSITORY_INIT__NATURAL_WD)) { - if ((error = git_str_sets(&worktree_path, work_dir)) < 0) - goto cleanup; - - if ((flags & GIT_REPOSITORY_INIT_RELATIVE_GITLINK)) - if ((error = git_fs_path_make_relative(&worktree_path, repo_dir)) < 0) - goto cleanup; - - SET_REPO_CONFIG(string, "core.worktree", worktree_path.ptr); - } else if (is_reinit) { - if (git_config_delete_entry(config, "core.worktree") < 0) - git_error_clear(); - } - } - - if (mode == GIT_REPOSITORY_INIT_SHARED_GROUP) { - SET_REPO_CONFIG(int32, "core.sharedrepository", 1); - SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true); - } - else if (mode == GIT_REPOSITORY_INIT_SHARED_ALL) { - SET_REPO_CONFIG(int32, "core.sharedrepository", 2); - SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true); - } - -cleanup: - git_str_dispose(&cfg_path); - git_str_dispose(&worktree_path); - git_config_free(config); - - return error; -} - -static int repo_reinit_submodule_fs(git_submodule *sm, const char *n, void *p) -{ - git_repository *smrepo = NULL; - GIT_UNUSED(n); GIT_UNUSED(p); - - if (git_submodule_open(&smrepo, sm) < 0 || - git_repository_reinit_filesystem(smrepo, true) < 0) - git_error_clear(); - git_repository_free(smrepo); - - return 0; -} - -int git_repository_reinit_filesystem(git_repository *repo, int recurse) -{ - int error = 0; - git_str path = GIT_STR_INIT; - git_config *config = NULL; - const char *repo_dir = git_repository_path(repo); - - if (!(error = repo_local_config(&config, &path, repo, repo_dir))) - error = repo_init_fs_configs( - config, path.ptr, repo_dir, git_repository_workdir(repo), true); - - git_config_free(config); - git_str_dispose(&path); - - git_repository__configmap_lookup_cache_clear(repo); - - if (!repo->is_bare && recurse) - (void)git_submodule_foreach(repo, repo_reinit_submodule_fs, NULL); - - return error; -} - -static int repo_write_template( - const char *git_dir, - bool allow_overwrite, - const char *file, - mode_t mode, - bool hidden, - const char *content) -{ - git_str path = GIT_STR_INIT; - int fd, error = 0, flags; - - if (git_str_joinpath(&path, git_dir, file) < 0) - return -1; - - if (allow_overwrite) - flags = O_WRONLY | O_CREAT | O_TRUNC; - else - flags = O_WRONLY | O_CREAT | O_EXCL; - - fd = p_open(git_str_cstr(&path), flags, mode); - - if (fd >= 0) { - error = p_write(fd, content, strlen(content)); - - p_close(fd); - } - else if (errno != EEXIST) - error = fd; - -#ifdef GIT_WIN32 - if (!error && hidden) { - if (git_win32__set_hidden(path.ptr, true) < 0) - error = -1; - } -#else - GIT_UNUSED(hidden); -#endif - - git_str_dispose(&path); - - if (error) - git_error_set(GIT_ERROR_OS, - "failed to initialize repository with template '%s'", file); - - return error; -} - -static int repo_write_gitlink( - const char *in_dir, const char *to_repo, bool use_relative_path) -{ - int error; - git_str buf = GIT_STR_INIT; - git_str path_to_repo = GIT_STR_INIT; - struct stat st; - - git_fs_path_dirname_r(&buf, to_repo); - git_fs_path_to_dir(&buf); - if (git_str_oom(&buf)) - return -1; - - /* don't write gitlink to natural workdir */ - if (git__suffixcmp(to_repo, "/" DOT_GIT "/") == 0 && - strcmp(in_dir, buf.ptr) == 0) - { - error = GIT_PASSTHROUGH; - goto cleanup; - } - - if ((error = git_str_joinpath(&buf, in_dir, DOT_GIT)) < 0) - goto cleanup; - - if (!p_stat(buf.ptr, &st) && !S_ISREG(st.st_mode)) { - git_error_set(GIT_ERROR_REPOSITORY, - "cannot overwrite gitlink file into path '%s'", in_dir); - error = GIT_EEXISTS; - goto cleanup; - } - - git_str_clear(&buf); - - error = git_str_sets(&path_to_repo, to_repo); - - if (!error && use_relative_path) - error = git_fs_path_make_relative(&path_to_repo, in_dir); - - if (!error) - error = git_str_join(&buf, ' ', GIT_FILE_CONTENT_PREFIX, path_to_repo.ptr); - - if (!error) - error = repo_write_template(in_dir, true, DOT_GIT, 0666, true, buf.ptr); - -cleanup: - git_str_dispose(&buf); - git_str_dispose(&path_to_repo); - return error; -} - -static mode_t pick_dir_mode(git_repository_init_options *opts) -{ - if (opts->mode == GIT_REPOSITORY_INIT_SHARED_UMASK) - return 0777; - if (opts->mode == GIT_REPOSITORY_INIT_SHARED_GROUP) - return (0775 | S_ISGID); - if (opts->mode == GIT_REPOSITORY_INIT_SHARED_ALL) - return (0777 | S_ISGID); - return opts->mode; -} - -#include "repo_template.h" - -static int repo_init_structure( - const char *repo_dir, - const char *work_dir, - git_repository_init_options *opts) -{ - int error = 0; - repo_template_item *tpl; - bool external_tpl = - ((opts->flags & GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE) != 0); - mode_t dmode = pick_dir_mode(opts); - bool chmod = opts->mode != GIT_REPOSITORY_INIT_SHARED_UMASK; - - /* Hide the ".git" directory */ -#ifdef GIT_WIN32 - if ((opts->flags & GIT_REPOSITORY_INIT__HAS_DOTGIT) != 0) { - if (git_win32__set_hidden(repo_dir, true) < 0) { - git_error_set(GIT_ERROR_OS, - "failed to mark Git repository folder as hidden"); - return -1; - } - } -#endif - - /* Create the .git gitlink if appropriate */ - if ((opts->flags & GIT_REPOSITORY_INIT_BARE) == 0 && - (opts->flags & GIT_REPOSITORY_INIT__NATURAL_WD) == 0) - { - if (repo_write_gitlink(work_dir, repo_dir, opts->flags & GIT_REPOSITORY_INIT_RELATIVE_GITLINK) < 0) - return -1; - } - - /* Copy external template if requested */ - if (external_tpl) { - git_config *cfg = NULL; - const char *tdir = NULL; - bool default_template = false; - git_str template_buf = GIT_STR_INIT; - - if (opts->template_path) - tdir = opts->template_path; - else if ((error = git_config_open_default(&cfg)) >= 0) { - if (!git_config__get_path(&template_buf, cfg, "init.templatedir")) - tdir = template_buf.ptr; - git_error_clear(); - } - - if (!tdir) { - if (!(error = git_sysdir_find_template_dir(&template_buf))) - tdir = template_buf.ptr; - default_template = true; - } - - /* - * If tdir was the empty string, treat it like tdir was a path to an - * empty directory (so, don't do any copying). This is the behavior - * that git(1) exhibits, although it doesn't seem to be officially - * documented. - */ - if (tdir && git__strcmp(tdir, "") != 0) { - uint32_t cpflags = GIT_CPDIR_COPY_SYMLINKS | - GIT_CPDIR_SIMPLE_TO_MODE | - GIT_CPDIR_COPY_DOTFILES; - if (opts->mode != GIT_REPOSITORY_INIT_SHARED_UMASK) - cpflags |= GIT_CPDIR_CHMOD_DIRS; - error = git_futils_cp_r(tdir, repo_dir, cpflags, dmode); - } - - git_str_dispose(&template_buf); - git_config_free(cfg); - - /* If tdir does not exist, then do not error out. This matches the - * behaviour of git(1), which just prints a warning and continues. - * TODO: issue warning when warning API is available. - * `git` prints to stderr: 'warning: templates not found in /path/to/tdir' - */ - if (error < 0) { - if (!default_template && error != GIT_ENOTFOUND) - return error; - - /* if template was default, ignore error and use internal */ - git_error_clear(); - external_tpl = false; - error = 0; - } - } - - /* Copy internal template - * - always ensure existence of dirs - * - only create files if no external template was specified - */ - for (tpl = repo_template; !error && tpl->path; ++tpl) { - if (!tpl->content) { - uint32_t mkdir_flags = GIT_MKDIR_PATH; - if (chmod) - mkdir_flags |= GIT_MKDIR_CHMOD; - - error = git_futils_mkdir_relative( - tpl->path, repo_dir, dmode, mkdir_flags, NULL); - } - else if (!external_tpl) { - const char *content = tpl->content; - - if (opts->description && strcmp(tpl->path, GIT_DESC_FILE) == 0) - content = opts->description; - - error = repo_write_template( - repo_dir, false, tpl->path, tpl->mode, false, content); - } - } - - return error; -} - -static int mkdir_parent(git_str *buf, uint32_t mode, bool skip2) -{ - /* When making parent directories during repository initialization - * don't try to set gid or grant world write access - */ - return git_futils_mkdir( - buf->ptr, mode & ~(S_ISGID | 0002), - GIT_MKDIR_PATH | GIT_MKDIR_VERIFY_DIR | - (skip2 ? GIT_MKDIR_SKIP_LAST2 : GIT_MKDIR_SKIP_LAST)); -} - -static int repo_init_directories( - git_str *repo_path, - git_str *wd_path, - const char *given_repo, - git_repository_init_options *opts) -{ - int error = 0; - bool is_bare, add_dotgit, has_dotgit, natural_wd; - mode_t dirmode; - - /* There are three possible rules for what we are allowed to create: - * - MKPATH means anything we need - * - MKDIR means just the .git directory and its parent and the workdir - * - Neither means only the .git directory can be created - * - * There are 5 "segments" of path that we might need to deal with: - * 1. The .git directory - * 2. The parent of the .git directory - * 3. Everything above the parent of the .git directory - * 4. The working directory (often the same as #2) - * 5. Everything above the working directory (often the same as #3) - * - * For all directories created, we start with the init_mode value for - * permissions and then strip off bits in some cases: - * - * For MKPATH, we create #3 (and #5) paths without S_ISGID or S_IWOTH - * For MKPATH and MKDIR, we create #2 (and #4) without S_ISGID - * For all rules, we create #1 using the untouched init_mode - */ - - /* set up repo path */ - - is_bare = ((opts->flags & GIT_REPOSITORY_INIT_BARE) != 0); - - add_dotgit = - (opts->flags & GIT_REPOSITORY_INIT_NO_DOTGIT_DIR) == 0 && - !is_bare && - git__suffixcmp(given_repo, "/" DOT_GIT) != 0 && - git__suffixcmp(given_repo, "/" GIT_DIR) != 0; - - if (git_str_joinpath(repo_path, given_repo, add_dotgit ? GIT_DIR : "") < 0) - return -1; - - has_dotgit = (git__suffixcmp(repo_path->ptr, "/" GIT_DIR) == 0); - if (has_dotgit) - opts->flags |= GIT_REPOSITORY_INIT__HAS_DOTGIT; - - /* set up workdir path */ - - if (!is_bare) { - if (opts->workdir_path) { - if (git_fs_path_join_unrooted( - wd_path, opts->workdir_path, repo_path->ptr, NULL) < 0) - return -1; - } else if (has_dotgit) { - if (git_fs_path_dirname_r(wd_path, repo_path->ptr) < 0) - return -1; - } else { - git_error_set(GIT_ERROR_REPOSITORY, "cannot pick working directory" - " for non-bare repository that isn't a '.git' directory"); - return -1; - } - - if (git_fs_path_to_dir(wd_path) < 0) - return -1; - } else { - git_str_clear(wd_path); - } - - natural_wd = - has_dotgit && - wd_path->size > 0 && - wd_path->size + strlen(GIT_DIR) == repo_path->size && - memcmp(repo_path->ptr, wd_path->ptr, wd_path->size) == 0; - if (natural_wd) - opts->flags |= GIT_REPOSITORY_INIT__NATURAL_WD; - - /* create directories as needed / requested */ - - dirmode = pick_dir_mode(opts); - - if ((opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0) { - /* create path #5 */ - if (wd_path->size > 0 && - (error = mkdir_parent(wd_path, dirmode, false)) < 0) - return error; - - /* create path #3 (if not the same as #5) */ - if (!natural_wd && - (error = mkdir_parent(repo_path, dirmode, has_dotgit)) < 0) - return error; - } - - if ((opts->flags & GIT_REPOSITORY_INIT_MKDIR) != 0 || - (opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0) - { - /* create path #4 */ - if (wd_path->size > 0 && - (error = git_futils_mkdir( - wd_path->ptr, dirmode & ~S_ISGID, - GIT_MKDIR_VERIFY_DIR)) < 0) - return error; - - /* create path #2 (if not the same as #4) */ - if (!natural_wd && - (error = git_futils_mkdir( - repo_path->ptr, dirmode & ~S_ISGID, - GIT_MKDIR_VERIFY_DIR | GIT_MKDIR_SKIP_LAST)) < 0) - return error; - } - - if ((opts->flags & GIT_REPOSITORY_INIT_MKDIR) != 0 || - (opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0 || - has_dotgit) - { - /* create path #1 */ - error = git_futils_mkdir(repo_path->ptr, dirmode, - GIT_MKDIR_VERIFY_DIR | ((dirmode & S_ISGID) ? GIT_MKDIR_CHMOD : 0)); - } - - /* prettify both directories now that they are created */ - - if (!error) { - error = git_fs_path_prettify_dir(repo_path, repo_path->ptr, NULL); - - if (!error && wd_path->size > 0) - error = git_fs_path_prettify_dir(wd_path, wd_path->ptr, NULL); - } - - return error; -} - -static int repo_init_head(const char *repo_dir, const char *given) -{ - git_config *cfg = NULL; - git_str head_path = GIT_STR_INIT, cfg_branch = GIT_STR_INIT; - const char *initial_head = NULL; - int error; - - if ((error = git_str_joinpath(&head_path, repo_dir, GIT_HEAD_FILE)) < 0) - goto out; - - /* - * A template may have set a HEAD; use that unless it's been - * overridden by the caller's given initial head setting. - */ - if (git_fs_path_exists(head_path.ptr) && !given) - goto out; - - if (given) { - initial_head = given; - } else if ((error = git_config_open_default(&cfg)) >= 0 && - (error = git_config__get_string_buf(&cfg_branch, cfg, "init.defaultbranch")) >= 0 && - *cfg_branch.ptr) { - initial_head = cfg_branch.ptr; - } - - if (!initial_head) - initial_head = GIT_BRANCH_DEFAULT; - - error = git_repository_create_head(repo_dir, initial_head); - -out: - git_config_free(cfg); - git_str_dispose(&head_path); - git_str_dispose(&cfg_branch); - - return error; -} - -static int repo_init_create_origin(git_repository *repo, const char *url) -{ - int error; - git_remote *remote; - - if (!(error = git_remote_create(&remote, repo, GIT_REMOTE_ORIGIN, url))) { - git_remote_free(remote); - } - - return error; -} - -int git_repository_init( - git_repository **repo_out, const char *path, unsigned is_bare) -{ - git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT; - - opts.flags = GIT_REPOSITORY_INIT_MKPATH; /* don't love this default */ - if (is_bare) - opts.flags |= GIT_REPOSITORY_INIT_BARE; - - return git_repository_init_ext(repo_out, path, &opts); -} - -int git_repository_init_ext( - git_repository **out, - const char *given_repo, - git_repository_init_options *opts) -{ - git_str repo_path = GIT_STR_INIT, wd_path = GIT_STR_INIT, - common_path = GIT_STR_INIT; - const char *wd; - bool is_valid; - int error; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(given_repo); - GIT_ASSERT_ARG(opts); - - GIT_ERROR_CHECK_VERSION(opts, GIT_REPOSITORY_INIT_OPTIONS_VERSION, "git_repository_init_options"); - - if ((error = repo_init_directories(&repo_path, &wd_path, given_repo, opts)) < 0) - goto out; - - wd = (opts->flags & GIT_REPOSITORY_INIT_BARE) ? NULL : git_str_cstr(&wd_path); - - if ((error = is_valid_repository_path(&is_valid, &repo_path, &common_path)) < 0) - goto out; - - if (is_valid) { - if ((opts->flags & GIT_REPOSITORY_INIT_NO_REINIT) != 0) { - git_error_set(GIT_ERROR_REPOSITORY, - "attempt to reinitialize '%s'", given_repo); - error = GIT_EEXISTS; - goto out; - } - - opts->flags |= GIT_REPOSITORY_INIT__IS_REINIT; - - if ((error = repo_init_config(repo_path.ptr, wd, opts->flags, opts->mode)) < 0) - goto out; - - /* TODO: reinitialize the templates */ - } else { - if ((error = repo_init_structure(repo_path.ptr, wd, opts)) < 0 || - (error = repo_init_config(repo_path.ptr, wd, opts->flags, opts->mode)) < 0 || - (error = repo_init_head(repo_path.ptr, opts->initial_head)) < 0) - goto out; - } - - if ((error = git_repository_open(out, repo_path.ptr)) < 0) - goto out; - - if (opts->origin_url && - (error = repo_init_create_origin(*out, opts->origin_url)) < 0) - goto out; - -out: - git_str_dispose(&common_path); - git_str_dispose(&repo_path); - git_str_dispose(&wd_path); - - return error; -} - -int git_repository_head_detached(git_repository *repo) -{ - git_reference *ref; - git_odb *odb = NULL; - int exists; - - if (git_repository_odb__weakptr(&odb, repo) < 0) - return -1; - - if (git_reference_lookup(&ref, repo, GIT_HEAD_FILE) < 0) - return -1; - - if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) { - git_reference_free(ref); - return 0; - } - - exists = git_odb_exists(odb, git_reference_target(ref)); - - git_reference_free(ref); - return exists; -} - -int git_repository_head_detached_for_worktree(git_repository *repo, const char *name) -{ - git_reference *ref = NULL; - int error; - - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(name); - - if ((error = git_repository_head_for_worktree(&ref, repo, name)) < 0) - goto out; - - error = (git_reference_type(ref) != GIT_REFERENCE_SYMBOLIC); -out: - git_reference_free(ref); - - return error; -} - -int git_repository_head(git_reference **head_out, git_repository *repo) -{ - git_reference *head; - int error; - - GIT_ASSERT_ARG(head_out); - - if ((error = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0) - return error; - - if (git_reference_type(head) == GIT_REFERENCE_DIRECT) { - *head_out = head; - return 0; - } - - error = git_reference_lookup_resolved(head_out, repo, git_reference_symbolic_target(head), -1); - git_reference_free(head); - - return error == GIT_ENOTFOUND ? GIT_EUNBORNBRANCH : error; -} - -int git_repository_head_for_worktree(git_reference **out, git_repository *repo, const char *name) -{ - git_repository *worktree_repo = NULL; - git_worktree *worktree = NULL; - git_reference *head = NULL; - int error; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(name); - - *out = NULL; - - if ((error = git_worktree_lookup(&worktree, repo, name)) < 0 || - (error = git_repository_open_from_worktree(&worktree_repo, worktree)) < 0 || - (error = git_reference_lookup(&head, worktree_repo, GIT_HEAD_FILE)) < 0) - goto out; - - if (git_reference_type(head) != GIT_REFERENCE_DIRECT) { - if ((error = git_reference_lookup_resolved(out, worktree_repo, git_reference_symbolic_target(head), -1)) < 0) - goto out; - } else { - *out = head; - head = NULL; - } - -out: - git_reference_free(head); - git_worktree_free(worktree); - git_repository_free(worktree_repo); - return error; -} - -int git_repository_foreach_worktree(git_repository *repo, - git_repository_foreach_worktree_cb cb, - void *payload) -{ - git_strarray worktrees = {0}; - git_repository *worktree_repo = NULL; - git_worktree *worktree = NULL; - int error; - size_t i; - - /* apply operation to repository supplied when commondir is empty, implying there's - * no linked worktrees to iterate, which can occur when using custom odb/refdb - */ - if (!repo->commondir) - return cb(repo, payload); - - if ((error = git_repository_open(&worktree_repo, repo->commondir)) < 0 || - (error = cb(worktree_repo, payload) != 0)) - goto out; - - git_repository_free(worktree_repo); - worktree_repo = NULL; - - if ((error = git_worktree_list(&worktrees, repo)) < 0) - goto out; - - for (i = 0; i < worktrees.count; i++) { - git_repository_free(worktree_repo); - worktree_repo = NULL; - git_worktree_free(worktree); - worktree = NULL; - - if ((error = git_worktree_lookup(&worktree, repo, worktrees.strings[i]) < 0) || - (error = git_repository_open_from_worktree(&worktree_repo, worktree)) < 0) { - if (error != GIT_ENOTFOUND) - goto out; - error = 0; - continue; - } - - if ((error = cb(worktree_repo, payload)) != 0) - goto out; - } - -out: - git_strarray_dispose(&worktrees); - git_repository_free(worktree_repo); - git_worktree_free(worktree); - return error; -} - -int git_repository_head_unborn(git_repository *repo) -{ - git_reference *ref = NULL; - int error; - - error = git_repository_head(&ref, repo); - git_reference_free(ref); - - if (error == GIT_EUNBORNBRANCH) { - git_error_clear(); - return 1; - } - - if (error < 0) - return -1; - - return 0; -} - -static int repo_contains_no_reference(git_repository *repo) -{ - git_reference_iterator *iter; - const char *refname; - int error; - - if ((error = git_reference_iterator_new(&iter, repo)) < 0) - return error; - - error = git_reference_next_name(&refname, iter); - git_reference_iterator_free(iter); - - if (error == GIT_ITEROVER) - return 1; - - return error; -} - -int git_repository_initialbranch(git_str *out, git_repository *repo) -{ - git_config *config; - git_config_entry *entry = NULL; - const char *branch; - int valid, error; - - if ((error = git_repository_config__weakptr(&config, repo)) < 0) - return error; - - if ((error = git_config_get_entry(&entry, config, "init.defaultbranch")) == 0 && - *entry->value) { - branch = entry->value; - } - else if (!error || error == GIT_ENOTFOUND) { - branch = GIT_BRANCH_DEFAULT; - } - else { - goto done; - } - - if ((error = git_str_puts(out, GIT_REFS_HEADS_DIR)) < 0 || - (error = git_str_puts(out, branch)) < 0 || - (error = git_reference_name_is_valid(&valid, out->ptr)) < 0) - goto done; - - if (!valid) { - git_error_set(GIT_ERROR_INVALID, "the value of init.defaultBranch is not a valid branch name"); - error = -1; - } - -done: - git_config_entry_free(entry); - return error; -} - -int git_repository_is_empty(git_repository *repo) -{ - git_reference *head = NULL; - git_str initialbranch = GIT_STR_INIT; - int result = 0; - - if ((result = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0 || - (result = git_repository_initialbranch(&initialbranch, repo)) < 0) - goto done; - - result = (git_reference_type(head) == GIT_REFERENCE_SYMBOLIC && - strcmp(git_reference_symbolic_target(head), initialbranch.ptr) == 0 && - repo_contains_no_reference(repo)); - -done: - git_reference_free(head); - git_str_dispose(&initialbranch); - - return result; -} - -static const char *resolved_parent_path(const git_repository *repo, git_repository_item_t item, git_repository_item_t fallback) -{ - const char *parent; - - switch (item) { - case GIT_REPOSITORY_ITEM_GITDIR: - parent = git_repository_path(repo); - break; - case GIT_REPOSITORY_ITEM_WORKDIR: - parent = git_repository_workdir(repo); - break; - case GIT_REPOSITORY_ITEM_COMMONDIR: - parent = git_repository_commondir(repo); - break; - default: - git_error_set(GIT_ERROR_INVALID, "invalid item directory"); - return NULL; - } - if (!parent && fallback != GIT_REPOSITORY_ITEM__LAST) - return resolved_parent_path(repo, fallback, GIT_REPOSITORY_ITEM__LAST); - - return parent; -} - -int git_repository_item_path( - git_buf *out, - const git_repository *repo, - git_repository_item_t item) -{ - GIT_BUF_WRAP_PRIVATE(out, git_repository__item_path, repo, item); -} - -int git_repository__item_path( - git_str *out, - const git_repository *repo, - git_repository_item_t item) -{ - const char *parent = resolved_parent_path(repo, items[item].parent, items[item].fallback); - if (parent == NULL) { - git_error_set(GIT_ERROR_INVALID, "path cannot exist in repository"); - return GIT_ENOTFOUND; - } - - if (git_str_sets(out, parent) < 0) - return -1; - - if (items[item].name) { - if (git_str_joinpath(out, parent, items[item].name) < 0) - return -1; - } - - if (items[item].directory) { - if (git_fs_path_to_dir(out) < 0) - return -1; - } - - return 0; -} - -const char *git_repository_path(const git_repository *repo) -{ - GIT_ASSERT_ARG_WITH_RETVAL(repo, NULL); - return repo->gitdir; -} - -const char *git_repository_workdir(const git_repository *repo) -{ - GIT_ASSERT_ARG_WITH_RETVAL(repo, NULL); - - if (repo->is_bare) - return NULL; - - return repo->workdir; -} - -int git_repository_workdir_path( - git_str *out, git_repository *repo, const char *path) -{ - int error; - - if (!repo->workdir) { - git_error_set(GIT_ERROR_REPOSITORY, "repository has no working directory"); - return GIT_EBAREREPO; - } - - if (!(error = git_str_joinpath(out, repo->workdir, path))) - error = git_path_validate_str_length(repo, out); - - return error; -} - -const char *git_repository_commondir(const git_repository *repo) -{ - GIT_ASSERT_ARG_WITH_RETVAL(repo, NULL); - return repo->commondir; -} - -int git_repository_set_workdir( - git_repository *repo, const char *workdir, int update_gitlink) -{ - int error = 0; - git_str path = GIT_STR_INIT; - - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(workdir); - - if (git_fs_path_prettify_dir(&path, workdir, NULL) < 0) - return -1; - - if (repo->workdir && strcmp(repo->workdir, path.ptr) == 0) - return 0; - - if (update_gitlink) { - git_config *config; - - if (git_repository_config__weakptr(&config, repo) < 0) - return -1; - - error = repo_write_gitlink(path.ptr, git_repository_path(repo), false); - - /* passthrough error means gitlink is unnecessary */ - if (error == GIT_PASSTHROUGH) - error = git_config_delete_entry(config, "core.worktree"); - else if (!error) - error = git_config_set_string(config, "core.worktree", path.ptr); - - if (!error) - error = git_config_set_bool(config, "core.bare", false); - } - - if (!error) { - char *old_workdir = repo->workdir; - - repo->workdir = git_str_detach(&path); - repo->is_bare = 0; - - git__free(old_workdir); - } - - return error; -} - -int git_repository_is_bare(const git_repository *repo) -{ - GIT_ASSERT_ARG(repo); - return repo->is_bare; -} - -int git_repository_is_worktree(const git_repository *repo) -{ - GIT_ASSERT_ARG(repo); - return repo->is_worktree; -} - -int git_repository_set_bare(git_repository *repo) -{ - int error; - git_config *config; - - GIT_ASSERT_ARG(repo); - - if (repo->is_bare) - return 0; - - if ((error = git_repository_config__weakptr(&config, repo)) < 0) - return error; - - if ((error = git_config_set_bool(config, "core.bare", true)) < 0) - return error; - - if ((error = git_config__update_entry(config, "core.worktree", NULL, true, true)) < 0) - return error; - - git__free(repo->workdir); - repo->workdir = NULL; - repo->is_bare = 1; - - return 0; -} - -int git_repository_head_tree(git_tree **tree, git_repository *repo) -{ - git_reference *head; - git_object *obj; - int error; - - if ((error = git_repository_head(&head, repo)) < 0) - return error; - - if ((error = git_reference_peel(&obj, head, GIT_OBJECT_TREE)) < 0) - goto cleanup; - - *tree = (git_tree *)obj; - -cleanup: - git_reference_free(head); - return error; -} - -int git_repository__set_orig_head(git_repository *repo, const git_oid *orig_head) -{ - git_filebuf file = GIT_FILEBUF_INIT; - git_str file_path = GIT_STR_INIT; - char orig_head_str[GIT_OID_HEXSZ]; - int error = 0; - - git_oid_fmt(orig_head_str, orig_head); - - if ((error = git_str_joinpath(&file_path, repo->gitdir, GIT_ORIG_HEAD_FILE)) == 0 && - (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) == 0 && - (error = git_filebuf_printf(&file, "%.*s\n", GIT_OID_HEXSZ, orig_head_str)) == 0) - error = git_filebuf_commit(&file); - - if (error < 0) - git_filebuf_cleanup(&file); - - git_str_dispose(&file_path); - - return error; -} - -static int git_repository__message(git_str *out, git_repository *repo) -{ - git_str path = GIT_STR_INIT; - struct stat st; - int error; - - if (git_str_joinpath(&path, repo->gitdir, GIT_MERGE_MSG_FILE) < 0) - return -1; - - if ((error = p_stat(git_str_cstr(&path), &st)) < 0) { - if (errno == ENOENT) - error = GIT_ENOTFOUND; - git_error_set(GIT_ERROR_OS, "could not access message file"); - } else { - error = git_futils_readbuffer(out, git_str_cstr(&path)); - } - - git_str_dispose(&path); - - return error; -} - -int git_repository_message(git_buf *out, git_repository *repo) -{ - GIT_BUF_WRAP_PRIVATE(out, git_repository__message, repo); -} - -int git_repository_message_remove(git_repository *repo) -{ - git_str path = GIT_STR_INIT; - int error; - - if (git_str_joinpath(&path, repo->gitdir, GIT_MERGE_MSG_FILE) < 0) - return -1; - - error = p_unlink(git_str_cstr(&path)); - git_str_dispose(&path); - - return error; -} - -int git_repository_hashfile( - git_oid *out, - git_repository *repo, - const char *path, - git_object_t type, - const char *as_path) -{ - int error; - git_filter_list *fl = NULL; - git_file fd = -1; - uint64_t len; - git_str full_path = GIT_STR_INIT; - const char *workdir = git_repository_workdir(repo); - - /* as_path can be NULL */ - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(path); - GIT_ASSERT_ARG(repo); - - if ((error = git_fs_path_join_unrooted(&full_path, path, workdir, NULL)) < 0 || - (error = git_path_validate_str_length(repo, &full_path)) < 0) - return error; - - /* - * NULL as_path means that we should derive it from the - * given path. - */ - if (!as_path) { - if (workdir && !git__prefixcmp(full_path.ptr, workdir)) - as_path = full_path.ptr + strlen(workdir); - else - as_path = ""; - } - - /* passing empty string for "as_path" indicated --no-filters */ - if (strlen(as_path) > 0) { - error = git_filter_list_load( - &fl, repo, NULL, as_path, - GIT_FILTER_TO_ODB, GIT_FILTER_DEFAULT); - - if (error < 0) - return error; - } - - /* at this point, error is a count of the number of loaded filters */ - - fd = git_futils_open_ro(full_path.ptr); - if (fd < 0) { - error = fd; - goto cleanup; - } - - if ((error = git_futils_filesize(&len, fd)) < 0) - goto cleanup; - - if (!git__is_sizet(len)) { - git_error_set(GIT_ERROR_OS, "file size overflow for 32-bit systems"); - error = -1; - goto cleanup; - } - - error = git_odb__hashfd_filtered(out, fd, (size_t)len, type, fl); - -cleanup: - if (fd >= 0) - p_close(fd); - git_filter_list_free(fl); - git_str_dispose(&full_path); - - return error; -} - -static int checkout_message(git_str *out, git_reference *old, const char *new) -{ - git_str_puts(out, "checkout: moving from "); - - if (git_reference_type(old) == GIT_REFERENCE_SYMBOLIC) - git_str_puts(out, git_reference__shorthand(git_reference_symbolic_target(old))); - else - git_str_puts(out, git_oid_tostr_s(git_reference_target(old))); - - git_str_puts(out, " to "); - - if (git_reference__is_branch(new) || - git_reference__is_tag(new) || - git_reference__is_remote(new)) - git_str_puts(out, git_reference__shorthand(new)); - else - git_str_puts(out, new); - - if (git_str_oom(out)) - return -1; - - return 0; -} - -static int detach(git_repository *repo, const git_oid *id, const char *new) -{ - int error; - git_str log_message = GIT_STR_INIT; - git_object *object = NULL, *peeled = NULL; - git_reference *new_head = NULL, *current = NULL; - - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(id); - - if ((error = git_reference_lookup(¤t, repo, GIT_HEAD_FILE)) < 0) - return error; - - if ((error = git_object_lookup(&object, repo, id, GIT_OBJECT_ANY)) < 0) - goto cleanup; - - if ((error = git_object_peel(&peeled, object, GIT_OBJECT_COMMIT)) < 0) - goto cleanup; - - if (new == NULL) - new = git_oid_tostr_s(git_object_id(peeled)); - - if ((error = checkout_message(&log_message, current, new)) < 0) - goto cleanup; - - error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_object_id(peeled), true, git_str_cstr(&log_message)); - -cleanup: - git_str_dispose(&log_message); - git_object_free(object); - git_object_free(peeled); - git_reference_free(current); - git_reference_free(new_head); - return error; -} - -int git_repository_set_head( - git_repository *repo, - const char *refname) -{ - git_reference *ref = NULL, *current = NULL, *new_head = NULL; - git_str log_message = GIT_STR_INIT; - int error; - - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(refname); - - if ((error = git_reference_lookup(¤t, repo, GIT_HEAD_FILE)) < 0) - return error; - - if ((error = checkout_message(&log_message, current, refname)) < 0) - goto cleanup; - - error = git_reference_lookup(&ref, repo, refname); - if (error < 0 && error != GIT_ENOTFOUND) - goto cleanup; - - if (ref && current->type == GIT_REFERENCE_SYMBOLIC && git__strcmp(current->target.symbolic, ref->name) && - git_reference_is_branch(ref) && git_branch_is_checked_out(ref)) { - git_error_set(GIT_ERROR_REPOSITORY, "cannot set HEAD to reference '%s' as it is the current HEAD " - "of a linked repository.", git_reference_name(ref)); - error = -1; - goto cleanup; - } - - if (!error) { - if (git_reference_is_branch(ref)) { - error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, - git_reference_name(ref), true, git_str_cstr(&log_message)); - } else { - error = detach(repo, git_reference_target(ref), - git_reference_is_tag(ref) || git_reference_is_remote(ref) ? refname : NULL); - } - } else if (git_reference__is_branch(refname)) { - error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, refname, - true, git_str_cstr(&log_message)); - } - -cleanup: - git_str_dispose(&log_message); - git_reference_free(current); - git_reference_free(ref); - git_reference_free(new_head); - return error; -} - -int git_repository_set_head_detached( - git_repository *repo, - const git_oid *committish) -{ - return detach(repo, committish, NULL); -} - -int git_repository_set_head_detached_from_annotated( - git_repository *repo, - const git_annotated_commit *committish) -{ - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(committish); - - return detach(repo, git_annotated_commit_id(committish), committish->description); -} - -int git_repository_detach_head(git_repository *repo) -{ - git_reference *old_head = NULL, *new_head = NULL, *current = NULL; - git_object *object = NULL; - git_str log_message = GIT_STR_INIT; - int error; - - GIT_ASSERT_ARG(repo); - - if ((error = git_reference_lookup(¤t, repo, GIT_HEAD_FILE)) < 0) - return error; - - if ((error = git_repository_head(&old_head, repo)) < 0) - goto cleanup; - - if ((error = git_object_lookup(&object, repo, git_reference_target(old_head), GIT_OBJECT_COMMIT)) < 0) - goto cleanup; - - if ((error = checkout_message(&log_message, current, git_oid_tostr_s(git_object_id(object)))) < 0) - goto cleanup; - - error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_reference_target(old_head), - 1, git_str_cstr(&log_message)); - -cleanup: - git_str_dispose(&log_message); - git_object_free(object); - git_reference_free(old_head); - git_reference_free(new_head); - git_reference_free(current); - return error; -} - -/** - * Loosely ported from git.git - * https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh#L198-289 - */ -int git_repository_state(git_repository *repo) -{ - git_str repo_path = GIT_STR_INIT; - int state = GIT_REPOSITORY_STATE_NONE; - - GIT_ASSERT_ARG(repo); - - if (git_str_puts(&repo_path, repo->gitdir) < 0) - return -1; - - if (git_fs_path_contains_file(&repo_path, GIT_REBASE_MERGE_INTERACTIVE_FILE)) - state = GIT_REPOSITORY_STATE_REBASE_INTERACTIVE; - else if (git_fs_path_contains_dir(&repo_path, GIT_REBASE_MERGE_DIR)) - state = GIT_REPOSITORY_STATE_REBASE_MERGE; - else if (git_fs_path_contains_file(&repo_path, GIT_REBASE_APPLY_REBASING_FILE)) - state = GIT_REPOSITORY_STATE_REBASE; - else if (git_fs_path_contains_file(&repo_path, GIT_REBASE_APPLY_APPLYING_FILE)) - state = GIT_REPOSITORY_STATE_APPLY_MAILBOX; - else if (git_fs_path_contains_dir(&repo_path, GIT_REBASE_APPLY_DIR)) - state = GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE; - else if (git_fs_path_contains_file(&repo_path, GIT_MERGE_HEAD_FILE)) - state = GIT_REPOSITORY_STATE_MERGE; - else if (git_fs_path_contains_file(&repo_path, GIT_REVERT_HEAD_FILE)) { - state = GIT_REPOSITORY_STATE_REVERT; - if (git_fs_path_contains_file(&repo_path, GIT_SEQUENCER_TODO_FILE)) { - state = GIT_REPOSITORY_STATE_REVERT_SEQUENCE; - } - } else if (git_fs_path_contains_file(&repo_path, GIT_CHERRYPICK_HEAD_FILE)) { - state = GIT_REPOSITORY_STATE_CHERRYPICK; - if (git_fs_path_contains_file(&repo_path, GIT_SEQUENCER_TODO_FILE)) { - state = GIT_REPOSITORY_STATE_CHERRYPICK_SEQUENCE; - } - } else if (git_fs_path_contains_file(&repo_path, GIT_BISECT_LOG_FILE)) - state = GIT_REPOSITORY_STATE_BISECT; - - git_str_dispose(&repo_path); - return state; -} - -int git_repository__cleanup_files( - git_repository *repo, const char *files[], size_t files_len) -{ - git_str buf = GIT_STR_INIT; - size_t i; - int error; - - for (error = 0, i = 0; !error && i < files_len; ++i) { - const char *path; - - if (git_str_joinpath(&buf, repo->gitdir, files[i]) < 0) - return -1; - - path = git_str_cstr(&buf); - - if (git_fs_path_isfile(path)) { - error = p_unlink(path); - } else if (git_fs_path_isdir(path)) { - error = git_futils_rmdir_r(path, NULL, - GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS); - } - - git_str_clear(&buf); - } - - git_str_dispose(&buf); - return error; -} - -static const char *state_files[] = { - GIT_MERGE_HEAD_FILE, - GIT_MERGE_MODE_FILE, - GIT_MERGE_MSG_FILE, - GIT_REVERT_HEAD_FILE, - GIT_CHERRYPICK_HEAD_FILE, - GIT_BISECT_LOG_FILE, - GIT_REBASE_MERGE_DIR, - GIT_REBASE_APPLY_DIR, - GIT_SEQUENCER_DIR, -}; - -int git_repository_state_cleanup(git_repository *repo) -{ - GIT_ASSERT_ARG(repo); - - return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files)); -} - -int git_repository_is_shallow(git_repository *repo) -{ - git_str path = GIT_STR_INIT; - struct stat st; - int error; - - if ((error = git_str_joinpath(&path, repo->gitdir, "shallow")) < 0) - return error; - - error = git_fs_path_lstat(path.ptr, &st); - git_str_dispose(&path); - - if (error == GIT_ENOTFOUND) { - git_error_clear(); - return 0; - } - - if (error < 0) - return error; - return st.st_size == 0 ? 0 : 1; -} - -int git_repository_init_options_init( - git_repository_init_options *opts, unsigned int version) -{ - GIT_INIT_STRUCTURE_FROM_TEMPLATE( - opts, version, git_repository_init_options, - GIT_REPOSITORY_INIT_OPTIONS_INIT); - return 0; -} - -#ifndef GIT_DEPRECATE_HARD -int git_repository_init_init_options( - git_repository_init_options *opts, unsigned int version) -{ - return git_repository_init_options_init(opts, version); -} -#endif - -int git_repository_ident(const char **name, const char **email, const git_repository *repo) -{ - *name = repo->ident_name; - *email = repo->ident_email; - - return 0; -} - -int git_repository_set_ident(git_repository *repo, const char *name, const char *email) -{ - char *tmp_name = NULL, *tmp_email = NULL; - - if (name) { - tmp_name = git__strdup(name); - GIT_ERROR_CHECK_ALLOC(tmp_name); - } - - if (email) { - tmp_email = git__strdup(email); - GIT_ERROR_CHECK_ALLOC(tmp_email); - } - - tmp_name = git_atomic_swap(repo->ident_name, tmp_name); - tmp_email = git_atomic_swap(repo->ident_email, tmp_email); - - git__free(tmp_name); - git__free(tmp_email); - - return 0; -} - -int git_repository_submodule_cache_all(git_repository *repo) -{ - GIT_ASSERT_ARG(repo); - return git_submodule_cache_init(&repo->submodule_cache, repo); -} - -int git_repository_submodule_cache_clear(git_repository *repo) -{ - int error = 0; - GIT_ASSERT_ARG(repo); - - error = git_submodule_cache_free(repo->submodule_cache); - repo->submodule_cache = NULL; - return error; -} diff --git a/vendor/libgit2/src/revparse.c b/vendor/libgit2/src/revparse.c deleted file mode 100644 index 9bc28e9f..00000000 --- a/vendor/libgit2/src/revparse.c +++ /dev/null @@ -1,949 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "common.h" - -#include "str.h" -#include "tree.h" -#include "refdb.h" -#include "regexp.h" -#include "date.h" - -#include "git2.h" - -static int maybe_sha_or_abbrev(git_object **out, git_repository *repo, const char *spec, size_t speclen) -{ - git_oid oid; - - if (git_oid_fromstrn(&oid, spec, speclen) < 0) - return GIT_ENOTFOUND; - - return git_object_lookup_prefix(out, repo, &oid, speclen, GIT_OBJECT_ANY); -} - -static int maybe_sha(git_object **out, git_repository *repo, const char *spec) -{ - size_t speclen = strlen(spec); - - if (speclen != GIT_OID_HEXSZ) - return GIT_ENOTFOUND; - - return maybe_sha_or_abbrev(out, repo, spec, speclen); -} - -static int maybe_abbrev(git_object **out, git_repository *repo, const char *spec) -{ - size_t speclen = strlen(spec); - - return maybe_sha_or_abbrev(out, repo, spec, speclen); -} - -static int build_regex(git_regexp *regex, const char *pattern) -{ - int error; - - if (*pattern == '\0') { - git_error_set(GIT_ERROR_REGEX, "empty pattern"); - return GIT_EINVALIDSPEC; - } - - error = git_regexp_compile(regex, pattern, 0); - if (!error) - return 0; - - git_regexp_dispose(regex); - - return error; -} - -static int maybe_describe(git_object**out, git_repository *repo, const char *spec) -{ - const char *substr; - int error; - git_regexp regex; - - substr = strstr(spec, "-g"); - - if (substr == NULL) - return GIT_ENOTFOUND; - - if (build_regex(®ex, ".+-[0-9]+-g[0-9a-fA-F]+") < 0) - return -1; - - error = git_regexp_match(®ex, spec); - git_regexp_dispose(®ex); - - if (error) - return GIT_ENOTFOUND; - - return maybe_abbrev(out, repo, substr+2); -} - -static int revparse_lookup_object( - git_object **object_out, - git_reference **reference_out, - git_repository *repo, - const char *spec) -{ - int error; - git_reference *ref; - - if ((error = maybe_sha(object_out, repo, spec)) != GIT_ENOTFOUND) - return error; - - error = git_reference_dwim(&ref, repo, spec); - if (!error) { - - error = git_object_lookup( - object_out, repo, git_reference_target(ref), GIT_OBJECT_ANY); - - if (!error) - *reference_out = ref; - - return error; - } - - if (error != GIT_ENOTFOUND) - return error; - - if ((strlen(spec) < GIT_OID_HEXSZ) && - ((error = maybe_abbrev(object_out, repo, spec)) != GIT_ENOTFOUND)) - return error; - - if ((error = maybe_describe(object_out, repo, spec)) != GIT_ENOTFOUND) - return error; - - git_error_set(GIT_ERROR_REFERENCE, "revspec '%s' not found", spec); - return GIT_ENOTFOUND; -} - -static int try_parse_numeric(int *n, const char *curly_braces_content) -{ - int32_t content; - const char *end_ptr; - - if (git__strntol32(&content, curly_braces_content, strlen(curly_braces_content), - &end_ptr, 10) < 0) - return -1; - - if (*end_ptr != '\0') - return -1; - - *n = (int)content; - return 0; -} - -static int retrieve_previously_checked_out_branch_or_revision(git_object **out, git_reference **base_ref, git_repository *repo, const char *identifier, size_t position) -{ - git_reference *ref = NULL; - git_reflog *reflog = NULL; - git_regexp preg; - int error = -1; - size_t i, numentries, cur; - const git_reflog_entry *entry; - const char *msg; - git_str buf = GIT_STR_INIT; - - cur = position; - - if (*identifier != '\0' || *base_ref != NULL) - return GIT_EINVALIDSPEC; - - if (build_regex(&preg, "checkout: moving from (.*) to .*") < 0) - return -1; - - if (git_reference_lookup(&ref, repo, GIT_HEAD_FILE) < 0) - goto cleanup; - - if (git_reflog_read(&reflog, repo, GIT_HEAD_FILE) < 0) - goto cleanup; - - numentries = git_reflog_entrycount(reflog); - - for (i = 0; i < numentries; i++) { - git_regmatch regexmatches[2]; - - entry = git_reflog_entry_byindex(reflog, i); - msg = git_reflog_entry_message(entry); - if (!msg) - continue; - - if (git_regexp_search(&preg, msg, 2, regexmatches) < 0) - continue; - - cur--; - - if (cur > 0) - continue; - - if ((git_str_put(&buf, msg+regexmatches[1].start, regexmatches[1].end - regexmatches[1].start)) < 0) - goto cleanup; - - if ((error = git_reference_dwim(base_ref, repo, git_str_cstr(&buf))) == 0) - goto cleanup; - - if (error < 0 && error != GIT_ENOTFOUND) - goto cleanup; - - error = maybe_abbrev(out, repo, git_str_cstr(&buf)); - - goto cleanup; - } - - error = GIT_ENOTFOUND; - -cleanup: - git_reference_free(ref); - git_str_dispose(&buf); - git_regexp_dispose(&preg); - git_reflog_free(reflog); - return error; -} - -static int retrieve_oid_from_reflog(git_oid *oid, git_reference *ref, size_t identifier) -{ - git_reflog *reflog; - size_t numentries; - const git_reflog_entry *entry = NULL; - bool search_by_pos = (identifier <= 100000000); - - if (git_reflog_read(&reflog, git_reference_owner(ref), git_reference_name(ref)) < 0) - return -1; - - numentries = git_reflog_entrycount(reflog); - - if (search_by_pos) { - if (numentries < identifier + 1) - goto notfound; - - entry = git_reflog_entry_byindex(reflog, identifier); - git_oid_cpy(oid, git_reflog_entry_id_new(entry)); - } else { - size_t i; - git_time commit_time; - - for (i = 0; i < numentries; i++) { - entry = git_reflog_entry_byindex(reflog, i); - commit_time = git_reflog_entry_committer(entry)->when; - - if (commit_time.time > (git_time_t)identifier) - continue; - - git_oid_cpy(oid, git_reflog_entry_id_new(entry)); - break; - } - - if (i == numentries) { - if (entry == NULL) - goto notfound; - - /* - * TODO: emit a warning (log for 'branch' only goes back to ...) - */ - git_oid_cpy(oid, git_reflog_entry_id_new(entry)); - } - } - - git_reflog_free(reflog); - return 0; - -notfound: - git_error_set( - GIT_ERROR_REFERENCE, - "reflog for '%s' has only %"PRIuZ" entries, asked for %"PRIuZ, - git_reference_name(ref), numentries, identifier); - - git_reflog_free(reflog); - return GIT_ENOTFOUND; -} - -static int retrieve_revobject_from_reflog(git_object **out, git_reference **base_ref, git_repository *repo, const char *identifier, size_t position) -{ - git_reference *ref; - git_oid oid; - int error = -1; - - if (*base_ref == NULL) { - if ((error = git_reference_dwim(&ref, repo, identifier)) < 0) - return error; - } else { - ref = *base_ref; - *base_ref = NULL; - } - - if (position == 0) { - error = git_object_lookup(out, repo, git_reference_target(ref), GIT_OBJECT_ANY); - goto cleanup; - } - - if ((error = retrieve_oid_from_reflog(&oid, ref, position)) < 0) - goto cleanup; - - error = git_object_lookup(out, repo, &oid, GIT_OBJECT_ANY); - -cleanup: - git_reference_free(ref); - return error; -} - -static int retrieve_remote_tracking_reference(git_reference **base_ref, const char *identifier, git_repository *repo) -{ - git_reference *tracking, *ref; - int error = -1; - - if (*base_ref == NULL) { - if ((error = git_reference_dwim(&ref, repo, identifier)) < 0) - return error; - } else { - ref = *base_ref; - *base_ref = NULL; - } - - if (!git_reference_is_branch(ref)) { - error = GIT_EINVALIDSPEC; - goto cleanup; - } - - if ((error = git_branch_upstream(&tracking, ref)) < 0) - goto cleanup; - - *base_ref = tracking; - -cleanup: - git_reference_free(ref); - return error; -} - -static int handle_at_syntax(git_object **out, git_reference **ref, const char *spec, size_t identifier_len, git_repository *repo, const char *curly_braces_content) -{ - bool is_numeric; - int parsed = 0, error = -1; - git_str identifier = GIT_STR_INIT; - git_time_t timestamp; - - GIT_ASSERT(*out == NULL); - - if (git_str_put(&identifier, spec, identifier_len) < 0) - return -1; - - is_numeric = !try_parse_numeric(&parsed, curly_braces_content); - - if (*curly_braces_content == '-' && (!is_numeric || parsed == 0)) { - error = GIT_EINVALIDSPEC; - goto cleanup; - } - - if (is_numeric) { - if (parsed < 0) - error = retrieve_previously_checked_out_branch_or_revision(out, ref, repo, git_str_cstr(&identifier), -parsed); - else - error = retrieve_revobject_from_reflog(out, ref, repo, git_str_cstr(&identifier), parsed); - - goto cleanup; - } - - if (!strcmp(curly_braces_content, "u") || !strcmp(curly_braces_content, "upstream")) { - error = retrieve_remote_tracking_reference(ref, git_str_cstr(&identifier), repo); - - goto cleanup; - } - - if (git_date_parse(×tamp, curly_braces_content) < 0) { - error = GIT_EINVALIDSPEC; - goto cleanup; - } - - error = retrieve_revobject_from_reflog(out, ref, repo, git_str_cstr(&identifier), (size_t)timestamp); - -cleanup: - git_str_dispose(&identifier); - return error; -} - -static git_object_t parse_obj_type(const char *str) -{ - if (!strcmp(str, "commit")) - return GIT_OBJECT_COMMIT; - - if (!strcmp(str, "tree")) - return GIT_OBJECT_TREE; - - if (!strcmp(str, "blob")) - return GIT_OBJECT_BLOB; - - if (!strcmp(str, "tag")) - return GIT_OBJECT_TAG; - - return GIT_OBJECT_INVALID; -} - -static int dereference_to_non_tag(git_object **out, git_object *obj) -{ - if (git_object_type(obj) == GIT_OBJECT_TAG) - return git_tag_peel(out, (git_tag *)obj); - - return git_object_dup(out, obj); -} - -static int handle_caret_parent_syntax(git_object **out, git_object *obj, int n) -{ - git_object *temp_commit = NULL; - int error; - - if ((error = git_object_peel(&temp_commit, obj, GIT_OBJECT_COMMIT)) < 0) - return (error == GIT_EAMBIGUOUS || error == GIT_ENOTFOUND) ? - GIT_EINVALIDSPEC : error; - - if (n == 0) { - *out = temp_commit; - return 0; - } - - error = git_commit_parent((git_commit **)out, (git_commit*)temp_commit, n - 1); - - git_object_free(temp_commit); - return error; -} - -static int handle_linear_syntax(git_object **out, git_object *obj, int n) -{ - git_object *temp_commit = NULL; - int error; - - if ((error = git_object_peel(&temp_commit, obj, GIT_OBJECT_COMMIT)) < 0) - return (error == GIT_EAMBIGUOUS || error == GIT_ENOTFOUND) ? - GIT_EINVALIDSPEC : error; - - error = git_commit_nth_gen_ancestor((git_commit **)out, (git_commit*)temp_commit, n); - - git_object_free(temp_commit); - return error; -} - -static int handle_colon_syntax( - git_object **out, - git_object *obj, - const char *path) -{ - git_object *tree; - int error = -1; - git_tree_entry *entry = NULL; - - if ((error = git_object_peel(&tree, obj, GIT_OBJECT_TREE)) < 0) - return error == GIT_ENOTFOUND ? GIT_EINVALIDSPEC : error; - - if (*path == '\0') { - *out = tree; - return 0; - } - - /* - * TODO: Handle the relative path syntax - * (:./relative/path and :../relative/path) - */ - if ((error = git_tree_entry_bypath(&entry, (git_tree *)tree, path)) < 0) - goto cleanup; - - error = git_tree_entry_to_object(out, git_object_owner(tree), entry); - -cleanup: - git_tree_entry_free(entry); - git_object_free(tree); - - return error; -} - -static int walk_and_search(git_object **out, git_revwalk *walk, git_regexp *regex) -{ - int error; - git_oid oid; - git_object *obj; - - while (!(error = git_revwalk_next(&oid, walk))) { - - error = git_object_lookup(&obj, git_revwalk_repository(walk), &oid, GIT_OBJECT_COMMIT); - if ((error < 0) && (error != GIT_ENOTFOUND)) - return -1; - - if (!git_regexp_match(regex, git_commit_message((git_commit*)obj))) { - *out = obj; - return 0; - } - - git_object_free(obj); - } - - if (error < 0 && error == GIT_ITEROVER) - error = GIT_ENOTFOUND; - - return error; -} - -static int handle_grep_syntax(git_object **out, git_repository *repo, const git_oid *spec_oid, const char *pattern) -{ - git_regexp preg; - git_revwalk *walk = NULL; - int error; - - if ((error = build_regex(&preg, pattern)) < 0) - return error; - - if ((error = git_revwalk_new(&walk, repo)) < 0) - goto cleanup; - - git_revwalk_sorting(walk, GIT_SORT_TIME); - - if (spec_oid == NULL) { - if ((error = git_revwalk_push_glob(walk, "refs/*")) < 0) - goto cleanup; - } else if ((error = git_revwalk_push(walk, spec_oid)) < 0) - goto cleanup; - - error = walk_and_search(out, walk, &preg); - -cleanup: - git_regexp_dispose(&preg); - git_revwalk_free(walk); - - return error; -} - -static int handle_caret_curly_syntax(git_object **out, git_object *obj, const char *curly_braces_content) -{ - git_object_t expected_type; - - if (*curly_braces_content == '\0') - return dereference_to_non_tag(out, obj); - - if (*curly_braces_content == '/') - return handle_grep_syntax(out, git_object_owner(obj), git_object_id(obj), curly_braces_content + 1); - - expected_type = parse_obj_type(curly_braces_content); - - if (expected_type == GIT_OBJECT_INVALID) - return GIT_EINVALIDSPEC; - - return git_object_peel(out, obj, expected_type); -} - -static int extract_curly_braces_content(git_str *buf, const char *spec, size_t *pos) -{ - git_str_clear(buf); - - GIT_ASSERT_ARG(spec[*pos] == '^' || spec[*pos] == '@'); - - (*pos)++; - - if (spec[*pos] == '\0' || spec[*pos] != '{') - return GIT_EINVALIDSPEC; - - (*pos)++; - - while (spec[*pos] != '}') { - if (spec[*pos] == '\0') - return GIT_EINVALIDSPEC; - - if (git_str_putc(buf, spec[(*pos)++]) < 0) - return -1; - } - - (*pos)++; - - return 0; -} - -static int extract_path(git_str *buf, const char *spec, size_t *pos) -{ - git_str_clear(buf); - - GIT_ASSERT_ARG(spec[*pos] == ':'); - - (*pos)++; - - if (git_str_puts(buf, spec + *pos) < 0) - return -1; - - *pos += git_str_len(buf); - - return 0; -} - -static int extract_how_many(int *n, const char *spec, size_t *pos) -{ - const char *end_ptr; - int parsed, accumulated; - char kind = spec[*pos]; - - GIT_ASSERT_ARG(spec[*pos] == '^' || spec[*pos] == '~'); - - accumulated = 0; - - do { - do { - (*pos)++; - accumulated++; - } while (spec[(*pos)] == kind && kind == '~'); - - if (git__isdigit(spec[*pos])) { - if (git__strntol32(&parsed, spec + *pos, strlen(spec + *pos), &end_ptr, 10) < 0) - return GIT_EINVALIDSPEC; - - accumulated += (parsed - 1); - *pos = end_ptr - spec; - } - - } while (spec[(*pos)] == kind && kind == '~'); - - *n = accumulated; - - return 0; -} - -static int object_from_reference(git_object **object, git_reference *reference) -{ - git_reference *resolved = NULL; - int error; - - if (git_reference_resolve(&resolved, reference) < 0) - return -1; - - error = git_object_lookup(object, reference->db->repo, git_reference_target(resolved), GIT_OBJECT_ANY); - git_reference_free(resolved); - - return error; -} - -static int ensure_base_rev_loaded(git_object **object, git_reference **reference, const char *spec, size_t identifier_len, git_repository *repo, bool allow_empty_identifier) -{ - int error; - git_str identifier = GIT_STR_INIT; - - if (*object != NULL) - return 0; - - if (*reference != NULL) - return object_from_reference(object, *reference); - - if (!allow_empty_identifier && identifier_len == 0) - return GIT_EINVALIDSPEC; - - if (git_str_put(&identifier, spec, identifier_len) < 0) - return -1; - - error = revparse_lookup_object(object, reference, repo, git_str_cstr(&identifier)); - git_str_dispose(&identifier); - - return error; -} - -static int ensure_base_rev_is_not_known_yet(git_object *object) -{ - if (object == NULL) - return 0; - - return GIT_EINVALIDSPEC; -} - -static bool any_left_hand_identifier(git_object *object, git_reference *reference, size_t identifier_len) -{ - if (object != NULL) - return true; - - if (reference != NULL) - return true; - - if (identifier_len > 0) - return true; - - return false; -} - -static int ensure_left_hand_identifier_is_not_known_yet(git_object *object, git_reference *reference) -{ - if (!ensure_base_rev_is_not_known_yet(object) && reference == NULL) - return 0; - - return GIT_EINVALIDSPEC; -} - -static int revparse( - git_object **object_out, - git_reference **reference_out, - size_t *identifier_len_out, - git_repository *repo, - const char *spec) -{ - size_t pos = 0, identifier_len = 0; - int error = -1, n; - git_str buf = GIT_STR_INIT; - - git_reference *reference = NULL; - git_object *base_rev = NULL; - - bool should_return_reference = true; - - GIT_ASSERT_ARG(object_out); - GIT_ASSERT_ARG(reference_out); - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(spec); - - *object_out = NULL; - *reference_out = NULL; - - while (spec[pos]) { - switch (spec[pos]) { - case '^': - should_return_reference = false; - - if ((error = ensure_base_rev_loaded(&base_rev, &reference, spec, identifier_len, repo, false)) < 0) - goto cleanup; - - if (spec[pos+1] == '{') { - git_object *temp_object = NULL; - - if ((error = extract_curly_braces_content(&buf, spec, &pos)) < 0) - goto cleanup; - - if ((error = handle_caret_curly_syntax(&temp_object, base_rev, git_str_cstr(&buf))) < 0) - goto cleanup; - - git_object_free(base_rev); - base_rev = temp_object; - } else { - git_object *temp_object = NULL; - - if ((error = extract_how_many(&n, spec, &pos)) < 0) - goto cleanup; - - if ((error = handle_caret_parent_syntax(&temp_object, base_rev, n)) < 0) - goto cleanup; - - git_object_free(base_rev); - base_rev = temp_object; - } - break; - - case '~': - { - git_object *temp_object = NULL; - - should_return_reference = false; - - if ((error = extract_how_many(&n, spec, &pos)) < 0) - goto cleanup; - - if ((error = ensure_base_rev_loaded(&base_rev, &reference, spec, identifier_len, repo, false)) < 0) - goto cleanup; - - if ((error = handle_linear_syntax(&temp_object, base_rev, n)) < 0) - goto cleanup; - - git_object_free(base_rev); - base_rev = temp_object; - break; - } - - case ':': - { - git_object *temp_object = NULL; - - should_return_reference = false; - - if ((error = extract_path(&buf, spec, &pos)) < 0) - goto cleanup; - - if (any_left_hand_identifier(base_rev, reference, identifier_len)) { - if ((error = ensure_base_rev_loaded(&base_rev, &reference, spec, identifier_len, repo, true)) < 0) - goto cleanup; - - if ((error = handle_colon_syntax(&temp_object, base_rev, git_str_cstr(&buf))) < 0) - goto cleanup; - } else { - if (*git_str_cstr(&buf) == '/') { - if ((error = handle_grep_syntax(&temp_object, repo, NULL, git_str_cstr(&buf) + 1)) < 0) - goto cleanup; - } else { - - /* - * TODO: support merge-stage path lookup (":2:Makefile") - * and plain index blob lookup (:i-am/a/blob) - */ - git_error_set(GIT_ERROR_INVALID, "unimplemented"); - error = GIT_ERROR; - goto cleanup; - } - } - - git_object_free(base_rev); - base_rev = temp_object; - break; - } - - case '@': - if (spec[pos+1] == '{') { - git_object *temp_object = NULL; - - if ((error = extract_curly_braces_content(&buf, spec, &pos)) < 0) - goto cleanup; - - if ((error = ensure_base_rev_is_not_known_yet(base_rev)) < 0) - goto cleanup; - - if ((error = handle_at_syntax(&temp_object, &reference, spec, identifier_len, repo, git_str_cstr(&buf))) < 0) - goto cleanup; - - if (temp_object != NULL) - base_rev = temp_object; - break; - } else if (spec[pos+1] == '\0') { - spec = "HEAD"; - break; - } - /* fall through */ - - default: - if ((error = ensure_left_hand_identifier_is_not_known_yet(base_rev, reference)) < 0) - goto cleanup; - - pos++; - identifier_len++; - } - } - - if ((error = ensure_base_rev_loaded(&base_rev, &reference, spec, identifier_len, repo, false)) < 0) - goto cleanup; - - if (!should_return_reference) { - git_reference_free(reference); - reference = NULL; - } - - *object_out = base_rev; - *reference_out = reference; - *identifier_len_out = identifier_len; - error = 0; - -cleanup: - if (error) { - if (error == GIT_EINVALIDSPEC) - git_error_set(GIT_ERROR_INVALID, - "failed to parse revision specifier - Invalid pattern '%s'", spec); - - git_object_free(base_rev); - git_reference_free(reference); - } - - git_str_dispose(&buf); - return error; -} - -int git_revparse_ext( - git_object **object_out, - git_reference **reference_out, - git_repository *repo, - const char *spec) -{ - int error; - size_t identifier_len; - git_object *obj = NULL; - git_reference *ref = NULL; - - if ((error = revparse(&obj, &ref, &identifier_len, repo, spec)) < 0) - goto cleanup; - - *object_out = obj; - *reference_out = ref; - GIT_UNUSED(identifier_len); - - return 0; - -cleanup: - git_object_free(obj); - git_reference_free(ref); - return error; -} - -int git_revparse_single(git_object **out, git_repository *repo, const char *spec) -{ - int error; - git_object *obj = NULL; - git_reference *ref = NULL; - - *out = NULL; - - if ((error = git_revparse_ext(&obj, &ref, repo, spec)) < 0) - goto cleanup; - - git_reference_free(ref); - - *out = obj; - - return 0; - -cleanup: - git_object_free(obj); - git_reference_free(ref); - return error; -} - -int git_revparse( - git_revspec *revspec, - git_repository *repo, - const char *spec) -{ - const char *dotdot; - int error = 0; - - GIT_ASSERT_ARG(revspec); - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(spec); - - memset(revspec, 0x0, sizeof(*revspec)); - - if ((dotdot = strstr(spec, "..")) != NULL) { - char *lstr; - const char *rstr; - revspec->flags = GIT_REVSPEC_RANGE; - - /* - * Following git.git, don't allow '..' because it makes command line - * arguments which can be either paths or revisions ambiguous when the - * path is almost certainly intended. The empty range '...' is still - * allowed. - */ - if (!git__strcmp(spec, "..")) { - git_error_set(GIT_ERROR_INVALID, "Invalid pattern '..'"); - return GIT_EINVALIDSPEC; - } - - lstr = git__substrdup(spec, dotdot - spec); - rstr = dotdot + 2; - if (dotdot[2] == '.') { - revspec->flags |= GIT_REVSPEC_MERGE_BASE; - rstr++; - } - - error = git_revparse_single( - &revspec->from, - repo, - *lstr == '\0' ? "HEAD" : lstr); - - if (!error) { - error = git_revparse_single( - &revspec->to, - repo, - *rstr == '\0' ? "HEAD" : rstr); - } - - git__free((void*)lstr); - } else { - revspec->flags = GIT_REVSPEC_SINGLE; - error = git_revparse_single(&revspec->from, repo, spec); - } - - return error; -} diff --git a/vendor/libgit2/src/settings.h b/vendor/libgit2/src/settings.h deleted file mode 100644 index dc42ce93..00000000 --- a/vendor/libgit2/src/settings.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -extern int git_settings_global_init(void); - -extern const char *git_libgit2__user_agent(void); -extern const char *git_libgit2__ssl_ciphers(void); diff --git a/vendor/libgit2/src/signature.c b/vendor/libgit2/src/signature.c deleted file mode 100644 index 5d6ab572..00000000 --- a/vendor/libgit2/src/signature.c +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "signature.h" - -#include "repository.h" -#include "git2/common.h" -#include "posix.h" - -void git_signature_free(git_signature *sig) -{ - if (sig == NULL) - return; - - git__free(sig->name); - sig->name = NULL; - git__free(sig->email); - sig->email = NULL; - git__free(sig); -} - -static int signature_parse_error(const char *msg) -{ - git_error_set(GIT_ERROR_INVALID, "failed to parse signature - %s", msg); - return GIT_EINVALID; -} - -static int signature_error(const char *msg) -{ - git_error_set(GIT_ERROR_INVALID, "failed to parse signature - %s", msg); - return -1; -} - -static bool contains_angle_brackets(const char *input) -{ - return strchr(input, '<') != NULL || strchr(input, '>') != NULL; -} - -static bool is_crud(unsigned char c) -{ - return c <= 32 || - c == '.' || - c == ',' || - c == ':' || - c == ';' || - c == '<' || - c == '>' || - c == '"' || - c == '\\' || - c == '\''; -} - -static char *extract_trimmed(const char *ptr, size_t len) -{ - while (len && is_crud((unsigned char)ptr[0])) { - ptr++; len--; - } - - while (len && is_crud((unsigned char)ptr[len - 1])) { - len--; - } - - return git__substrdup(ptr, len); -} - -int git_signature_new(git_signature **sig_out, const char *name, const char *email, git_time_t time, int offset) -{ - git_signature *p = NULL; - - GIT_ASSERT_ARG(name); - GIT_ASSERT_ARG(email); - - *sig_out = NULL; - - if (contains_angle_brackets(name) || - contains_angle_brackets(email)) { - return signature_error( - "Neither `name` nor `email` should contain angle brackets chars."); - } - - p = git__calloc(1, sizeof(git_signature)); - GIT_ERROR_CHECK_ALLOC(p); - - p->name = extract_trimmed(name, strlen(name)); - GIT_ERROR_CHECK_ALLOC(p->name); - p->email = extract_trimmed(email, strlen(email)); - GIT_ERROR_CHECK_ALLOC(p->email); - - if (p->name[0] == '\0' || p->email[0] == '\0') { - git_signature_free(p); - return signature_error("Signature cannot have an empty name or email"); - } - - p->when.time = time; - p->when.offset = offset; - p->when.sign = (offset < 0) ? '-' : '+'; - - *sig_out = p; - return 0; -} - -int git_signature_dup(git_signature **dest, const git_signature *source) -{ - git_signature *signature; - - if (source == NULL) - return 0; - - signature = git__calloc(1, sizeof(git_signature)); - GIT_ERROR_CHECK_ALLOC(signature); - - signature->name = git__strdup(source->name); - GIT_ERROR_CHECK_ALLOC(signature->name); - - signature->email = git__strdup(source->email); - GIT_ERROR_CHECK_ALLOC(signature->email); - - signature->when.time = source->when.time; - signature->when.offset = source->when.offset; - signature->when.sign = source->when.sign; - - *dest = signature; - - return 0; -} - -int git_signature__pdup(git_signature **dest, const git_signature *source, git_pool *pool) -{ - git_signature *signature; - - if (source == NULL) - return 0; - - signature = git_pool_mallocz(pool, sizeof(git_signature)); - GIT_ERROR_CHECK_ALLOC(signature); - - signature->name = git_pool_strdup(pool, source->name); - GIT_ERROR_CHECK_ALLOC(signature->name); - - signature->email = git_pool_strdup(pool, source->email); - GIT_ERROR_CHECK_ALLOC(signature->email); - - signature->when.time = source->when.time; - signature->when.offset = source->when.offset; - signature->when.sign = source->when.sign; - - *dest = signature; - - return 0; -} - -int git_signature_now(git_signature **sig_out, const char *name, const char *email) -{ - time_t now; - time_t offset; - struct tm *utc_tm; - git_signature *sig; - struct tm _utc; - - *sig_out = NULL; - - /* - * Get the current time as seconds since the epoch and - * transform that into a tm struct containing the time at - * UTC. Give that to mktime which considers it a local time - * (tm_isdst = -1 asks it to take DST into account) and gives - * us that time as seconds since the epoch. The difference - * between its return value and 'now' is our offset to UTC. - */ - time(&now); - utc_tm = p_gmtime_r(&now, &_utc); - utc_tm->tm_isdst = -1; - offset = (time_t)difftime(now, mktime(utc_tm)); - offset /= 60; - - if (git_signature_new(&sig, name, email, now, (int)offset) < 0) - return -1; - - *sig_out = sig; - - return 0; -} - -int git_signature_default(git_signature **out, git_repository *repo) -{ - int error; - git_config *cfg; - const char *user_name, *user_email; - - if ((error = git_repository_config_snapshot(&cfg, repo)) < 0) - return error; - - if (!(error = git_config_get_string(&user_name, cfg, "user.name")) && - !(error = git_config_get_string(&user_email, cfg, "user.email"))) - error = git_signature_now(out, user_name, user_email); - - git_config_free(cfg); - return error; -} - -int git_signature__parse(git_signature *sig, const char **buffer_out, - const char *buffer_end, const char *header, char ender) -{ - const char *buffer = *buffer_out; - const char *email_start, *email_end; - - memset(sig, 0, sizeof(git_signature)); - - if (ender && - (buffer_end = memchr(buffer, ender, buffer_end - buffer)) == NULL) - return signature_parse_error("no newline given"); - - if (header) { - const size_t header_len = strlen(header); - - if (buffer + header_len >= buffer_end || memcmp(buffer, header, header_len) != 0) - return signature_parse_error("expected prefix doesn't match actual"); - - buffer += header_len; - } - - email_start = git__memrchr(buffer, '<', buffer_end - buffer); - email_end = git__memrchr(buffer, '>', buffer_end - buffer); - - if (!email_start || !email_end || email_end <= email_start) - return signature_parse_error("malformed e-mail"); - - email_start += 1; - sig->name = extract_trimmed(buffer, email_start - buffer - 1); - sig->email = extract_trimmed(email_start, email_end - email_start); - - /* Do we even have a time at the end of the signature? */ - if (email_end + 2 < buffer_end) { - const char *time_start = email_end + 2; - const char *time_end; - - if (git__strntol64(&sig->when.time, time_start, - buffer_end - time_start, &time_end, 10) < 0) { - git__free(sig->name); - git__free(sig->email); - sig->name = sig->email = NULL; - return signature_parse_error("invalid Unix timestamp"); - } - - /* do we have a timezone? */ - if (time_end + 1 < buffer_end) { - int offset, hours, mins; - const char *tz_start, *tz_end; - - tz_start = time_end + 1; - - if ((tz_start[0] != '-' && tz_start[0] != '+') || - git__strntol32(&offset, tz_start + 1, - buffer_end - tz_start - 1, &tz_end, 10) < 0) { - /* malformed timezone, just assume it's zero */ - offset = 0; - } - - hours = offset / 100; - mins = offset % 100; - - /* - * only store timezone if it's not overflowing; - * see http://www.worldtimezone.com/faq.html - */ - if (hours <= 14 && mins <= 59) { - sig->when.offset = (hours * 60) + mins; - sig->when.sign = tz_start[0]; - if (tz_start[0] == '-') - sig->when.offset = -sig->when.offset; - } - } - } - - *buffer_out = buffer_end + 1; - return 0; -} - -int git_signature_from_buffer(git_signature **out, const char *buf) -{ - git_signature *sig; - const char *buf_end; - int error; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(buf); - - *out = NULL; - - sig = git__calloc(1, sizeof(git_signature)); - GIT_ERROR_CHECK_ALLOC(sig); - - buf_end = buf + strlen(buf); - error = git_signature__parse(sig, &buf, buf_end, NULL, '\0'); - - if (error) - git__free(sig); - else - *out = sig; - - return error; -} - -void git_signature__writebuf(git_str *buf, const char *header, const git_signature *sig) -{ - int offset, hours, mins; - char sign; - - offset = sig->when.offset; - sign = (sig->when.offset < 0 || sig->when.sign == '-') ? '-' : '+'; - - if (offset < 0) - offset = -offset; - - hours = offset / 60; - mins = offset % 60; - - git_str_printf(buf, "%s%s <%s> %u %c%02d%02d\n", - header ? header : "", sig->name, sig->email, - (unsigned)sig->when.time, sign, hours, mins); -} - -bool git_signature__equal(const git_signature *one, const git_signature *two) -{ - GIT_ASSERT_ARG(one); - GIT_ASSERT_ARG(two); - - return - git__strcmp(one->name, two->name) == 0 && - git__strcmp(one->email, two->email) == 0 && - one->when.time == two->when.time && - one->when.offset == two->when.offset && - one->when.sign == two->when.sign; -} - diff --git a/vendor/libgit2/src/streams/mbedtls.c b/vendor/libgit2/src/streams/mbedtls.c deleted file mode 100644 index 0cf5c8af..00000000 --- a/vendor/libgit2/src/streams/mbedtls.c +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "streams/mbedtls.h" - -#ifdef GIT_MBEDTLS - -#include - -#include "runtime.h" -#include "stream.h" -#include "streams/socket.h" -#include "netops.h" -#include "git2/transport.h" -#include "util.h" - -#ifndef GIT_DEFAULT_CERT_LOCATION -#define GIT_DEFAULT_CERT_LOCATION NULL -#endif - -/* Work around C90-conformance issues */ -#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) -# if defined(_MSC_VER) -# define inline __inline -# elif defined(__GNUC__) -# define inline __inline__ -# else -# define inline -# endif -#endif - -#include -#include -#include -#include -#include - -#undef inline - -#define GIT_SSL_DEFAULT_CIPHERS "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-DSS-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-DSS-WITH-AES-256-GCM-SHA384:TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256:TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA:TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA:TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384:TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384:TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA:TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-DSS-WITH-AES-128-CBC-SHA256:TLS-DHE-DSS-WITH-AES-256-CBC-SHA256:TLS-DHE-DSS-WITH-AES-128-CBC-SHA:TLS-DHE-DSS-WITH-AES-256-CBC-SHA:TLS-RSA-WITH-AES-128-GCM-SHA256:TLS-RSA-WITH-AES-256-GCM-SHA384:TLS-RSA-WITH-AES-128-CBC-SHA256:TLS-RSA-WITH-AES-256-CBC-SHA256:TLS-RSA-WITH-AES-128-CBC-SHA:TLS-RSA-WITH-AES-256-CBC-SHA" -#define GIT_SSL_DEFAULT_CIPHERS_COUNT 30 - -static mbedtls_ssl_config *git__ssl_conf; -static int ciphers_list[GIT_SSL_DEFAULT_CIPHERS_COUNT]; -static mbedtls_entropy_context *mbedtls_entropy; - -/** - * This function aims to clean-up the SSL context which - * we allocated. - */ -static void shutdown_ssl(void) -{ - if (git__ssl_conf) { - mbedtls_x509_crt_free(git__ssl_conf->ca_chain); - git__free(git__ssl_conf->ca_chain); - mbedtls_ctr_drbg_free(git__ssl_conf->p_rng); - git__free(git__ssl_conf->p_rng); - mbedtls_ssl_config_free(git__ssl_conf); - git__free(git__ssl_conf); - git__ssl_conf = NULL; - } - if (mbedtls_entropy) { - mbedtls_entropy_free(mbedtls_entropy); - git__free(mbedtls_entropy); - mbedtls_entropy = NULL; - } -} - -int git_mbedtls_stream_global_init(void) -{ - int loaded = 0; - char *crtpath = GIT_DEFAULT_CERT_LOCATION; - struct stat statbuf; - mbedtls_ctr_drbg_context *ctr_drbg = NULL; - - size_t ciphers_known = 0; - char *cipher_name = NULL; - char *cipher_string = NULL; - char *cipher_string_tmp = NULL; - - git__ssl_conf = git__malloc(sizeof(mbedtls_ssl_config)); - GIT_ERROR_CHECK_ALLOC(git__ssl_conf); - - mbedtls_ssl_config_init(git__ssl_conf); - if (mbedtls_ssl_config_defaults(git__ssl_conf, - MBEDTLS_SSL_IS_CLIENT, - MBEDTLS_SSL_TRANSPORT_STREAM, - MBEDTLS_SSL_PRESET_DEFAULT) != 0) { - git_error_set(GIT_ERROR_SSL, "failed to initialize mbedTLS"); - goto cleanup; - } - - /* configure TLSv1 */ - mbedtls_ssl_conf_min_version(git__ssl_conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0); - - /* verify_server_cert is responsible for making the check. - * OPTIONAL because REQUIRED drops the certificate as soon as the check - * is made, so we can never see the certificate and override it. */ - mbedtls_ssl_conf_authmode(git__ssl_conf, MBEDTLS_SSL_VERIFY_OPTIONAL); - - /* set the list of allowed ciphersuites */ - ciphers_known = 0; - cipher_string = cipher_string_tmp = git__strdup(GIT_SSL_DEFAULT_CIPHERS); - GIT_ERROR_CHECK_ALLOC(cipher_string); - - while ((cipher_name = git__strtok(&cipher_string_tmp, ":")) != NULL) { - int cipherid = mbedtls_ssl_get_ciphersuite_id(cipher_name); - if (cipherid == 0) continue; - - if (ciphers_known >= ARRAY_SIZE(ciphers_list)) { - git_error_set(GIT_ERROR_SSL, "out of cipher list space"); - goto cleanup; - } - - ciphers_list[ciphers_known++] = cipherid; - } - git__free(cipher_string); - - if (!ciphers_known) { - git_error_set(GIT_ERROR_SSL, "no cipher could be enabled"); - goto cleanup; - } - mbedtls_ssl_conf_ciphersuites(git__ssl_conf, ciphers_list); - - /* Seeding the random number generator */ - mbedtls_entropy = git__malloc(sizeof(mbedtls_entropy_context)); - GIT_ERROR_CHECK_ALLOC(mbedtls_entropy); - - mbedtls_entropy_init(mbedtls_entropy); - - ctr_drbg = git__malloc(sizeof(mbedtls_ctr_drbg_context)); - GIT_ERROR_CHECK_ALLOC(ctr_drbg); - - mbedtls_ctr_drbg_init(ctr_drbg); - - if (mbedtls_ctr_drbg_seed(ctr_drbg, - mbedtls_entropy_func, - mbedtls_entropy, NULL, 0) != 0) { - git_error_set(GIT_ERROR_SSL, "failed to initialize mbedTLS entropy pool"); - goto cleanup; - } - - mbedtls_ssl_conf_rng(git__ssl_conf, mbedtls_ctr_drbg_random, ctr_drbg); - - /* load default certificates */ - if (crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISREG(statbuf.st_mode)) - loaded = (git_mbedtls__set_cert_location(crtpath, NULL) == 0); - if (!loaded && crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) - loaded = (git_mbedtls__set_cert_location(NULL, crtpath) == 0); - - return git_runtime_shutdown_register(shutdown_ssl); - -cleanup: - mbedtls_ctr_drbg_free(ctr_drbg); - git__free(ctr_drbg); - mbedtls_ssl_config_free(git__ssl_conf); - git__free(git__ssl_conf); - git__ssl_conf = NULL; - - return -1; -} - -static int bio_read(void *b, unsigned char *buf, size_t len) -{ - git_stream *io = (git_stream *) b; - return (int) git_stream_read(io, buf, min(len, INT_MAX)); -} - -static int bio_write(void *b, const unsigned char *buf, size_t len) -{ - git_stream *io = (git_stream *) b; - return (int) git_stream_write(io, (const char *)buf, min(len, INT_MAX), 0); -} - -static int ssl_set_error(mbedtls_ssl_context *ssl, int error) -{ - char errbuf[512]; - int ret = -1; - - GIT_ASSERT(error != MBEDTLS_ERR_SSL_WANT_READ); - GIT_ASSERT(error != MBEDTLS_ERR_SSL_WANT_WRITE); - - if (error != 0) - mbedtls_strerror( error, errbuf, 512 ); - - switch(error) { - case 0: - git_error_set(GIT_ERROR_SSL, "SSL error: unknown error"); - break; - - case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: - git_error_set(GIT_ERROR_SSL, "SSL error: %#04x [%x] - %s", error, ssl->session_negotiate->verify_result, errbuf); - ret = GIT_ECERTIFICATE; - break; - - default: - git_error_set(GIT_ERROR_SSL, "SSL error: %#04x - %s", error, errbuf); - } - - return ret; -} - -static int ssl_teardown(mbedtls_ssl_context *ssl) -{ - int ret = 0; - - ret = mbedtls_ssl_close_notify(ssl); - if (ret < 0) - ret = ssl_set_error(ssl, ret); - - mbedtls_ssl_free(ssl); - return ret; -} - -static int verify_server_cert(mbedtls_ssl_context *ssl) -{ - int ret = -1; - - if ((ret = mbedtls_ssl_get_verify_result(ssl)) != 0) { - char vrfy_buf[512]; - int len = mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "", ret); - if (len >= 1) vrfy_buf[len - 1] = '\0'; /* Remove trailing \n */ - git_error_set(GIT_ERROR_SSL, "the SSL certificate is invalid: %#04x - %s", ret, vrfy_buf); - return GIT_ECERTIFICATE; - } - - return 0; -} - -typedef struct { - git_stream parent; - git_stream *io; - int owned; - bool connected; - char *host; - mbedtls_ssl_context *ssl; - git_cert_x509 cert_info; -} mbedtls_stream; - - -static int mbedtls_connect(git_stream *stream) -{ - int ret; - mbedtls_stream *st = (mbedtls_stream *) stream; - - if (st->owned && (ret = git_stream_connect(st->io)) < 0) - return ret; - - st->connected = true; - - mbedtls_ssl_set_hostname(st->ssl, st->host); - - mbedtls_ssl_set_bio(st->ssl, st->io, bio_write, bio_read, NULL); - - if ((ret = mbedtls_ssl_handshake(st->ssl)) != 0) - return ssl_set_error(st->ssl, ret); - - return verify_server_cert(st->ssl); -} - -static int mbedtls_certificate(git_cert **out, git_stream *stream) -{ - unsigned char *encoded_cert; - mbedtls_stream *st = (mbedtls_stream *) stream; - - const mbedtls_x509_crt *cert = mbedtls_ssl_get_peer_cert(st->ssl); - if (!cert) { - git_error_set(GIT_ERROR_SSL, "the server did not provide a certificate"); - return -1; - } - - /* Retrieve the length of the certificate first */ - if (cert->raw.len == 0) { - git_error_set(GIT_ERROR_NET, "failed to retrieve certificate information"); - return -1; - } - - encoded_cert = git__malloc(cert->raw.len); - GIT_ERROR_CHECK_ALLOC(encoded_cert); - memcpy(encoded_cert, cert->raw.p, cert->raw.len); - - st->cert_info.parent.cert_type = GIT_CERT_X509; - st->cert_info.data = encoded_cert; - st->cert_info.len = cert->raw.len; - - *out = &st->cert_info.parent; - - return 0; -} - -static int mbedtls_set_proxy(git_stream *stream, const git_proxy_options *proxy_options) -{ - mbedtls_stream *st = (mbedtls_stream *) stream; - - return git_stream_set_proxy(st->io, proxy_options); -} - -static ssize_t mbedtls_stream_write(git_stream *stream, const char *data, size_t len, int flags) -{ - mbedtls_stream *st = (mbedtls_stream *) stream; - int written; - - GIT_UNUSED(flags); - - /* - * `mbedtls_ssl_write` can only represent INT_MAX bytes - * written via its return value. We thus need to clamp - * the maximum number of bytes written. - */ - len = min(len, INT_MAX); - - if ((written = mbedtls_ssl_write(st->ssl, (const unsigned char *)data, len)) <= 0) - return ssl_set_error(st->ssl, written); - - return written; -} - -static ssize_t mbedtls_stream_read(git_stream *stream, void *data, size_t len) -{ - mbedtls_stream *st = (mbedtls_stream *) stream; - int ret; - - if ((ret = mbedtls_ssl_read(st->ssl, (unsigned char *)data, len)) <= 0) - ssl_set_error(st->ssl, ret); - - return ret; -} - -static int mbedtls_stream_close(git_stream *stream) -{ - mbedtls_stream *st = (mbedtls_stream *) stream; - int ret = 0; - - if (st->connected && (ret = ssl_teardown(st->ssl)) != 0) - return -1; - - st->connected = false; - - return st->owned ? git_stream_close(st->io) : 0; -} - -static void mbedtls_stream_free(git_stream *stream) -{ - mbedtls_stream *st = (mbedtls_stream *) stream; - - if (st->owned) - git_stream_free(st->io); - - git__free(st->host); - git__free(st->cert_info.data); - mbedtls_ssl_free(st->ssl); - git__free(st->ssl); - git__free(st); -} - -static int mbedtls_stream_wrap( - git_stream **out, - git_stream *in, - const char *host, - int owned) -{ - mbedtls_stream *st; - int error; - - st = git__calloc(1, sizeof(mbedtls_stream)); - GIT_ERROR_CHECK_ALLOC(st); - - st->io = in; - st->owned = owned; - - st->ssl = git__malloc(sizeof(mbedtls_ssl_context)); - GIT_ERROR_CHECK_ALLOC(st->ssl); - mbedtls_ssl_init(st->ssl); - if (mbedtls_ssl_setup(st->ssl, git__ssl_conf)) { - git_error_set(GIT_ERROR_SSL, "failed to create ssl object"); - error = -1; - goto out_err; - } - - st->host = git__strdup(host); - GIT_ERROR_CHECK_ALLOC(st->host); - - st->parent.version = GIT_STREAM_VERSION; - st->parent.encrypted = 1; - st->parent.proxy_support = git_stream_supports_proxy(st->io); - st->parent.connect = mbedtls_connect; - st->parent.certificate = mbedtls_certificate; - st->parent.set_proxy = mbedtls_set_proxy; - st->parent.read = mbedtls_stream_read; - st->parent.write = mbedtls_stream_write; - st->parent.close = mbedtls_stream_close; - st->parent.free = mbedtls_stream_free; - - *out = (git_stream *) st; - return 0; - -out_err: - mbedtls_ssl_free(st->ssl); - git_stream_close(st->io); - git_stream_free(st->io); - git__free(st); - - return error; -} - -int git_mbedtls_stream_wrap( - git_stream **out, - git_stream *in, - const char *host) -{ - return mbedtls_stream_wrap(out, in, host, 0); -} - -int git_mbedtls_stream_new( - git_stream **out, - const char *host, - const char *port) -{ - git_stream *stream; - int error; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(host); - GIT_ASSERT_ARG(port); - - if ((error = git_socket_stream_new(&stream, host, port)) < 0) - return error; - - if ((error = mbedtls_stream_wrap(out, stream, host, 1)) < 0) { - git_stream_close(stream); - git_stream_free(stream); - } - - return error; -} - -int git_mbedtls__set_cert_location(const char *file, const char *path) -{ - int ret = 0; - char errbuf[512]; - mbedtls_x509_crt *cacert; - - GIT_ASSERT_ARG(file || path); - - cacert = git__malloc(sizeof(mbedtls_x509_crt)); - GIT_ERROR_CHECK_ALLOC(cacert); - - mbedtls_x509_crt_init(cacert); - if (file) - ret = mbedtls_x509_crt_parse_file(cacert, file); - if (ret >= 0 && path) - ret = mbedtls_x509_crt_parse_path(cacert, path); - /* mbedtls_x509_crt_parse_path returns the number of invalid certs on success */ - if (ret < 0) { - mbedtls_x509_crt_free(cacert); - git__free(cacert); - mbedtls_strerror( ret, errbuf, 512 ); - git_error_set(GIT_ERROR_SSL, "failed to load CA certificates: %#04x - %s", ret, errbuf); - return -1; - } - - mbedtls_x509_crt_free(git__ssl_conf->ca_chain); - git__free(git__ssl_conf->ca_chain); - mbedtls_ssl_conf_ca_chain(git__ssl_conf, cacert, NULL); - - return 0; -} - -#else - -#include "stream.h" - -int git_mbedtls_stream_global_init(void) -{ - return 0; -} - -#endif diff --git a/vendor/libgit2/src/streams/openssl.c b/vendor/libgit2/src/streams/openssl.c deleted file mode 100644 index 89c96780..00000000 --- a/vendor/libgit2/src/streams/openssl.c +++ /dev/null @@ -1,747 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "streams/openssl.h" -#include "streams/openssl_legacy.h" -#include "streams/openssl_dynamic.h" - -#ifdef GIT_OPENSSL - -#include - -#include "common.h" -#include "runtime.h" -#include "settings.h" -#include "posix.h" -#include "stream.h" -#include "streams/socket.h" -#include "netops.h" -#include "git2/transport.h" -#include "git2/sys/openssl.h" - -#ifndef GIT_WIN32 -# include -# include -# include -#endif - -#ifndef GIT_OPENSSL_DYNAMIC -# include -# include -# include -# include -#endif - -SSL_CTX *git__ssl_ctx; - -#define GIT_SSL_DEFAULT_CIPHERS "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES128-SHA256:DHE-DSS-AES256-SHA256:DHE-DSS-AES128-SHA:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA" - - -static BIO_METHOD *git_stream_bio_method; -static int init_bio_method(void); - -/** - * This function aims to clean-up the SSL context which - * we allocated. - */ -static void shutdown_ssl(void) -{ - if (git_stream_bio_method) { - BIO_meth_free(git_stream_bio_method); - git_stream_bio_method = NULL; - } - - if (git__ssl_ctx) { - SSL_CTX_free(git__ssl_ctx); - git__ssl_ctx = NULL; - } -} - -#ifdef VALGRIND -# if !defined(GIT_OPENSSL_LEGACY) && !defined(GIT_OPENSSL_DYNAMIC) - -static void *git_openssl_malloc(size_t bytes, const char *file, int line) -{ - GIT_UNUSED(file); - GIT_UNUSED(line); - return git__calloc(1, bytes); -} - -static void *git_openssl_realloc(void *mem, size_t size, const char *file, int line) -{ - GIT_UNUSED(file); - GIT_UNUSED(line); - return git__realloc(mem, size); -} - -static void git_openssl_free(void *mem, const char *file, int line) -{ - GIT_UNUSED(file); - GIT_UNUSED(line); - git__free(mem); -} -# else /* !GIT_OPENSSL_LEGACY && !GIT_OPENSSL_DYNAMIC */ -static void *git_openssl_malloc(size_t bytes) -{ - return git__calloc(1, bytes); -} - -static void *git_openssl_realloc(void *mem, size_t size) -{ - return git__realloc(mem, size); -} - -static void git_openssl_free(void *mem) -{ - git__free(mem); -} -# endif /* !GIT_OPENSSL_LEGACY && !GIT_OPENSSL_DYNAMIC */ -#endif /* VALGRIND */ - -static int openssl_init(void) -{ - long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; - const char *ciphers = git_libgit2__ssl_ciphers(); -#ifdef VALGRIND - static bool allocators_initialized = false; -#endif - - /* Older OpenSSL and MacOS OpenSSL doesn't have this */ -#ifdef SSL_OP_NO_COMPRESSION - ssl_opts |= SSL_OP_NO_COMPRESSION; -#endif - -#ifdef VALGRIND - /* - * Swap in our own allocator functions that initialize - * allocated memory to avoid spurious valgrind warnings. - * Don't error on failure; many builds of OpenSSL do not - * allow you to set these functions. - */ - if (!allocators_initialized) { - CRYPTO_set_mem_functions(git_openssl_malloc, - git_openssl_realloc, - git_openssl_free); - allocators_initialized = true; - } -#endif - - OPENSSL_init_ssl(0, NULL); - - /* - * Load SSLv{2,3} and TLSv1 so that we can talk with servers - * which use the SSL hellos, which are often used for - * compatibility. We then disable SSL so we only allow OpenSSL - * to speak TLSv1 to perform the encryption itself. - */ - if (!(git__ssl_ctx = SSL_CTX_new(SSLv23_method()))) - goto error; - - SSL_CTX_set_options(git__ssl_ctx, ssl_opts); - SSL_CTX_set_mode(git__ssl_ctx, SSL_MODE_AUTO_RETRY); - SSL_CTX_set_verify(git__ssl_ctx, SSL_VERIFY_NONE, NULL); - if (!SSL_CTX_set_default_verify_paths(git__ssl_ctx)) - goto error; - - if (!ciphers) - ciphers = GIT_SSL_DEFAULT_CIPHERS; - - if(!SSL_CTX_set_cipher_list(git__ssl_ctx, ciphers)) - goto error; - - if (init_bio_method() < 0) - goto error; - - return git_runtime_shutdown_register(shutdown_ssl); - -error: - git_error_set(GIT_ERROR_NET, "could not initialize openssl: %s", - ERR_error_string(ERR_get_error(), NULL)); - SSL_CTX_free(git__ssl_ctx); - git__ssl_ctx = NULL; - return -1; -} - -/* - * When we use dynamic loading, we defer OpenSSL initialization until - * it's first used. `openssl_ensure_initialized` will do the work - * under a mutex. - */ -git_mutex openssl_mutex; -bool openssl_initialized; - -int git_openssl_stream_global_init(void) -{ -#ifndef GIT_OPENSSL_DYNAMIC - return openssl_init(); -#else - if (git_mutex_init(&openssl_mutex) != 0) - return -1; - - return 0; -#endif -} - -static int openssl_ensure_initialized(void) -{ -#ifdef GIT_OPENSSL_DYNAMIC - int error = 0; - - if (git_mutex_lock(&openssl_mutex) != 0) - return -1; - - if (!openssl_initialized) { - if ((error = git_openssl_stream_dynamic_init()) == 0) - error = openssl_init(); - - openssl_initialized = true; - } - - error |= git_mutex_unlock(&openssl_mutex); - return error; - -#else - return 0; -#endif -} - -#if !defined(GIT_OPENSSL_LEGACY) && !defined(GIT_OPENSSL_DYNAMIC) -int git_openssl_set_locking(void) -{ -# ifdef GIT_THREADS - return 0; -# else - git_error_set(GIT_ERROR_THREAD, "libgit2 was not built with threads"); - return -1; -# endif -} -#endif - - -static int bio_create(BIO *b) -{ - BIO_set_init(b, 1); - BIO_set_data(b, NULL); - - return 1; -} - -static int bio_destroy(BIO *b) -{ - if (!b) - return 0; - - BIO_set_data(b, NULL); - - return 1; -} - -static int bio_read(BIO *b, char *buf, int len) -{ - git_stream *io = (git_stream *) BIO_get_data(b); - - return (int) git_stream_read(io, buf, len); -} - -static int bio_write(BIO *b, const char *buf, int len) -{ - git_stream *io = (git_stream *) BIO_get_data(b); - return (int) git_stream_write(io, buf, len, 0); -} - -static long bio_ctrl(BIO *b, int cmd, long num, void *ptr) -{ - GIT_UNUSED(b); - GIT_UNUSED(num); - GIT_UNUSED(ptr); - - if (cmd == BIO_CTRL_FLUSH) - return 1; - - return 0; -} - -static int bio_gets(BIO *b, char *buf, int len) -{ - GIT_UNUSED(b); - GIT_UNUSED(buf); - GIT_UNUSED(len); - return -1; -} - -static int bio_puts(BIO *b, const char *str) -{ - return bio_write(b, str, strlen(str)); -} - -static int init_bio_method(void) -{ - /* Set up the BIO_METHOD we use for wrapping our own stream implementations */ - git_stream_bio_method = BIO_meth_new(BIO_TYPE_SOURCE_SINK | BIO_get_new_index(), "git_stream"); - GIT_ERROR_CHECK_ALLOC(git_stream_bio_method); - - BIO_meth_set_write(git_stream_bio_method, bio_write); - BIO_meth_set_read(git_stream_bio_method, bio_read); - BIO_meth_set_puts(git_stream_bio_method, bio_puts); - BIO_meth_set_gets(git_stream_bio_method, bio_gets); - BIO_meth_set_ctrl(git_stream_bio_method, bio_ctrl); - BIO_meth_set_create(git_stream_bio_method, bio_create); - BIO_meth_set_destroy(git_stream_bio_method, bio_destroy); - - return 0; -} - -static int ssl_set_error(SSL *ssl, int error) -{ - int err; - unsigned long e; - - err = SSL_get_error(ssl, error); - - GIT_ASSERT(err != SSL_ERROR_WANT_READ); - GIT_ASSERT(err != SSL_ERROR_WANT_WRITE); - - switch (err) { - case SSL_ERROR_WANT_CONNECT: - case SSL_ERROR_WANT_ACCEPT: - git_error_set(GIT_ERROR_SSL, "SSL error: connection failure"); - break; - case SSL_ERROR_WANT_X509_LOOKUP: - git_error_set(GIT_ERROR_SSL, "SSL error: x509 error"); - break; - case SSL_ERROR_SYSCALL: - e = ERR_get_error(); - if (e > 0) { - char errmsg[256]; - ERR_error_string_n(e, errmsg, sizeof(errmsg)); - git_error_set(GIT_ERROR_NET, "SSL error: %s", errmsg); - break; - } else if (error < 0) { - git_error_set(GIT_ERROR_OS, "SSL error: syscall failure"); - break; - } - git_error_set(GIT_ERROR_SSL, "SSL error: received early EOF"); - return GIT_EEOF; - break; - case SSL_ERROR_SSL: - { - char errmsg[256]; - e = ERR_get_error(); - ERR_error_string_n(e, errmsg, sizeof(errmsg)); - git_error_set(GIT_ERROR_SSL, "SSL error: %s", errmsg); - break; - } - case SSL_ERROR_NONE: - case SSL_ERROR_ZERO_RETURN: - default: - git_error_set(GIT_ERROR_SSL, "SSL error: unknown error"); - break; - } - return -1; -} - -static int ssl_teardown(SSL *ssl) -{ - int ret; - - ret = SSL_shutdown(ssl); - if (ret < 0) - ret = ssl_set_error(ssl, ret); - else - ret = 0; - - return ret; -} - -static int check_host_name(const char *name, const char *host) -{ - if (!strcasecmp(name, host)) - return 0; - - if (gitno__match_host(name, host) < 0) - return -1; - - return 0; -} - -static int verify_server_cert(SSL *ssl, const char *host) -{ - X509 *cert = NULL; - X509_NAME *peer_name; - ASN1_STRING *str; - unsigned char *peer_cn = NULL; - int matched = -1, type = GEN_DNS; - GENERAL_NAMES *alts; - struct in6_addr addr6; - struct in_addr addr4; - void *addr = NULL; - int i = -1, j, error = 0; - - if (SSL_get_verify_result(ssl) != X509_V_OK) { - git_error_set(GIT_ERROR_SSL, "the SSL certificate is invalid"); - return GIT_ECERTIFICATE; - } - - /* Try to parse the host as an IP address to see if it is */ - if (p_inet_pton(AF_INET, host, &addr4)) { - type = GEN_IPADD; - addr = &addr4; - } else { - if (p_inet_pton(AF_INET6, host, &addr6)) { - type = GEN_IPADD; - addr = &addr6; - } - } - - - cert = SSL_get_peer_certificate(ssl); - if (!cert) { - error = -1; - git_error_set(GIT_ERROR_SSL, "the server did not provide a certificate"); - goto cleanup; - } - - /* Check the alternative names */ - alts = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); - if (alts) { - int num; - - num = sk_GENERAL_NAME_num(alts); - for (i = 0; i < num && matched != 1; i++) { - const GENERAL_NAME *gn = sk_GENERAL_NAME_value(alts, i); - const char *name = (char *) ASN1_STRING_get0_data(gn->d.ia5); - size_t namelen = (size_t) ASN1_STRING_length(gn->d.ia5); - - /* Skip any names of a type we're not looking for */ - if (gn->type != type) - continue; - - if (type == GEN_DNS) { - /* If it contains embedded NULs, don't even try */ - if (memchr(name, '\0', namelen)) - continue; - - if (check_host_name(name, host) < 0) - matched = 0; - else - matched = 1; - } else if (type == GEN_IPADD) { - /* Here name isn't so much a name but a binary representation of the IP */ - matched = addr && !!memcmp(name, addr, namelen); - } - } - } - GENERAL_NAMES_free(alts); - - if (matched == 0) - goto cert_fail_name; - - if (matched == 1) { - goto cleanup; - } - - /* If no alternative names are available, check the common name */ - peer_name = X509_get_subject_name(cert); - if (peer_name == NULL) - goto on_error; - - if (peer_name) { - /* Get the index of the last CN entry */ - while ((j = X509_NAME_get_index_by_NID(peer_name, NID_commonName, i)) >= 0) - i = j; - } - - if (i < 0) - goto on_error; - - str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(peer_name, i)); - if (str == NULL) - goto on_error; - - /* Work around a bug in OpenSSL whereby ASN1_STRING_to_UTF8 fails if it's already in utf-8 */ - if (ASN1_STRING_type(str) == V_ASN1_UTF8STRING) { - int size = ASN1_STRING_length(str); - - if (size > 0) { - peer_cn = OPENSSL_malloc(size + 1); - GIT_ERROR_CHECK_ALLOC(peer_cn); - memcpy(peer_cn, ASN1_STRING_get0_data(str), size); - peer_cn[size] = '\0'; - } else { - goto cert_fail_name; - } - } else { - int size = ASN1_STRING_to_UTF8(&peer_cn, str); - GIT_ERROR_CHECK_ALLOC(peer_cn); - if (memchr(peer_cn, '\0', size)) - goto cert_fail_name; - } - - if (check_host_name((char *)peer_cn, host) < 0) - goto cert_fail_name; - - goto cleanup; - -cert_fail_name: - error = GIT_ECERTIFICATE; - git_error_set(GIT_ERROR_SSL, "hostname does not match certificate"); - goto cleanup; - -on_error: - error = ssl_set_error(ssl, 0); - goto cleanup; - -cleanup: - X509_free(cert); - OPENSSL_free(peer_cn); - return error; -} - -typedef struct { - git_stream parent; - git_stream *io; - int owned; - bool connected; - char *host; - SSL *ssl; - git_cert_x509 cert_info; -} openssl_stream; - -static int openssl_connect(git_stream *stream) -{ - int ret; - BIO *bio; - openssl_stream *st = (openssl_stream *) stream; - - if (st->owned && (ret = git_stream_connect(st->io)) < 0) - return ret; - - bio = BIO_new(git_stream_bio_method); - GIT_ERROR_CHECK_ALLOC(bio); - - BIO_set_data(bio, st->io); - SSL_set_bio(st->ssl, bio, bio); - - /* specify the host in case SNI is needed */ -#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - SSL_set_tlsext_host_name(st->ssl, st->host); -#endif - - if ((ret = SSL_connect(st->ssl)) <= 0) - return ssl_set_error(st->ssl, ret); - - st->connected = true; - - return verify_server_cert(st->ssl, st->host); -} - -static int openssl_certificate(git_cert **out, git_stream *stream) -{ - openssl_stream *st = (openssl_stream *) stream; - X509 *cert = SSL_get_peer_certificate(st->ssl); - unsigned char *guard, *encoded_cert = NULL; - int error, len; - - /* Retrieve the length of the certificate first */ - len = i2d_X509(cert, NULL); - if (len < 0) { - git_error_set(GIT_ERROR_NET, "failed to retrieve certificate information"); - error = -1; - goto out; - } - - encoded_cert = git__malloc(len); - GIT_ERROR_CHECK_ALLOC(encoded_cert); - /* i2d_X509 makes 'guard' point to just after the data */ - guard = encoded_cert; - - len = i2d_X509(cert, &guard); - if (len < 0) { - git_error_set(GIT_ERROR_NET, "failed to retrieve certificate information"); - error = -1; - goto out; - } - - st->cert_info.parent.cert_type = GIT_CERT_X509; - st->cert_info.data = encoded_cert; - st->cert_info.len = len; - encoded_cert = NULL; - - *out = &st->cert_info.parent; - error = 0; - -out: - git__free(encoded_cert); - X509_free(cert); - return error; -} - -static int openssl_set_proxy(git_stream *stream, const git_proxy_options *proxy_opts) -{ - openssl_stream *st = (openssl_stream *) stream; - - return git_stream_set_proxy(st->io, proxy_opts); -} - -static ssize_t openssl_write(git_stream *stream, const char *data, size_t data_len, int flags) -{ - openssl_stream *st = (openssl_stream *) stream; - int ret, len = min(data_len, INT_MAX); - - GIT_UNUSED(flags); - - if ((ret = SSL_write(st->ssl, data, len)) <= 0) - return ssl_set_error(st->ssl, ret); - - return ret; -} - -static ssize_t openssl_read(git_stream *stream, void *data, size_t len) -{ - openssl_stream *st = (openssl_stream *) stream; - int ret; - - if ((ret = SSL_read(st->ssl, data, len)) <= 0) - return ssl_set_error(st->ssl, ret); - - return ret; -} - -static int openssl_close(git_stream *stream) -{ - openssl_stream *st = (openssl_stream *) stream; - int ret; - - if (st->connected && (ret = ssl_teardown(st->ssl)) < 0) - return -1; - - st->connected = false; - - return st->owned ? git_stream_close(st->io) : 0; -} - -static void openssl_free(git_stream *stream) -{ - openssl_stream *st = (openssl_stream *) stream; - - if (st->owned) - git_stream_free(st->io); - - SSL_free(st->ssl); - git__free(st->host); - git__free(st->cert_info.data); - git__free(st); -} - -static int openssl_stream_wrap( - git_stream **out, - git_stream *in, - const char *host, - int owned) -{ - openssl_stream *st; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(in); - GIT_ASSERT_ARG(host); - - st = git__calloc(1, sizeof(openssl_stream)); - GIT_ERROR_CHECK_ALLOC(st); - - st->io = in; - st->owned = owned; - - st->ssl = SSL_new(git__ssl_ctx); - if (st->ssl == NULL) { - git_error_set(GIT_ERROR_SSL, "failed to create ssl object"); - git__free(st); - return -1; - } - - st->host = git__strdup(host); - GIT_ERROR_CHECK_ALLOC(st->host); - - st->parent.version = GIT_STREAM_VERSION; - st->parent.encrypted = 1; - st->parent.proxy_support = git_stream_supports_proxy(st->io); - st->parent.connect = openssl_connect; - st->parent.certificate = openssl_certificate; - st->parent.set_proxy = openssl_set_proxy; - st->parent.read = openssl_read; - st->parent.write = openssl_write; - st->parent.close = openssl_close; - st->parent.free = openssl_free; - - *out = (git_stream *) st; - return 0; -} - -int git_openssl_stream_wrap(git_stream **out, git_stream *in, const char *host) -{ - if (openssl_ensure_initialized() < 0) - return -1; - - return openssl_stream_wrap(out, in, host, 0); -} - -int git_openssl_stream_new(git_stream **out, const char *host, const char *port) -{ - git_stream *stream = NULL; - int error; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(host); - GIT_ASSERT_ARG(port); - - if (openssl_ensure_initialized() < 0) - return -1; - - if ((error = git_socket_stream_new(&stream, host, port)) < 0) - return error; - - if ((error = openssl_stream_wrap(out, stream, host, 1)) < 0) { - git_stream_close(stream); - git_stream_free(stream); - } - - return error; -} - -int git_openssl__set_cert_location(const char *file, const char *path) -{ - if (openssl_ensure_initialized() < 0) - return -1; - - if (SSL_CTX_load_verify_locations(git__ssl_ctx, file, path) == 0) { - char errmsg[256]; - - ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg)); - git_error_set(GIT_ERROR_SSL, "OpenSSL error: failed to load certificates: %s", - errmsg); - - return -1; - } - return 0; -} - -#else - -#include "stream.h" -#include "git2/sys/openssl.h" - -int git_openssl_stream_global_init(void) -{ - return 0; -} - -int git_openssl_set_locking(void) -{ - git_error_set(GIT_ERROR_SSL, "libgit2 was not built with OpenSSL support"); - return -1; -} - -#endif diff --git a/vendor/libgit2/src/streams/socket.c b/vendor/libgit2/src/streams/socket.c deleted file mode 100644 index 9415fe89..00000000 --- a/vendor/libgit2/src/streams/socket.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "streams/socket.h" - -#include "posix.h" -#include "netops.h" -#include "registry.h" -#include "stream.h" - -#ifndef _WIN32 -# include -# include -# include -# include -# include -# include -# include -#else -# include -# include -# ifdef _MSC_VER -# pragma comment(lib, "ws2_32") -# endif -#endif - -#ifdef GIT_WIN32 -static void net_set_error(const char *str) -{ - int error = WSAGetLastError(); - char * win32_error = git_win32_get_error_message(error); - - if (win32_error) { - git_error_set(GIT_ERROR_NET, "%s: %s", str, win32_error); - git__free(win32_error); - } else { - git_error_set(GIT_ERROR_NET, "%s", str); - } -} -#else -static void net_set_error(const char *str) -{ - git_error_set(GIT_ERROR_NET, "%s: %s", str, strerror(errno)); -} -#endif - -static int close_socket(GIT_SOCKET s) -{ - if (s == INVALID_SOCKET) - return 0; - -#ifdef GIT_WIN32 - if (SOCKET_ERROR == closesocket(s)) - return -1; - - if (0 != WSACleanup()) { - git_error_set(GIT_ERROR_OS, "winsock cleanup failed"); - return -1; - } - - return 0; -#else - return close(s); -#endif - -} - -static int socket_connect(git_stream *stream) -{ - struct addrinfo *info = NULL, *p; - struct addrinfo hints; - git_socket_stream *st = (git_socket_stream *) stream; - GIT_SOCKET s = INVALID_SOCKET; - int ret; - -#ifdef GIT_WIN32 - /* on win32, the WSA context needs to be initialized - * before any socket calls can be performed */ - WSADATA wsd; - - if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) { - git_error_set(GIT_ERROR_OS, "winsock init failed"); - return -1; - } - - if (LOBYTE(wsd.wVersion) != 2 || HIBYTE(wsd.wVersion) != 2) { - WSACleanup(); - git_error_set(GIT_ERROR_OS, "winsock init failed"); - return -1; - } -#endif - - memset(&hints, 0x0, sizeof(struct addrinfo)); - hints.ai_socktype = SOCK_STREAM; - hints.ai_family = AF_UNSPEC; - - if ((ret = p_getaddrinfo(st->host, st->port, &hints, &info)) != 0) { - git_error_set(GIT_ERROR_NET, - "failed to resolve address for %s: %s", st->host, p_gai_strerror(ret)); - return -1; - } - - for (p = info; p != NULL; p = p->ai_next) { - s = socket(p->ai_family, p->ai_socktype | SOCK_CLOEXEC, p->ai_protocol); - - if (s == INVALID_SOCKET) - continue; - - if (connect(s, p->ai_addr, (socklen_t)p->ai_addrlen) == 0) - break; - - /* If we can't connect, try the next one */ - close_socket(s); - s = INVALID_SOCKET; - } - - /* Oops, we couldn't connect to any address */ - if (s == INVALID_SOCKET && p == NULL) { - git_error_set(GIT_ERROR_OS, "failed to connect to %s", st->host); - p_freeaddrinfo(info); - return -1; - } - - st->s = s; - p_freeaddrinfo(info); - return 0; -} - -static ssize_t socket_write(git_stream *stream, const char *data, size_t len, int flags) -{ - git_socket_stream *st = (git_socket_stream *) stream; - ssize_t written; - - errno = 0; - - if ((written = p_send(st->s, data, len, flags)) < 0) { - net_set_error("error sending data"); - return -1; - } - - return written; -} - -static ssize_t socket_read(git_stream *stream, void *data, size_t len) -{ - ssize_t ret; - git_socket_stream *st = (git_socket_stream *) stream; - - if ((ret = p_recv(st->s, data, len, 0)) < 0) - net_set_error("error receiving socket data"); - - return ret; -} - -static int socket_close(git_stream *stream) -{ - git_socket_stream *st = (git_socket_stream *) stream; - int error; - - error = close_socket(st->s); - st->s = INVALID_SOCKET; - - return error; -} - -static void socket_free(git_stream *stream) -{ - git_socket_stream *st = (git_socket_stream *) stream; - - git__free(st->host); - git__free(st->port); - git__free(st); -} - -static int default_socket_stream_new( - git_stream **out, - const char *host, - const char *port) -{ - git_socket_stream *st; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(host); - GIT_ASSERT_ARG(port); - - st = git__calloc(1, sizeof(git_socket_stream)); - GIT_ERROR_CHECK_ALLOC(st); - - st->host = git__strdup(host); - GIT_ERROR_CHECK_ALLOC(st->host); - - if (port) { - st->port = git__strdup(port); - GIT_ERROR_CHECK_ALLOC(st->port); - } - - st->parent.version = GIT_STREAM_VERSION; - st->parent.connect = socket_connect; - st->parent.write = socket_write; - st->parent.read = socket_read; - st->parent.close = socket_close; - st->parent.free = socket_free; - st->s = INVALID_SOCKET; - - *out = (git_stream *) st; - return 0; -} - -int git_socket_stream_new( - git_stream **out, - const char *host, - const char *port) -{ - int (*init)(git_stream **, const char *, const char *) = NULL; - git_stream_registration custom = {0}; - int error; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(host); - GIT_ASSERT_ARG(port); - - if ((error = git_stream_registry_lookup(&custom, GIT_STREAM_STANDARD)) == 0) - init = custom.init; - else if (error == GIT_ENOTFOUND) - init = default_socket_stream_new; - else - return error; - - if (!init) { - git_error_set(GIT_ERROR_NET, "there is no socket stream available"); - return -1; - } - - return init(out, host, port); -} diff --git a/vendor/libgit2/src/sysdir.c b/vendor/libgit2/src/sysdir.c deleted file mode 100644 index 450cb509..00000000 --- a/vendor/libgit2/src/sysdir.c +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "sysdir.h" - -#include "runtime.h" -#include "str.h" -#include "fs_path.h" -#include -#if GIT_WIN32 -#include "win32/findfile.h" -#else -#include -#include -#endif - -static int git_sysdir_guess_programdata_dirs(git_str *out) -{ -#ifdef GIT_WIN32 - return git_win32__find_programdata_dirs(out); -#else - git_str_clear(out); - return 0; -#endif -} - -static int git_sysdir_guess_system_dirs(git_str *out) -{ -#ifdef GIT_WIN32 - return git_win32__find_system_dirs(out, "etc"); -#else - return git_str_sets(out, "/etc"); -#endif -} - -#ifndef GIT_WIN32 -static int get_passwd_home(git_str *out, uid_t uid) -{ - struct passwd pwd, *pwdptr; - char *buf = NULL; - long buflen; - int error; - - GIT_ASSERT_ARG(out); - - if ((buflen = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) - buflen = 1024; - - do { - buf = git__realloc(buf, buflen); - error = getpwuid_r(uid, &pwd, buf, buflen, &pwdptr); - buflen *= 2; - } while (error == ERANGE && buflen <= 8192); - - if (error) { - git_error_set(GIT_ERROR_OS, "failed to get passwd entry"); - goto out; - } - - if (!pwdptr) { - git_error_set(GIT_ERROR_OS, "no passwd entry found for user"); - goto out; - } - - if ((error = git_str_puts(out, pwdptr->pw_dir)) < 0) - goto out; - -out: - git__free(buf); - return error; -} -#endif - -static int git_sysdir_guess_global_dirs(git_str *out) -{ -#ifdef GIT_WIN32 - return git_win32__find_global_dirs(out); -#else - int error; - uid_t uid, euid; - const char *sandbox_id; - - uid = getuid(); - euid = geteuid(); - - /** - * If APP_SANDBOX_CONTAINER_ID is set, we are running in a - * sandboxed environment on macOS. - */ - sandbox_id = getenv("APP_SANDBOX_CONTAINER_ID"); - - /* - * In case we are running setuid, use the configuration - * of the effective user. - * - * If we are running in a sandboxed environment on macOS, - * we have to get the HOME dir from the password entry file. - */ - if (!sandbox_id && uid == euid) - error = git__getenv(out, "HOME"); - else - error = get_passwd_home(out, euid); - - if (error == GIT_ENOTFOUND) { - git_error_clear(); - error = 0; - } - - return error; -#endif -} - -static int git_sysdir_guess_xdg_dirs(git_str *out) -{ -#ifdef GIT_WIN32 - return git_win32__find_xdg_dirs(out); -#else - git_str env = GIT_STR_INIT; - int error; - uid_t uid, euid; - - uid = getuid(); - euid = geteuid(); - - /* - * In case we are running setuid, only look up passwd - * directory of the effective user. - */ - if (uid == euid) { - if ((error = git__getenv(&env, "XDG_CONFIG_HOME")) == 0) - error = git_str_joinpath(out, env.ptr, "git"); - - if (error == GIT_ENOTFOUND && (error = git__getenv(&env, "HOME")) == 0) - error = git_str_joinpath(out, env.ptr, ".config/git"); - } else { - if ((error = get_passwd_home(&env, euid)) == 0) - error = git_str_joinpath(out, env.ptr, ".config/git"); - } - - if (error == GIT_ENOTFOUND) { - git_error_clear(); - error = 0; - } - - git_str_dispose(&env); - return error; -#endif -} - -static int git_sysdir_guess_template_dirs(git_str *out) -{ -#ifdef GIT_WIN32 - return git_win32__find_system_dirs(out, "share/git-core/templates"); -#else - return git_str_sets(out, "/usr/share/git-core/templates"); -#endif -} - -struct git_sysdir__dir { - git_str buf; - int (*guess)(git_str *out); -}; - -static struct git_sysdir__dir git_sysdir__dirs[] = { - { GIT_STR_INIT, git_sysdir_guess_system_dirs }, - { GIT_STR_INIT, git_sysdir_guess_global_dirs }, - { GIT_STR_INIT, git_sysdir_guess_xdg_dirs }, - { GIT_STR_INIT, git_sysdir_guess_programdata_dirs }, - { GIT_STR_INIT, git_sysdir_guess_template_dirs }, -}; - -static void git_sysdir_global_shutdown(void) -{ - size_t i; - - for (i = 0; i < ARRAY_SIZE(git_sysdir__dirs); ++i) - git_str_dispose(&git_sysdir__dirs[i].buf); -} - -int git_sysdir_global_init(void) -{ - size_t i; - int error = 0; - - for (i = 0; !error && i < ARRAY_SIZE(git_sysdir__dirs); i++) - error = git_sysdir__dirs[i].guess(&git_sysdir__dirs[i].buf); - - if (error) - return error; - - return git_runtime_shutdown_register(git_sysdir_global_shutdown); -} - -int git_sysdir_reset(void) -{ - size_t i; - int error = 0; - - for (i = 0; !error && i < ARRAY_SIZE(git_sysdir__dirs); ++i) { - git_str_dispose(&git_sysdir__dirs[i].buf); - error = git_sysdir__dirs[i].guess(&git_sysdir__dirs[i].buf); - } - - return error; -} - -static int git_sysdir_check_selector(git_sysdir_t which) -{ - if (which < ARRAY_SIZE(git_sysdir__dirs)) - return 0; - - git_error_set(GIT_ERROR_INVALID, "config directory selector out of range"); - return -1; -} - - -int git_sysdir_get(const git_str **out, git_sysdir_t which) -{ - GIT_ASSERT_ARG(out); - - *out = NULL; - - GIT_ERROR_CHECK_ERROR(git_sysdir_check_selector(which)); - - *out = &git_sysdir__dirs[which].buf; - return 0; -} - -#define PATH_MAGIC "$PATH" - -int git_sysdir_set(git_sysdir_t which, const char *search_path) -{ - const char *expand_path = NULL; - git_str merge = GIT_STR_INIT; - - GIT_ERROR_CHECK_ERROR(git_sysdir_check_selector(which)); - - if (search_path != NULL) - expand_path = strstr(search_path, PATH_MAGIC); - - /* reset the default if this path has been cleared */ - if (!search_path) - git_sysdir__dirs[which].guess(&git_sysdir__dirs[which].buf); - - /* if $PATH is not referenced, then just set the path */ - if (!expand_path) { - if (search_path) - git_str_sets(&git_sysdir__dirs[which].buf, search_path); - - goto done; - } - - /* otherwise set to join(before $PATH, old value, after $PATH) */ - if (expand_path > search_path) - git_str_set(&merge, search_path, expand_path - search_path); - - if (git_str_len(&git_sysdir__dirs[which].buf)) - git_str_join(&merge, GIT_PATH_LIST_SEPARATOR, - merge.ptr, git_sysdir__dirs[which].buf.ptr); - - expand_path += strlen(PATH_MAGIC); - if (*expand_path) - git_str_join(&merge, GIT_PATH_LIST_SEPARATOR, merge.ptr, expand_path); - - git_str_swap(&git_sysdir__dirs[which].buf, &merge); - git_str_dispose(&merge); - -done: - if (git_str_oom(&git_sysdir__dirs[which].buf)) - return -1; - - return 0; -} - -static int git_sysdir_find_in_dirlist( - git_str *path, - const char *name, - git_sysdir_t which, - const char *label) -{ - size_t len; - const char *scan, *next = NULL; - const git_str *syspath; - - GIT_ERROR_CHECK_ERROR(git_sysdir_get(&syspath, which)); - if (!syspath || !git_str_len(syspath)) - goto done; - - for (scan = git_str_cstr(syspath); scan; scan = next) { - /* find unescaped separator or end of string */ - for (next = scan; *next; ++next) { - if (*next == GIT_PATH_LIST_SEPARATOR && - (next <= scan || next[-1] != '\\')) - break; - } - - len = (size_t)(next - scan); - next = (*next ? next + 1 : NULL); - if (!len) - continue; - - GIT_ERROR_CHECK_ERROR(git_str_set(path, scan, len)); - if (name) - GIT_ERROR_CHECK_ERROR(git_str_joinpath(path, path->ptr, name)); - - if (git_fs_path_exists(path->ptr)) - return 0; - } - -done: - if (name) - git_error_set(GIT_ERROR_OS, "the %s file '%s' doesn't exist", label, name); - else - git_error_set(GIT_ERROR_OS, "the %s directory doesn't exist", label); - git_str_dispose(path); - return GIT_ENOTFOUND; -} - -int git_sysdir_find_system_file(git_str *path, const char *filename) -{ - return git_sysdir_find_in_dirlist( - path, filename, GIT_SYSDIR_SYSTEM, "system"); -} - -int git_sysdir_find_global_file(git_str *path, const char *filename) -{ - return git_sysdir_find_in_dirlist( - path, filename, GIT_SYSDIR_GLOBAL, "global"); -} - -int git_sysdir_find_xdg_file(git_str *path, const char *filename) -{ - return git_sysdir_find_in_dirlist( - path, filename, GIT_SYSDIR_XDG, "global/xdg"); -} - -int git_sysdir_find_programdata_file(git_str *path, const char *filename) -{ - return git_sysdir_find_in_dirlist( - path, filename, GIT_SYSDIR_PROGRAMDATA, "ProgramData"); -} - -int git_sysdir_find_template_dir(git_str *path) -{ - return git_sysdir_find_in_dirlist( - path, NULL, GIT_SYSDIR_TEMPLATE, "template"); -} - -int git_sysdir_expand_global_file(git_str *path, const char *filename) -{ - int error; - - if ((error = git_sysdir_find_global_file(path, NULL)) == 0) { - if (filename) - error = git_str_joinpath(path, path->ptr, filename); - } - - return error; -} diff --git a/vendor/libgit2/src/sysdir.h b/vendor/libgit2/src/sysdir.h deleted file mode 100644 index 568f2794..00000000 --- a/vendor/libgit2/src/sysdir.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_sysdir_h__ -#define INCLUDE_sysdir_h__ - -#include "common.h" - -#include "posix.h" -#include "str.h" - -/** - * Find a "global" file (i.e. one in a user's home directory). - * - * @param path buffer to write the full path into - * @param filename name of file to find in the home directory - * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error - */ -extern int git_sysdir_find_global_file(git_str *path, const char *filename); - -/** - * Find an "XDG" file (i.e. one in user's XDG config path). - * - * @param path buffer to write the full path into - * @param filename name of file to find in the home directory - * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error - */ -extern int git_sysdir_find_xdg_file(git_str *path, const char *filename); - -/** - * Find a "system" file (i.e. one shared for all users of the system). - * - * @param path buffer to write the full path into - * @param filename name of file to find in the home directory - * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error - */ -extern int git_sysdir_find_system_file(git_str *path, const char *filename); - -/** - * Find a "ProgramData" file (i.e. one in %PROGRAMDATA%) - * - * @param path buffer to write the full path into - * @param filename name of file to find in the ProgramData directory - * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error - */ -extern int git_sysdir_find_programdata_file(git_str *path, const char *filename); - -/** - * Find template directory. - * - * @param path buffer to write the full path into - * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error - */ -extern int git_sysdir_find_template_dir(git_str *path); - -/** - * Expand the name of a "global" file (i.e. one in a user's home - * directory). Unlike `find_global_file` (above), this makes no - * attempt to check for the existence of the file, and is useful if - * you want the full path regardless of existence. - * - * @param path buffer to write the full path into - * @param filename name of file in the home directory - * @return 0 on success or -1 on error - */ -extern int git_sysdir_expand_global_file(git_str *path, const char *filename); - -typedef enum { - GIT_SYSDIR_SYSTEM = 0, - GIT_SYSDIR_GLOBAL = 1, - GIT_SYSDIR_XDG = 2, - GIT_SYSDIR_PROGRAMDATA = 3, - GIT_SYSDIR_TEMPLATE = 4, - GIT_SYSDIR__MAX = 5 -} git_sysdir_t; - -/** - * Configures global data for configuration file search paths. - * - * @return 0 on success, <0 on failure - */ -extern int git_sysdir_global_init(void); - -/** - * Get the search path for global/system/xdg files - * - * @param out pointer to git_str containing search path - * @param which which list of paths to return - * @return 0 on success, <0 on failure - */ -extern int git_sysdir_get(const git_str **out, git_sysdir_t which); - -/** - * Set search paths for global/system/xdg files - * - * The first occurrence of the magic string "$PATH" in the new value will - * be replaced with the old value of the search path. - * - * @param which Which search path to modify - * @param paths New search path (separated by GIT_PATH_LIST_SEPARATOR) - * @return 0 on success, <0 on failure (allocation error) - */ -extern int git_sysdir_set(git_sysdir_t which, const char *paths); - -/** - * Reset search paths for global/system/xdg files. - */ -extern int git_sysdir_reset(void); - -#endif diff --git a/vendor/libgit2/src/thread.h b/vendor/libgit2/src/thread.h deleted file mode 100644 index 4bbac9fd..00000000 --- a/vendor/libgit2/src/thread.h +++ /dev/null @@ -1,479 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_thread_h__ -#define INCLUDE_thread_h__ - -#if defined(GIT_THREADS) - -#if defined(__clang__) - -# if (__clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 1)) -# error Atomic primitives do not exist on this version of clang; configure libgit2 with -DUSE_THREADS=OFF -# else -# define GIT_BUILTIN_ATOMIC -# endif - -#elif defined(__GNUC__) - -# if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1)) -# error Atomic primitives do not exist on this version of gcc; configure libgit2 with -DUSE_THREADS=OFF -# elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) -# define GIT_BUILTIN_ATOMIC -# else -# define GIT_BUILTIN_SYNC -# endif - -#endif - -#endif /* GIT_THREADS */ - -/* Common operations even if threading has been disabled */ -typedef struct { -#if defined(GIT_WIN32) - volatile long val; -#else - volatile int val; -#endif -} git_atomic32; - -#ifdef GIT_ARCH_64 - -typedef struct { -#if defined(GIT_WIN32) - volatile __int64 val; -#else - volatile int64_t val; -#endif -} git_atomic64; - -typedef git_atomic64 git_atomic_ssize; - -#define git_atomic_ssize_set git_atomic64_set -#define git_atomic_ssize_add git_atomic64_add -#define git_atomic_ssize_get git_atomic64_get - -#else - -typedef git_atomic32 git_atomic_ssize; - -#define git_atomic_ssize_set git_atomic32_set -#define git_atomic_ssize_add git_atomic32_add -#define git_atomic_ssize_get git_atomic32_get - -#endif - -#ifdef GIT_THREADS - -#ifdef GIT_WIN32 -# include "win32/thread.h" -#else -# include "unix/pthread.h" -#endif - -/* - * Atomically sets the contents of *a to be val. - */ -GIT_INLINE(void) git_atomic32_set(git_atomic32 *a, int val) -{ -#if defined(GIT_WIN32) - InterlockedExchange(&a->val, (LONG)val); -#elif defined(GIT_BUILTIN_ATOMIC) - __atomic_store_n(&a->val, val, __ATOMIC_SEQ_CST); -#elif defined(GIT_BUILTIN_SYNC) - __sync_lock_test_and_set(&a->val, val); -#else -# error "Unsupported architecture for atomic operations" -#endif -} - -/* - * Atomically increments the contents of *a by 1, and stores the result back into *a. - * @return the result of the operation. - */ -GIT_INLINE(int) git_atomic32_inc(git_atomic32 *a) -{ -#if defined(GIT_WIN32) - return InterlockedIncrement(&a->val); -#elif defined(GIT_BUILTIN_ATOMIC) - return __atomic_add_fetch(&a->val, 1, __ATOMIC_SEQ_CST); -#elif defined(GIT_BUILTIN_SYNC) - return __sync_add_and_fetch(&a->val, 1); -#else -# error "Unsupported architecture for atomic operations" -#endif -} - -/* - * Atomically adds the contents of *a and addend, and stores the result back into *a. - * @return the result of the operation. - */ -GIT_INLINE(int) git_atomic32_add(git_atomic32 *a, int32_t addend) -{ -#if defined(GIT_WIN32) - return InterlockedAdd(&a->val, addend); -#elif defined(GIT_BUILTIN_ATOMIC) - return __atomic_add_fetch(&a->val, addend, __ATOMIC_SEQ_CST); -#elif defined(GIT_BUILTIN_SYNC) - return __sync_add_and_fetch(&a->val, addend); -#else -# error "Unsupported architecture for atomic operations" -#endif -} - -/* - * Atomically decrements the contents of *a by 1, and stores the result back into *a. - * @return the result of the operation. - */ -GIT_INLINE(int) git_atomic32_dec(git_atomic32 *a) -{ -#if defined(GIT_WIN32) - return InterlockedDecrement(&a->val); -#elif defined(GIT_BUILTIN_ATOMIC) - return __atomic_sub_fetch(&a->val, 1, __ATOMIC_SEQ_CST); -#elif defined(GIT_BUILTIN_SYNC) - return __sync_sub_and_fetch(&a->val, 1); -#else -# error "Unsupported architecture for atomic operations" -#endif -} - -/* - * Atomically gets the contents of *a. - * @return the contents of *a. - */ -GIT_INLINE(int) git_atomic32_get(git_atomic32 *a) -{ -#if defined(GIT_WIN32) - return (int)InterlockedCompareExchange(&a->val, 0, 0); -#elif defined(GIT_BUILTIN_ATOMIC) - return __atomic_load_n(&a->val, __ATOMIC_SEQ_CST); -#elif defined(GIT_BUILTIN_SYNC) - return __sync_val_compare_and_swap(&a->val, 0, 0); -#else -# error "Unsupported architecture for atomic operations" -#endif -} - -GIT_INLINE(void *) git_atomic__compare_and_swap( - void * volatile *ptr, void *oldval, void *newval) -{ -#if defined(GIT_WIN32) - return InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval); -#elif defined(GIT_BUILTIN_ATOMIC) - void *foundval = oldval; - __atomic_compare_exchange(ptr, &foundval, &newval, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); - return foundval; -#elif defined(GIT_BUILTIN_SYNC) - return __sync_val_compare_and_swap(ptr, oldval, newval); -#else -# error "Unsupported architecture for atomic operations" -#endif -} - -GIT_INLINE(volatile void *) git_atomic__swap( - void * volatile *ptr, void *newval) -{ -#if defined(GIT_WIN32) - return InterlockedExchangePointer(ptr, newval); -#elif defined(GIT_BUILTIN_ATOMIC) - void * foundval = NULL; - __atomic_exchange(ptr, &newval, &foundval, __ATOMIC_SEQ_CST); - return foundval; -#elif defined(GIT_BUILTIN_SYNC) - return (volatile void *)__sync_lock_test_and_set(ptr, newval); -#else -# error "Unsupported architecture for atomic operations" -#endif -} - -GIT_INLINE(volatile void *) git_atomic__load(void * volatile *ptr) -{ -#if defined(GIT_WIN32) - void *newval = NULL, *oldval = NULL; - return (volatile void *)InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval); -#elif defined(GIT_BUILTIN_ATOMIC) - return (volatile void *)__atomic_load_n(ptr, __ATOMIC_SEQ_CST); -#elif defined(GIT_BUILTIN_SYNC) - return (volatile void *)__sync_val_compare_and_swap(ptr, 0, 0); -#else -# error "Unsupported architecture for atomic operations" -#endif -} - -#ifdef GIT_ARCH_64 - -/* - * Atomically adds the contents of *a and addend, and stores the result back into *a. - * @return the result of the operation. - */ -GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend) -{ -#if defined(GIT_WIN32) - return InterlockedAdd64(&a->val, addend); -#elif defined(GIT_BUILTIN_ATOMIC) - return __atomic_add_fetch(&a->val, addend, __ATOMIC_SEQ_CST); -#elif defined(GIT_BUILTIN_SYNC) - return __sync_add_and_fetch(&a->val, addend); -#else -# error "Unsupported architecture for atomic operations" -#endif -} - -/* - * Atomically sets the contents of *a to be val. - */ -GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val) -{ -#if defined(GIT_WIN32) - InterlockedExchange64(&a->val, val); -#elif defined(GIT_BUILTIN_ATOMIC) - __atomic_store_n(&a->val, val, __ATOMIC_SEQ_CST); -#elif defined(GIT_BUILTIN_SYNC) - __sync_lock_test_and_set(&a->val, val); -#else -# error "Unsupported architecture for atomic operations" -#endif -} - -/* - * Atomically gets the contents of *a. - * @return the contents of *a. - */ -GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a) -{ -#if defined(GIT_WIN32) - return (int64_t)InterlockedCompareExchange64(&a->val, 0, 0); -#elif defined(GIT_BUILTIN_ATOMIC) - return __atomic_load_n(&a->val, __ATOMIC_SEQ_CST); -#elif defined(GIT_BUILTIN_SYNC) - return __sync_val_compare_and_swap(&a->val, 0, 0); -#else -# error "Unsupported architecture for atomic operations" -#endif -} - -#endif - -#else - -#define git_threads_global_init git__noop - -#define git_thread unsigned int -#define git_thread_create(thread, start_routine, arg) git__noop() -#define git_thread_join(id, status) git__noop() - -/* Pthreads Mutex */ -#define git_mutex unsigned int -#define git_mutex_init(a) git__noop() -#define git_mutex_init(a) git__noop() -#define git_mutex_lock(a) git__noop() -#define git_mutex_unlock(a) git__noop() -#define git_mutex_free(a) git__noop() - -/* Pthreads condition vars */ -#define git_cond unsigned int -#define git_cond_init(c) git__noop() -#define git_cond_free(c) git__noop() -#define git_cond_wait(c, l) git__noop() -#define git_cond_signal(c) git__noop() -#define git_cond_broadcast(c) git__noop() - -/* Pthreads rwlock */ -#define git_rwlock unsigned int -#define git_rwlock_init(a) git__noop() -#define git_rwlock_rdlock(a) git__noop() -#define git_rwlock_rdunlock(a) git__noop() -#define git_rwlock_wrlock(a) git__noop() -#define git_rwlock_wrunlock(a) git__noop() -#define git_rwlock_free(a) git__noop() -#define GIT_RWLOCK_STATIC_INIT 0 - - -GIT_INLINE(void) git_atomic32_set(git_atomic32 *a, int val) -{ - a->val = val; -} - -GIT_INLINE(int) git_atomic32_inc(git_atomic32 *a) -{ - return ++a->val; -} - -GIT_INLINE(int) git_atomic32_add(git_atomic32 *a, int32_t addend) -{ - a->val += addend; - return a->val; -} - -GIT_INLINE(int) git_atomic32_dec(git_atomic32 *a) -{ - return --a->val; -} - -GIT_INLINE(int) git_atomic32_get(git_atomic32 *a) -{ - return (int)a->val; -} - -GIT_INLINE(void *) git_atomic__compare_and_swap( - void * volatile *ptr, void *oldval, void *newval) -{ - void *foundval = *ptr; - if (foundval == oldval) - *ptr = newval; - return foundval; -} - -GIT_INLINE(volatile void *) git_atomic__swap( - void * volatile *ptr, void *newval) -{ - volatile void *old = *ptr; - *ptr = newval; - return old; -} - -GIT_INLINE(volatile void *) git_atomic__load(void * volatile *ptr) -{ - return *ptr; -} - -#ifdef GIT_ARCH_64 - -GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend) -{ - a->val += addend; - return a->val; -} - -GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val) -{ - a->val = val; -} - -GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a) -{ - return (int64_t)a->val; -} - -#endif - -#endif - -/* - * Atomically replace the contents of *ptr (if they are equal to oldval) with - * newval. ptr must point to a pointer or a value that is the same size as a - * pointer. This is semantically compatible with: - * - * #define git_atomic_compare_and_swap(ptr, oldval, newval) \ - * ({ \ - * void *foundval = *ptr; \ - * if (foundval == oldval) \ - * *ptr = newval; \ - * foundval; \ - * }) - * - * @return the original contents of *ptr. - */ -#define git_atomic_compare_and_swap(ptr, oldval, newval) \ - git_atomic__compare_and_swap((void * volatile *)ptr, oldval, newval) - -/* - * Atomically replace the contents of v with newval. v must be the same size as - * a pointer. This is semantically compatible with: - * - * #define git_atomic_swap(v, newval) \ - * ({ \ - * volatile void *old = v; \ - * v = newval; \ - * old; \ - * }) - * - * @return the original contents of v. - */ -#define git_atomic_swap(v, newval) \ - (void *)git_atomic__swap((void * volatile *)&(v), newval) - -/* - * Atomically reads the contents of v. v must be the same size as a pointer. - * This is semantically compatible with: - * - * #define git_atomic_load(v) v - * - * @return the contents of v. - */ -#define git_atomic_load(v) \ - (void *)git_atomic__load((void * volatile *)&(v)) - -#if defined(GIT_THREADS) - -# if defined(GIT_WIN32) -# define GIT_MEMORY_BARRIER MemoryBarrier() -# elif defined(GIT_BUILTIN_ATOMIC) -# define GIT_MEMORY_BARRIER __atomic_thread_fence(__ATOMIC_SEQ_CST) -# elif defined(GIT_BUILTIN_SYNC) -# define GIT_MEMORY_BARRIER __sync_synchronize() -# endif - -#else - -# define GIT_MEMORY_BARRIER /* noop */ - -#endif - -/* Thread-local data */ - -#if !defined(GIT_THREADS) -# define git_tlsdata_key int -#elif defined(GIT_WIN32) -# define git_tlsdata_key DWORD -#elif defined(_POSIX_THREADS) -# define git_tlsdata_key pthread_key_t -#else -# error unknown threading model -#endif - -/** - * Create a thread-local data key. The destroy function will be - * called upon thread exit. On some platforms, it may be called - * when all threads have deleted their keys. - * - * Note that the tlsdata functions do not set an error message on - * failure; this is because the error handling in libgit2 is itself - * handled by thread-local data storage. - * - * @param key the tlsdata key - * @param destroy_fn function pointer called upon thread exit - * @return 0 on success, non-zero on failure - */ -int git_tlsdata_init(git_tlsdata_key *key, void (GIT_SYSTEM_CALL *destroy_fn)(void *)); - -/** - * Set a the thread-local value for the given key. - * - * @param key the tlsdata key to store data on - * @param value the pointer to store - * @return 0 on success, non-zero on failure - */ -int git_tlsdata_set(git_tlsdata_key key, void *value); - -/** - * Get the thread-local value for the given key. - * - * @param key the tlsdata key to retrieve the value of - * @return the pointer stored with git_tlsdata_set - */ -void *git_tlsdata_get(git_tlsdata_key key); - -/** - * Delete the given thread-local key. - * - * @param key the tlsdata key to dispose - * @return 0 on success, non-zero on failure - */ -int git_tlsdata_dispose(git_tlsdata_key key); - -#endif diff --git a/vendor/libgit2/src/threadstate.c b/vendor/libgit2/src/threadstate.c deleted file mode 100644 index 9e3ef581..00000000 --- a/vendor/libgit2/src/threadstate.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "threadstate.h" -#include "runtime.h" - -/** - * Handle the thread-local state - * - * `git_threadstate_global_init` will be called as part - * of `git_libgit2_init` (which itself must be called - * before calling any other function in the library). - * - * This function allocates a TLS index to store the per- - * thread state. - * - * Any internal method that requires thread-local state - * will then call `git_threadstate_get()` which returns a - * pointer to the thread-local state structure; this - * structure is lazily allocated on each thread. - * - * This mechanism will register a shutdown handler - * (`git_threadstate_global_shutdown`) which will free the - * TLS index. This shutdown handler will be called by - * `git_libgit2_shutdown`. - */ - -static git_tlsdata_key tls_key; - -static void threadstate_dispose(git_threadstate *threadstate) -{ - if (!threadstate) - return; - - if (threadstate->error_t.message != git_str__initstr) - git__free(threadstate->error_t.message); - threadstate->error_t.message = NULL; -} - -static void GIT_SYSTEM_CALL threadstate_free(void *threadstate) -{ - threadstate_dispose(threadstate); - git__free(threadstate); -} - -static void git_threadstate_global_shutdown(void) -{ - git_threadstate *threadstate; - - threadstate = git_tlsdata_get(tls_key); - git_tlsdata_set(tls_key, NULL); - - threadstate_dispose(threadstate); - git__free(threadstate); - - git_tlsdata_dispose(tls_key); -} - -int git_threadstate_global_init(void) -{ - if (git_tlsdata_init(&tls_key, &threadstate_free) != 0) - return -1; - - return git_runtime_shutdown_register(git_threadstate_global_shutdown); -} - -git_threadstate *git_threadstate_get(void) -{ - git_threadstate *threadstate; - - if ((threadstate = git_tlsdata_get(tls_key)) != NULL) - return threadstate; - - if ((threadstate = git__calloc(1, sizeof(git_threadstate))) == NULL || - git_str_init(&threadstate->error_buf, 0) < 0) - return NULL; - - git_tlsdata_set(tls_key, threadstate); - return threadstate; -} diff --git a/vendor/libgit2/src/threadstate.h b/vendor/libgit2/src/threadstate.h deleted file mode 100644 index c10f26b5..00000000 --- a/vendor/libgit2/src/threadstate.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_threadstate_h__ -#define INCLUDE_threadstate_h__ - -#include "common.h" - -typedef struct { - git_error *last_error; - git_error error_t; - git_str error_buf; - char oid_fmt[GIT_OID_HEXSZ+1]; -} git_threadstate; - -extern int git_threadstate_global_init(void); -extern git_threadstate *git_threadstate_get(void); - -#define GIT_THREADSTATE (git_threadstate_get()) - -#endif diff --git a/vendor/libgit2/src/trailer.c b/vendor/libgit2/src/trailer.c deleted file mode 100644 index 4761c992..00000000 --- a/vendor/libgit2/src/trailer.c +++ /dev/null @@ -1,430 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#include "array.h" -#include "common.h" -#include "git2/message.h" - -#include -#include -#include - -#define COMMENT_LINE_CHAR '#' -#define TRAILER_SEPARATORS ":" - -static const char *const git_generated_prefixes[] = { - "Signed-off-by: ", - "(cherry picked from commit ", - NULL -}; - -static int is_blank_line(const char *str) -{ - const char *s = str; - while (*s && *s != '\n' && isspace(*s)) - s++; - return !*s || *s == '\n'; -} - -static const char *next_line(const char *str) -{ - const char *nl = strchr(str, '\n'); - - if (nl) { - return nl + 1; - } else { - /* return pointer to the NUL terminator: */ - return str + strlen(str); - } -} - -/* - * Return the position of the start of the last line. If len is 0, return 0. - */ -static bool last_line(size_t *out, const char *buf, size_t len) -{ - size_t i; - - *out = 0; - - if (len == 0) - return false; - if (len == 1) - return true; - - /* - * Skip the last character (in addition to the null terminator), - * because if the last character is a newline, it is considered as part - * of the last line anyway. - */ - i = len - 2; - - for (; i > 0; i--) { - if (buf[i] == '\n') { - *out = i + 1; - return true; - } - } - return true; -} - -/* - * If the given line is of the form - * "..." or "...", sets out - * to the location of the separator and returns true. Otherwise, returns - * false. The optional whitespace is allowed there primarily to allow things - * like "Bug #43" where is "Bug" and is "#". - * - * The separator-starts-line case (in which this function returns true and - * sets out to 0) is distinguished from the non-well-formed-line case (in - * which this function returns false) because some callers of this function - * need such a distinction. - */ -static bool find_separator(size_t *out, const char *line, const char *separators) -{ - int whitespace_found = 0; - const char *c; - for (c = line; *c; c++) { - if (strchr(separators, *c)) { - *out = c - line; - return true; - } - - if (!whitespace_found && (isalnum(*c) || *c == '-')) - continue; - if (c != line && (*c == ' ' || *c == '\t')) { - whitespace_found = 1; - continue; - } - break; - } - return false; -} - -/* - * Inspect the given string and determine the true "end" of the log message, in - * order to find where to put a new Signed-off-by: line. Ignored are - * trailing comment lines and blank lines. To support "git commit -s - * --amend" on an existing commit, we also ignore "Conflicts:". To - * support "git commit -v", we truncate at cut lines. - * - * Returns the number of bytes from the tail to ignore, to be fed as - * the second parameter to append_signoff(). - */ -static size_t ignore_non_trailer(const char *buf, size_t len) -{ - size_t boc = 0, bol = 0; - int in_old_conflicts_block = 0; - size_t cutoff = len; - - while (bol < cutoff) { - const char *next_line = memchr(buf + bol, '\n', len - bol); - - if (!next_line) - next_line = buf + len; - else - next_line++; - - if (buf[bol] == COMMENT_LINE_CHAR || buf[bol] == '\n') { - /* is this the first of the run of comments? */ - if (!boc) - boc = bol; - /* otherwise, it is just continuing */ - } else if (git__prefixcmp(buf + bol, "Conflicts:\n") == 0) { - in_old_conflicts_block = 1; - if (!boc) - boc = bol; - } else if (in_old_conflicts_block && buf[bol] == '\t') { - ; /* a pathname in the conflicts block */ - } else if (boc) { - /* the previous was not trailing comment */ - boc = 0; - in_old_conflicts_block = 0; - } - bol = next_line - buf; - } - return boc ? len - boc : len - cutoff; -} - -/* - * Return the position of the start of the patch or the length of str if there - * is no patch in the message. - */ -static size_t find_patch_start(const char *str) -{ - const char *s; - - for (s = str; *s; s = next_line(s)) { - if (git__prefixcmp(s, "---") == 0) - return s - str; - } - - return s - str; -} - -/* - * Return the position of the first trailer line or len if there are no - * trailers. - */ -static size_t find_trailer_start(const char *buf, size_t len) -{ - const char *s; - size_t end_of_title, l; - int only_spaces = 1; - int recognized_prefix = 0, trailer_lines = 0, non_trailer_lines = 0; - /* - * Number of possible continuation lines encountered. This will be - * reset to 0 if we encounter a trailer (since those lines are to be - * considered continuations of that trailer), and added to - * non_trailer_lines if we encounter a non-trailer (since those lines - * are to be considered non-trailers). - */ - int possible_continuation_lines = 0; - - /* The first paragraph is the title and cannot be trailers */ - for (s = buf; s < buf + len; s = next_line(s)) { - if (s[0] == COMMENT_LINE_CHAR) - continue; - if (is_blank_line(s)) - break; - } - end_of_title = s - buf; - - /* - * Get the start of the trailers by looking starting from the end for a - * blank line before a set of non-blank lines that (i) are all - * trailers, or (ii) contains at least one Git-generated trailer and - * consists of at least 25% trailers. - */ - l = len; - while (last_line(&l, buf, l) && l >= end_of_title) { - const char *bol = buf + l; - const char *const *p; - size_t separator_pos = 0; - - if (bol[0] == COMMENT_LINE_CHAR) { - non_trailer_lines += possible_continuation_lines; - possible_continuation_lines = 0; - continue; - } - if (is_blank_line(bol)) { - if (only_spaces) - continue; - non_trailer_lines += possible_continuation_lines; - if (recognized_prefix && - trailer_lines * 3 >= non_trailer_lines) - return next_line(bol) - buf; - else if (trailer_lines && !non_trailer_lines) - return next_line(bol) - buf; - return len; - } - only_spaces = 0; - - for (p = git_generated_prefixes; *p; p++) { - if (git__prefixcmp(bol, *p) == 0) { - trailer_lines++; - possible_continuation_lines = 0; - recognized_prefix = 1; - goto continue_outer_loop; - } - } - - find_separator(&separator_pos, bol, TRAILER_SEPARATORS); - if (separator_pos >= 1 && !isspace(bol[0])) { - trailer_lines++; - possible_continuation_lines = 0; - if (recognized_prefix) - continue; - } else if (isspace(bol[0])) - possible_continuation_lines++; - else { - non_trailer_lines++; - non_trailer_lines += possible_continuation_lines; - possible_continuation_lines = 0; - } -continue_outer_loop: - ; - } - - return len; -} - -/* Return the position of the end of the trailers. */ -static size_t find_trailer_end(const char *buf, size_t len) -{ - return len - ignore_non_trailer(buf, len); -} - -static char *extract_trailer_block(const char *message, size_t *len) -{ - size_t patch_start = find_patch_start(message); - size_t trailer_end = find_trailer_end(message, patch_start); - size_t trailer_start = find_trailer_start(message, trailer_end); - - size_t trailer_len = trailer_end - trailer_start; - - char *buffer = git__malloc(trailer_len + 1); - if (buffer == NULL) - return NULL; - - memcpy(buffer, message + trailer_start, trailer_len); - buffer[trailer_len] = 0; - - *len = trailer_len; - - return buffer; -} - -enum trailer_state { - S_START = 0, - S_KEY = 1, - S_KEY_WS = 2, - S_SEP_WS = 3, - S_VALUE = 4, - S_VALUE_NL = 5, - S_VALUE_END = 6, - S_IGNORE = 7 -}; - -#define NEXT(st) { state = (st); ptr++; continue; } -#define GOTO(st) { state = (st); continue; } - -typedef git_array_t(git_message_trailer) git_array_trailer_t; - -int git_message_trailers(git_message_trailer_array *trailer_arr, const char *message) -{ - enum trailer_state state = S_START; - int rc = 0; - char *ptr; - char *key = NULL; - char *value = NULL; - git_array_trailer_t arr = GIT_ARRAY_INIT; - - size_t trailer_len; - char *trailer = extract_trailer_block(message, &trailer_len); - if (trailer == NULL) - return -1; - - for (ptr = trailer;;) { - switch (state) { - case S_START: { - if (*ptr == 0) { - goto ret; - } - - key = ptr; - GOTO(S_KEY); - } - case S_KEY: { - if (*ptr == 0) { - goto ret; - } - - if (isalnum(*ptr) || *ptr == '-') { - /* legal key character */ - NEXT(S_KEY); - } - - if (*ptr == ' ' || *ptr == '\t') { - /* optional whitespace before separator */ - *ptr = 0; - NEXT(S_KEY_WS); - } - - if (strchr(TRAILER_SEPARATORS, *ptr)) { - *ptr = 0; - NEXT(S_SEP_WS); - } - - /* illegal character */ - GOTO(S_IGNORE); - } - case S_KEY_WS: { - if (*ptr == 0) { - goto ret; - } - - if (*ptr == ' ' || *ptr == '\t') { - NEXT(S_KEY_WS); - } - - if (strchr(TRAILER_SEPARATORS, *ptr)) { - NEXT(S_SEP_WS); - } - - /* illegal character */ - GOTO(S_IGNORE); - } - case S_SEP_WS: { - if (*ptr == 0) { - goto ret; - } - - if (*ptr == ' ' || *ptr == '\t') { - NEXT(S_SEP_WS); - } - - value = ptr; - NEXT(S_VALUE); - } - case S_VALUE: { - if (*ptr == 0) { - GOTO(S_VALUE_END); - } - - if (*ptr == '\n') { - NEXT(S_VALUE_NL); - } - - NEXT(S_VALUE); - } - case S_VALUE_NL: { - if (*ptr == ' ') { - /* continuation; */ - NEXT(S_VALUE); - } - - ptr[-1] = 0; - GOTO(S_VALUE_END); - } - case S_VALUE_END: { - git_message_trailer *t = git_array_alloc(arr); - - t->key = key; - t->value = value; - - key = NULL; - value = NULL; - - GOTO(S_START); - } - case S_IGNORE: { - if (*ptr == 0) { - goto ret; - } - - if (*ptr == '\n') { - NEXT(S_START); - } - - NEXT(S_IGNORE); - } - } - } - -ret: - trailer_arr->_trailer_block = trailer; - trailer_arr->trailers = arr.ptr; - trailer_arr->count = arr.size; - - return rc; -} - -void git_message_trailer_array_free(git_message_trailer_array *arr) -{ - git__free(arr->_trailer_block); - git__free(arr->trailers); -} diff --git a/vendor/libgit2/src/transports/auth_negotiate.c b/vendor/libgit2/src/transports/auth_negotiate.c deleted file mode 100644 index 6380504b..00000000 --- a/vendor/libgit2/src/transports/auth_negotiate.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "auth_negotiate.h" - -#if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK) - -#include "git2.h" -#include "auth.h" -#include "git2/sys/credential.h" - -#ifdef GIT_GSSFRAMEWORK -#import -#elif defined(GIT_GSSAPI) -#include -#include -#endif - -static gss_OID_desc negotiate_oid_spnego = - { 6, (void *) "\x2b\x06\x01\x05\x05\x02" }; -static gss_OID_desc negotiate_oid_krb5 = - { 9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }; - -static gss_OID negotiate_oids[] = - { &negotiate_oid_spnego, &negotiate_oid_krb5, NULL }; - -typedef struct { - git_http_auth_context parent; - unsigned configured : 1, - complete : 1; - git_str target; - char *challenge; - gss_ctx_id_t gss_context; - gss_OID oid; -} http_auth_negotiate_context; - -static void negotiate_err_set( - OM_uint32 status_major, - OM_uint32 status_minor, - const char *message) -{ - gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER; - OM_uint32 status_display, context = 0; - - if (gss_display_status(&status_display, status_major, GSS_C_GSS_CODE, - GSS_C_NO_OID, &context, &buffer) == GSS_S_COMPLETE) { - git_error_set(GIT_ERROR_NET, "%s: %.*s (%d.%d)", - message, (int)buffer.length, (const char *)buffer.value, - status_major, status_minor); - gss_release_buffer(&status_minor, &buffer); - } else { - git_error_set(GIT_ERROR_NET, "%s: unknown negotiate error (%d.%d)", - message, status_major, status_minor); - } -} - -static int negotiate_set_challenge( - git_http_auth_context *c, - const char *challenge) -{ - http_auth_negotiate_context *ctx = (http_auth_negotiate_context *)c; - - GIT_ASSERT_ARG(ctx); - GIT_ASSERT_ARG(challenge); - GIT_ASSERT(ctx->configured); - - git__free(ctx->challenge); - - ctx->challenge = git__strdup(challenge); - GIT_ERROR_CHECK_ALLOC(ctx->challenge); - - return 0; -} - -static void negotiate_context_dispose(http_auth_negotiate_context *ctx) -{ - OM_uint32 status_minor; - - if (ctx->gss_context != GSS_C_NO_CONTEXT) { - gss_delete_sec_context( - &status_minor, &ctx->gss_context, GSS_C_NO_BUFFER); - ctx->gss_context = GSS_C_NO_CONTEXT; - } - - git_str_dispose(&ctx->target); - - git__free(ctx->challenge); - ctx->challenge = NULL; -} - -static int negotiate_next_token( - git_str *buf, - git_http_auth_context *c, - git_credential *cred) -{ - http_auth_negotiate_context *ctx = (http_auth_negotiate_context *)c; - OM_uint32 status_major, status_minor; - gss_buffer_desc target_buffer = GSS_C_EMPTY_BUFFER, - input_token = GSS_C_EMPTY_BUFFER, - output_token = GSS_C_EMPTY_BUFFER; - gss_buffer_t input_token_ptr = GSS_C_NO_BUFFER; - git_str input_buf = GIT_STR_INIT; - gss_name_t server = NULL; - gss_OID mech; - size_t challenge_len; - int error = 0; - - GIT_ASSERT_ARG(buf); - GIT_ASSERT_ARG(ctx); - GIT_ASSERT_ARG(cred); - - GIT_ASSERT(ctx->configured); - GIT_ASSERT(cred->credtype == GIT_CREDENTIAL_DEFAULT); - - if (ctx->complete) - return 0; - - target_buffer.value = (void *)ctx->target.ptr; - target_buffer.length = ctx->target.size; - - status_major = gss_import_name(&status_minor, &target_buffer, - GSS_C_NT_HOSTBASED_SERVICE, &server); - - if (GSS_ERROR(status_major)) { - negotiate_err_set(status_major, status_minor, - "could not parse principal"); - error = -1; - goto done; - } - - challenge_len = ctx->challenge ? strlen(ctx->challenge) : 0; - - if (challenge_len < 9 || memcmp(ctx->challenge, "Negotiate", 9) != 0) { - git_error_set(GIT_ERROR_NET, "server did not request negotiate"); - error = -1; - goto done; - } - - if (challenge_len > 9) { - if (git_str_decode_base64(&input_buf, - ctx->challenge + 10, challenge_len - 10) < 0) { - git_error_set(GIT_ERROR_NET, "invalid negotiate challenge from server"); - error = -1; - goto done; - } - - input_token.value = input_buf.ptr; - input_token.length = input_buf.size; - input_token_ptr = &input_token; - } else if (ctx->gss_context != GSS_C_NO_CONTEXT) { - negotiate_context_dispose(ctx); - } - - mech = &negotiate_oid_spnego; - - status_major = gss_init_sec_context( - &status_minor, - GSS_C_NO_CREDENTIAL, - &ctx->gss_context, - server, - mech, - GSS_C_DELEG_FLAG | GSS_C_MUTUAL_FLAG, - GSS_C_INDEFINITE, - GSS_C_NO_CHANNEL_BINDINGS, - input_token_ptr, - NULL, - &output_token, - NULL, - NULL); - - if (GSS_ERROR(status_major)) { - negotiate_err_set(status_major, status_minor, "negotiate failure"); - error = -1; - goto done; - } - - /* This message merely told us auth was complete; we do not respond. */ - if (status_major == GSS_S_COMPLETE) { - negotiate_context_dispose(ctx); - ctx->complete = 1; - goto done; - } - - if (output_token.length == 0) { - git_error_set(GIT_ERROR_NET, "GSSAPI did not return token"); - error = -1; - goto done; - } - - git_str_puts(buf, "Negotiate "); - git_str_encode_base64(buf, output_token.value, output_token.length); - - if (git_str_oom(buf)) - error = -1; - -done: - gss_release_name(&status_minor, &server); - gss_release_buffer(&status_minor, (gss_buffer_t) &output_token); - git_str_dispose(&input_buf); - return error; -} - -static int negotiate_is_complete(git_http_auth_context *c) -{ - http_auth_negotiate_context *ctx = (http_auth_negotiate_context *)c; - - GIT_ASSERT_ARG(ctx); - - return (ctx->complete == 1); -} - -static void negotiate_context_free(git_http_auth_context *c) -{ - http_auth_negotiate_context *ctx = (http_auth_negotiate_context *)c; - - negotiate_context_dispose(ctx); - - ctx->configured = 0; - ctx->complete = 0; - ctx->oid = NULL; - - git__free(ctx); -} - -static int negotiate_init_context( - http_auth_negotiate_context *ctx, - const git_net_url *url) -{ - OM_uint32 status_major, status_minor; - gss_OID item, *oid; - gss_OID_set mechanism_list; - size_t i; - - /* Query supported mechanisms looking for SPNEGO) */ - status_major = gss_indicate_mechs(&status_minor, &mechanism_list); - - if (GSS_ERROR(status_major)) { - negotiate_err_set(status_major, status_minor, - "could not query mechanisms"); - return -1; - } - - if (mechanism_list) { - for (oid = negotiate_oids; *oid; oid++) { - for (i = 0; i < mechanism_list->count; i++) { - item = &mechanism_list->elements[i]; - - if (item->length == (*oid)->length && - memcmp(item->elements, (*oid)->elements, item->length) == 0) { - ctx->oid = *oid; - break; - } - - } - - if (ctx->oid) - break; - } - } - - gss_release_oid_set(&status_minor, &mechanism_list); - - if (!ctx->oid) { - git_error_set(GIT_ERROR_NET, "negotiate authentication is not supported"); - return GIT_EAUTH; - } - - git_str_puts(&ctx->target, "HTTP@"); - git_str_puts(&ctx->target, url->host); - - if (git_str_oom(&ctx->target)) - return -1; - - ctx->gss_context = GSS_C_NO_CONTEXT; - ctx->configured = 1; - - return 0; -} - -int git_http_auth_negotiate( - git_http_auth_context **out, - const git_net_url *url) -{ - http_auth_negotiate_context *ctx; - - *out = NULL; - - ctx = git__calloc(1, sizeof(http_auth_negotiate_context)); - GIT_ERROR_CHECK_ALLOC(ctx); - - if (negotiate_init_context(ctx, url) < 0) { - git__free(ctx); - return -1; - } - - ctx->parent.type = GIT_HTTP_AUTH_NEGOTIATE; - ctx->parent.credtypes = GIT_CREDENTIAL_DEFAULT; - ctx->parent.connection_affinity = 1; - ctx->parent.set_challenge = negotiate_set_challenge; - ctx->parent.next_token = negotiate_next_token; - ctx->parent.is_complete = negotiate_is_complete; - ctx->parent.free = negotiate_context_free; - - *out = (git_http_auth_context *)ctx; - - return 0; -} - -#endif /* GIT_GSSAPI */ - diff --git a/vendor/libgit2/src/transports/auth_ntlm.c b/vendor/libgit2/src/transports/auth_ntlm.c deleted file mode 100644 index f49ce101..00000000 --- a/vendor/libgit2/src/transports/auth_ntlm.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "auth_ntlm.h" - -#include "common.h" -#include "str.h" -#include "auth.h" -#include "git2/sys/credential.h" - -#ifdef GIT_NTLM - -#include "ntlmclient.h" - -typedef struct { - git_http_auth_context parent; - ntlm_client *ntlm; - char *challenge; - bool complete; -} http_auth_ntlm_context; - -static int ntlm_set_challenge( - git_http_auth_context *c, - const char *challenge) -{ - http_auth_ntlm_context *ctx = (http_auth_ntlm_context *)c; - - GIT_ASSERT_ARG(ctx); - GIT_ASSERT_ARG(challenge); - - git__free(ctx->challenge); - - ctx->challenge = git__strdup(challenge); - GIT_ERROR_CHECK_ALLOC(ctx->challenge); - - return 0; -} - -static int ntlm_set_credentials(http_auth_ntlm_context *ctx, git_credential *_cred) -{ - git_credential_userpass_plaintext *cred; - const char *sep, *username; - char *domain = NULL, *domainuser = NULL; - int error = 0; - - GIT_ASSERT(_cred->credtype == GIT_CREDENTIAL_USERPASS_PLAINTEXT); - cred = (git_credential_userpass_plaintext *)_cred; - - if ((sep = strchr(cred->username, '\\')) != NULL) { - domain = git__strndup(cred->username, (sep - cred->username)); - GIT_ERROR_CHECK_ALLOC(domain); - - domainuser = git__strdup(sep + 1); - GIT_ERROR_CHECK_ALLOC(domainuser); - - username = domainuser; - } else { - username = cred->username; - } - - if (ntlm_client_set_credentials(ctx->ntlm, - username, domain, cred->password) < 0) { - git_error_set(GIT_ERROR_NET, "could not set credentials: %s", - ntlm_client_errmsg(ctx->ntlm)); - error = -1; - goto done; - } - -done: - git__free(domain); - git__free(domainuser); - return error; -} - -static int ntlm_next_token( - git_str *buf, - git_http_auth_context *c, - git_credential *cred) -{ - http_auth_ntlm_context *ctx = (http_auth_ntlm_context *)c; - git_str input_buf = GIT_STR_INIT; - const unsigned char *msg; - size_t challenge_len, msg_len; - int error = GIT_EAUTH; - - GIT_ASSERT_ARG(buf); - GIT_ASSERT_ARG(ctx); - - GIT_ASSERT(ctx->ntlm); - - challenge_len = ctx->challenge ? strlen(ctx->challenge) : 0; - - if (ctx->complete) - ntlm_client_reset(ctx->ntlm); - - /* - * Set us complete now since it's the default case; the one - * incomplete case (successfully created a client request) - * will explicitly set that it requires a second step. - */ - ctx->complete = true; - - if (cred && ntlm_set_credentials(ctx, cred) != 0) - goto done; - - if (challenge_len < 4) { - git_error_set(GIT_ERROR_NET, "no ntlm challenge sent from server"); - goto done; - } else if (challenge_len == 4) { - if (memcmp(ctx->challenge, "NTLM", 4) != 0) { - git_error_set(GIT_ERROR_NET, "server did not request NTLM"); - goto done; - } - - if (ntlm_client_negotiate(&msg, &msg_len, ctx->ntlm) != 0) { - git_error_set(GIT_ERROR_NET, "ntlm authentication failed: %s", - ntlm_client_errmsg(ctx->ntlm)); - goto done; - } - - ctx->complete = false; - } else { - if (memcmp(ctx->challenge, "NTLM ", 5) != 0) { - git_error_set(GIT_ERROR_NET, "challenge from server was not NTLM"); - goto done; - } - - if (git_str_decode_base64(&input_buf, - ctx->challenge + 5, challenge_len - 5) < 0) { - git_error_set(GIT_ERROR_NET, "invalid NTLM challenge from server"); - goto done; - } - - if (ntlm_client_set_challenge(ctx->ntlm, - (const unsigned char *)input_buf.ptr, input_buf.size) != 0) { - git_error_set(GIT_ERROR_NET, "ntlm challenge failed: %s", - ntlm_client_errmsg(ctx->ntlm)); - goto done; - } - - if (ntlm_client_response(&msg, &msg_len, ctx->ntlm) != 0) { - git_error_set(GIT_ERROR_NET, "ntlm authentication failed: %s", - ntlm_client_errmsg(ctx->ntlm)); - goto done; - } - } - - git_str_puts(buf, "NTLM "); - git_str_encode_base64(buf, (const char *)msg, msg_len); - - if (git_str_oom(buf)) - goto done; - - error = 0; - -done: - git_str_dispose(&input_buf); - return error; -} - -static int ntlm_is_complete(git_http_auth_context *c) -{ - http_auth_ntlm_context *ctx = (http_auth_ntlm_context *)c; - - GIT_ASSERT_ARG(ctx); - return (ctx->complete == true); -} - -static void ntlm_context_free(git_http_auth_context *c) -{ - http_auth_ntlm_context *ctx = (http_auth_ntlm_context *)c; - - ntlm_client_free(ctx->ntlm); - git__free(ctx->challenge); - git__free(ctx); -} - -static int ntlm_init_context( - http_auth_ntlm_context *ctx, - const git_net_url *url) -{ - GIT_UNUSED(url); - - if ((ctx->ntlm = ntlm_client_init(NTLM_CLIENT_DEFAULTS)) == NULL) { - git_error_set_oom(); - return -1; - } - - return 0; -} - -int git_http_auth_ntlm( - git_http_auth_context **out, - const git_net_url *url) -{ - http_auth_ntlm_context *ctx; - - GIT_UNUSED(url); - - *out = NULL; - - ctx = git__calloc(1, sizeof(http_auth_ntlm_context)); - GIT_ERROR_CHECK_ALLOC(ctx); - - if (ntlm_init_context(ctx, url) < 0) { - git__free(ctx); - return -1; - } - - ctx->parent.type = GIT_HTTP_AUTH_NTLM; - ctx->parent.credtypes = GIT_CREDENTIAL_USERPASS_PLAINTEXT; - ctx->parent.connection_affinity = 1; - ctx->parent.set_challenge = ntlm_set_challenge; - ctx->parent.next_token = ntlm_next_token; - ctx->parent.is_complete = ntlm_is_complete; - ctx->parent.free = ntlm_context_free; - - *out = (git_http_auth_context *)ctx; - - return 0; -} - -#endif /* GIT_NTLM */ diff --git a/vendor/libgit2/src/transports/http.c b/vendor/libgit2/src/transports/http.c deleted file mode 100644 index 7db5582c..00000000 --- a/vendor/libgit2/src/transports/http.c +++ /dev/null @@ -1,760 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "common.h" - -#ifndef GIT_WINHTTP - -#include "http_parser.h" -#include "net.h" -#include "netops.h" -#include "remote.h" -#include "smart.h" -#include "auth.h" -#include "http.h" -#include "auth_negotiate.h" -#include "auth_ntlm.h" -#include "trace.h" -#include "streams/tls.h" -#include "streams/socket.h" -#include "httpclient.h" -#include "git2/sys/credential.h" - -bool git_http__expect_continue = false; - -typedef enum { - HTTP_STATE_NONE = 0, - HTTP_STATE_SENDING_REQUEST, - HTTP_STATE_RECEIVING_RESPONSE, - HTTP_STATE_DONE -} http_state; - -typedef struct { - git_http_method method; - const char *url; - const char *request_type; - const char *response_type; - unsigned int initial : 1, - chunked : 1; -} http_service; - -typedef struct { - git_smart_subtransport_stream parent; - const http_service *service; - http_state state; - unsigned replay_count; -} http_stream; - -typedef struct { - git_net_url url; - - git_credential *cred; - unsigned auth_schemetypes; - unsigned url_cred_presented : 1; -} http_server; - -typedef struct { - git_smart_subtransport parent; - transport_smart *owner; - - http_server server; - http_server proxy; - - git_http_client *http_client; -} http_subtransport; - -static const http_service upload_pack_ls_service = { - GIT_HTTP_METHOD_GET, "/info/refs?service=git-upload-pack", - NULL, - "application/x-git-upload-pack-advertisement", - 1, - 0 -}; -static const http_service upload_pack_service = { - GIT_HTTP_METHOD_POST, "/git-upload-pack", - "application/x-git-upload-pack-request", - "application/x-git-upload-pack-result", - 0, - 0 -}; -static const http_service receive_pack_ls_service = { - GIT_HTTP_METHOD_GET, "/info/refs?service=git-receive-pack", - NULL, - "application/x-git-receive-pack-advertisement", - 1, - 0 -}; -static const http_service receive_pack_service = { - GIT_HTTP_METHOD_POST, "/git-receive-pack", - "application/x-git-receive-pack-request", - "application/x-git-receive-pack-result", - 0, - 1 -}; - -#define SERVER_TYPE_REMOTE "remote" -#define SERVER_TYPE_PROXY "proxy" - -#define OWNING_SUBTRANSPORT(s) ((http_subtransport *)(s)->parent.subtransport) - -static int apply_url_credentials( - git_credential **cred, - unsigned int allowed_types, - const char *username, - const char *password) -{ - GIT_ASSERT_ARG(username); - - if (!password) - password = ""; - - if (allowed_types & GIT_CREDENTIAL_USERPASS_PLAINTEXT) - return git_credential_userpass_plaintext_new(cred, username, password); - - if ((allowed_types & GIT_CREDENTIAL_DEFAULT) && *username == '\0' && *password == '\0') - return git_credential_default_new(cred); - - return GIT_PASSTHROUGH; -} - -GIT_INLINE(void) free_cred(git_credential **cred) -{ - if (*cred) { - git_credential_free(*cred); - (*cred) = NULL; - } -} - -static int handle_auth( - http_server *server, - const char *server_type, - const char *url, - unsigned int allowed_schemetypes, - unsigned int allowed_credtypes, - git_credential_acquire_cb callback, - void *callback_payload) -{ - int error = 1; - - if (server->cred) - free_cred(&server->cred); - - /* Start with URL-specified credentials, if there were any. */ - if ((allowed_credtypes & GIT_CREDENTIAL_USERPASS_PLAINTEXT) && - !server->url_cred_presented && - server->url.username) { - error = apply_url_credentials(&server->cred, allowed_credtypes, server->url.username, server->url.password); - server->url_cred_presented = 1; - - /* treat GIT_PASSTHROUGH as if callback isn't set */ - if (error == GIT_PASSTHROUGH) - error = 1; - } - - if (error > 0 && callback) { - error = callback(&server->cred, url, server->url.username, allowed_credtypes, callback_payload); - - /* treat GIT_PASSTHROUGH as if callback isn't set */ - if (error == GIT_PASSTHROUGH) - error = 1; - } - - if (error > 0) { - git_error_set(GIT_ERROR_HTTP, "%s authentication required but no callback set", server_type); - error = GIT_EAUTH; - } - - if (!error) - server->auth_schemetypes = allowed_schemetypes; - - return error; -} - -GIT_INLINE(int) handle_remote_auth( - http_stream *stream, - git_http_response *response) -{ - http_subtransport *transport = OWNING_SUBTRANSPORT(stream); - git_remote_connect_options *connect_opts = &transport->owner->connect_opts; - - if (response->server_auth_credtypes == 0) { - git_error_set(GIT_ERROR_HTTP, "server requires authentication that we do not support"); - return GIT_EAUTH; - } - - /* Otherwise, prompt for credentials. */ - return handle_auth( - &transport->server, - SERVER_TYPE_REMOTE, - transport->owner->url, - response->server_auth_schemetypes, - response->server_auth_credtypes, - connect_opts->callbacks.credentials, - connect_opts->callbacks.payload); -} - -GIT_INLINE(int) handle_proxy_auth( - http_stream *stream, - git_http_response *response) -{ - http_subtransport *transport = OWNING_SUBTRANSPORT(stream); - git_remote_connect_options *connect_opts = &transport->owner->connect_opts; - - if (response->proxy_auth_credtypes == 0) { - git_error_set(GIT_ERROR_HTTP, "proxy requires authentication that we do not support"); - return GIT_EAUTH; - } - - /* Otherwise, prompt for credentials. */ - return handle_auth( - &transport->proxy, - SERVER_TYPE_PROXY, - connect_opts->proxy_opts.url, - response->server_auth_schemetypes, - response->proxy_auth_credtypes, - connect_opts->proxy_opts.credentials, - connect_opts->proxy_opts.payload); -} - -static bool allow_redirect(http_stream *stream) -{ - http_subtransport *transport = OWNING_SUBTRANSPORT(stream); - - switch (transport->owner->connect_opts.follow_redirects) { - case GIT_REMOTE_REDIRECT_INITIAL: - return (stream->service->initial == 1); - case GIT_REMOTE_REDIRECT_ALL: - return true; - default: - return false; - } -} - -static int handle_response( - bool *complete, - http_stream *stream, - git_http_response *response, - bool allow_replay) -{ - http_subtransport *transport = OWNING_SUBTRANSPORT(stream); - int error; - - *complete = false; - - if (allow_replay && git_http_response_is_redirect(response)) { - if (!response->location) { - git_error_set(GIT_ERROR_HTTP, "redirect without location"); - return -1; - } - - if (git_net_url_apply_redirect(&transport->server.url, response->location, allow_redirect(stream), stream->service->url) < 0) { - return -1; - } - - return 0; - } else if (git_http_response_is_redirect(response)) { - git_error_set(GIT_ERROR_HTTP, "unexpected redirect"); - return -1; - } - - /* If we're in the middle of challenge/response auth, continue. */ - if (allow_replay && response->resend_credentials) { - return 0; - } else if (allow_replay && response->status == GIT_HTTP_STATUS_UNAUTHORIZED) { - if ((error = handle_remote_auth(stream, response)) < 0) - return error; - - return git_http_client_skip_body(transport->http_client); - } else if (allow_replay && response->status == GIT_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED) { - if ((error = handle_proxy_auth(stream, response)) < 0) - return error; - - return git_http_client_skip_body(transport->http_client); - } else if (response->status == GIT_HTTP_STATUS_UNAUTHORIZED || - response->status == GIT_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED) { - git_error_set(GIT_ERROR_HTTP, "unexpected authentication failure"); - return GIT_EAUTH; - } - - if (response->status != GIT_HTTP_STATUS_OK) { - git_error_set(GIT_ERROR_HTTP, "unexpected http status code: %d", response->status); - return -1; - } - - /* The response must contain a Content-Type header. */ - if (!response->content_type) { - git_error_set(GIT_ERROR_HTTP, "no content-type header in response"); - return -1; - } - - /* The Content-Type header must match our expectation. */ - if (strcmp(response->content_type, stream->service->response_type) != 0) { - git_error_set(GIT_ERROR_HTTP, "invalid content-type: '%s'", response->content_type); - return -1; - } - - *complete = true; - stream->state = HTTP_STATE_RECEIVING_RESPONSE; - return 0; -} - -static int lookup_proxy( - bool *out_use, - http_subtransport *transport) -{ - git_remote_connect_options *connect_opts = &transport->owner->connect_opts; - const char *proxy; - git_remote *remote; - char *config = NULL; - int error = 0; - - *out_use = false; - git_net_url_dispose(&transport->proxy.url); - - switch (connect_opts->proxy_opts.type) { - case GIT_PROXY_SPECIFIED: - proxy = connect_opts->proxy_opts.url; - break; - - case GIT_PROXY_AUTO: - remote = transport->owner->owner; - - error = git_remote__http_proxy(&config, remote, &transport->server.url); - - if (error || !config) - goto done; - - proxy = config; - break; - - default: - return 0; - } - - if (!proxy || - (error = git_net_url_parse(&transport->proxy.url, proxy)) < 0) - goto done; - - *out_use = true; - -done: - git__free(config); - return error; -} - -static int generate_request( - git_net_url *url, - git_http_request *request, - http_stream *stream, - size_t len) -{ - http_subtransport *transport = OWNING_SUBTRANSPORT(stream); - bool use_proxy = false; - int error; - - if ((error = git_net_url_joinpath(url, - &transport->server.url, stream->service->url)) < 0 || - (error = lookup_proxy(&use_proxy, transport)) < 0) - return error; - - request->method = stream->service->method; - request->url = url; - request->credentials = transport->server.cred; - request->proxy = use_proxy ? &transport->proxy.url : NULL; - request->proxy_credentials = transport->proxy.cred; - request->custom_headers = &transport->owner->connect_opts.custom_headers; - - if (stream->service->method == GIT_HTTP_METHOD_POST) { - request->chunked = stream->service->chunked; - request->content_length = stream->service->chunked ? 0 : len; - request->content_type = stream->service->request_type; - request->accept = stream->service->response_type; - request->expect_continue = git_http__expect_continue; - } - - return 0; -} - -/* - * Read from an HTTP transport - for the first invocation of this function - * (ie, when stream->state == HTTP_STATE_NONE), we'll send a GET request - * to the remote host. We will stream that data back on all subsequent - * calls. - */ -static int http_stream_read( - git_smart_subtransport_stream *s, - char *buffer, - size_t buffer_size, - size_t *out_len) -{ - http_stream *stream = (http_stream *)s; - http_subtransport *transport = OWNING_SUBTRANSPORT(stream); - git_net_url url = GIT_NET_URL_INIT; - git_net_url proxy_url = GIT_NET_URL_INIT; - git_http_request request = {0}; - git_http_response response = {0}; - bool complete; - int error; - - *out_len = 0; - - if (stream->state == HTTP_STATE_NONE) { - stream->state = HTTP_STATE_SENDING_REQUEST; - stream->replay_count = 0; - } - - /* - * Formulate the URL, send the request and read the response - * headers. Some of the request body may also be read. - */ - while (stream->state == HTTP_STATE_SENDING_REQUEST && - stream->replay_count < GIT_HTTP_REPLAY_MAX) { - git_net_url_dispose(&url); - git_net_url_dispose(&proxy_url); - git_http_response_dispose(&response); - - if ((error = generate_request(&url, &request, stream, 0)) < 0 || - (error = git_http_client_send_request( - transport->http_client, &request)) < 0 || - (error = git_http_client_read_response( - &response, transport->http_client)) < 0 || - (error = handle_response(&complete, stream, &response, true)) < 0) - goto done; - - if (complete) - break; - - stream->replay_count++; - } - - if (stream->state == HTTP_STATE_SENDING_REQUEST) { - git_error_set(GIT_ERROR_HTTP, "too many redirects or authentication replays"); - error = GIT_ERROR; /* not GIT_EAUTH, because the exact cause is unclear */ - goto done; - } - - GIT_ASSERT(stream->state == HTTP_STATE_RECEIVING_RESPONSE); - - error = git_http_client_read_body(transport->http_client, buffer, buffer_size); - - if (error > 0) { - *out_len = error; - error = 0; - } - -done: - git_net_url_dispose(&url); - git_net_url_dispose(&proxy_url); - git_http_response_dispose(&response); - - return error; -} - -static bool needs_probe(http_stream *stream) -{ - http_subtransport *transport = OWNING_SUBTRANSPORT(stream); - - return (transport->server.auth_schemetypes == GIT_HTTP_AUTH_NTLM || - transport->server.auth_schemetypes == GIT_HTTP_AUTH_NEGOTIATE); -} - -static int send_probe(http_stream *stream) -{ - http_subtransport *transport = OWNING_SUBTRANSPORT(stream); - git_http_client *client = transport->http_client; - const char *probe = "0000"; - size_t len = 4; - git_net_url url = GIT_NET_URL_INIT; - git_http_request request = {0}; - git_http_response response = {0}; - bool complete = false; - size_t step, steps = 1; - int error; - - /* NTLM requires a full challenge/response */ - if (transport->server.auth_schemetypes == GIT_HTTP_AUTH_NTLM) - steps = GIT_AUTH_STEPS_NTLM; - - /* - * Send at most two requests: one without any authentication to see - * if we get prompted to authenticate. If we do, send a second one - * with the first authentication message. The final authentication - * message with the response will occur with the *actual* POST data. - */ - for (step = 0; step < steps && !complete; step++) { - git_net_url_dispose(&url); - git_http_response_dispose(&response); - - if ((error = generate_request(&url, &request, stream, len)) < 0 || - (error = git_http_client_send_request(client, &request)) < 0 || - (error = git_http_client_send_body(client, probe, len)) < 0 || - (error = git_http_client_read_response(&response, client)) < 0 || - (error = git_http_client_skip_body(client)) < 0 || - (error = handle_response(&complete, stream, &response, true)) < 0) - goto done; - } - -done: - git_http_response_dispose(&response); - git_net_url_dispose(&url); - return error; -} - -/* -* Write to an HTTP transport - for the first invocation of this function -* (ie, when stream->state == HTTP_STATE_NONE), we'll send a POST request -* to the remote host. If we're sending chunked data, then subsequent calls -* will write the additional data given in the buffer. If we're not chunking, -* then the caller should have given us all the data in the original call. -* The caller should call http_stream_read_response to get the result. -*/ -static int http_stream_write( - git_smart_subtransport_stream *s, - const char *buffer, - size_t len) -{ - http_stream *stream = GIT_CONTAINER_OF(s, http_stream, parent); - http_subtransport *transport = OWNING_SUBTRANSPORT(stream); - git_net_url url = GIT_NET_URL_INIT; - git_http_request request = {0}; - git_http_response response = {0}; - int error; - - while (stream->state == HTTP_STATE_NONE && - stream->replay_count < GIT_HTTP_REPLAY_MAX) { - - git_net_url_dispose(&url); - git_http_response_dispose(&response); - - /* - * If we're authenticating with a connection-based mechanism - * (NTLM, Kerberos), send a "probe" packet. Servers SHOULD - * authenticate an entire keep-alive connection, so ideally - * we should not need to authenticate but some servers do - * not support this. By sending a probe packet, we'll be - * able to follow up with a second POST using the actual - * data (and, in the degenerate case, the authentication - * header as well). - */ - if (needs_probe(stream) && (error = send_probe(stream)) < 0) - goto done; - - /* Send the regular POST request. */ - if ((error = generate_request(&url, &request, stream, len)) < 0 || - (error = git_http_client_send_request( - transport->http_client, &request)) < 0) - goto done; - - if (request.expect_continue && - git_http_client_has_response(transport->http_client)) { - bool complete; - - /* - * If we got a response to an expect/continue, then - * it's something other than a 100 and we should - * deal with the response somehow. - */ - if ((error = git_http_client_read_response(&response, transport->http_client)) < 0 || - (error = handle_response(&complete, stream, &response, true)) < 0) - goto done; - } else { - stream->state = HTTP_STATE_SENDING_REQUEST; - } - - stream->replay_count++; - } - - if (stream->state == HTTP_STATE_NONE) { - git_error_set(GIT_ERROR_HTTP, - "too many redirects or authentication replays"); - error = GIT_ERROR; /* not GIT_EAUTH because the exact cause is unclear */ - goto done; - } - - GIT_ASSERT(stream->state == HTTP_STATE_SENDING_REQUEST); - - error = git_http_client_send_body(transport->http_client, buffer, len); - -done: - git_http_response_dispose(&response); - git_net_url_dispose(&url); - return error; -} - -/* -* Read from an HTTP transport after it has been written to. This is the -* response from a POST request made by http_stream_write. -*/ -static int http_stream_read_response( - git_smart_subtransport_stream *s, - char *buffer, - size_t buffer_size, - size_t *out_len) -{ - http_stream *stream = (http_stream *)s; - http_subtransport *transport = OWNING_SUBTRANSPORT(stream); - git_http_client *client = transport->http_client; - git_http_response response = {0}; - bool complete; - int error; - - *out_len = 0; - - if (stream->state == HTTP_STATE_SENDING_REQUEST) { - if ((error = git_http_client_read_response(&response, client)) < 0 || - (error = handle_response(&complete, stream, &response, false)) < 0) - goto done; - - GIT_ASSERT(complete); - stream->state = HTTP_STATE_RECEIVING_RESPONSE; - } - - error = git_http_client_read_body(client, buffer, buffer_size); - - if (error > 0) { - *out_len = error; - error = 0; - } - -done: - git_http_response_dispose(&response); - return error; -} - -static void http_stream_free(git_smart_subtransport_stream *stream) -{ - http_stream *s = GIT_CONTAINER_OF(stream, http_stream, parent); - git__free(s); -} - -static const http_service *select_service(git_smart_service_t action) -{ - switch (action) { - case GIT_SERVICE_UPLOADPACK_LS: - return &upload_pack_ls_service; - case GIT_SERVICE_UPLOADPACK: - return &upload_pack_service; - case GIT_SERVICE_RECEIVEPACK_LS: - return &receive_pack_ls_service; - case GIT_SERVICE_RECEIVEPACK: - return &receive_pack_service; - } - - return NULL; -} - -static int http_action( - git_smart_subtransport_stream **out, - git_smart_subtransport *t, - const char *url, - git_smart_service_t action) -{ - http_subtransport *transport = GIT_CONTAINER_OF(t, http_subtransport, parent); - git_remote_connect_options *connect_opts = &transport->owner->connect_opts; - http_stream *stream; - const http_service *service; - int error; - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(t); - - *out = NULL; - - /* - * If we've seen a redirect then preserve the location that we've - * been given. This is important to continue authorization against - * the redirect target, not the user-given source; the endpoint may - * have redirected us from HTTP->HTTPS and is using an auth mechanism - * that would be insecure in plaintext (eg, HTTP Basic). - */ - if (!git_net_url_valid(&transport->server.url) && - (error = git_net_url_parse(&transport->server.url, url)) < 0) - return error; - - if ((service = select_service(action)) == NULL) { - git_error_set(GIT_ERROR_HTTP, "invalid action"); - return -1; - } - - stream = git__calloc(sizeof(http_stream), 1); - GIT_ERROR_CHECK_ALLOC(stream); - - if (!transport->http_client) { - git_http_client_options opts = {0}; - - opts.server_certificate_check_cb = connect_opts->callbacks.certificate_check; - opts.server_certificate_check_payload = connect_opts->callbacks.payload; - opts.proxy_certificate_check_cb = connect_opts->proxy_opts.certificate_check; - opts.proxy_certificate_check_payload = connect_opts->proxy_opts.payload; - - if (git_http_client_new(&transport->http_client, &opts) < 0) - return -1; - } - - stream->service = service; - stream->parent.subtransport = &transport->parent; - - if (service->method == GIT_HTTP_METHOD_GET) { - stream->parent.read = http_stream_read; - } else { - stream->parent.write = http_stream_write; - stream->parent.read = http_stream_read_response; - } - - stream->parent.free = http_stream_free; - - *out = (git_smart_subtransport_stream *)stream; - return 0; -} - -static int http_close(git_smart_subtransport *t) -{ - http_subtransport *transport = GIT_CONTAINER_OF(t, http_subtransport, parent); - - free_cred(&transport->server.cred); - free_cred(&transport->proxy.cred); - - transport->server.url_cred_presented = false; - transport->proxy.url_cred_presented = false; - - git_net_url_dispose(&transport->server.url); - git_net_url_dispose(&transport->proxy.url); - - return 0; -} - -static void http_free(git_smart_subtransport *t) -{ - http_subtransport *transport = GIT_CONTAINER_OF(t, http_subtransport, parent); - - git_http_client_free(transport->http_client); - - http_close(t); - git__free(transport); -} - -int git_smart_subtransport_http(git_smart_subtransport **out, git_transport *owner, void *param) -{ - http_subtransport *transport; - - GIT_UNUSED(param); - - GIT_ASSERT_ARG(out); - - transport = git__calloc(sizeof(http_subtransport), 1); - GIT_ERROR_CHECK_ALLOC(transport); - - transport->owner = (transport_smart *)owner; - transport->parent.action = http_action; - transport->parent.close = http_close; - transport->parent.free = http_free; - - *out = (git_smart_subtransport *) transport; - return 0; -} - -#endif /* !GIT_WINHTTP */ diff --git a/vendor/libgit2/src/transports/http.h b/vendor/libgit2/src/transports/http.h deleted file mode 100644 index 8e8e7226..00000000 --- a/vendor/libgit2/src/transports/http.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#ifndef INCLUDE_transports_http_h__ -#define INCLUDE_transports_http_h__ - -#include "settings.h" -#include "httpclient.h" - -#define GIT_HTTP_REPLAY_MAX 15 - -extern bool git_http__expect_continue; - -GIT_INLINE(int) git_http__user_agent(git_str *buf) -{ - const char *ua = git_libgit2__user_agent(); - - if (!ua) - ua = "libgit2 " LIBGIT2_VERSION; - - return git_str_printf(buf, "git/2.0 (%s)", ua); -} - -#endif diff --git a/vendor/libgit2/src/transports/local.c b/vendor/libgit2/src/transports/local.c deleted file mode 100644 index 6c754a03..00000000 --- a/vendor/libgit2/src/transports/local.c +++ /dev/null @@ -1,754 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "common.h" - -#include "pack-objects.h" -#include "refs.h" -#include "posix.h" -#include "fs_path.h" -#include "repository.h" -#include "odb.h" -#include "push.h" -#include "remote.h" -#include "proxy.h" - -#include "git2/types.h" -#include "git2/net.h" -#include "git2/repository.h" -#include "git2/object.h" -#include "git2/tag.h" -#include "git2/transport.h" -#include "git2/revwalk.h" -#include "git2/odb_backend.h" -#include "git2/pack.h" -#include "git2/commit.h" -#include "git2/revparse.h" -#include "git2/sys/remote.h" - -typedef struct { - git_transport parent; - git_remote *owner; - char *url; - int direction; - git_atomic32 cancelled; - git_repository *repo; - git_remote_connect_options connect_opts; - git_vector refs; - unsigned connected : 1, - have_refs : 1; -} transport_local; - -static void free_head(git_remote_head *head) -{ - git__free(head->name); - git__free(head->symref_target); - git__free(head); -} - -static void free_heads(git_vector *heads) -{ - git_remote_head *head; - size_t i; - - git_vector_foreach(heads, i, head) - free_head(head); - - git_vector_free(heads); -} - -static int add_ref(transport_local *t, const char *name) -{ - const char peeled[] = "^{}"; - git_reference *ref, *resolved; - git_remote_head *head; - git_oid obj_id; - git_object *obj = NULL, *target = NULL; - git_str buf = GIT_STR_INIT; - int error; - - if ((error = git_reference_lookup(&ref, t->repo, name)) < 0) - return error; - - error = git_reference_resolve(&resolved, ref); - if (error < 0) { - git_reference_free(ref); - if (!strcmp(name, GIT_HEAD_FILE) && error == GIT_ENOTFOUND) { - /* This is actually okay. Empty repos often have a HEAD that - * points to a nonexistent "refs/heads/master". */ - git_error_clear(); - return 0; - } - return error; - } - - git_oid_cpy(&obj_id, git_reference_target(resolved)); - git_reference_free(resolved); - - head = git__calloc(1, sizeof(git_remote_head)); - GIT_ERROR_CHECK_ALLOC(head); - - head->name = git__strdup(name); - GIT_ERROR_CHECK_ALLOC(head->name); - - git_oid_cpy(&head->oid, &obj_id); - - if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) { - head->symref_target = git__strdup(git_reference_symbolic_target(ref)); - GIT_ERROR_CHECK_ALLOC(head->symref_target); - } - git_reference_free(ref); - - if ((error = git_vector_insert(&t->refs, head)) < 0) { - free_head(head); - return error; - } - - /* If it's not a tag, we don't need to try to peel it */ - if (git__prefixcmp(name, GIT_REFS_TAGS_DIR)) - return 0; - - if ((error = git_object_lookup(&obj, t->repo, &head->oid, GIT_OBJECT_ANY)) < 0) - return error; - - head = NULL; - - /* If it's not an annotated tag, or if we're mocking - * git-receive-pack, just get out */ - if (git_object_type(obj) != GIT_OBJECT_TAG || - t->direction != GIT_DIRECTION_FETCH) { - git_object_free(obj); - return 0; - } - - /* And if it's a tag, peel it, and add it to the list */ - head = git__calloc(1, sizeof(git_remote_head)); - GIT_ERROR_CHECK_ALLOC(head); - - if (git_str_join(&buf, 0, name, peeled) < 0) { - free_head(head); - return -1; - } - head->name = git_str_detach(&buf); - - if (!(error = git_tag_peel(&target, (git_tag *)obj))) { - git_oid_cpy(&head->oid, git_object_id(target)); - - if ((error = git_vector_insert(&t->refs, head)) < 0) { - free_head(head); - } - } - - git_object_free(obj); - git_object_free(target); - - return error; -} - -static int store_refs(transport_local *t) -{ - size_t i; - git_remote_head *head; - git_strarray ref_names = {0}; - - GIT_ASSERT_ARG(t); - - if (git_reference_list(&ref_names, t->repo) < 0) - goto on_error; - - /* Clear all heads we might have fetched in a previous connect */ - git_vector_foreach(&t->refs, i, head) { - git__free(head->name); - git__free(head); - } - - /* Clear the vector so we can reuse it */ - git_vector_clear(&t->refs); - - /* Sort the references first */ - git__tsort((void **)ref_names.strings, ref_names.count, &git__strcmp_cb); - - /* Add HEAD iff direction is fetch */ - if (t->direction == GIT_DIRECTION_FETCH && add_ref(t, GIT_HEAD_FILE) < 0) - goto on_error; - - for (i = 0; i < ref_names.count; ++i) { - if (add_ref(t, ref_names.strings[i]) < 0) - goto on_error; - } - - t->have_refs = 1; - git_strarray_dispose(&ref_names); - return 0; - -on_error: - git_vector_free(&t->refs); - git_strarray_dispose(&ref_names); - return -1; -} - -/* - * Try to open the url as a git directory. The direction doesn't - * matter in this case because we're calculating the heads ourselves. - */ -static int local_connect( - git_transport *transport, - const char *url, - int direction, - const git_remote_connect_options *connect_opts) -{ - git_repository *repo; - int error; - transport_local *t = (transport_local *)transport; - const char *path; - git_str buf = GIT_STR_INIT; - - if (t->connected) - return 0; - - if (git_remote_connect_options_normalize(&t->connect_opts, t->owner->repo, connect_opts) < 0) - return -1; - - free_heads(&t->refs); - - t->url = git__strdup(url); - GIT_ERROR_CHECK_ALLOC(t->url); - t->direction = direction; - - /* 'url' may be a url or path; convert to a path */ - if ((error = git_fs_path_from_url_or_path(&buf, url)) < 0) { - git_str_dispose(&buf); - return error; - } - path = git_str_cstr(&buf); - - error = git_repository_open(&repo, path); - - git_str_dispose(&buf); - - if (error < 0) - return -1; - - t->repo = repo; - - if (store_refs(t) < 0) - return -1; - - t->connected = 1; - - return 0; -} - -static int local_set_connect_opts( - git_transport *transport, - const git_remote_connect_options *connect_opts) -{ - transport_local *t = (transport_local *)transport; - - if (!t->connected) { - git_error_set(GIT_ERROR_NET, "cannot reconfigure a transport that is not connected"); - return -1; - } - - return git_remote_connect_options_normalize(&t->connect_opts, t->owner->repo, connect_opts); -} - -static int local_capabilities(unsigned int *capabilities, git_transport *transport) -{ - GIT_UNUSED(transport); - - *capabilities = GIT_REMOTE_CAPABILITY_TIP_OID | - GIT_REMOTE_CAPABILITY_REACHABLE_OID; - return 0; -} - -static int local_ls(const git_remote_head ***out, size_t *size, git_transport *transport) -{ - transport_local *t = (transport_local *)transport; - - if (!t->have_refs) { - git_error_set(GIT_ERROR_NET, "the transport has not yet loaded the refs"); - return -1; - } - - *out = (const git_remote_head **)t->refs.contents; - *size = t->refs.length; - - return 0; -} - -static int local_negotiate_fetch( - git_transport *transport, - git_repository *repo, - const git_remote_head * const *refs, - size_t count) -{ - transport_local *t = (transport_local*)transport; - git_remote_head *rhead; - unsigned int i; - - GIT_UNUSED(refs); - GIT_UNUSED(count); - - /* Fill in the loids */ - git_vector_foreach(&t->refs, i, rhead) { - git_object *obj; - - int error = git_revparse_single(&obj, repo, rhead->name); - if (!error) - git_oid_cpy(&rhead->loid, git_object_id(obj)); - else if (error != GIT_ENOTFOUND) - return error; - else - git_error_clear(); - git_object_free(obj); - } - - return 0; -} - -static int local_push_update_remote_ref( - git_repository *remote_repo, - const char *lref, - const char *rref, - git_oid *loid, - git_oid *roid) -{ - int error; - git_reference *remote_ref = NULL; - - /* check for lhs, if it's empty it means to delete */ - if (lref[0] != '\0') { - /* Create or update a ref */ - error = git_reference_create(NULL, remote_repo, rref, loid, - !git_oid_is_zero(roid), NULL); - } else { - /* Delete a ref */ - if ((error = git_reference_lookup(&remote_ref, remote_repo, rref)) < 0) { - if (error == GIT_ENOTFOUND) - error = 0; - return error; - } - - error = git_reference_delete(remote_ref); - git_reference_free(remote_ref); - } - - return error; -} - -static int transfer_to_push_transfer(const git_indexer_progress *stats, void *payload) -{ - const git_remote_callbacks *cbs = payload; - - if (!cbs || !cbs->push_transfer_progress) - return 0; - - return cbs->push_transfer_progress(stats->received_objects, stats->total_objects, stats->received_bytes, - cbs->payload); -} - -static int local_push( - git_transport *transport, - git_push *push) -{ - transport_local *t = (transport_local *)transport; - git_remote_callbacks *cbs = &t->connect_opts.callbacks; - git_repository *remote_repo = NULL; - push_spec *spec; - char *url = NULL; - const char *path; - git_str buf = GIT_STR_INIT, odb_path = GIT_STR_INIT; - int error; - size_t j; - - /* 'push->remote->url' may be a url or path; convert to a path */ - if ((error = git_fs_path_from_url_or_path(&buf, push->remote->url)) < 0) { - git_str_dispose(&buf); - return error; - } - path = git_str_cstr(&buf); - - error = git_repository_open(&remote_repo, path); - - git_str_dispose(&buf); - - if (error < 0) - return error; - - /* We don't currently support pushing locally to non-bare repos. Proper - non-bare repo push support would require checking configs to see if - we should override the default 'don't let this happen' behavior. - - Note that this is only an issue when pushing to the current branch, - but we forbid all pushes just in case */ - if (!remote_repo->is_bare) { - error = GIT_EBAREREPO; - git_error_set(GIT_ERROR_INVALID, "local push doesn't (yet) support pushing to non-bare repos."); - goto on_error; - } - - if ((error = git_repository__item_path(&odb_path, remote_repo, GIT_REPOSITORY_ITEM_OBJECTS)) < 0 - || (error = git_str_joinpath(&odb_path, odb_path.ptr, "pack")) < 0) - goto on_error; - - error = git_packbuilder_write(push->pb, odb_path.ptr, 0, transfer_to_push_transfer, (void *) cbs); - git_str_dispose(&odb_path); - - if (error < 0) - goto on_error; - - push->unpack_ok = 1; - - git_vector_foreach(&push->specs, j, spec) { - push_status *status; - const git_error *last; - char *ref = spec->refspec.dst; - - status = git__calloc(1, sizeof(push_status)); - if (!status) - goto on_error; - - status->ref = git__strdup(ref); - if (!status->ref) { - git_push_status_free(status); - goto on_error; - } - - error = local_push_update_remote_ref(remote_repo, spec->refspec.src, spec->refspec.dst, - &spec->loid, &spec->roid); - - switch (error) { - case GIT_OK: - break; - case GIT_EINVALIDSPEC: - status->msg = git__strdup("funny refname"); - break; - case GIT_ENOTFOUND: - status->msg = git__strdup("Remote branch not found to delete"); - break; - default: - last = git_error_last(); - - if (last && last->message) - status->msg = git__strdup(last->message); - else - status->msg = git__strdup("Unspecified error encountered"); - break; - } - - /* failed to allocate memory for a status message */ - if (error < 0 && !status->msg) { - git_push_status_free(status); - goto on_error; - } - - /* failed to insert the ref update status */ - if ((error = git_vector_insert(&push->status, status)) < 0) { - git_push_status_free(status); - goto on_error; - } - } - - if (push->specs.length) { - url = git__strdup(t->url); - - if (!url || t->parent.close(&t->parent) < 0 || - t->parent.connect(&t->parent, url, - GIT_DIRECTION_PUSH, NULL)) - goto on_error; - } - - error = 0; - -on_error: - git_repository_free(remote_repo); - git__free(url); - - return error; -} - -typedef struct foreach_data { - git_indexer_progress *stats; - git_indexer_progress_cb progress_cb; - void *progress_payload; - git_odb_writepack *writepack; -} foreach_data; - -static int foreach_cb(void *buf, size_t len, void *payload) -{ - foreach_data *data = (foreach_data*)payload; - - data->stats->received_bytes += len; - return data->writepack->append(data->writepack, buf, len, data->stats); -} - -static const char *counting_objects_fmt = "Counting objects %d\r"; -static const char *compressing_objects_fmt = "Compressing objects: %.0f%% (%d/%d)"; - -static int local_counting(int stage, unsigned int current, unsigned int total, void *payload) -{ - git_str progress_info = GIT_STR_INIT; - transport_local *t = payload; - int error; - - if (!t->connect_opts.callbacks.sideband_progress) - return 0; - - if (stage == GIT_PACKBUILDER_ADDING_OBJECTS) { - git_str_printf(&progress_info, counting_objects_fmt, current); - } else if (stage == GIT_PACKBUILDER_DELTAFICATION) { - float perc = (((float) current) / total) * 100; - git_str_printf(&progress_info, compressing_objects_fmt, perc, current, total); - if (current == total) - git_str_printf(&progress_info, ", done\n"); - else - git_str_putc(&progress_info, '\r'); - - } - - if (git_str_oom(&progress_info)) - return -1; - - if (progress_info.size > INT_MAX) { - git_error_set(GIT_ERROR_NET, "remote sent overly large progress data"); - git_str_dispose(&progress_info); - return -1; - } - - - error = t->connect_opts.callbacks.sideband_progress( - progress_info.ptr, - (int)progress_info.size, - t->connect_opts.callbacks.payload); - - git_str_dispose(&progress_info); - return error; -} - -static int foreach_reference_cb(git_reference *reference, void *payload) -{ - git_revwalk *walk = (git_revwalk *)payload; - int error; - - if (git_reference_type(reference) != GIT_REFERENCE_DIRECT) { - git_reference_free(reference); - return 0; - } - - error = git_revwalk_hide(walk, git_reference_target(reference)); - /* The reference is in the local repository, so the target may not - * exist on the remote. It also may not be a commit. */ - if (error == GIT_ENOTFOUND || error == GIT_ERROR_INVALID) { - git_error_clear(); - error = 0; - } - - git_reference_free(reference); - - return error; -} - -static int local_download_pack( - git_transport *transport, - git_repository *repo, - git_indexer_progress *stats) -{ - transport_local *t = (transport_local*)transport; - git_revwalk *walk = NULL; - git_remote_head *rhead; - unsigned int i; - int error = -1; - git_packbuilder *pack = NULL; - git_odb_writepack *writepack = NULL; - git_odb *odb = NULL; - git_str progress_info = GIT_STR_INIT; - foreach_data data = {0}; - - if ((error = git_revwalk_new(&walk, t->repo)) < 0) - goto cleanup; - - git_revwalk_sorting(walk, GIT_SORT_TIME); - - if ((error = git_packbuilder_new(&pack, t->repo)) < 0) - goto cleanup; - - git_packbuilder_set_callbacks(pack, local_counting, t); - - stats->total_objects = 0; - stats->indexed_objects = 0; - stats->received_objects = 0; - stats->received_bytes = 0; - - git_vector_foreach(&t->refs, i, rhead) { - git_object *obj; - if ((error = git_object_lookup(&obj, t->repo, &rhead->oid, GIT_OBJECT_ANY)) < 0) - goto cleanup; - - if (git_object_type(obj) == GIT_OBJECT_COMMIT) { - /* Revwalker includes only wanted commits */ - error = git_revwalk_push(walk, &rhead->oid); - } else { - /* Tag or some other wanted object. Add it on its own */ - error = git_packbuilder_insert_recur(pack, &rhead->oid, rhead->name); - } - git_object_free(obj); - if (error < 0) - goto cleanup; - } - - if ((error = git_reference_foreach(repo, foreach_reference_cb, walk))) - goto cleanup; - - if ((error = git_packbuilder_insert_walk(pack, walk))) - goto cleanup; - - if (t->connect_opts.callbacks.sideband_progress) { - if ((error = git_str_printf( - &progress_info, - counting_objects_fmt, - git_packbuilder_object_count(pack))) < 0 || - (error = t->connect_opts.callbacks.sideband_progress( - progress_info.ptr, - (int)progress_info.size, - t->connect_opts.callbacks.payload)) < 0) - goto cleanup; - } - - /* Walk the objects, building a packfile */ - if ((error = git_repository_odb__weakptr(&odb, repo)) < 0) - goto cleanup; - - /* One last one with the newline */ - if (t->connect_opts.callbacks.sideband_progress) { - git_str_clear(&progress_info); - - if ((error = git_str_printf( - &progress_info, - counting_objects_fmt, - git_packbuilder_object_count(pack))) < 0 || - (error = git_str_putc(&progress_info, '\n')) < 0 || - (error = t->connect_opts.callbacks.sideband_progress( - progress_info.ptr, - (int)progress_info.size, - t->connect_opts.callbacks.payload)) < 0) - goto cleanup; - } - - if ((error = git_odb_write_pack( - &writepack, - odb, - t->connect_opts.callbacks.transfer_progress, - t->connect_opts.callbacks.payload)) < 0) - goto cleanup; - - /* Write the data to the ODB */ - data.stats = stats; - data.progress_cb = t->connect_opts.callbacks.transfer_progress; - data.progress_payload = t->connect_opts.callbacks.payload; - data.writepack = writepack; - - /* autodetect */ - git_packbuilder_set_threads(pack, 0); - - if ((error = git_packbuilder_foreach(pack, foreach_cb, &data)) != 0) - goto cleanup; - - error = writepack->commit(writepack, stats); - -cleanup: - if (writepack) writepack->free(writepack); - git_str_dispose(&progress_info); - git_packbuilder_free(pack); - git_revwalk_free(walk); - return error; -} - -static int local_is_connected(git_transport *transport) -{ - transport_local *t = (transport_local *)transport; - - return t->connected; -} - -static void local_cancel(git_transport *transport) -{ - transport_local *t = (transport_local *)transport; - - git_atomic32_set(&t->cancelled, 1); -} - -static int local_close(git_transport *transport) -{ - transport_local *t = (transport_local *)transport; - - t->connected = 0; - - if (t->repo) { - git_repository_free(t->repo); - t->repo = NULL; - } - - if (t->url) { - git__free(t->url); - t->url = NULL; - } - - return 0; -} - -static void local_free(git_transport *transport) -{ - transport_local *t = (transport_local *)transport; - - free_heads(&t->refs); - - /* Close the transport, if it's still open. */ - local_close(transport); - - /* Free the transport */ - git__free(t); -} - -/************** - * Public API * - **************/ - -int git_transport_local(git_transport **out, git_remote *owner, void *param) -{ - int error; - transport_local *t; - - GIT_UNUSED(param); - - t = git__calloc(1, sizeof(transport_local)); - GIT_ERROR_CHECK_ALLOC(t); - - t->parent.version = GIT_TRANSPORT_VERSION; - t->parent.connect = local_connect; - t->parent.set_connect_opts = local_set_connect_opts; - t->parent.capabilities = local_capabilities; - t->parent.negotiate_fetch = local_negotiate_fetch; - t->parent.download_pack = local_download_pack; - t->parent.push = local_push; - t->parent.close = local_close; - t->parent.free = local_free; - t->parent.ls = local_ls; - t->parent.is_connected = local_is_connected; - t->parent.cancel = local_cancel; - - if ((error = git_vector_init(&t->refs, 0, NULL)) < 0) { - git__free(t); - return error; - } - - t->owner = owner; - - *out = (git_transport *) t; - - return 0; -} diff --git a/vendor/libgit2/src/transports/smart_pkt.c b/vendor/libgit2/src/transports/smart_pkt.c deleted file mode 100644 index b42edd0d..00000000 --- a/vendor/libgit2/src/transports/smart_pkt.c +++ /dev/null @@ -1,637 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "common.h" - -#include "smart.h" -#include "util.h" -#include "netops.h" -#include "posix.h" -#include "str.h" - -#include "git2/types.h" -#include "git2/errors.h" -#include "git2/refs.h" -#include "git2/revwalk.h" - -#include - -#define PKT_LEN_SIZE 4 -static const char pkt_done_str[] = "0009done\n"; -static const char pkt_flush_str[] = "0000"; -static const char pkt_have_prefix[] = "0032have "; -static const char pkt_want_prefix[] = "0032want "; - -static int flush_pkt(git_pkt **out) -{ - git_pkt *pkt; - - pkt = git__malloc(sizeof(git_pkt)); - GIT_ERROR_CHECK_ALLOC(pkt); - - pkt->type = GIT_PKT_FLUSH; - *out = pkt; - - return 0; -} - -/* the rest of the line will be useful for multi_ack and multi_ack_detailed */ -static int ack_pkt(git_pkt **out, const char *line, size_t len) -{ - git_pkt_ack *pkt; - - pkt = git__calloc(1, sizeof(git_pkt_ack)); - GIT_ERROR_CHECK_ALLOC(pkt); - pkt->type = GIT_PKT_ACK; - - if (git__prefixncmp(line, len, "ACK ")) - goto out_err; - line += 4; - len -= 4; - - if (len < GIT_OID_HEXSZ || git_oid_fromstr(&pkt->oid, line) < 0) - goto out_err; - line += GIT_OID_HEXSZ; - len -= GIT_OID_HEXSZ; - - if (len && line[0] == ' ') { - line++; - len--; - - if (!git__prefixncmp(line, len, "continue")) - pkt->status = GIT_ACK_CONTINUE; - else if (!git__prefixncmp(line, len, "common")) - pkt->status = GIT_ACK_COMMON; - else if (!git__prefixncmp(line, len, "ready")) - pkt->status = GIT_ACK_READY; - else - goto out_err; - } - - *out = (git_pkt *) pkt; - - return 0; - -out_err: - git_error_set(GIT_ERROR_NET, "error parsing ACK pkt-line"); - git__free(pkt); - return -1; -} - -static int nak_pkt(git_pkt **out) -{ - git_pkt *pkt; - - pkt = git__malloc(sizeof(git_pkt)); - GIT_ERROR_CHECK_ALLOC(pkt); - - pkt->type = GIT_PKT_NAK; - *out = pkt; - - return 0; -} - -static int comment_pkt(git_pkt **out, const char *line, size_t len) -{ - git_pkt_comment *pkt; - size_t alloclen; - - GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_pkt_comment), len); - GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1); - pkt = git__malloc(alloclen); - GIT_ERROR_CHECK_ALLOC(pkt); - - pkt->type = GIT_PKT_COMMENT; - memcpy(pkt->comment, line, len); - pkt->comment[len] = '\0'; - - *out = (git_pkt *) pkt; - - return 0; -} - -static int err_pkt(git_pkt **out, const char *line, size_t len) -{ - git_pkt_err *pkt = NULL; - size_t alloclen; - - /* Remove "ERR " from the line */ - if (git__prefixncmp(line, len, "ERR ")) - goto out_err; - line += 4; - len -= 4; - - GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_pkt_progress), len); - GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1); - pkt = git__malloc(alloclen); - GIT_ERROR_CHECK_ALLOC(pkt); - pkt->type = GIT_PKT_ERR; - pkt->len = len; - - memcpy(pkt->error, line, len); - pkt->error[len] = '\0'; - - *out = (git_pkt *) pkt; - - return 0; - -out_err: - git_error_set(GIT_ERROR_NET, "error parsing ERR pkt-line"); - git__free(pkt); - return -1; -} - -static int data_pkt(git_pkt **out, const char *line, size_t len) -{ - git_pkt_data *pkt; - size_t alloclen; - - line++; - len--; - - GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_pkt_progress), len); - pkt = git__malloc(alloclen); - GIT_ERROR_CHECK_ALLOC(pkt); - - pkt->type = GIT_PKT_DATA; - pkt->len = len; - memcpy(pkt->data, line, len); - - *out = (git_pkt *) pkt; - - return 0; -} - -static int sideband_progress_pkt(git_pkt **out, const char *line, size_t len) -{ - git_pkt_progress *pkt; - size_t alloclen; - - line++; - len--; - - GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_pkt_progress), len); - pkt = git__malloc(alloclen); - GIT_ERROR_CHECK_ALLOC(pkt); - - pkt->type = GIT_PKT_PROGRESS; - pkt->len = len; - memcpy(pkt->data, line, len); - - *out = (git_pkt *) pkt; - - return 0; -} - -static int sideband_error_pkt(git_pkt **out, const char *line, size_t len) -{ - git_pkt_err *pkt; - size_t alloc_len; - - line++; - len--; - - GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, sizeof(git_pkt_err), len); - GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 1); - pkt = git__malloc(alloc_len); - GIT_ERROR_CHECK_ALLOC(pkt); - - pkt->type = GIT_PKT_ERR; - pkt->len = (int)len; - memcpy(pkt->error, line, len); - pkt->error[len] = '\0'; - - *out = (git_pkt *)pkt; - - return 0; -} - -/* - * Parse an other-ref line. - */ -static int ref_pkt(git_pkt **out, const char *line, size_t len) -{ - git_pkt_ref *pkt; - size_t alloclen; - - pkt = git__calloc(1, sizeof(git_pkt_ref)); - GIT_ERROR_CHECK_ALLOC(pkt); - pkt->type = GIT_PKT_REF; - - if (len < GIT_OID_HEXSZ || git_oid_fromstr(&pkt->head.oid, line) < 0) - goto out_err; - line += GIT_OID_HEXSZ; - len -= GIT_OID_HEXSZ; - - if (git__prefixncmp(line, len, " ")) - goto out_err; - line++; - len--; - - if (!len) - goto out_err; - - if (line[len - 1] == '\n') - --len; - - GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, len, 1); - pkt->head.name = git__malloc(alloclen); - GIT_ERROR_CHECK_ALLOC(pkt->head.name); - - memcpy(pkt->head.name, line, len); - pkt->head.name[len] = '\0'; - - if (strlen(pkt->head.name) < len) - pkt->capabilities = strchr(pkt->head.name, '\0') + 1; - - *out = (git_pkt *)pkt; - return 0; - -out_err: - git_error_set(GIT_ERROR_NET, "error parsing REF pkt-line"); - if (pkt) - git__free(pkt->head.name); - git__free(pkt); - return -1; -} - -static int ok_pkt(git_pkt **out, const char *line, size_t len) -{ - git_pkt_ok *pkt; - size_t alloc_len; - - pkt = git__malloc(sizeof(*pkt)); - GIT_ERROR_CHECK_ALLOC(pkt); - pkt->type = GIT_PKT_OK; - - if (git__prefixncmp(line, len, "ok ")) - goto out_err; - line += 3; - len -= 3; - - if (len && line[len - 1] == '\n') - --len; - - GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, len, 1); - pkt->ref = git__malloc(alloc_len); - GIT_ERROR_CHECK_ALLOC(pkt->ref); - - memcpy(pkt->ref, line, len); - pkt->ref[len] = '\0'; - - *out = (git_pkt *)pkt; - return 0; - -out_err: - git_error_set(GIT_ERROR_NET, "error parsing OK pkt-line"); - git__free(pkt); - return -1; -} - -static int ng_pkt(git_pkt **out, const char *line, size_t len) -{ - git_pkt_ng *pkt; - const char *ptr, *eol; - size_t alloclen; - - pkt = git__malloc(sizeof(*pkt)); - GIT_ERROR_CHECK_ALLOC(pkt); - - pkt->ref = NULL; - pkt->type = GIT_PKT_NG; - - eol = line + len; - - if (git__prefixncmp(line, len, "ng ")) - goto out_err; - line += 3; - - if (!(ptr = memchr(line, ' ', eol - line))) - goto out_err; - len = ptr - line; - - GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, len, 1); - pkt->ref = git__malloc(alloclen); - GIT_ERROR_CHECK_ALLOC(pkt->ref); - - memcpy(pkt->ref, line, len); - pkt->ref[len] = '\0'; - - line = ptr + 1; - if (line >= eol) - goto out_err; - - if (!(ptr = memchr(line, '\n', eol - line))) - goto out_err; - len = ptr - line; - - GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, len, 1); - pkt->msg = git__malloc(alloclen); - GIT_ERROR_CHECK_ALLOC(pkt->msg); - - memcpy(pkt->msg, line, len); - pkt->msg[len] = '\0'; - - *out = (git_pkt *)pkt; - return 0; - -out_err: - git_error_set(GIT_ERROR_NET, "invalid packet line"); - git__free(pkt->ref); - git__free(pkt); - return -1; -} - -static int unpack_pkt(git_pkt **out, const char *line, size_t len) -{ - git_pkt_unpack *pkt; - - pkt = git__malloc(sizeof(*pkt)); - GIT_ERROR_CHECK_ALLOC(pkt); - pkt->type = GIT_PKT_UNPACK; - - if (!git__prefixncmp(line, len, "unpack ok")) - pkt->unpack_ok = 1; - else - pkt->unpack_ok = 0; - - *out = (git_pkt *)pkt; - return 0; -} - -static int parse_len(size_t *out, const char *line, size_t linelen) -{ - char num[PKT_LEN_SIZE + 1]; - int i, k, error; - int32_t len; - const char *num_end; - - /* Not even enough for the length */ - if (linelen < PKT_LEN_SIZE) - return GIT_EBUFS; - - memcpy(num, line, PKT_LEN_SIZE); - num[PKT_LEN_SIZE] = '\0'; - - for (i = 0; i < PKT_LEN_SIZE; ++i) { - if (!isxdigit(num[i])) { - /* Make sure there are no special characters before passing to error message */ - for (k = 0; k < PKT_LEN_SIZE; ++k) { - if(!isprint(num[k])) { - num[k] = '.'; - } - } - - git_error_set(GIT_ERROR_NET, "invalid hex digit in length: '%s'", num); - return -1; - } - } - - if ((error = git__strntol32(&len, num, PKT_LEN_SIZE, &num_end, 16)) < 0) - return error; - - if (len < 0) - return -1; - - *out = (size_t) len; - return 0; -} - -/* - * As per the documentation, the syntax is: - * - * pkt-line = data-pkt / flush-pkt - * data-pkt = pkt-len pkt-payload - * pkt-len = 4*(HEXDIG) - * pkt-payload = (pkt-len -4)*(OCTET) - * flush-pkt = "0000" - * - * Which means that the first four bytes are the length of the line, - * in ASCII hexadecimal (including itself) - */ - -int git_pkt_parse_line( - git_pkt **pkt, const char **endptr, const char *line, size_t linelen) -{ - int error; - size_t len; - - if ((error = parse_len(&len, line, linelen)) < 0) { - /* - * If we fail to parse the length, it might be - * because the server is trying to send us the - * packfile already or because we do not yet have - * enough data. - */ - if (error == GIT_EBUFS) - ; - else if (!git__prefixncmp(line, linelen, "PACK")) - git_error_set(GIT_ERROR_NET, "unexpected pack file"); - else - git_error_set(GIT_ERROR_NET, "bad packet length"); - return error; - } - - /* - * Make sure there is enough in the buffer to satisfy - * this line. - */ - if (linelen < len) - return GIT_EBUFS; - - /* - * The length has to be exactly 0 in case of a flush - * packet or greater than PKT_LEN_SIZE, as the decoded - * length includes its own encoded length of four bytes. - */ - if (len != 0 && len < PKT_LEN_SIZE) - return GIT_ERROR; - - line += PKT_LEN_SIZE; - /* - * The Git protocol does not specify empty lines as part - * of the protocol. Not knowing what to do with an empty - * line, we should return an error upon hitting one. - */ - if (len == PKT_LEN_SIZE) { - git_error_set_str(GIT_ERROR_NET, "Invalid empty packet"); - return GIT_ERROR; - } - - if (len == 0) { /* Flush pkt */ - *endptr = line; - return flush_pkt(pkt); - } - - len -= PKT_LEN_SIZE; /* the encoded length includes its own size */ - - if (*line == GIT_SIDE_BAND_DATA) - error = data_pkt(pkt, line, len); - else if (*line == GIT_SIDE_BAND_PROGRESS) - error = sideband_progress_pkt(pkt, line, len); - else if (*line == GIT_SIDE_BAND_ERROR) - error = sideband_error_pkt(pkt, line, len); - else if (!git__prefixncmp(line, len, "ACK")) - error = ack_pkt(pkt, line, len); - else if (!git__prefixncmp(line, len, "NAK")) - error = nak_pkt(pkt); - else if (!git__prefixncmp(line, len, "ERR")) - error = err_pkt(pkt, line, len); - else if (*line == '#') - error = comment_pkt(pkt, line, len); - else if (!git__prefixncmp(line, len, "ok")) - error = ok_pkt(pkt, line, len); - else if (!git__prefixncmp(line, len, "ng")) - error = ng_pkt(pkt, line, len); - else if (!git__prefixncmp(line, len, "unpack")) - error = unpack_pkt(pkt, line, len); - else - error = ref_pkt(pkt, line, len); - - *endptr = line + len; - - return error; -} - -void git_pkt_free(git_pkt *pkt) -{ - if (pkt == NULL) { - return; - } - if (pkt->type == GIT_PKT_REF) { - git_pkt_ref *p = (git_pkt_ref *) pkt; - git__free(p->head.name); - git__free(p->head.symref_target); - } - - if (pkt->type == GIT_PKT_OK) { - git_pkt_ok *p = (git_pkt_ok *) pkt; - git__free(p->ref); - } - - if (pkt->type == GIT_PKT_NG) { - git_pkt_ng *p = (git_pkt_ng *) pkt; - git__free(p->ref); - git__free(p->msg); - } - - git__free(pkt); -} - -int git_pkt_buffer_flush(git_str *buf) -{ - return git_str_put(buf, pkt_flush_str, strlen(pkt_flush_str)); -} - -static int buffer_want_with_caps(const git_remote_head *head, transport_smart_caps *caps, git_str *buf) -{ - git_str str = GIT_STR_INIT; - char oid[GIT_OID_HEXSZ +1] = {0}; - size_t len; - - /* Prefer multi_ack_detailed */ - if (caps->multi_ack_detailed) - git_str_puts(&str, GIT_CAP_MULTI_ACK_DETAILED " "); - else if (caps->multi_ack) - git_str_puts(&str, GIT_CAP_MULTI_ACK " "); - - /* Prefer side-band-64k if the server supports both */ - if (caps->side_band_64k) - git_str_printf(&str, "%s ", GIT_CAP_SIDE_BAND_64K); - else if (caps->side_band) - git_str_printf(&str, "%s ", GIT_CAP_SIDE_BAND); - - if (caps->include_tag) - git_str_puts(&str, GIT_CAP_INCLUDE_TAG " "); - - if (caps->thin_pack) - git_str_puts(&str, GIT_CAP_THIN_PACK " "); - - if (caps->ofs_delta) - git_str_puts(&str, GIT_CAP_OFS_DELTA " "); - - if (git_str_oom(&str)) - return -1; - - len = strlen("XXXXwant ") + GIT_OID_HEXSZ + 1 /* NUL */ + - git_str_len(&str) + 1 /* LF */; - - if (len > 0xffff) { - git_error_set(GIT_ERROR_NET, - "tried to produce packet with invalid length %" PRIuZ, len); - return -1; - } - - git_str_grow_by(buf, len); - git_oid_fmt(oid, &head->oid); - git_str_printf(buf, - "%04xwant %s %s\n", (unsigned int)len, oid, git_str_cstr(&str)); - git_str_dispose(&str); - - GIT_ERROR_CHECK_ALLOC_STR(buf); - - return 0; -} - -/* - * All "want" packets have the same length and format, so what we do - * is overwrite the OID each time. - */ - -int git_pkt_buffer_wants( - const git_remote_head * const *refs, - size_t count, - transport_smart_caps *caps, - git_str *buf) -{ - size_t i = 0; - const git_remote_head *head; - - if (caps->common) { - for (; i < count; ++i) { - head = refs[i]; - if (!head->local) - break; - } - - if (buffer_want_with_caps(refs[i], caps, buf) < 0) - return -1; - - i++; - } - - for (; i < count; ++i) { - char oid[GIT_OID_HEXSZ]; - - head = refs[i]; - if (head->local) - continue; - - git_oid_fmt(oid, &head->oid); - git_str_put(buf, pkt_want_prefix, strlen(pkt_want_prefix)); - git_str_put(buf, oid, GIT_OID_HEXSZ); - git_str_putc(buf, '\n'); - if (git_str_oom(buf)) - return -1; - } - - return git_pkt_buffer_flush(buf); -} - -int git_pkt_buffer_have(git_oid *oid, git_str *buf) -{ - char oidhex[GIT_OID_HEXSZ + 1]; - - memset(oidhex, 0x0, sizeof(oidhex)); - git_oid_fmt(oidhex, oid); - return git_str_printf(buf, "%s%s\n", pkt_have_prefix, oidhex); -} - -int git_pkt_buffer_done(git_str *buf) -{ - return git_str_puts(buf, pkt_done_str); -} diff --git a/vendor/libgit2/src/transports/ssh.c b/vendor/libgit2/src/transports/ssh.c deleted file mode 100644 index 89f08523..00000000 --- a/vendor/libgit2/src/transports/ssh.c +++ /dev/null @@ -1,915 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "ssh.h" - -#ifdef GIT_SSH -#include -#endif - -#include "runtime.h" -#include "net.h" -#include "netops.h" -#include "smart.h" -#include "streams/socket.h" - -#include "git2/credential.h" -#include "git2/sys/credential.h" - -#ifdef GIT_SSH - -#define OWNING_SUBTRANSPORT(s) ((ssh_subtransport *)(s)->parent.subtransport) - -static const char cmd_uploadpack[] = "git-upload-pack"; -static const char cmd_receivepack[] = "git-receive-pack"; - -typedef struct { - git_smart_subtransport_stream parent; - git_stream *io; - LIBSSH2_SESSION *session; - LIBSSH2_CHANNEL *channel; - const char *cmd; - git_net_url url; - unsigned sent_command : 1; -} ssh_stream; - -typedef struct { - git_smart_subtransport parent; - transport_smart *owner; - ssh_stream *current_stream; - git_credential *cred; - char *cmd_uploadpack; - char *cmd_receivepack; -} ssh_subtransport; - -static int list_auth_methods(int *out, LIBSSH2_SESSION *session, const char *username); - -static void ssh_error(LIBSSH2_SESSION *session, const char *errmsg) -{ - char *ssherr; - libssh2_session_last_error(session, &ssherr, NULL, 0); - - git_error_set(GIT_ERROR_SSH, "%s: %s", errmsg, ssherr); -} - -/* - * Create a git protocol request. - * - * For example: git-upload-pack '/libgit2/libgit2' - */ -static int gen_proto(git_str *request, const char *cmd, git_net_url *url) -{ - const char *repo; - - repo = url->path; - - if (repo && repo[0] == '/' && repo[1] == '~') - repo++; - - if (!repo || !repo[0]) { - git_error_set(GIT_ERROR_NET, "malformed git protocol URL"); - return -1; - } - - git_str_puts(request, cmd); - git_str_puts(request, " '"); - git_str_puts(request, repo); - git_str_puts(request, "'"); - - if (git_str_oom(request)) - return -1; - - return 0; -} - -static int send_command(ssh_stream *s) -{ - int error; - git_str request = GIT_STR_INIT; - - error = gen_proto(&request, s->cmd, &s->url); - if (error < 0) - goto cleanup; - - error = libssh2_channel_exec(s->channel, request.ptr); - if (error < LIBSSH2_ERROR_NONE) { - ssh_error(s->session, "SSH could not execute request"); - goto cleanup; - } - - s->sent_command = 1; - -cleanup: - git_str_dispose(&request); - return error; -} - -static int ssh_stream_read( - git_smart_subtransport_stream *stream, - char *buffer, - size_t buf_size, - size_t *bytes_read) -{ - int rc; - ssh_stream *s = GIT_CONTAINER_OF(stream, ssh_stream, parent); - - *bytes_read = 0; - - if (!s->sent_command && send_command(s) < 0) - return -1; - - if ((rc = libssh2_channel_read(s->channel, buffer, buf_size)) < LIBSSH2_ERROR_NONE) { - ssh_error(s->session, "SSH could not read data"); - return -1; - } - - /* - * If we can't get anything out of stdout, it's typically a - * not-found error, so read from stderr and signal EOF on - * stderr. - */ - if (rc == 0) { - if ((rc = libssh2_channel_read_stderr(s->channel, buffer, buf_size)) > 0) { - git_error_set(GIT_ERROR_SSH, "%*s", rc, buffer); - return GIT_EEOF; - } else if (rc < LIBSSH2_ERROR_NONE) { - ssh_error(s->session, "SSH could not read stderr"); - return -1; - } - } - - - *bytes_read = rc; - - return 0; -} - -static int ssh_stream_write( - git_smart_subtransport_stream *stream, - const char *buffer, - size_t len) -{ - ssh_stream *s = GIT_CONTAINER_OF(stream, ssh_stream, parent); - size_t off = 0; - ssize_t ret = 0; - - if (!s->sent_command && send_command(s) < 0) - return -1; - - do { - ret = libssh2_channel_write(s->channel, buffer + off, len - off); - if (ret < 0) - break; - - off += ret; - - } while (off < len); - - if (ret < 0) { - ssh_error(s->session, "SSH could not write data"); - return -1; - } - - return 0; -} - -static void ssh_stream_free(git_smart_subtransport_stream *stream) -{ - ssh_stream *s = GIT_CONTAINER_OF(stream, ssh_stream, parent); - ssh_subtransport *t; - - if (!stream) - return; - - t = OWNING_SUBTRANSPORT(s); - t->current_stream = NULL; - - if (s->channel) { - libssh2_channel_close(s->channel); - libssh2_channel_free(s->channel); - s->channel = NULL; - } - - if (s->session) { - libssh2_session_disconnect(s->session, "closing transport"); - libssh2_session_free(s->session); - s->session = NULL; - } - - if (s->io) { - git_stream_close(s->io); - git_stream_free(s->io); - s->io = NULL; - } - - git_net_url_dispose(&s->url); - git__free(s); -} - -static int ssh_stream_alloc( - ssh_subtransport *t, - const char *cmd, - git_smart_subtransport_stream **stream) -{ - ssh_stream *s; - - GIT_ASSERT_ARG(stream); - - s = git__calloc(sizeof(ssh_stream), 1); - GIT_ERROR_CHECK_ALLOC(s); - - s->parent.subtransport = &t->parent; - s->parent.read = ssh_stream_read; - s->parent.write = ssh_stream_write; - s->parent.free = ssh_stream_free; - - s->cmd = cmd; - - *stream = &s->parent; - return 0; -} - -static int ssh_agent_auth(LIBSSH2_SESSION *session, git_credential_ssh_key *c) { - int rc = LIBSSH2_ERROR_NONE; - - struct libssh2_agent_publickey *curr, *prev = NULL; - - LIBSSH2_AGENT *agent = libssh2_agent_init(session); - - if (agent == NULL) - return -1; - - rc = libssh2_agent_connect(agent); - - if (rc != LIBSSH2_ERROR_NONE) - goto shutdown; - - rc = libssh2_agent_list_identities(agent); - - if (rc != LIBSSH2_ERROR_NONE) - goto shutdown; - - while (1) { - rc = libssh2_agent_get_identity(agent, &curr, prev); - - if (rc < 0) - goto shutdown; - - /* rc is set to 1 whenever the ssh agent ran out of keys to check. - * Set the error code to authentication failure rather than erroring - * out with an untranslatable error code. - */ - if (rc == 1) { - rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED; - goto shutdown; - } - - rc = libssh2_agent_userauth(agent, c->username, curr); - - if (rc == 0) - break; - - prev = curr; - } - -shutdown: - - if (rc != LIBSSH2_ERROR_NONE) - ssh_error(session, "error authenticating"); - - libssh2_agent_disconnect(agent); - libssh2_agent_free(agent); - - return rc; -} - -static int _git_ssh_authenticate_session( - LIBSSH2_SESSION *session, - git_credential *cred) -{ - int rc; - - do { - git_error_clear(); - switch (cred->credtype) { - case GIT_CREDENTIAL_USERPASS_PLAINTEXT: { - git_credential_userpass_plaintext *c = (git_credential_userpass_plaintext *)cred; - rc = libssh2_userauth_password(session, c->username, c->password); - break; - } - case GIT_CREDENTIAL_SSH_KEY: { - git_credential_ssh_key *c = (git_credential_ssh_key *)cred; - - if (c->privatekey) - rc = libssh2_userauth_publickey_fromfile( - session, c->username, c->publickey, - c->privatekey, c->passphrase); - else - rc = ssh_agent_auth(session, c); - - break; - } - case GIT_CREDENTIAL_SSH_CUSTOM: { - git_credential_ssh_custom *c = (git_credential_ssh_custom *)cred; - - rc = libssh2_userauth_publickey( - session, c->username, (const unsigned char *)c->publickey, - c->publickey_len, c->sign_callback, &c->payload); - break; - } - case GIT_CREDENTIAL_SSH_INTERACTIVE: { - void **abstract = libssh2_session_abstract(session); - git_credential_ssh_interactive *c = (git_credential_ssh_interactive *)cred; - - /* ideally, we should be able to set this by calling - * libssh2_session_init_ex() instead of libssh2_session_init(). - * libssh2's API is inconsistent here i.e. libssh2_userauth_publickey() - * allows you to pass the `abstract` as part of the call, whereas - * libssh2_userauth_keyboard_interactive() does not! - * - * The only way to set the `abstract` pointer is by calling - * libssh2_session_abstract(), which will replace the existing - * pointer as is done below. This is safe for now (at time of writing), - * but may not be valid in future. - */ - *abstract = c->payload; - - rc = libssh2_userauth_keyboard_interactive( - session, c->username, c->prompt_callback); - break; - } -#ifdef GIT_SSH_MEMORY_CREDENTIALS - case GIT_CREDENTIAL_SSH_MEMORY: { - git_credential_ssh_key *c = (git_credential_ssh_key *)cred; - - GIT_ASSERT(c->username); - GIT_ASSERT(c->privatekey); - - rc = libssh2_userauth_publickey_frommemory( - session, - c->username, - strlen(c->username), - c->publickey, - c->publickey ? strlen(c->publickey) : 0, - c->privatekey, - strlen(c->privatekey), - c->passphrase); - break; - } -#endif - default: - rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED; - } - } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); - - if (rc == LIBSSH2_ERROR_PASSWORD_EXPIRED || - rc == LIBSSH2_ERROR_AUTHENTICATION_FAILED || - rc == LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED) - return GIT_EAUTH; - - if (rc != LIBSSH2_ERROR_NONE) { - if (!git_error_last()) - ssh_error(session, "Failed to authenticate SSH session"); - return -1; - } - - return 0; -} - -static int request_creds(git_credential **out, ssh_subtransport *t, const char *user, int auth_methods) -{ - int error, no_callback = 0; - git_credential *cred = NULL; - - if (!t->owner->connect_opts.callbacks.credentials) { - no_callback = 1; - } else { - error = t->owner->connect_opts.callbacks.credentials( - &cred, - t->owner->url, - user, - auth_methods, - t->owner->connect_opts.callbacks.payload); - - if (error == GIT_PASSTHROUGH) { - no_callback = 1; - } else if (error < 0) { - return error; - } else if (!cred) { - git_error_set(GIT_ERROR_SSH, "callback failed to initialize SSH credentials"); - return -1; - } - } - - if (no_callback) { - git_error_set(GIT_ERROR_SSH, "authentication required but no callback set"); - return GIT_EAUTH; - } - - if (!(cred->credtype & auth_methods)) { - cred->free(cred); - git_error_set(GIT_ERROR_SSH, "authentication callback returned unsupported credentials type"); - return GIT_EAUTH; - } - - *out = cred; - - return 0; -} - -static int _git_ssh_session_create( - LIBSSH2_SESSION **session, - git_stream *io) -{ - int rc = 0; - LIBSSH2_SESSION *s; - git_socket_stream *socket = GIT_CONTAINER_OF(io, git_socket_stream, parent); - - GIT_ASSERT_ARG(session); - - s = libssh2_session_init(); - if (!s) { - git_error_set(GIT_ERROR_NET, "failed to initialize SSH session"); - return -1; - } - - do { - rc = libssh2_session_handshake(s, socket->s); - } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); - - if (rc != LIBSSH2_ERROR_NONE) { - ssh_error(s, "failed to start SSH session"); - libssh2_session_free(s); - return -1; - } - - libssh2_session_set_blocking(s, 1); - - *session = s; - - return 0; -} - -#define SSH_DEFAULT_PORT "22" - -static int _git_ssh_setup_conn( - ssh_subtransport *t, - const char *url, - const char *cmd, - git_smart_subtransport_stream **stream) -{ - int auth_methods, error = 0; - ssh_stream *s; - git_credential *cred = NULL; - LIBSSH2_SESSION *session=NULL; - LIBSSH2_CHANNEL *channel=NULL; - - t->current_stream = NULL; - - *stream = NULL; - if (ssh_stream_alloc(t, cmd, stream) < 0) - return -1; - - s = (ssh_stream *)*stream; - s->session = NULL; - s->channel = NULL; - - if (git_net_str_is_url(url)) - error = git_net_url_parse(&s->url, url); - else - error = git_net_url_parse_scp(&s->url, url); - - if (error < 0) - goto done; - - if ((error = git_socket_stream_new(&s->io, s->url.host, s->url.port)) < 0 || - (error = git_stream_connect(s->io)) < 0) - goto done; - - if ((error = _git_ssh_session_create(&session, s->io)) < 0) - goto done; - - if (t->owner->connect_opts.callbacks.certificate_check != NULL) { - git_cert_hostkey cert = {{ 0 }}, *cert_ptr; - const char *key; - size_t cert_len; - int cert_type; - - cert.parent.cert_type = GIT_CERT_HOSTKEY_LIBSSH2; - - key = libssh2_session_hostkey(session, &cert_len, &cert_type); - if (key != NULL) { - cert.type |= GIT_CERT_SSH_RAW; - cert.hostkey = key; - cert.hostkey_len = cert_len; - switch (cert_type) { - case LIBSSH2_HOSTKEY_TYPE_RSA: - cert.raw_type = GIT_CERT_SSH_RAW_TYPE_RSA; - break; - case LIBSSH2_HOSTKEY_TYPE_DSS: - cert.raw_type = GIT_CERT_SSH_RAW_TYPE_DSS; - break; - -#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256 - case LIBSSH2_HOSTKEY_TYPE_ECDSA_256: - cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_256; - break; - case LIBSSH2_HOSTKEY_TYPE_ECDSA_384: - cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_384; - break; - case LIBSSH2_KNOWNHOST_KEY_ECDSA_521: - cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_521; - break; -#endif - -#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519 - case LIBSSH2_HOSTKEY_TYPE_ED25519: - cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ED25519; - break; -#endif - default: - cert.raw_type = GIT_CERT_SSH_RAW_TYPE_UNKNOWN; - } - } - -#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 - key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA256); - if (key != NULL) { - cert.type |= GIT_CERT_SSH_SHA256; - memcpy(&cert.hash_sha256, key, 32); - } -#endif - - key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1); - if (key != NULL) { - cert.type |= GIT_CERT_SSH_SHA1; - memcpy(&cert.hash_sha1, key, 20); - } - - key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5); - if (key != NULL) { - cert.type |= GIT_CERT_SSH_MD5; - memcpy(&cert.hash_md5, key, 16); - } - - if (cert.type == 0) { - git_error_set(GIT_ERROR_SSH, "unable to get the host key"); - error = -1; - goto done; - } - - /* We don't currently trust any hostkeys */ - git_error_clear(); - - cert_ptr = &cert; - - error = t->owner->connect_opts.callbacks.certificate_check( - (git_cert *)cert_ptr, - 0, - s->url.host, - t->owner->connect_opts.callbacks.payload); - - if (error < 0 && error != GIT_PASSTHROUGH) { - if (!git_error_last()) - git_error_set(GIT_ERROR_NET, "user cancelled hostkey check"); - - goto done; - } - } - - /* we need the username to ask for auth methods */ - if (!s->url.username) { - if ((error = request_creds(&cred, t, NULL, GIT_CREDENTIAL_USERNAME)) < 0) - goto done; - - s->url.username = git__strdup(((git_credential_username *) cred)->username); - cred->free(cred); - cred = NULL; - if (!s->url.username) - goto done; - } else if (s->url.username && s->url.password) { - if ((error = git_credential_userpass_plaintext_new(&cred, s->url.username, s->url.password)) < 0) - goto done; - } - - if ((error = list_auth_methods(&auth_methods, session, s->url.username)) < 0) - goto done; - - error = GIT_EAUTH; - /* if we already have something to try */ - if (cred && auth_methods & cred->credtype) - error = _git_ssh_authenticate_session(session, cred); - - while (error == GIT_EAUTH) { - if (cred) { - cred->free(cred); - cred = NULL; - } - - if ((error = request_creds(&cred, t, s->url.username, auth_methods)) < 0) - goto done; - - if (strcmp(s->url.username, git_credential_get_username(cred))) { - git_error_set(GIT_ERROR_SSH, "username does not match previous request"); - error = -1; - goto done; - } - - error = _git_ssh_authenticate_session(session, cred); - - if (error == GIT_EAUTH) { - /* refresh auth methods */ - if ((error = list_auth_methods(&auth_methods, session, s->url.username)) < 0) - goto done; - else - error = GIT_EAUTH; - } - } - - if (error < 0) - goto done; - - channel = libssh2_channel_open_session(session); - if (!channel) { - error = -1; - ssh_error(session, "Failed to open SSH channel"); - goto done; - } - - libssh2_channel_set_blocking(channel, 1); - - s->session = session; - s->channel = channel; - - t->current_stream = s; - -done: - if (error < 0) { - ssh_stream_free(*stream); - - if (session) - libssh2_session_free(session); - } - - if (cred) - cred->free(cred); - - return error; -} - -static int ssh_uploadpack_ls( - ssh_subtransport *t, - const char *url, - git_smart_subtransport_stream **stream) -{ - const char *cmd = t->cmd_uploadpack ? t->cmd_uploadpack : cmd_uploadpack; - - return _git_ssh_setup_conn(t, url, cmd, stream); -} - -static int ssh_uploadpack( - ssh_subtransport *t, - const char *url, - git_smart_subtransport_stream **stream) -{ - GIT_UNUSED(url); - - if (t->current_stream) { - *stream = &t->current_stream->parent; - return 0; - } - - git_error_set(GIT_ERROR_NET, "must call UPLOADPACK_LS before UPLOADPACK"); - return -1; -} - -static int ssh_receivepack_ls( - ssh_subtransport *t, - const char *url, - git_smart_subtransport_stream **stream) -{ - const char *cmd = t->cmd_receivepack ? t->cmd_receivepack : cmd_receivepack; - - - return _git_ssh_setup_conn(t, url, cmd, stream); -} - -static int ssh_receivepack( - ssh_subtransport *t, - const char *url, - git_smart_subtransport_stream **stream) -{ - GIT_UNUSED(url); - - if (t->current_stream) { - *stream = &t->current_stream->parent; - return 0; - } - - git_error_set(GIT_ERROR_NET, "must call RECEIVEPACK_LS before RECEIVEPACK"); - return -1; -} - -static int _ssh_action( - git_smart_subtransport_stream **stream, - git_smart_subtransport *subtransport, - const char *url, - git_smart_service_t action) -{ - ssh_subtransport *t = GIT_CONTAINER_OF(subtransport, ssh_subtransport, parent); - - switch (action) { - case GIT_SERVICE_UPLOADPACK_LS: - return ssh_uploadpack_ls(t, url, stream); - - case GIT_SERVICE_UPLOADPACK: - return ssh_uploadpack(t, url, stream); - - case GIT_SERVICE_RECEIVEPACK_LS: - return ssh_receivepack_ls(t, url, stream); - - case GIT_SERVICE_RECEIVEPACK: - return ssh_receivepack(t, url, stream); - } - - *stream = NULL; - return -1; -} - -static int _ssh_close(git_smart_subtransport *subtransport) -{ - ssh_subtransport *t = GIT_CONTAINER_OF(subtransport, ssh_subtransport, parent); - - GIT_ASSERT(!t->current_stream); - - GIT_UNUSED(t); - - return 0; -} - -static void _ssh_free(git_smart_subtransport *subtransport) -{ - ssh_subtransport *t = GIT_CONTAINER_OF(subtransport, ssh_subtransport, parent); - - git__free(t->cmd_uploadpack); - git__free(t->cmd_receivepack); - git__free(t); -} - -#define SSH_AUTH_PUBLICKEY "publickey" -#define SSH_AUTH_PASSWORD "password" -#define SSH_AUTH_KEYBOARD_INTERACTIVE "keyboard-interactive" - -static int list_auth_methods(int *out, LIBSSH2_SESSION *session, const char *username) -{ - const char *list, *ptr; - - *out = 0; - - list = libssh2_userauth_list(session, username, strlen(username)); - - /* either error, or the remote accepts NONE auth, which is bizarre, let's punt */ - if (list == NULL && !libssh2_userauth_authenticated(session)) { - ssh_error(session, "Failed to retrieve list of SSH authentication methods"); - return GIT_EAUTH; - } - - ptr = list; - while (ptr) { - if (*ptr == ',') - ptr++; - - if (!git__prefixcmp(ptr, SSH_AUTH_PUBLICKEY)) { - *out |= GIT_CREDENTIAL_SSH_KEY; - *out |= GIT_CREDENTIAL_SSH_CUSTOM; -#ifdef GIT_SSH_MEMORY_CREDENTIALS - *out |= GIT_CREDENTIAL_SSH_MEMORY; -#endif - ptr += strlen(SSH_AUTH_PUBLICKEY); - continue; - } - - if (!git__prefixcmp(ptr, SSH_AUTH_PASSWORD)) { - *out |= GIT_CREDENTIAL_USERPASS_PLAINTEXT; - ptr += strlen(SSH_AUTH_PASSWORD); - continue; - } - - if (!git__prefixcmp(ptr, SSH_AUTH_KEYBOARD_INTERACTIVE)) { - *out |= GIT_CREDENTIAL_SSH_INTERACTIVE; - ptr += strlen(SSH_AUTH_KEYBOARD_INTERACTIVE); - continue; - } - - /* Skip it if we don't know it */ - ptr = strchr(ptr, ','); - } - - return 0; -} -#endif - -int git_smart_subtransport_ssh( - git_smart_subtransport **out, git_transport *owner, void *param) -{ -#ifdef GIT_SSH - ssh_subtransport *t; - - GIT_ASSERT_ARG(out); - - GIT_UNUSED(param); - - t = git__calloc(sizeof(ssh_subtransport), 1); - GIT_ERROR_CHECK_ALLOC(t); - - t->owner = (transport_smart *)owner; - t->parent.action = _ssh_action; - t->parent.close = _ssh_close; - t->parent.free = _ssh_free; - - *out = (git_smart_subtransport *) t; - return 0; -#else - GIT_UNUSED(owner); - GIT_UNUSED(param); - - GIT_ASSERT_ARG(out); - *out = NULL; - - git_error_set(GIT_ERROR_INVALID, "cannot create SSH transport. Library was built without SSH support"); - return -1; -#endif -} - -int git_transport_ssh_with_paths(git_transport **out, git_remote *owner, void *payload) -{ -#ifdef GIT_SSH - git_strarray *paths = (git_strarray *) payload; - git_transport *transport; - transport_smart *smart; - ssh_subtransport *t; - int error; - git_smart_subtransport_definition ssh_definition = { - git_smart_subtransport_ssh, - 0, /* no RPC */ - NULL, - }; - - if (paths->count != 2) { - git_error_set(GIT_ERROR_SSH, "invalid ssh paths, must be two strings"); - return GIT_EINVALIDSPEC; - } - - if ((error = git_transport_smart(&transport, owner, &ssh_definition)) < 0) - return error; - - smart = (transport_smart *) transport; - t = (ssh_subtransport *) smart->wrapped; - - t->cmd_uploadpack = git__strdup(paths->strings[0]); - GIT_ERROR_CHECK_ALLOC(t->cmd_uploadpack); - t->cmd_receivepack = git__strdup(paths->strings[1]); - GIT_ERROR_CHECK_ALLOC(t->cmd_receivepack); - - *out = transport; - return 0; -#else - GIT_UNUSED(owner); - GIT_UNUSED(payload); - - GIT_ASSERT_ARG(out); - *out = NULL; - - git_error_set(GIT_ERROR_INVALID, "cannot create SSH transport. Library was built without SSH support"); - return -1; -#endif -} - -#ifdef GIT_SSH -static void shutdown_ssh(void) -{ - libssh2_exit(); -} -#endif - -int git_transport_ssh_global_init(void) -{ -#ifdef GIT_SSH - if (libssh2_init(0) < 0) { - git_error_set(GIT_ERROR_SSH, "unable to initialize libssh2"); - return -1; - } - - return git_runtime_shutdown_register(shutdown_ssh); - -#else - - /* Nothing to initialize */ - return 0; - -#endif -} diff --git a/vendor/libgit2/src/transports/ssh.h b/vendor/libgit2/src/transports/ssh.h deleted file mode 100644 index d3e741f1..00000000 --- a/vendor/libgit2/src/transports/ssh.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_transports_ssh_h__ -#define INCLUDE_transports_ssh_h__ - -#include "common.h" - -int git_transport_ssh_global_init(void); - -#endif diff --git a/vendor/libgit2/src/tree.c b/vendor/libgit2/src/tree.c deleted file mode 100644 index a1545dc2..00000000 --- a/vendor/libgit2/src/tree.c +++ /dev/null @@ -1,1331 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "tree.h" - -#include "commit.h" -#include "git2/repository.h" -#include "git2/object.h" -#include "futils.h" -#include "tree-cache.h" -#include "index.h" -#include "path.h" - -#define DEFAULT_TREE_SIZE 16 -#define MAX_FILEMODE_BYTES 6 - -#define TREE_ENTRY_CHECK_NAMELEN(n) \ - if (n > UINT16_MAX) { git_error_set(GIT_ERROR_INVALID, "tree entry path too long"); } - -static bool valid_filemode(const int filemode) -{ - return (filemode == GIT_FILEMODE_TREE - || filemode == GIT_FILEMODE_BLOB - || filemode == GIT_FILEMODE_BLOB_EXECUTABLE - || filemode == GIT_FILEMODE_LINK - || filemode == GIT_FILEMODE_COMMIT); -} - -GIT_INLINE(git_filemode_t) normalize_filemode(git_filemode_t filemode) -{ - /* Tree bits set, but it's not a commit */ - if (GIT_MODE_TYPE(filemode) == GIT_FILEMODE_TREE) - return GIT_FILEMODE_TREE; - - /* If any of the x bits are set */ - if (GIT_PERMS_IS_EXEC(filemode)) - return GIT_FILEMODE_BLOB_EXECUTABLE; - - /* 16XXXX means commit */ - if (GIT_MODE_TYPE(filemode) == GIT_FILEMODE_COMMIT) - return GIT_FILEMODE_COMMIT; - - /* 12XXXX means symlink */ - if (GIT_MODE_TYPE(filemode) == GIT_FILEMODE_LINK) - return GIT_FILEMODE_LINK; - - /* Otherwise, return a blob */ - return GIT_FILEMODE_BLOB; -} - -static int valid_entry_name(git_repository *repo, const char *filename) -{ - return *filename != '\0' && - git_path_is_valid(repo, filename, 0, - GIT_FS_PATH_REJECT_TRAVERSAL | GIT_PATH_REJECT_DOT_GIT | GIT_FS_PATH_REJECT_SLASH); -} - -static int entry_sort_cmp(const void *a, const void *b) -{ - const git_tree_entry *e1 = (const git_tree_entry *)a; - const git_tree_entry *e2 = (const git_tree_entry *)b; - - return git_fs_path_cmp( - e1->filename, e1->filename_len, git_tree_entry__is_tree(e1), - e2->filename, e2->filename_len, git_tree_entry__is_tree(e2), - git__strncmp); -} - -int git_tree_entry_cmp(const git_tree_entry *e1, const git_tree_entry *e2) -{ - return entry_sort_cmp(e1, e2); -} - -/** - * Allocate a new self-contained entry, with enough space after it to - * store the filename and the id. - */ -static git_tree_entry *alloc_entry(const char *filename, size_t filename_len, const git_oid *id) -{ - git_tree_entry *entry = NULL; - size_t tree_len; - - TREE_ENTRY_CHECK_NAMELEN(filename_len); - - if (GIT_ADD_SIZET_OVERFLOW(&tree_len, sizeof(git_tree_entry), filename_len) || - GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, 1) || - GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, GIT_OID_RAWSZ)) - return NULL; - - entry = git__calloc(1, tree_len); - if (!entry) - return NULL; - - { - char *filename_ptr; - void *id_ptr; - - filename_ptr = ((char *) entry) + sizeof(git_tree_entry); - memcpy(filename_ptr, filename, filename_len); - entry->filename = filename_ptr; - - id_ptr = filename_ptr + filename_len + 1; - git_oid_cpy(id_ptr, id); - entry->oid = id_ptr; - } - - entry->filename_len = (uint16_t)filename_len; - - return entry; -} - -struct tree_key_search { - const char *filename; - uint16_t filename_len; -}; - -static int homing_search_cmp(const void *key, const void *array_member) -{ - const struct tree_key_search *ksearch = key; - const git_tree_entry *entry = array_member; - - const uint16_t len1 = ksearch->filename_len; - const uint16_t len2 = entry->filename_len; - - return memcmp( - ksearch->filename, - entry->filename, - len1 < len2 ? len1 : len2 - ); -} - -/* - * Search for an entry in a given tree. - * - * Note that this search is performed in two steps because - * of the way tree entries are sorted internally in git: - * - * Entries in a tree are not sorted alphabetically; two entries - * with the same root prefix will have different positions - * depending on whether they are folders (subtrees) or normal files. - * - * Consequently, it is not possible to find an entry on the tree - * with a binary search if you don't know whether the filename - * you're looking for is a folder or a normal file. - * - * To work around this, we first perform a homing binary search - * on the tree, using the minimal length root prefix of our filename. - * Once the comparisons for this homing search start becoming - * ambiguous because of folder vs file sorting, we look linearly - * around the area for our target file. - */ -static int tree_key_search( - size_t *at_pos, - const git_tree *tree, - const char *filename, - size_t filename_len) -{ - struct tree_key_search ksearch; - const git_tree_entry *entry; - size_t homing, i; - - TREE_ENTRY_CHECK_NAMELEN(filename_len); - - ksearch.filename = filename; - ksearch.filename_len = (uint16_t)filename_len; - - /* Initial homing search; find an entry on the tree with - * the same prefix as the filename we're looking for */ - - if (git_array_search(&homing, - tree->entries, &homing_search_cmp, &ksearch) < 0) - return GIT_ENOTFOUND; /* just a signal error; not passed back to user */ - - /* We found a common prefix. Look forward as long as - * there are entries that share the common prefix */ - for (i = homing; i < tree->entries.size; ++i) { - entry = git_array_get(tree->entries, i); - - if (homing_search_cmp(&ksearch, entry) < 0) - break; - - if (entry->filename_len == filename_len && - memcmp(filename, entry->filename, filename_len) == 0) { - if (at_pos) - *at_pos = i; - - return 0; - } - } - - /* If we haven't found our filename yet, look backwards - * too as long as we have entries with the same prefix */ - if (homing > 0) { - i = homing - 1; - - do { - entry = git_array_get(tree->entries, i); - - if (homing_search_cmp(&ksearch, entry) > 0) - break; - - if (entry->filename_len == filename_len && - memcmp(filename, entry->filename, filename_len) == 0) { - if (at_pos) - *at_pos = i; - - return 0; - } - } while (i-- > 0); - } - - /* The filename doesn't exist at all */ - return GIT_ENOTFOUND; -} - -void git_tree_entry_free(git_tree_entry *entry) -{ - if (entry == NULL) - return; - - git__free(entry); -} - -int git_tree_entry_dup(git_tree_entry **dest, const git_tree_entry *source) -{ - git_tree_entry *cpy; - - GIT_ASSERT_ARG(source); - - cpy = alloc_entry(source->filename, source->filename_len, source->oid); - if (cpy == NULL) - return -1; - - cpy->attr = source->attr; - - *dest = cpy; - return 0; -} - -void git_tree__free(void *_tree) -{ - git_tree *tree = _tree; - - git_odb_object_free(tree->odb_obj); - git_array_clear(tree->entries); - git__free(tree); -} - -git_filemode_t git_tree_entry_filemode(const git_tree_entry *entry) -{ - return normalize_filemode(entry->attr); -} - -git_filemode_t git_tree_entry_filemode_raw(const git_tree_entry *entry) -{ - return entry->attr; -} - -const char *git_tree_entry_name(const git_tree_entry *entry) -{ - GIT_ASSERT_ARG_WITH_RETVAL(entry, NULL); - return entry->filename; -} - -const git_oid *git_tree_entry_id(const git_tree_entry *entry) -{ - GIT_ASSERT_ARG_WITH_RETVAL(entry, NULL); - return entry->oid; -} - -git_object_t git_tree_entry_type(const git_tree_entry *entry) -{ - GIT_ASSERT_ARG_WITH_RETVAL(entry, GIT_OBJECT_INVALID); - - if (S_ISGITLINK(entry->attr)) - return GIT_OBJECT_COMMIT; - else if (S_ISDIR(entry->attr)) - return GIT_OBJECT_TREE; - else - return GIT_OBJECT_BLOB; -} - -int git_tree_entry_to_object( - git_object **object_out, - git_repository *repo, - const git_tree_entry *entry) -{ - GIT_ASSERT_ARG(entry); - GIT_ASSERT_ARG(object_out); - - return git_object_lookup(object_out, repo, entry->oid, GIT_OBJECT_ANY); -} - -static const git_tree_entry *entry_fromname( - const git_tree *tree, const char *name, size_t name_len) -{ - size_t idx; - - if (tree_key_search(&idx, tree, name, name_len) < 0) - return NULL; - - return git_array_get(tree->entries, idx); -} - -const git_tree_entry *git_tree_entry_byname( - const git_tree *tree, const char *filename) -{ - GIT_ASSERT_ARG_WITH_RETVAL(tree, NULL); - GIT_ASSERT_ARG_WITH_RETVAL(filename, NULL); - - return entry_fromname(tree, filename, strlen(filename)); -} - -const git_tree_entry *git_tree_entry_byindex( - const git_tree *tree, size_t idx) -{ - GIT_ASSERT_ARG_WITH_RETVAL(tree, NULL); - return git_array_get(tree->entries, idx); -} - -const git_tree_entry *git_tree_entry_byid( - const git_tree *tree, const git_oid *id) -{ - size_t i; - const git_tree_entry *e; - - GIT_ASSERT_ARG_WITH_RETVAL(tree, NULL); - - git_array_foreach(tree->entries, i, e) { - if (memcmp(&e->oid->id, &id->id, sizeof(id->id)) == 0) - return e; - } - - return NULL; -} - -size_t git_tree_entrycount(const git_tree *tree) -{ - GIT_ASSERT_ARG_WITH_RETVAL(tree, 0); - return tree->entries.size; -} - -size_t git_treebuilder_entrycount(git_treebuilder *bld) -{ - GIT_ASSERT_ARG_WITH_RETVAL(bld, 0); - - return git_strmap_size(bld->map); -} - -GIT_INLINE(void) set_error(const char *str, const char *path) -{ - if (path) - git_error_set(GIT_ERROR_TREE, "%s - %s", str, path); - else - git_error_set(GIT_ERROR_TREE, "%s", str); -} - -static int tree_error(const char *str, const char *path) -{ - set_error(str, path); - return -1; -} - -static int tree_parse_error(const char *str, const char *path) -{ - set_error(str, path); - return GIT_EINVALID; -} - -static int parse_mode(uint16_t *mode_out, const char *buffer, size_t buffer_len, const char **buffer_out) -{ - int32_t mode; - int error; - - if (!buffer_len || git__isspace(*buffer)) - return -1; - - if ((error = git__strntol32(&mode, buffer, buffer_len, buffer_out, 8)) < 0) - return error; - - if (mode < 0 || mode > UINT16_MAX) - return -1; - - *mode_out = mode; - - return 0; -} - -int git_tree__parse_raw(void *_tree, const char *data, size_t size) -{ - git_tree *tree = _tree; - const char *buffer; - const char *buffer_end; - - buffer = data; - buffer_end = buffer + size; - - tree->odb_obj = NULL; - git_array_init_to_size(tree->entries, DEFAULT_TREE_SIZE); - GIT_ERROR_CHECK_ARRAY(tree->entries); - - while (buffer < buffer_end) { - git_tree_entry *entry; - size_t filename_len; - const char *nul; - uint16_t attr; - - if (parse_mode(&attr, buffer, buffer_end - buffer, &buffer) < 0 || !buffer) - return tree_parse_error("failed to parse tree: can't parse filemode", NULL); - - if (buffer >= buffer_end || (*buffer++) != ' ') - return tree_parse_error("failed to parse tree: missing space after filemode", NULL); - - if ((nul = memchr(buffer, 0, buffer_end - buffer)) == NULL) - return tree_parse_error("failed to parse tree: object is corrupted", NULL); - - if ((filename_len = nul - buffer) == 0 || filename_len > UINT16_MAX) - return tree_parse_error("failed to parse tree: can't parse filename", NULL); - - if ((buffer_end - (nul + 1)) < GIT_OID_RAWSZ) - return tree_parse_error("failed to parse tree: can't parse OID", NULL); - - /* Allocate the entry */ - { - entry = git_array_alloc(tree->entries); - GIT_ERROR_CHECK_ALLOC(entry); - - entry->attr = attr; - entry->filename_len = (uint16_t)filename_len; - entry->filename = buffer; - entry->oid = (git_oid *) ((char *) buffer + filename_len + 1); - } - - buffer += filename_len + 1; - buffer += GIT_OID_RAWSZ; - } - - return 0; -} - -int git_tree__parse(void *_tree, git_odb_object *odb_obj) -{ - git_tree *tree = _tree; - const char *data = git_odb_object_data(odb_obj); - size_t size = git_odb_object_size(odb_obj); - int error; - - if ((error = git_tree__parse_raw(tree, data, size)) < 0 || - (error = git_odb_object_dup(&tree->odb_obj, odb_obj)) < 0) - return error; - - return error; -} - -static size_t find_next_dir(const char *dirname, git_index *index, size_t start) -{ - size_t dirlen, i, entries = git_index_entrycount(index); - - dirlen = strlen(dirname); - for (i = start; i < entries; ++i) { - const git_index_entry *entry = git_index_get_byindex(index, i); - if (strlen(entry->path) < dirlen || - memcmp(entry->path, dirname, dirlen) || - (dirlen > 0 && entry->path[dirlen] != '/')) { - break; - } - } - - return i; -} - -static git_object_t otype_from_mode(git_filemode_t filemode) -{ - switch (filemode) { - case GIT_FILEMODE_TREE: - return GIT_OBJECT_TREE; - case GIT_FILEMODE_COMMIT: - return GIT_OBJECT_COMMIT; - default: - return GIT_OBJECT_BLOB; - } -} - -static int check_entry(git_repository *repo, const char *filename, const git_oid *id, git_filemode_t filemode) -{ - if (!valid_filemode(filemode)) - return tree_error("failed to insert entry: invalid filemode for file", filename); - - if (!valid_entry_name(repo, filename)) - return tree_error("failed to insert entry: invalid name for a tree entry", filename); - - if (git_oid_is_zero(id)) - return tree_error("failed to insert entry: invalid null OID", filename); - - if (filemode != GIT_FILEMODE_COMMIT && - !git_object__is_valid(repo, id, otype_from_mode(filemode))) - return tree_error("failed to insert entry: invalid object specified", filename); - - return 0; -} - -static int git_treebuilder__write_with_buffer( - git_oid *oid, - git_treebuilder *bld, - git_str *buf) -{ - int error = 0; - size_t i, entrycount; - git_odb *odb; - git_tree_entry *entry; - git_vector entries = GIT_VECTOR_INIT; - - git_str_clear(buf); - - entrycount = git_strmap_size(bld->map); - if ((error = git_vector_init(&entries, entrycount, entry_sort_cmp)) < 0) - goto out; - - if (buf->asize == 0 && - (error = git_str_grow(buf, entrycount * 72)) < 0) - goto out; - - git_strmap_foreach_value(bld->map, entry, { - if ((error = git_vector_insert(&entries, entry)) < 0) - goto out; - }); - - git_vector_sort(&entries); - - for (i = 0; i < entries.length && !error; ++i) { - entry = git_vector_get(&entries, i); - - git_str_printf(buf, "%o ", entry->attr); - git_str_put(buf, entry->filename, entry->filename_len + 1); - git_str_put(buf, (char *)entry->oid->id, GIT_OID_RAWSZ); - - if (git_str_oom(buf)) { - error = -1; - goto out; - } - } - - if ((error = git_repository_odb__weakptr(&odb, bld->repo)) == 0) - error = git_odb_write(oid, odb, buf->ptr, buf->size, GIT_OBJECT_TREE); - -out: - git_vector_free(&entries); - - return error; -} - -static int append_entry( - git_treebuilder *bld, - const char *filename, - const git_oid *id, - git_filemode_t filemode, - bool validate) -{ - git_tree_entry *entry; - int error = 0; - - if (validate && ((error = check_entry(bld->repo, filename, id, filemode)) < 0)) - return error; - - entry = alloc_entry(filename, strlen(filename), id); - GIT_ERROR_CHECK_ALLOC(entry); - - entry->attr = (uint16_t)filemode; - - if ((error = git_strmap_set(bld->map, entry->filename, entry)) < 0) { - git_tree_entry_free(entry); - git_error_set(GIT_ERROR_TREE, "failed to append entry %s to the tree builder", filename); - return -1; - } - - return 0; -} - -static int write_tree( - git_oid *oid, - git_repository *repo, - git_index *index, - const char *dirname, - size_t start, - git_str *shared_buf) -{ - git_treebuilder *bld = NULL; - size_t i, entries = git_index_entrycount(index); - int error; - size_t dirname_len = strlen(dirname); - const git_tree_cache *cache; - - cache = git_tree_cache_get(index->tree, dirname); - if (cache != NULL && cache->entry_count >= 0){ - git_oid_cpy(oid, &cache->oid); - return (int)find_next_dir(dirname, index, start); - } - - if ((error = git_treebuilder_new(&bld, repo, NULL)) < 0 || bld == NULL) - return -1; - - /* - * This loop is unfortunate, but necessary. The index doesn't have - * any directories, so we need to handle that manually, and we - * need to keep track of the current position. - */ - for (i = start; i < entries; ++i) { - const git_index_entry *entry = git_index_get_byindex(index, i); - const char *filename, *next_slash; - - /* - * If we've left our (sub)tree, exit the loop and return. The - * first check is an early out (and security for the - * third). The second check is a simple prefix comparison. The - * third check catches situations where there is a directory - * win32/sys and a file win32mmap.c. Without it, the following - * code believes there is a file win32/mmap.c - */ - if (strlen(entry->path) < dirname_len || - memcmp(entry->path, dirname, dirname_len) || - (dirname_len > 0 && entry->path[dirname_len] != '/')) { - break; - } - - filename = entry->path + dirname_len; - if (*filename == '/') - filename++; - next_slash = strchr(filename, '/'); - if (next_slash) { - git_oid sub_oid; - int written; - char *subdir, *last_comp; - - subdir = git__strndup(entry->path, next_slash - entry->path); - GIT_ERROR_CHECK_ALLOC(subdir); - - /* Write out the subtree */ - written = write_tree(&sub_oid, repo, index, subdir, i, shared_buf); - if (written < 0) { - git__free(subdir); - goto on_error; - } else { - i = written - 1; /* -1 because of the loop increment */ - } - - /* - * We need to figure out what we want toinsert - * into this tree. If we're traversing - * deps/zlib/, then we only want to write - * 'zlib' into the tree. - */ - last_comp = strrchr(subdir, '/'); - if (last_comp) { - last_comp++; /* Get rid of the '/' */ - } else { - last_comp = subdir; - } - - error = append_entry(bld, last_comp, &sub_oid, S_IFDIR, true); - git__free(subdir); - if (error < 0) - goto on_error; - } else { - error = append_entry(bld, filename, &entry->id, entry->mode, true); - if (error < 0) - goto on_error; - } - } - - if (git_treebuilder__write_with_buffer(oid, bld, shared_buf) < 0) - goto on_error; - - git_treebuilder_free(bld); - return (int)i; - -on_error: - git_treebuilder_free(bld); - return -1; -} - -int git_tree__write_index( - git_oid *oid, git_index *index, git_repository *repo) -{ - int ret; - git_tree *tree; - git_str shared_buf = GIT_STR_INIT; - bool old_ignore_case = false; - - GIT_ASSERT_ARG(oid); - GIT_ASSERT_ARG(index); - GIT_ASSERT_ARG(repo); - - if (git_index_has_conflicts(index)) { - git_error_set(GIT_ERROR_INDEX, - "cannot create a tree from a not fully merged index."); - return GIT_EUNMERGED; - } - - if (index->tree != NULL && index->tree->entry_count >= 0) { - git_oid_cpy(oid, &index->tree->oid); - return 0; - } - - /* The tree cache didn't help us; we'll have to write - * out a tree. If the index is ignore_case, we must - * make it case-sensitive for the duration of the tree-write - * operation. */ - - if (index->ignore_case) { - old_ignore_case = true; - git_index__set_ignore_case(index, false); - } - - ret = write_tree(oid, repo, index, "", 0, &shared_buf); - git_str_dispose(&shared_buf); - - if (old_ignore_case) - git_index__set_ignore_case(index, true); - - index->tree = NULL; - - if (ret < 0) - return ret; - - git_pool_clear(&index->tree_pool); - - if ((ret = git_tree_lookup(&tree, repo, oid)) < 0) - return ret; - - /* Read the tree cache into the index */ - ret = git_tree_cache_read_tree(&index->tree, tree, &index->tree_pool); - git_tree_free(tree); - - return ret; -} - -int git_treebuilder_new( - git_treebuilder **builder_p, - git_repository *repo, - const git_tree *source) -{ - git_treebuilder *bld; - size_t i; - - GIT_ASSERT_ARG(builder_p); - GIT_ASSERT_ARG(repo); - - bld = git__calloc(1, sizeof(git_treebuilder)); - GIT_ERROR_CHECK_ALLOC(bld); - - bld->repo = repo; - - if (git_strmap_new(&bld->map) < 0) { - git__free(bld); - return -1; - } - - if (source != NULL) { - git_tree_entry *entry_src; - - git_array_foreach(source->entries, i, entry_src) { - if (append_entry( - bld, entry_src->filename, - entry_src->oid, - entry_src->attr, - false) < 0) - goto on_error; - } - } - - *builder_p = bld; - return 0; - -on_error: - git_treebuilder_free(bld); - return -1; -} - -int git_treebuilder_insert( - const git_tree_entry **entry_out, - git_treebuilder *bld, - const char *filename, - const git_oid *id, - git_filemode_t filemode) -{ - git_tree_entry *entry; - int error; - - GIT_ASSERT_ARG(bld); - GIT_ASSERT_ARG(id); - GIT_ASSERT_ARG(filename); - - if ((error = check_entry(bld->repo, filename, id, filemode)) < 0) - return error; - - if ((entry = git_strmap_get(bld->map, filename)) != NULL) { - git_oid_cpy((git_oid *) entry->oid, id); - } else { - entry = alloc_entry(filename, strlen(filename), id); - GIT_ERROR_CHECK_ALLOC(entry); - - if ((error = git_strmap_set(bld->map, entry->filename, entry)) < 0) { - git_tree_entry_free(entry); - git_error_set(GIT_ERROR_TREE, "failed to insert %s", filename); - return -1; - } - } - - entry->attr = filemode; - - if (entry_out) - *entry_out = entry; - - return 0; -} - -static git_tree_entry *treebuilder_get(git_treebuilder *bld, const char *filename) -{ - GIT_ASSERT_ARG_WITH_RETVAL(bld, NULL); - GIT_ASSERT_ARG_WITH_RETVAL(filename, NULL); - - return git_strmap_get(bld->map, filename); -} - -const git_tree_entry *git_treebuilder_get(git_treebuilder *bld, const char *filename) -{ - return treebuilder_get(bld, filename); -} - -int git_treebuilder_remove(git_treebuilder *bld, const char *filename) -{ - git_tree_entry *entry = treebuilder_get(bld, filename); - - if (entry == NULL) - return tree_error("failed to remove entry: file isn't in the tree", filename); - - git_strmap_delete(bld->map, filename); - git_tree_entry_free(entry); - - return 0; -} - -int git_treebuilder_write(git_oid *oid, git_treebuilder *bld) -{ - GIT_ASSERT_ARG(oid); - GIT_ASSERT_ARG(bld); - - return git_treebuilder__write_with_buffer(oid, bld, &bld->write_cache); -} - -int git_treebuilder_filter( - git_treebuilder *bld, - git_treebuilder_filter_cb filter, - void *payload) -{ - const char *filename; - git_tree_entry *entry; - - GIT_ASSERT_ARG(bld); - GIT_ASSERT_ARG(filter); - - git_strmap_foreach(bld->map, filename, entry, { - if (filter(entry, payload)) { - git_strmap_delete(bld->map, filename); - git_tree_entry_free(entry); - } - }); - - return 0; -} - -int git_treebuilder_clear(git_treebuilder *bld) -{ - git_tree_entry *e; - - GIT_ASSERT_ARG(bld); - - git_strmap_foreach_value(bld->map, e, git_tree_entry_free(e)); - git_strmap_clear(bld->map); - - return 0; -} - -void git_treebuilder_free(git_treebuilder *bld) -{ - if (bld == NULL) - return; - - git_str_dispose(&bld->write_cache); - git_treebuilder_clear(bld); - git_strmap_free(bld->map); - git__free(bld); -} - -static size_t subpath_len(const char *path) -{ - const char *slash_pos = strchr(path, '/'); - if (slash_pos == NULL) - return strlen(path); - - return slash_pos - path; -} - -int git_tree_entry_bypath( - git_tree_entry **entry_out, - const git_tree *root, - const char *path) -{ - int error = 0; - git_tree *subtree; - const git_tree_entry *entry; - size_t filename_len; - - /* Find how long is the current path component (i.e. - * the filename between two slashes */ - filename_len = subpath_len(path); - - if (filename_len == 0) { - git_error_set(GIT_ERROR_TREE, "invalid tree path given"); - return GIT_ENOTFOUND; - } - - entry = entry_fromname(root, path, filename_len); - - if (entry == NULL) { - git_error_set(GIT_ERROR_TREE, - "the path '%.*s' does not exist in the given tree", (int) filename_len, path); - return GIT_ENOTFOUND; - } - - switch (path[filename_len]) { - case '/': - /* If there are more components in the path... - * then this entry *must* be a tree */ - if (!git_tree_entry__is_tree(entry)) { - git_error_set(GIT_ERROR_TREE, - "the path '%.*s' exists but is not a tree", (int) filename_len, path); - return GIT_ENOTFOUND; - } - - /* If there's only a slash left in the path, we - * return the current entry; otherwise, we keep - * walking down the path */ - if (path[filename_len + 1] != '\0') - break; - /* fall through */ - case '\0': - /* If there are no more components in the path, return - * this entry */ - return git_tree_entry_dup(entry_out, entry); - } - - if (git_tree_lookup(&subtree, root->object.repo, entry->oid) < 0) - return -1; - - error = git_tree_entry_bypath( - entry_out, - subtree, - path + filename_len + 1 - ); - - git_tree_free(subtree); - return error; -} - -static int tree_walk( - const git_tree *tree, - git_treewalk_cb callback, - git_str *path, - void *payload, - bool preorder) -{ - int error = 0; - size_t i; - const git_tree_entry *entry; - - git_array_foreach(tree->entries, i, entry) { - if (preorder) { - error = callback(path->ptr, entry, payload); - if (error < 0) { /* negative value stops iteration */ - git_error_set_after_callback_function(error, "git_tree_walk"); - break; - } - if (error > 0) { /* positive value skips this entry */ - error = 0; - continue; - } - } - - if (git_tree_entry__is_tree(entry)) { - git_tree *subtree; - size_t path_len = git_str_len(path); - - error = git_tree_lookup(&subtree, tree->object.repo, entry->oid); - if (error < 0) - break; - - /* append the next entry to the path */ - git_str_puts(path, entry->filename); - git_str_putc(path, '/'); - - if (git_str_oom(path)) - error = -1; - else - error = tree_walk(subtree, callback, path, payload, preorder); - - git_tree_free(subtree); - if (error != 0) - break; - - git_str_truncate(path, path_len); - } - - if (!preorder) { - error = callback(path->ptr, entry, payload); - if (error < 0) { /* negative value stops iteration */ - git_error_set_after_callback_function(error, "git_tree_walk"); - break; - } - error = 0; - } - } - - return error; -} - -int git_tree_walk( - const git_tree *tree, - git_treewalk_mode mode, - git_treewalk_cb callback, - void *payload) -{ - int error = 0; - git_str root_path = GIT_STR_INIT; - - if (mode != GIT_TREEWALK_POST && mode != GIT_TREEWALK_PRE) { - git_error_set(GIT_ERROR_INVALID, "invalid walking mode for tree walk"); - return -1; - } - - error = tree_walk( - tree, callback, &root_path, payload, (mode == GIT_TREEWALK_PRE)); - - git_str_dispose(&root_path); - - return error; -} - -static int compare_entries(const void *_a, const void *_b) -{ - const git_tree_update *a = (git_tree_update *) _a; - const git_tree_update *b = (git_tree_update *) _b; - - return strcmp(a->path, b->path); -} - -static int on_dup_entry(void **old, void *new) -{ - GIT_UNUSED(old); GIT_UNUSED(new); - - git_error_set(GIT_ERROR_TREE, "duplicate entries given for update"); - return -1; -} - -/* - * We keep the previous tree and the new one at each level of the - * stack. When we leave a level we're done with that tree and we can - * write it out to the odb. - */ -typedef struct { - git_treebuilder *bld; - git_tree *tree; - char *name; -} tree_stack_entry; - -/** Count how many slashes (i.e. path components) there are in this string */ -GIT_INLINE(size_t) count_slashes(const char *path) -{ - size_t count = 0; - const char *slash; - - while ((slash = strchr(path, '/')) != NULL) { - count++; - path = slash + 1; - } - - return count; -} - -static bool next_component(git_str *out, const char *in) -{ - const char *slash = strchr(in, '/'); - - git_str_clear(out); - - if (slash) - git_str_put(out, in, slash - in); - - return !!slash; -} - -static int create_popped_tree(tree_stack_entry *current, tree_stack_entry *popped, git_str *component) -{ - int error; - git_oid new_tree; - - git_tree_free(popped->tree); - - /* If the tree would be empty, remove it from the one higher up */ - if (git_treebuilder_entrycount(popped->bld) == 0) { - git_treebuilder_free(popped->bld); - error = git_treebuilder_remove(current->bld, popped->name); - git__free(popped->name); - return error; - } - - error = git_treebuilder_write(&new_tree, popped->bld); - git_treebuilder_free(popped->bld); - - if (error < 0) { - git__free(popped->name); - return error; - } - - /* We've written out the tree, now we have to put the new value into its parent */ - git_str_clear(component); - git_str_puts(component, popped->name); - git__free(popped->name); - - GIT_ERROR_CHECK_ALLOC(component->ptr); - - /* Error out if this would create a D/F conflict in this update */ - if (current->tree) { - const git_tree_entry *to_replace; - to_replace = git_tree_entry_byname(current->tree, component->ptr); - if (to_replace && git_tree_entry_type(to_replace) != GIT_OBJECT_TREE) { - git_error_set(GIT_ERROR_TREE, "D/F conflict when updating tree"); - return -1; - } - } - - return git_treebuilder_insert(NULL, current->bld, component->ptr, &new_tree, GIT_FILEMODE_TREE); -} - -int git_tree_create_updated(git_oid *out, git_repository *repo, git_tree *baseline, size_t nupdates, const git_tree_update *updates) -{ - git_array_t(tree_stack_entry) stack = GIT_ARRAY_INIT; - tree_stack_entry *root_elem; - git_vector entries; - int error; - size_t i; - git_str component = GIT_STR_INIT; - - if ((error = git_vector_init(&entries, nupdates, compare_entries)) < 0) - return error; - - /* Sort the entries for treversal */ - for (i = 0 ; i < nupdates; i++) { - if ((error = git_vector_insert_sorted(&entries, (void *) &updates[i], on_dup_entry)) < 0) - goto cleanup; - } - - root_elem = git_array_alloc(stack); - GIT_ERROR_CHECK_ALLOC(root_elem); - memset(root_elem, 0, sizeof(*root_elem)); - - if (baseline && (error = git_tree_dup(&root_elem->tree, baseline)) < 0) - goto cleanup; - - if ((error = git_treebuilder_new(&root_elem->bld, repo, root_elem->tree)) < 0) - goto cleanup; - - for (i = 0; i < nupdates; i++) { - const git_tree_update *last_update = i == 0 ? NULL : git_vector_get(&entries, i-1); - const git_tree_update *update = git_vector_get(&entries, i); - size_t common_prefix = 0, steps_up, j; - const char *path; - - /* Figure out how much we need to change from the previous tree */ - if (last_update) - common_prefix = git_fs_path_common_dirlen(last_update->path, update->path); - - /* - * The entries are sorted, so when we find we're no - * longer in the same directory, we need to abandon - * the old tree (steps up) and dive down to the next - * one. - */ - steps_up = last_update == NULL ? 0 : count_slashes(&last_update->path[common_prefix]); - - for (j = 0; j < steps_up; j++) { - tree_stack_entry *current, *popped = git_array_pop(stack); - GIT_ASSERT(popped); - - current = git_array_last(stack); - GIT_ASSERT(current); - - if ((error = create_popped_tree(current, popped, &component)) < 0) - goto cleanup; - } - - /* Now that we've created the trees we popped from the stack, let's go back down */ - path = &update->path[common_prefix]; - while (next_component(&component, path)) { - tree_stack_entry *last, *new_entry; - const git_tree_entry *entry; - - last = git_array_last(stack); - entry = last->tree ? git_tree_entry_byname(last->tree, component.ptr) : NULL; - if (!entry) - entry = treebuilder_get(last->bld, component.ptr); - - if (entry && git_tree_entry_type(entry) != GIT_OBJECT_TREE) { - git_error_set(GIT_ERROR_TREE, "D/F conflict when updating tree"); - error = -1; - goto cleanup; - } - - new_entry = git_array_alloc(stack); - GIT_ERROR_CHECK_ALLOC(new_entry); - memset(new_entry, 0, sizeof(*new_entry)); - - new_entry->tree = NULL; - if (entry && (error = git_tree_lookup(&new_entry->tree, repo, git_tree_entry_id(entry))) < 0) - goto cleanup; - - if ((error = git_treebuilder_new(&new_entry->bld, repo, new_entry->tree)) < 0) - goto cleanup; - - new_entry->name = git__strdup(component.ptr); - GIT_ERROR_CHECK_ALLOC(new_entry->name); - - /* Get to the start of the next component */ - path += component.size + 1; - } - - /* After all that, we're finally at the place where we want to perform the update */ - switch (update->action) { - case GIT_TREE_UPDATE_UPSERT: - { - /* Make sure we're replacing something of the same type */ - tree_stack_entry *last = git_array_last(stack); - char *basename = git_fs_path_basename(update->path); - const git_tree_entry *e = git_treebuilder_get(last->bld, basename); - if (e && git_tree_entry_type(e) != git_object__type_from_filemode(update->filemode)) { - git__free(basename); - git_error_set(GIT_ERROR_TREE, "cannot replace '%s' with '%s' at '%s'", - git_object_type2string(git_tree_entry_type(e)), - git_object_type2string(git_object__type_from_filemode(update->filemode)), - update->path); - error = -1; - goto cleanup; - } - - error = git_treebuilder_insert(NULL, last->bld, basename, &update->id, update->filemode); - git__free(basename); - break; - } - case GIT_TREE_UPDATE_REMOVE: - { - tree_stack_entry *last = git_array_last(stack); - char *basename = git_fs_path_basename(update->path); - error = git_treebuilder_remove(last->bld, basename); - git__free(basename); - break; - } - default: - git_error_set(GIT_ERROR_TREE, "unknown action for update"); - error = -1; - goto cleanup; - } - - if (error < 0) - goto cleanup; - } - - /* We're done, go up the stack again and write out the tree */ - { - tree_stack_entry *current = NULL, *popped = NULL; - while ((popped = git_array_pop(stack)) != NULL) { - current = git_array_last(stack); - /* We've reached the top, current is the root tree */ - if (!current) - break; - - if ((error = create_popped_tree(current, popped, &component)) < 0) - goto cleanup; - } - - /* Write out the root tree */ - git__free(popped->name); - git_tree_free(popped->tree); - - error = git_treebuilder_write(out, popped->bld); - git_treebuilder_free(popped->bld); - if (error < 0) - goto cleanup; - } - -cleanup: - { - tree_stack_entry *e; - while ((e = git_array_pop(stack)) != NULL) { - git_treebuilder_free(e->bld); - git_tree_free(e->tree); - git__free(e->name); - } - } - - git_str_dispose(&component); - git_array_clear(stack); - git_vector_free(&entries); - return error; -} - -/* Deprecated Functions */ - -#ifndef GIT_DEPRECATE_HARD - -int git_treebuilder_write_with_buffer(git_oid *oid, git_treebuilder *bld, git_buf *buf) -{ - GIT_UNUSED(buf); - - return git_treebuilder_write(oid, bld); -} - -#endif diff --git a/vendor/libgit2/src/unix/map.c b/vendor/libgit2/src/unix/map.c deleted file mode 100644 index 23fcb786..00000000 --- a/vendor/libgit2/src/unix/map.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "common.h" - -#if !defined(GIT_WIN32) && !defined(NO_MMAP) - -#include "map.h" -#include -#include -#include - -int git__page_size(size_t *page_size) -{ - long sc_page_size = sysconf(_SC_PAGE_SIZE); - if (sc_page_size < 0) { - git_error_set(GIT_ERROR_OS, "can't determine system page size"); - return -1; - } - *page_size = (size_t) sc_page_size; - return 0; -} - -int git__mmap_alignment(size_t *alignment) -{ - return git__page_size(alignment); -} - -int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset) -{ - int mprot = PROT_READ; - int mflag = 0; - - GIT_MMAP_VALIDATE(out, len, prot, flags); - - out->data = NULL; - out->len = 0; - - if (prot & GIT_PROT_WRITE) - mprot |= PROT_WRITE; - - if ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED) - mflag = MAP_SHARED; - else if ((flags & GIT_MAP_TYPE) == GIT_MAP_PRIVATE) - mflag = MAP_PRIVATE; - else - mflag = MAP_SHARED; - - out->data = mmap(NULL, len, mprot, mflag, fd, offset); - - if (!out->data || out->data == MAP_FAILED) { - git_error_set(GIT_ERROR_OS, "failed to mmap. Could not write data"); - return -1; - } - - out->len = len; - - return 0; -} - -int p_munmap(git_map *map) -{ - GIT_ASSERT_ARG(map); - munmap(map->data, map->len); - map->data = NULL; - map->len = 0; - - return 0; -} - -#endif - diff --git a/vendor/libgit2/src/unix/posix.h b/vendor/libgit2/src/unix/posix.h deleted file mode 100644 index 49065e53..00000000 --- a/vendor/libgit2/src/unix/posix.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_unix_posix_h__ -#define INCLUDE_unix_posix_h__ - -#include "common.h" - -#include -#include -#include -#include -#include - -typedef int GIT_SOCKET; -#define INVALID_SOCKET -1 - -#define p_lseek(f,n,w) lseek(f, n, w) -#define p_fstat(f,b) fstat(f, b) -#define p_lstat(p,b) lstat(p,b) -#define p_stat(p,b) stat(p, b) - -#if defined(GIT_USE_STAT_MTIMESPEC) -# define st_atime_nsec st_atimespec.tv_nsec -# define st_mtime_nsec st_mtimespec.tv_nsec -# define st_ctime_nsec st_ctimespec.tv_nsec -#elif defined(GIT_USE_STAT_MTIM) -# define st_atime_nsec st_atim.tv_nsec -# define st_mtime_nsec st_mtim.tv_nsec -# define st_ctime_nsec st_ctim.tv_nsec -#elif !defined(GIT_USE_STAT_MTIME_NSEC) && defined(GIT_USE_NSEC) -# error GIT_USE_NSEC defined but unknown struct stat nanosecond type -#endif - -#define p_utimes(f, t) utimes(f, t) - -#define p_readlink(a, b, c) readlink(a, b, c) -#define p_symlink(o,n) symlink(o, n) -#define p_link(o,n) link(o, n) -#define p_unlink(p) unlink(p) -#define p_mkdir(p,m) mkdir(p, m) -extern char *p_realpath(const char *, char *); - -GIT_INLINE(int) p_fsync(int fd) -{ - p_fsync__cnt++; - return fsync(fd); -} - -#define p_recv(s,b,l,f) recv(s,b,l,f) -#define p_send(s,b,l,f) send(s,b,l,f) -#define p_inet_pton(a, b, c) inet_pton(a, b, c) - -#define p_strcasecmp(s1, s2) strcasecmp(s1, s2) -#define p_strncasecmp(s1, s2, c) strncasecmp(s1, s2, c) -#define p_vsnprintf(b, c, f, a) vsnprintf(b, c, f, a) -#define p_snprintf snprintf -#define p_chdir(p) chdir(p) -#define p_rmdir(p) rmdir(p) -#define p_access(p,m) access(p,m) -#define p_ftruncate(fd, sz) ftruncate(fd, sz) - -/* - * Pre-Android 5 did not implement a virtual filesystem atop FAT - * partitions for Unix permissions, which causes chmod to fail. However, - * Unix permissions have no effect on Android anyway as file permissions - * are not actually managed this way, so treating it as a no-op across - * all Android is safe. - */ -#ifdef __ANDROID__ -# define p_chmod(p,m) 0 -#else -# define p_chmod(p,m) chmod(p, m) -#endif - -/* see win32/posix.h for explanation about why this exists */ -#define p_lstat_posixly(p,b) lstat(p,b) - -#define p_localtime_r(c, r) localtime_r(c, r) -#define p_gmtime_r(c, r) gmtime_r(c, r) - -#define p_timeval timeval - -#ifdef GIT_USE_FUTIMENS -GIT_INLINE(int) p_futimes(int f, const struct p_timeval t[2]) -{ - struct timespec s[2]; - s[0].tv_sec = t[0].tv_sec; - s[0].tv_nsec = t[0].tv_usec * 1000; - s[1].tv_sec = t[1].tv_sec; - s[1].tv_nsec = t[1].tv_usec * 1000; - return futimens(f, s); -} -#else -# define p_futimes futimes -#endif - -#define p_pread(f, d, s, o) pread(f, d, s, o) -#define p_pwrite(f, d, s, o) pwrite(f, d, s, o) - -#endif diff --git a/vendor/libgit2/src/unix/realpath.c b/vendor/libgit2/src/unix/realpath.c deleted file mode 100644 index f1ca669f..00000000 --- a/vendor/libgit2/src/unix/realpath.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "common.h" - -#ifndef GIT_WIN32 - -#include -#include -#include -#include - -char *p_realpath(const char *pathname, char *resolved) -{ - char *ret; - if ((ret = realpath(pathname, resolved)) == NULL) - return NULL; - -#ifdef __OpenBSD__ - /* The OpenBSD realpath function behaves differently, - * figure out if the file exists */ - if (access(ret, F_OK) < 0) - ret = NULL; -#endif - return ret; -} - -#endif diff --git a/vendor/libgit2/src/utf8.c b/vendor/libgit2/src/utf8.c deleted file mode 100644 index 77065cb7..00000000 --- a/vendor/libgit2/src/utf8.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "utf8.h" - -#include "common.h" - -/* - * git_utf8_iterate is taken from the utf8proc project, - * http://www.public-software-group.org/utf8proc - * - * Copyright (c) 2009 Public Software Group e. V., Berlin, Germany - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the ""Software""), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -static const uint8_t utf8proc_utf8class[256] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static int utf8_charlen(const uint8_t *str, size_t str_len) -{ - uint8_t length; - size_t i; - - length = utf8proc_utf8class[str[0]]; - if (!length) - return -1; - - if (str_len > 0 && length > str_len) - return -1; - - for (i = 1; i < length; i++) { - if ((str[i] & 0xC0) != 0x80) - return -1; - } - - return (int)length; -} - -int git_utf8_iterate(uint32_t *out, const char *_str, size_t str_len) -{ - const uint8_t *str = (const uint8_t *)_str; - uint32_t uc = 0; - int length; - - *out = 0; - - if ((length = utf8_charlen(str, str_len)) < 0) - return -1; - - switch (length) { - case 1: - uc = str[0]; - break; - case 2: - uc = ((str[0] & 0x1F) << 6) + (str[1] & 0x3F); - if (uc < 0x80) uc = -1; - break; - case 3: - uc = ((str[0] & 0x0F) << 12) + ((str[1] & 0x3F) << 6) - + (str[2] & 0x3F); - if (uc < 0x800 || (uc >= 0xD800 && uc < 0xE000) || - (uc >= 0xFDD0 && uc < 0xFDF0)) uc = -1; - break; - case 4: - uc = ((str[0] & 0x07) << 18) + ((str[1] & 0x3F) << 12) - + ((str[2] & 0x3F) << 6) + (str[3] & 0x3F); - if (uc < 0x10000 || uc >= 0x110000) uc = -1; - break; - default: - return -1; - } - - if ((uc & 0xFFFF) >= 0xFFFE) - return -1; - - *out = uc; - return length; -} - -size_t git_utf8_char_length(const char *_str, size_t str_len) -{ - const uint8_t *str = (const uint8_t *)_str; - size_t offset = 0, count = 0; - - while (offset < str_len) { - int length = utf8_charlen(str + offset, str_len - offset); - - if (length < 0) - length = 1; - - offset += length; - count++; - } - - return count; -} - -size_t git_utf8_valid_buf_length(const char *_str, size_t str_len) -{ - const uint8_t *str = (const uint8_t *)_str; - size_t offset = 0; - - while (offset < str_len) { - int length = utf8_charlen(str + offset, str_len - offset); - - if (length < 0) - break; - - offset += length; - } - - return offset; -} diff --git a/vendor/libgit2/src/util/CMakeLists.txt b/vendor/libgit2/src/util/CMakeLists.txt new file mode 100644 index 00000000..ee35eb96 --- /dev/null +++ b/vendor/libgit2/src/util/CMakeLists.txt @@ -0,0 +1,79 @@ +# util: a shared library for common utility functions for libgit2 projects + +add_library(util OBJECT) +set_target_properties(util PROPERTIES C_STANDARD 90) +set_target_properties(util PROPERTIES C_EXTENSIONS OFF) + +configure_file(git2_features.h.in git2_features.h) + +set(UTIL_INCLUDES + "${PROJECT_BINARY_DIR}/src/util" + "${PROJECT_BINARY_DIR}/include" + "${PROJECT_SOURCE_DIR}/src/util" + "${PROJECT_SOURCE_DIR}/include") + +file(GLOB UTIL_SRC *.c *.h allocators/*.c allocators/*.h hash.h) +list(SORT UTIL_SRC) + +# +# Platform specific sources +# + +if(WIN32 AND NOT CYGWIN) + file(GLOB UTIL_SRC_OS win32/*.c win32/*.h) + list(SORT UTIL_SRC_OS) +elseif(NOT AMIGA) + file(GLOB UTIL_SRC_OS unix/*.c unix/*.h) + list(SORT UTIL_SRC_OS) +endif() + +# +# Hash backend selection +# + +if(USE_SHA1 STREQUAL "CollisionDetection") + file(GLOB UTIL_SRC_SHA1 hash/collisiondetect.* hash/sha1dc/*) + target_compile_definitions(util PRIVATE SHA1DC_NO_STANDARD_INCLUDES=1) + target_compile_definitions(util PRIVATE SHA1DC_CUSTOM_INCLUDE_SHA1_C=\"git2_util.h\") + target_compile_definitions(util PRIVATE SHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C=\"git2_util.h\") +elseif(USE_SHA1 STREQUAL "OpenSSL" OR USE_SHA1 STREQUAL "OpenSSL-Dynamic") + add_definitions(-DOPENSSL_API_COMPAT=0x10100000L) + file(GLOB UTIL_SRC_SHA1 hash/openssl.*) +elseif(USE_SHA1 STREQUAL "CommonCrypto") + file(GLOB UTIL_SRC_SHA1 hash/common_crypto.*) +elseif(USE_SHA1 STREQUAL "mbedTLS") + file(GLOB UTIL_SRC_SHA1 hash/mbedtls.*) +elseif(USE_SHA1 STREQUAL "Win32") + file(GLOB UTIL_SRC_SHA1 hash/win32.*) +else() + message(FATAL_ERROR "Asked for unknown SHA1 backend: ${USE_SHA1}") +endif() + +list(SORT UTIL_SRC_SHA1) + +if(USE_SHA256 STREQUAL "Builtin") + file(GLOB UTIL_SRC_SHA256 hash/builtin.* hash/rfc6234/*) +elseif(USE_SHA256 STREQUAL "OpenSSL" OR USE_SHA256 STREQUAL "OpenSSL-Dynamic") + add_definitions(-DOPENSSL_API_COMPAT=0x10100000L) + file(GLOB UTIL_SRC_SHA256 hash/openssl.*) +elseif(USE_SHA256 STREQUAL "CommonCrypto") + file(GLOB UTIL_SRC_SHA256 hash/common_crypto.*) +elseif(USE_SHA256 STREQUAL "mbedTLS") + file(GLOB UTIL_SRC_SHA256 hash/mbedtls.*) +elseif(USE_SHA256 STREQUAL "Win32") + file(GLOB UTIL_SRC_SHA256 hash/win32.*) +else() + message(FATAL_ERROR "Asked for unknown SHA256 backend: ${USE_SHA256}") +endif() + +list(SORT UTIL_SRC_SHA256) + +# +# Build the library +# + +target_sources(util PRIVATE ${UTIL_SRC} ${UTIL_SRC_OS} ${UTIL_SRC_SHA1} ${UTIL_SRC_SHA256}) +ide_split_sources(util) + +target_include_directories(util PRIVATE ${UTIL_INCLUDES} ${LIBGIT2_DEPENDENCY_INCLUDES} PUBLIC ${libgit2_SOURCE_DIR}/include) +target_include_directories(util SYSTEM PRIVATE ${LIBGIT2_SYSTEM_INCLUDES}) diff --git a/vendor/libgit2/src/util/alloc.c b/vendor/libgit2/src/util/alloc.c new file mode 100644 index 00000000..998b0aea --- /dev/null +++ b/vendor/libgit2/src/util/alloc.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "alloc.h" +#include "runtime.h" + +#include "allocators/stdalloc.h" +#include "allocators/debugalloc.h" +#include "allocators/failalloc.h" +#include "allocators/win32_leakcheck.h" + +/* Fail any allocation until git_libgit2_init is called. */ +git_allocator git__allocator = { + git_failalloc_malloc, + git_failalloc_realloc, + git_failalloc_free +}; + +void *git__calloc(size_t nelem, size_t elsize) +{ + size_t newsize; + void *ptr; + + if (GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize)) + return NULL; + + if ((ptr = git__malloc(newsize))) + memset(ptr, 0, newsize); + + return ptr; +} + +void *git__reallocarray(void *ptr, size_t nelem, size_t elsize) +{ + size_t newsize; + + if (GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize)) + return NULL; + + return git__realloc(ptr, newsize); +} + +void *git__mallocarray(size_t nelem, size_t elsize) +{ + return git__reallocarray(NULL, nelem, elsize); +} + +char *git__strdup(const char *str) +{ + size_t len = strlen(str) + 1; + void *ptr = git__malloc(len); + + if (ptr) + memcpy(ptr, str, len); + + return ptr; +} + +char *git__strndup(const char *str, size_t n) +{ + size_t len = p_strnlen(str, n); + char *ptr = git__malloc(len + 1); + + if (ptr) { + memcpy(ptr, str, len); + ptr[len] = '\0'; + } + + return ptr; +} + +char *git__substrdup(const char *str, size_t n) +{ + char *ptr = git__malloc(n + 1); + + if (ptr) { + memcpy(ptr, str, n); + ptr[n] = '\0'; + } + + return ptr; +} + +static int setup_default_allocator(void) +{ +#if defined(GIT_WIN32_LEAKCHECK) + return git_win32_leakcheck_init_allocator(&git__allocator); +#elif defined(GIT_DEBUG_STRICT_ALLOC) + return git_debugalloc_init_allocator(&git__allocator); +#else + return git_stdalloc_init_allocator(&git__allocator); +#endif +} + +int git_allocator_global_init(void) +{ + /* + * We don't want to overwrite any allocator which has been set + * before the init function is called. + */ + if (git__allocator.gmalloc != git_failalloc_malloc) + return 0; + + return setup_default_allocator(); +} + +int git_allocator_setup(git_allocator *allocator) +{ + if (!allocator) + return setup_default_allocator(); + + memcpy(&git__allocator, allocator, sizeof(*allocator)); + return 0; +} diff --git a/vendor/libgit2/src/util/alloc.h b/vendor/libgit2/src/util/alloc.h new file mode 100644 index 00000000..32b614b2 --- /dev/null +++ b/vendor/libgit2/src/util/alloc.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_alloc_h__ +#define INCLUDE_alloc_h__ + +#include "git2/sys/alloc.h" + +#include "git2_util.h" + +extern git_allocator git__allocator; + +GIT_INLINE(void *) git__malloc(size_t len) +{ + void *p = git__allocator.gmalloc(len, __FILE__, __LINE__); + + if (!p) + git_error_set_oom(); + + return p; +} + +GIT_INLINE(void *) git__realloc(void *ptr, size_t size) +{ + void *p = git__allocator.grealloc(ptr, size, __FILE__, __LINE__); + + if (!p) + git_error_set_oom(); + + return p; +} + +GIT_INLINE(void) git__free(void *ptr) +{ + git__allocator.gfree(ptr); +} + +extern void *git__calloc(size_t nelem, size_t elsize); +extern void *git__mallocarray(size_t nelem, size_t elsize); +extern void *git__reallocarray(void *ptr, size_t nelem, size_t elsize); + +extern char *git__strdup(const char *str); +extern char *git__strndup(const char *str, size_t n); +extern char *git__substrdup(const char *str, size_t n); + +/** + * This function is being called by our global setup routines to + * initialize the standard allocator. + */ +int git_allocator_global_init(void); + +/** + * Switch out libgit2's global memory allocator + * + * @param allocator The new allocator that should be used. All function pointers + * of it need to be set correctly. + * @return An error code or 0. + */ +int git_allocator_setup(git_allocator *allocator); + +#endif diff --git a/vendor/libgit2/src/util/allocators/debugalloc.c b/vendor/libgit2/src/util/allocators/debugalloc.c new file mode 100644 index 00000000..44022cd7 --- /dev/null +++ b/vendor/libgit2/src/util/allocators/debugalloc.c @@ -0,0 +1,73 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "debugalloc.h" + +static void *debugalloc__malloc(size_t len, const char *file, int line) +{ + unsigned char *ptr; + size_t total = len + sizeof(size_t); + + GIT_UNUSED(file); + GIT_UNUSED(line); + + if (!len || (ptr = malloc(total)) == NULL) + return NULL; + + memcpy(ptr, &len, sizeof(size_t)); + return ptr + sizeof(size_t); +} + +static void *debugalloc__realloc(void *_ptr, size_t len, const char *file, int line) +{ + unsigned char *ptr = _ptr, *newptr; + size_t original_len; + size_t total = len + sizeof(size_t); + + GIT_UNUSED(file); + GIT_UNUSED(line); + + if (!len && !ptr) + return NULL; + + if (!len) { + free(ptr - sizeof(size_t)); + return NULL; + } + + if ((newptr = malloc(total)) == NULL) + return NULL; + + if (ptr) { + memcpy(&original_len, ptr - sizeof(size_t), sizeof(size_t)); + memcpy(newptr + sizeof(size_t), ptr, min(len, original_len)); + + memset(ptr - sizeof(size_t), 0xfd, original_len + sizeof(size_t)); + free(ptr - sizeof(size_t)); + } + + memcpy(newptr, &len, sizeof(size_t)); + return newptr + sizeof(size_t); +} + +static void debugalloc__free(void *_ptr) +{ + unsigned char *ptr = _ptr; + + if (!ptr) + return; + + free(ptr - sizeof(size_t)); +} + +int git_debugalloc_init_allocator(git_allocator *allocator) +{ + allocator->gmalloc = debugalloc__malloc; + allocator->grealloc = debugalloc__realloc; + allocator->gfree = debugalloc__free; + return 0; +} diff --git a/vendor/libgit2/src/util/allocators/debugalloc.h b/vendor/libgit2/src/util/allocators/debugalloc.h new file mode 100644 index 00000000..dea0ca31 --- /dev/null +++ b/vendor/libgit2/src/util/allocators/debugalloc.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_allocators_debugalloc_h__ +#define INCLUDE_allocators_debugalloc_h__ + +#include "git2_util.h" + +#include "alloc.h" + +int git_debugalloc_init_allocator(git_allocator *allocator); + +#endif diff --git a/vendor/libgit2/src/util/allocators/failalloc.c b/vendor/libgit2/src/util/allocators/failalloc.c new file mode 100644 index 00000000..c1025e32 --- /dev/null +++ b/vendor/libgit2/src/util/allocators/failalloc.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "failalloc.h" + +void *git_failalloc_malloc(size_t len, const char *file, int line) +{ + GIT_UNUSED(len); + GIT_UNUSED(file); + GIT_UNUSED(line); + + return NULL; +} + +void *git_failalloc_realloc(void *ptr, size_t size, const char *file, int line) +{ + GIT_UNUSED(ptr); + GIT_UNUSED(size); + GIT_UNUSED(file); + GIT_UNUSED(line); + + return NULL; +} + +void git_failalloc_free(void *ptr) +{ + GIT_UNUSED(ptr); +} diff --git a/vendor/libgit2/src/util/allocators/failalloc.h b/vendor/libgit2/src/util/allocators/failalloc.h new file mode 100644 index 00000000..a3788e63 --- /dev/null +++ b/vendor/libgit2/src/util/allocators/failalloc.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_allocators_failalloc_h__ +#define INCLUDE_allocators_failalloc_h__ + +#include "git2_util.h" + +extern void *git_failalloc_malloc(size_t len, const char *file, int line); +extern void *git_failalloc_realloc(void *ptr, size_t size, const char *file, int line); +extern void git_failalloc_free(void *ptr); + +#endif diff --git a/vendor/libgit2/src/util/allocators/stdalloc.c b/vendor/libgit2/src/util/allocators/stdalloc.c new file mode 100644 index 00000000..65ec40fb --- /dev/null +++ b/vendor/libgit2/src/util/allocators/stdalloc.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "stdalloc.h" + +static void *stdalloc__malloc(size_t len, const char *file, int line) +{ + GIT_UNUSED(file); + GIT_UNUSED(line); + + return malloc(len); +} + +static void *stdalloc__realloc(void *ptr, size_t size, const char *file, int line) +{ + GIT_UNUSED(file); + GIT_UNUSED(line); + + return realloc(ptr, size); +} + +static void stdalloc__free(void *ptr) +{ + free(ptr); +} + +int git_stdalloc_init_allocator(git_allocator *allocator) +{ + allocator->gmalloc = stdalloc__malloc; + allocator->grealloc = stdalloc__realloc; + allocator->gfree = stdalloc__free; + return 0; +} diff --git a/vendor/libgit2/src/allocators/stdalloc.h b/vendor/libgit2/src/util/allocators/stdalloc.h similarity index 94% rename from vendor/libgit2/src/allocators/stdalloc.h rename to vendor/libgit2/src/util/allocators/stdalloc.h index fa23fe6e..955038cb 100644 --- a/vendor/libgit2/src/allocators/stdalloc.h +++ b/vendor/libgit2/src/util/allocators/stdalloc.h @@ -8,7 +8,7 @@ #ifndef INCLUDE_allocators_stdalloc_h__ #define INCLUDE_allocators_stdalloc_h__ -#include "common.h" +#include "git2_util.h" #include "alloc.h" diff --git a/vendor/libgit2/src/util/allocators/win32_leakcheck.c b/vendor/libgit2/src/util/allocators/win32_leakcheck.c new file mode 100644 index 00000000..cdf16d34 --- /dev/null +++ b/vendor/libgit2/src/util/allocators/win32_leakcheck.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "win32_leakcheck.h" + +#if defined(GIT_WIN32_LEAKCHECK) + +#include "win32/w32_leakcheck.h" + +static void *leakcheck_malloc(size_t len, const char *file, int line) +{ + void *ptr = _malloc_dbg(len, _NORMAL_BLOCK, git_win32_leakcheck_stacktrace(1,file), line); + if (!ptr) git_error_set_oom(); + return ptr; +} + +static void *leakcheck_realloc(void *ptr, size_t size, const char *file, int line) +{ + void *new_ptr = _realloc_dbg(ptr, size, _NORMAL_BLOCK, git_win32_leakcheck_stacktrace(1,file), line); + if (!new_ptr) git_error_set_oom(); + return new_ptr; +} + +static void leakcheck_free(void *ptr) +{ + free(ptr); +} + +int git_win32_leakcheck_init_allocator(git_allocator *allocator) +{ + allocator->gmalloc = leakcheck_malloc; + allocator->grealloc = leakcheck_realloc; + allocator->gfree = leakcheck_free; + return 0; +} + +#else + +int git_win32_leakcheck_init_allocator(git_allocator *allocator) +{ + GIT_UNUSED(allocator); + git_error_set(GIT_EINVALID, "leakcheck memory allocator not available"); + return -1; +} + +#endif diff --git a/vendor/libgit2/src/allocators/win32_leakcheck.h b/vendor/libgit2/src/util/allocators/win32_leakcheck.h similarity index 94% rename from vendor/libgit2/src/allocators/win32_leakcheck.h rename to vendor/libgit2/src/util/allocators/win32_leakcheck.h index 089690f9..edcd9307 100644 --- a/vendor/libgit2/src/allocators/win32_leakcheck.h +++ b/vendor/libgit2/src/util/allocators/win32_leakcheck.h @@ -8,7 +8,7 @@ #ifndef INCLUDE_allocators_win32_leakcheck_h #define INCLUDE_allocators_win32_leakcheck_h -#include "common.h" +#include "git2_util.h" #include "alloc.h" diff --git a/vendor/libgit2/src/array.h b/vendor/libgit2/src/util/array.h similarity index 76% rename from vendor/libgit2/src/array.h rename to vendor/libgit2/src/util/array.h index e97688b3..515e6e3a 100644 --- a/vendor/libgit2/src/array.h +++ b/vendor/libgit2/src/util/array.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_array_h__ #define INCLUDE_array_h__ -#include "common.h" +#include "git2_util.h" /* * Use this to declare a typesafe resizable array of items, a la: @@ -33,44 +33,48 @@ #define git_array_init_to_size(a, desired) \ do { (a).size = 0; (a).asize = desired; (a).ptr = git__calloc(desired, sizeof(*(a).ptr)); } while (0) +#define git_array_dispose(a) \ + do { git__free((a).ptr); } while (0) + #define git_array_clear(a) \ do { git__free((a).ptr); git_array_init(a); } while (0) #define GIT_ERROR_CHECK_ARRAY(a) GIT_ERROR_CHECK_ALLOC((a).ptr) - -typedef git_array_t(char) git_array_generic_t; - -/* use a generic array for growth, return 0 on success */ -GIT_INLINE(int) git_array_grow(void *_a, size_t item_size) +GIT_INLINE(void *) git_array__alloc(void *arr, size_t *size, size_t *asize, size_t item_size) { - volatile git_array_generic_t *a = _a; size_t new_size; - char *new_array; + void *new_array; + + if (*size < *asize) + return arr; - if (a->size < 8) { + if (*size < 8) { new_size = 8; } else { - if (GIT_MULTIPLY_SIZET_OVERFLOW(&new_size, a->size, 3)) + if (GIT_MULTIPLY_SIZET_OVERFLOW(&new_size, *asize, 3)) goto on_oom; + new_size /= 2; } - if ((new_array = git__reallocarray(a->ptr, new_size, item_size)) == NULL) + if ((new_array = git__reallocarray(arr, new_size, item_size)) == NULL) goto on_oom; - a->ptr = new_array; - a->asize = new_size; - return 0; + *asize = new_size; + + return new_array; on_oom: - git_array_clear(*a); - return -1; + git__free(arr); + *size = 0; + *asize = 0; + return NULL; } #define git_array_alloc(a) \ - (((a).size < (a).asize || git_array_grow(&(a), sizeof(*(a).ptr)) == 0) ? \ - &(a).ptr[(a).size++] : (void *)NULL) + (((a).size < (a).asize || \ + ((a).ptr = git_array__alloc((a).ptr, &(a).size, &(a).asize, sizeof(*(a).ptr))) != NULL) ? &(a).ptr[(a).size++] : (void *)NULL) #define git_array_last(a) ((a).size ? &(a).ptr[(a).size - 1] : (void *)NULL) @@ -85,12 +89,14 @@ GIT_INLINE(int) git_array_grow(void *_a, size_t item_size) #define git_array_foreach(a, i, element) \ for ((i) = 0; (i) < (a).size && ((element) = &(a).ptr[(i)]); (i)++) +typedef int (*git_array_compare_cb)(const void *, const void *); + GIT_INLINE(int) git_array__search( size_t *out, void *array_ptr, size_t item_size, size_t array_len, - int (*compare)(const void *, const void *), + git_array_compare_cb compare, const void *key) { size_t lim; diff --git a/vendor/libgit2/src/assert_safe.h b/vendor/libgit2/src/util/assert_safe.h similarity index 79% rename from vendor/libgit2/src/assert_safe.h rename to vendor/libgit2/src/util/assert_safe.h index 8c261100..cc0bac55 100644 --- a/vendor/libgit2/src/assert_safe.h +++ b/vendor/libgit2/src/util/assert_safe.h @@ -24,6 +24,8 @@ # define GIT_ASSERT_WITH_RETVAL(expr, fail) assert(expr) # define GIT_ASSERT_ARG_WITH_RETVAL(expr, fail) assert(expr) + +# define GIT_ASSERT_WITH_CLEANUP(expr, cleanup) assert(expr) #else /** Internal consistency check to stop the function. */ @@ -53,6 +55,20 @@ } \ } while(0) +/** + * Go to to the given label on assertion failures; useful when you have + * taken a lock or otherwise need to release a resource. + */ +# define GIT_ASSERT_WITH_CLEANUP(expr, cleanup) \ + GIT_ASSERT__WITH_CLEANUP(expr, GIT_ERROR_INTERNAL, "unrecoverable internal error", cleanup) + +# define GIT_ASSERT__WITH_CLEANUP(expr, code, msg, cleanup) do { \ + if (!(expr)) { \ + git_error_set(code, "%s: '%s'", msg, #expr); \ + cleanup; \ + } \ + } while(0) + #endif /* GIT_ASSERT_HARD */ #endif diff --git a/vendor/libgit2/src/bitvec.h b/vendor/libgit2/src/util/bitvec.h similarity index 100% rename from vendor/libgit2/src/bitvec.h rename to vendor/libgit2/src/util/bitvec.h diff --git a/vendor/libgit2/src/cc-compat.h b/vendor/libgit2/src/util/cc-compat.h similarity index 97% rename from vendor/libgit2/src/cc-compat.h rename to vendor/libgit2/src/util/cc-compat.h index a0971e86..ede6e9aa 100644 --- a/vendor/libgit2/src/cc-compat.h +++ b/vendor/libgit2/src/util/cc-compat.h @@ -43,8 +43,10 @@ __typeof__(x) _unused __attribute__((unused)); \ _unused = (x); \ } while (0) +# define GIT_UNUSED_ARG __attribute__((unused)) #else # define GIT_UNUSED(x) ((void)(x)) +# define GIT_UNUSED_ARG #endif /* Define the printf format specifier to use for size_t output */ diff --git a/vendor/libgit2/src/util/ctype_compat.h b/vendor/libgit2/src/util/ctype_compat.h new file mode 100644 index 00000000..462c8a17 --- /dev/null +++ b/vendor/libgit2/src/util/ctype_compat.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_ctype_compat_h__ +#define INCLUDE_ctype_compat_h__ + +/* + * The Microsoft C runtime (MSVCRT) may take a heavy lock on the + * locale in order to figure out how the `ctype` functions work. + * This is deeply slow. Provide our own to avoid that. + */ + +#ifdef GIT_WIN32 + +GIT_INLINE(int) git__tolower(int c) +{ + return (c >= 'A' && c <= 'Z') ? (c + 32) : c; +} + +GIT_INLINE(int) git__toupper(int c) +{ + return (c >= 'a' && c <= 'z') ? (c - 32) : c; +} + +GIT_INLINE(bool) git__isalpha(int c) +{ + return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')); +} + +GIT_INLINE(bool) git__isdigit(int c) +{ + return (c >= '0' && c <= '9'); +} + +GIT_INLINE(bool) git__isalnum(int c) +{ + return git__isalpha(c) || git__isdigit(c); +} + +GIT_INLINE(bool) git__isspace(int c) +{ + return (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r' || c == '\v'); +} + +GIT_INLINE(bool) git__isxdigit(int c) +{ + return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); +} + +GIT_INLINE(bool) git__isprint(int c) +{ + return (c >= ' ' && c <= '~'); +} + +#else +# define git__tolower(a) tolower((unsigned char)(a)) +# define git__toupper(a) toupper((unsigned char)(a)) + +# define git__isalpha(a) (!!isalpha((unsigned char)(a))) +# define git__isdigit(a) (!!isdigit((unsigned char)(a))) +# define git__isalnum(a) (!!isalnum((unsigned char)(a))) +# define git__isspace(a) (!!isspace((unsigned char)(a))) +# define git__isxdigit(a) (!!isxdigit((unsigned char)(a))) +# define git__isprint(a) (!!isprint((unsigned char)(a))) +#endif + +#endif diff --git a/vendor/libgit2/src/date.c b/vendor/libgit2/src/util/date.c similarity index 96% rename from vendor/libgit2/src/date.c rename to vendor/libgit2/src/util/date.c index 0e5ffc96..872cb81f 100644 --- a/vendor/libgit2/src/date.c +++ b/vendor/libgit2/src/util/date.c @@ -1,10 +1,11 @@ /* - * GIT - The information manager from hell + * Copyright (C) the libgit2 contributors. All rights reserved. * - * Copyright (C) Linus Torvalds, 2005 + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. */ -#include "common.h" +#include "git2_util.h" #ifndef GIT_WIN32 #include @@ -128,9 +129,9 @@ static size_t match_string(const char *date, const char *str) for (i = 0; *date; date++, str++, i++) { if (*date == *str) continue; - if (toupper(*date) == toupper(*str)) + if (git__toupper(*date) == git__toupper(*str)) continue; - if (!isalnum(*date)) + if (!git__isalnum(*date)) break; return 0; } @@ -142,7 +143,7 @@ static int skip_alpha(const char *date) int i = 0; do { i++; - } while (isalpha(date[i])); + } while (git__isalpha(date[i])); return i; } @@ -250,7 +251,7 @@ static size_t match_multi_number(unsigned long num, char c, const char *date, ch num2 = strtol(end+1, &end, 10); num3 = -1; - if (*end == c && isdigit(end[1])) + if (*end == c && git__isdigit(end[1])) num3 = strtol(end+1, &end, 10); /* Time? Date? */ @@ -348,7 +349,7 @@ static size_t match_digit(const char *date, struct tm *tm, int *offset, int *tm_ case '.': case '/': case '-': - if (isdigit(end[1])) { + if (git__isdigit(end[1])) { size_t match = match_multi_number(num, *end, date, end, tm); if (match) return match; @@ -363,7 +364,7 @@ static size_t match_digit(const char *date, struct tm *tm, int *offset, int *tm_ n = 0; do { n++; - } while (isdigit(date[n])); + } while (git__isdigit(date[n])); /* Four-digit year or a timezone? */ if (n == 4) { @@ -513,11 +514,11 @@ static int parse_date_basic(const char *date, git_time_t *timestamp, int *offset if (!c || c == '\n') break; - if (isalpha(c)) + if (git__isalpha(c)) match = match_alpha(date, &tm, offset); - else if (isdigit(c)) + else if (git__isdigit(c)) match = match_digit(date, &tm, offset, &tm_gmt); - else if ((c == '-' || c == '+') && isdigit(date[1])) + else if ((c == '-' || c == '+') && git__isdigit(date[1])) match = match_tz(date, offset); if (!match) { @@ -681,7 +682,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm const char *end = date; int i; - while (isalpha(*++end)) + while (git__isalpha(*++end)) /* scan to non-alpha */; for (i = 0; i < 12; i++) { @@ -782,7 +783,7 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num) case '.': case '/': case '-': - if (isdigit(end[1])) { + if (git__isdigit(end[1])) { size_t match = match_multi_number(number, *end, date, end, tm); if (match) return date + match; @@ -842,13 +843,13 @@ static git_time_t approxidate_str(const char *date, if (!c) break; date++; - if (isdigit(c)) { + if (git__isdigit(c)) { pending_number(&tm, &number); date = approxidate_digit(date-1, &tm, &number); touched = 1; continue; } - if (isalpha(c)) + if (git__isalpha(c)) date = approxidate_alpha(date-1, &tm, &now, &number, &touched); } pending_number(&tm, &number); diff --git a/vendor/libgit2/src/date.h b/vendor/libgit2/src/util/date.h similarity index 100% rename from vendor/libgit2/src/date.h rename to vendor/libgit2/src/util/date.h diff --git a/vendor/libgit2/src/util/errors.c b/vendor/libgit2/src/util/errors.c new file mode 100644 index 00000000..feed6a83 --- /dev/null +++ b/vendor/libgit2/src/util/errors.c @@ -0,0 +1,401 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "git2_util.h" + +#include "errors.h" +#include "posix.h" +#include "str.h" +#include "runtime.h" + +/* + * Some static error data that is used when we're out of memory, TLS + * has not been setup, or TLS has failed. + */ + +static git_error oom_error = { + "Out of memory", + GIT_ERROR_NOMEMORY +}; + +static git_error uninitialized_error = { + "library has not been initialized", + GIT_ERROR_INVALID +}; + +static git_error tlsdata_error = { + "thread-local data initialization failure", + GIT_ERROR_THREAD +}; + +static git_error no_error = { + "no error", + GIT_ERROR_NONE +}; + +#define IS_STATIC_ERROR(err) \ + ((err) == &oom_error || (err) == &uninitialized_error || \ + (err) == &tlsdata_error || (err) == &no_error) + +/* Per-thread error state (TLS) */ + +static git_tlsdata_key tls_key; + +struct error_threadstate { + /* The error message buffer. */ + git_str message; + + /* Error information, set by `git_error_set` and friends. */ + git_error error; + + /* + * The last error to occur; points to the error member of this + * struct _or_ a static error. + */ + git_error *last; +}; + +static void threadstate_dispose(struct error_threadstate *threadstate) +{ + if (!threadstate) + return; + + git_str_dispose(&threadstate->message); +} + +static struct error_threadstate *threadstate_get(void) +{ + struct error_threadstate *threadstate; + + if ((threadstate = git_tlsdata_get(tls_key)) != NULL) + return threadstate; + + /* + * Avoid git__malloc here, since if it fails, it sets an error + * message, which requires thread state, which would allocate + * here, which would fail, which would set an error message... + */ + + if ((threadstate = git__allocator.gmalloc( + sizeof(struct error_threadstate), + __FILE__, __LINE__)) == NULL) + return NULL; + + memset(threadstate, 0, sizeof(struct error_threadstate)); + + if (git_str_init(&threadstate->message, 0) < 0) { + git__allocator.gfree(threadstate); + return NULL; + } + + git_tlsdata_set(tls_key, threadstate); + return threadstate; +} + +static void GIT_SYSTEM_CALL threadstate_free(void *threadstate) +{ + threadstate_dispose(threadstate); + git__free(threadstate); +} + +static void git_error_global_shutdown(void) +{ + struct error_threadstate *threadstate; + + threadstate = git_tlsdata_get(tls_key); + git_tlsdata_set(tls_key, NULL); + + threadstate_dispose(threadstate); + git__free(threadstate); + + git_tlsdata_dispose(tls_key); +} + +int git_error_global_init(void) +{ + if (git_tlsdata_init(&tls_key, &threadstate_free) != 0) + return -1; + + return git_runtime_shutdown_register(git_error_global_shutdown); +} + +static void set_error_from_buffer(int error_class) +{ + struct error_threadstate *threadstate = threadstate_get(); + git_error *error; + git_str *buf; + + if (!threadstate) + return; + + error = &threadstate->error; + buf = &threadstate->message; + + error->message = buf->ptr; + error->klass = error_class; + + threadstate->last = error; +} + +static void set_error(int error_class, char *string) +{ + struct error_threadstate *threadstate = threadstate_get(); + git_str *buf; + + if (!threadstate) + return; + + buf = &threadstate->message; + + git_str_clear(buf); + + if (string) + git_str_puts(buf, string); + + if (!git_str_oom(buf)) + set_error_from_buffer(error_class); +} + +void git_error_set_oom(void) +{ + struct error_threadstate *threadstate = threadstate_get(); + + if (!threadstate) + return; + + threadstate->last = &oom_error; +} + +void git_error_set(int error_class, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + git_error_vset(error_class, fmt, ap); + va_end(ap); +} + +void git_error_vset(int error_class, const char *fmt, va_list ap) +{ +#ifdef GIT_WIN32 + DWORD win32_error_code = (error_class == GIT_ERROR_OS) ? GetLastError() : 0; +#endif + + struct error_threadstate *threadstate = threadstate_get(); + int error_code = (error_class == GIT_ERROR_OS) ? errno : 0; + git_str *buf; + + if (!threadstate) + return; + + buf = &threadstate->message; + + git_str_clear(buf); + + if (fmt) { + git_str_vprintf(buf, fmt, ap); + if (error_class == GIT_ERROR_OS) + git_str_PUTS(buf, ": "); + } + + if (error_class == GIT_ERROR_OS) { +#ifdef GIT_WIN32 + char *win32_error = git_win32_get_error_message(win32_error_code); + if (win32_error) { + git_str_puts(buf, win32_error); + git__free(win32_error); + + SetLastError(0); + } + else +#endif + if (error_code) + git_str_puts(buf, strerror(error_code)); + + if (error_code) + errno = 0; + } + + if (!git_str_oom(buf)) + set_error_from_buffer(error_class); +} + +int git_error_set_str(int error_class, const char *string) +{ + struct error_threadstate *threadstate = threadstate_get(); + git_str *buf; + + GIT_ASSERT_ARG(string); + + if (!threadstate) + return -1; + + buf = &threadstate->message; + + git_str_clear(buf); + git_str_puts(buf, string); + + if (git_str_oom(buf)) + return -1; + + set_error_from_buffer(error_class); + return 0; +} + +void git_error_clear(void) +{ + struct error_threadstate *threadstate = threadstate_get(); + + if (!threadstate) + return; + + if (threadstate->last != NULL) { + set_error(0, NULL); + threadstate->last = NULL; + } + + errno = 0; +#ifdef GIT_WIN32 + SetLastError(0); +#endif +} + +bool git_error_exists(void) +{ + struct error_threadstate *threadstate; + + if ((threadstate = threadstate_get()) == NULL) + return true; + + return threadstate->last != NULL; +} + +const git_error *git_error_last(void) +{ + struct error_threadstate *threadstate; + + /* If the library is not initialized, return a static error. */ + if (!git_runtime_init_count()) + return &uninitialized_error; + + if ((threadstate = threadstate_get()) == NULL) + return &tlsdata_error; + + if (!threadstate->last) + return &no_error; + + return threadstate->last; +} + +int git_error_save(git_error **out) +{ + struct error_threadstate *threadstate = threadstate_get(); + git_error *error, *dup; + + if (!threadstate) { + *out = &tlsdata_error; + return -1; + } + + error = threadstate->last; + + if (!error || error == &no_error) { + *out = &no_error; + return 0; + } else if (IS_STATIC_ERROR(error)) { + *out = error; + return 0; + } + + if ((dup = git__malloc(sizeof(git_error))) == NULL) { + *out = &oom_error; + return -1; + } + + dup->klass = error->klass; + dup->message = git__strdup(error->message); + + if (!dup->message) { + *out = &oom_error; + return -1; + } + + *out = dup; + return 0; +} + +int git_error_restore(git_error *error) +{ + struct error_threadstate *threadstate = threadstate_get(); + + GIT_ASSERT_ARG(error); + + if (IS_STATIC_ERROR(error) && threadstate) + threadstate->last = error; + else + set_error(error->klass, error->message); + + git_error_free(error); + return 0; +} + +void git_error_free(git_error *error) +{ + if (!error) + return; + + if (IS_STATIC_ERROR(error)) + return; + + git__free(error->message); + git__free(error); +} + +int git_error_system_last(void) +{ +#ifdef GIT_WIN32 + return GetLastError(); +#else + return errno; +#endif +} + +void git_error_system_set(int code) +{ +#ifdef GIT_WIN32 + SetLastError(code); +#else + errno = code; +#endif +} + +/* Deprecated error values and functions */ + +#ifndef GIT_DEPRECATE_HARD + +#include "git2/deprecated.h" + +const git_error *giterr_last(void) +{ + return git_error_last(); +} + +void giterr_clear(void) +{ + git_error_clear(); +} + +void giterr_set_str(int error_class, const char *string) +{ + git_error_set_str(error_class, string); +} + +void giterr_set_oom(void) +{ + git_error_set_oom(); +} +#endif diff --git a/vendor/libgit2/src/util/errors.h b/vendor/libgit2/src/util/errors.h new file mode 100644 index 00000000..8d587755 --- /dev/null +++ b/vendor/libgit2/src/util/errors.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_errors_h__ +#define INCLUDE_errors_h__ + +#include "git2_util.h" +#include "git2/sys/errors.h" + +/* Initialize the error thread-state. */ +int git_error_global_init(void); + +/* + * `vprintf`-style formatting for the error message for this thread. + */ +void git_error_vset(int error_class, const char *fmt, va_list ap); + +/** + * Determines whether an error exists. + */ +bool git_error_exists(void); + +/** + * Set error message for user callback if needed. + * + * If the error code in non-zero and no error message is set, this + * sets a generic error message. + * + * @return This always returns the `error_code` parameter. + */ +GIT_INLINE(int) git_error_set_after_callback_function( + int error_code, const char *action) +{ + if (error_code) { + if (!git_error_exists()) + git_error_set(GIT_ERROR_CALLBACK, + "%s callback returned %d", action, error_code); + } + return error_code; +} + +#ifdef GIT_WIN32 +#define git_error_set_after_callback(code) \ + git_error_set_after_callback_function((code), __FUNCTION__) +#else +#define git_error_set_after_callback(code) \ + git_error_set_after_callback_function((code), __func__) +#endif + +/** + * Gets the system error code for this thread. + */ +int git_error_system_last(void); + +/** + * Sets the system error code for this thread. + */ +void git_error_system_set(int code); + +/** + * Capture current error state to restore later, returning error code. + * If `error_code` is zero, this does not clear the current error state. + * You must either restore this error state, or free it. + * + * This function returns 0 on success, or -1 on failure. If the function + * fails, the `out` structure is set to the failure error message and + * the normal system error message is not updated. + */ +extern int git_error_save(git_error **out); + +/** + * Restore thread error state to the given value. The given value is + * freed and `git_error_free` need not be called on it. + */ +extern int git_error_restore(git_error *error); + +/** Free an error state. */ +extern void git_error_free(git_error *error); + +#endif diff --git a/vendor/libgit2/src/util/filebuf.c b/vendor/libgit2/src/util/filebuf.c new file mode 100644 index 00000000..7afb76b8 --- /dev/null +++ b/vendor/libgit2/src/util/filebuf.c @@ -0,0 +1,600 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "filebuf.h" + +#include "futils.h" + +static const size_t WRITE_BUFFER_SIZE = (4096 * 2); + +enum buferr_t { + BUFERR_OK = 0, + BUFERR_WRITE, + BUFERR_ZLIB, + BUFERR_MEM +}; + +#define ENSURE_BUF_OK(buf) if ((buf)->last_error != BUFERR_OK) { return -1; } + +static int verify_last_error(git_filebuf *file) +{ + switch (file->last_error) { + case BUFERR_WRITE: + git_error_set(GIT_ERROR_OS, "failed to write out file"); + return -1; + + case BUFERR_MEM: + git_error_set_oom(); + return -1; + + case BUFERR_ZLIB: + git_error_set(GIT_ERROR_ZLIB, + "Buffer error when writing out ZLib data"); + return -1; + + default: + return 0; + } +} + +static int lock_file(git_filebuf *file, int flags, mode_t mode) +{ + if (git_fs_path_exists(file->path_lock) == true) { + git_error_clear(); /* actual OS error code just confuses */ + git_error_set(GIT_ERROR_OS, + "failed to lock file '%s' for writing", file->path_lock); + return GIT_ELOCKED; + } + + /* create path to the file buffer is required */ + if (flags & GIT_FILEBUF_CREATE_LEADING_DIRS) { + /* XXX: Should dirmode here be configurable? Or is 0777 always fine? */ + file->fd = git_futils_creat_locked_withpath(file->path_lock, 0777, mode); + } else { + file->fd = git_futils_creat_locked(file->path_lock, mode); + } + + if (file->fd < 0) + return file->fd; + + file->fd_is_open = true; + + if ((flags & GIT_FILEBUF_APPEND) && git_fs_path_exists(file->path_original) == true) { + git_file source; + char buffer[GIT_BUFSIZE_FILEIO]; + ssize_t read_bytes; + int error = 0; + + source = p_open(file->path_original, O_RDONLY); + if (source < 0) { + git_error_set(GIT_ERROR_OS, + "failed to open file '%s' for reading", + file->path_original); + return -1; + } + + while ((read_bytes = p_read(source, buffer, sizeof(buffer))) > 0) { + if ((error = p_write(file->fd, buffer, read_bytes)) < 0) + break; + if (file->compute_digest) + git_hash_update(&file->digest, buffer, read_bytes); + } + + p_close(source); + + if (read_bytes < 0) { + git_error_set(GIT_ERROR_OS, "failed to read file '%s'", file->path_original); + return -1; + } else if (error < 0) { + git_error_set(GIT_ERROR_OS, "failed to write file '%s'", file->path_lock); + return -1; + } + } + + return 0; +} + +void git_filebuf_cleanup(git_filebuf *file) +{ + if (file->fd_is_open && file->fd >= 0) + p_close(file->fd); + + if (file->created_lock && !file->did_rename && file->path_lock && git_fs_path_exists(file->path_lock)) + p_unlink(file->path_lock); + + if (file->compute_digest) { + git_hash_ctx_cleanup(&file->digest); + file->compute_digest = 0; + } + + if (file->buffer) + git__free(file->buffer); + + /* use the presence of z_buf to decide if we need to deflateEnd */ + if (file->z_buf) { + git__free(file->z_buf); + deflateEnd(&file->zs); + } + + if (file->path_original) + git__free(file->path_original); + if (file->path_lock) + git__free(file->path_lock); + + memset(file, 0x0, sizeof(git_filebuf)); + file->fd = -1; +} + +GIT_INLINE(int) flush_buffer(git_filebuf *file) +{ + int result = file->write(file, file->buffer, file->buf_pos); + file->buf_pos = 0; + return result; +} + +int git_filebuf_flush(git_filebuf *file) +{ + return flush_buffer(file); +} + +static int write_normal(git_filebuf *file, void *source, size_t len) +{ + if (len > 0) { + if (p_write(file->fd, (void *)source, len) < 0) { + file->last_error = BUFERR_WRITE; + return -1; + } + + if (file->compute_digest) + git_hash_update(&file->digest, source, len); + } + + return 0; +} + +static int write_deflate(git_filebuf *file, void *source, size_t len) +{ + z_stream *zs = &file->zs; + + if (len > 0 || file->flush_mode == Z_FINISH) { + zs->next_in = source; + zs->avail_in = (uInt)len; + + do { + size_t have; + + zs->next_out = file->z_buf; + zs->avail_out = (uInt)file->buf_size; + + if (deflate(zs, file->flush_mode) == Z_STREAM_ERROR) { + file->last_error = BUFERR_ZLIB; + return -1; + } + + have = file->buf_size - (size_t)zs->avail_out; + + if (p_write(file->fd, file->z_buf, have) < 0) { + file->last_error = BUFERR_WRITE; + return -1; + } + + } while (zs->avail_out == 0); + + GIT_ASSERT(zs->avail_in == 0); + + if (file->compute_digest) + git_hash_update(&file->digest, source, len); + } + + return 0; +} + +#define MAX_SYMLINK_DEPTH 5 + +static int resolve_symlink(git_str *out, const char *path) +{ + int i, error, root; + ssize_t ret; + struct stat st; + git_str curpath = GIT_STR_INIT, target = GIT_STR_INIT; + + if ((error = git_str_grow(&target, GIT_PATH_MAX + 1)) < 0 || + (error = git_str_puts(&curpath, path)) < 0) + return error; + + for (i = 0; i < MAX_SYMLINK_DEPTH; i++) { + error = p_lstat(curpath.ptr, &st); + if (error < 0 && errno == ENOENT) { + error = git_str_puts(out, curpath.ptr); + goto cleanup; + } + + if (error < 0) { + git_error_set(GIT_ERROR_OS, "failed to stat '%s'", curpath.ptr); + error = -1; + goto cleanup; + } + + if (!S_ISLNK(st.st_mode)) { + error = git_str_puts(out, curpath.ptr); + goto cleanup; + } + + ret = p_readlink(curpath.ptr, target.ptr, GIT_PATH_MAX); + if (ret < 0) { + git_error_set(GIT_ERROR_OS, "failed to read symlink '%s'", curpath.ptr); + error = -1; + goto cleanup; + } + + if (ret == GIT_PATH_MAX) { + git_error_set(GIT_ERROR_INVALID, "symlink target too long"); + error = -1; + goto cleanup; + } + + /* readlink(2) won't NUL-terminate for us */ + target.ptr[ret] = '\0'; + target.size = ret; + + root = git_fs_path_root(target.ptr); + if (root >= 0) { + if ((error = git_str_sets(&curpath, target.ptr)) < 0) + goto cleanup; + } else { + git_str dir = GIT_STR_INIT; + + if ((error = git_fs_path_dirname_r(&dir, curpath.ptr)) < 0) + goto cleanup; + + git_str_swap(&curpath, &dir); + git_str_dispose(&dir); + + if ((error = git_fs_path_apply_relative(&curpath, target.ptr)) < 0) + goto cleanup; + } + } + + git_error_set(GIT_ERROR_INVALID, "maximum symlink depth reached"); + error = -1; + +cleanup: + git_str_dispose(&curpath); + git_str_dispose(&target); + return error; +} + +int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode) +{ + return git_filebuf_open_withsize(file, path, flags, mode, WRITE_BUFFER_SIZE); +} + +int git_filebuf_open_withsize(git_filebuf *file, const char *path, int flags, mode_t mode, size_t size) +{ + int compression, error = -1; + size_t path_len, alloc_len; + + GIT_ASSERT_ARG(file); + GIT_ASSERT_ARG(path); + GIT_ASSERT(file->buffer == NULL); + + memset(file, 0x0, sizeof(git_filebuf)); + + if (flags & GIT_FILEBUF_DO_NOT_BUFFER) + file->do_not_buffer = true; + + if (flags & GIT_FILEBUF_FSYNC) + file->do_fsync = true; + + file->buf_size = size; + file->buf_pos = 0; + file->fd = -1; + file->last_error = BUFERR_OK; + + /* Allocate the main cache buffer */ + if (!file->do_not_buffer) { + file->buffer = git__malloc(file->buf_size); + GIT_ERROR_CHECK_ALLOC(file->buffer); + } + + /* If we are hashing on-write, allocate a new hash context */ + if (flags & GIT_FILEBUF_HASH_SHA1) { + file->compute_digest = 1; + + if (git_hash_ctx_init(&file->digest, GIT_HASH_ALGORITHM_SHA1) < 0) + goto cleanup; + } else if (flags & GIT_FILEBUF_HASH_SHA256) { + file->compute_digest = 1; + + if (git_hash_ctx_init(&file->digest, GIT_HASH_ALGORITHM_SHA256) < 0) + goto cleanup; + } + + compression = flags >> GIT_FILEBUF_DEFLATE_SHIFT; + + /* If we are deflating on-write, */ + if (compression != 0) { + /* Initialize the ZLib stream */ + if (deflateInit(&file->zs, compression) != Z_OK) { + git_error_set(GIT_ERROR_ZLIB, "failed to initialize zlib"); + goto cleanup; + } + + /* Allocate the Zlib cache buffer */ + file->z_buf = git__malloc(file->buf_size); + GIT_ERROR_CHECK_ALLOC(file->z_buf); + + /* Never flush */ + file->flush_mode = Z_NO_FLUSH; + file->write = &write_deflate; + } else { + file->write = &write_normal; + } + + /* If we are writing to a temp file */ + if (flags & GIT_FILEBUF_TEMPORARY) { + git_str tmp_path = GIT_STR_INIT; + + /* Open the file as temporary for locking */ + file->fd = git_futils_mktmp(&tmp_path, path, mode); + + if (file->fd < 0) { + git_str_dispose(&tmp_path); + goto cleanup; + } + file->fd_is_open = true; + file->created_lock = true; + + /* No original path */ + file->path_original = NULL; + file->path_lock = git_str_detach(&tmp_path); + GIT_ERROR_CHECK_ALLOC(file->path_lock); + } else { + git_str resolved_path = GIT_STR_INIT; + + if ((error = resolve_symlink(&resolved_path, path)) < 0) + goto cleanup; + + /* Save the original path of the file */ + path_len = resolved_path.size; + file->path_original = git_str_detach(&resolved_path); + + /* create the locking path by appending ".lock" to the original */ + GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, path_len, GIT_FILELOCK_EXTLENGTH); + file->path_lock = git__malloc(alloc_len); + GIT_ERROR_CHECK_ALLOC(file->path_lock); + + memcpy(file->path_lock, file->path_original, path_len); + memcpy(file->path_lock + path_len, GIT_FILELOCK_EXTENSION, GIT_FILELOCK_EXTLENGTH); + + if (git_fs_path_isdir(file->path_original)) { + git_error_set(GIT_ERROR_FILESYSTEM, "path '%s' is a directory", file->path_original); + error = GIT_EDIRECTORY; + goto cleanup; + } + + /* open the file for locking */ + if ((error = lock_file(file, flags, mode)) < 0) + goto cleanup; + + file->created_lock = true; + } + + return 0; + +cleanup: + git_filebuf_cleanup(file); + return error; +} + +int git_filebuf_hash(unsigned char *out, git_filebuf *file) +{ + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(file); + GIT_ASSERT_ARG(file->compute_digest); + + flush_buffer(file); + + if (verify_last_error(file) < 0) + return -1; + + git_hash_final(out, &file->digest); + git_hash_ctx_cleanup(&file->digest); + file->compute_digest = 0; + + return 0; +} + +int git_filebuf_commit_at(git_filebuf *file, const char *path) +{ + git__free(file->path_original); + file->path_original = git__strdup(path); + GIT_ERROR_CHECK_ALLOC(file->path_original); + + return git_filebuf_commit(file); +} + +int git_filebuf_commit(git_filebuf *file) +{ + /* temporary files cannot be committed */ + GIT_ASSERT_ARG(file); + GIT_ASSERT(file->path_original); + + file->flush_mode = Z_FINISH; + flush_buffer(file); + + if (verify_last_error(file) < 0) + goto on_error; + + file->fd_is_open = false; + + if (file->do_fsync && p_fsync(file->fd) < 0) { + git_error_set(GIT_ERROR_OS, "failed to fsync '%s'", file->path_lock); + goto on_error; + } + + if (p_close(file->fd) < 0) { + git_error_set(GIT_ERROR_OS, "failed to close file at '%s'", file->path_lock); + goto on_error; + } + + file->fd = -1; + + if (p_rename(file->path_lock, file->path_original) < 0) { + git_error_set(GIT_ERROR_OS, "failed to rename lockfile to '%s'", file->path_original); + goto on_error; + } + + if (file->do_fsync && git_futils_fsync_parent(file->path_original) < 0) + goto on_error; + + file->did_rename = true; + + git_filebuf_cleanup(file); + return 0; + +on_error: + git_filebuf_cleanup(file); + return -1; +} + +GIT_INLINE(void) add_to_cache(git_filebuf *file, const void *buf, size_t len) +{ + memcpy(file->buffer + file->buf_pos, buf, len); + file->buf_pos += len; +} + +int git_filebuf_write(git_filebuf *file, const void *buff, size_t len) +{ + const unsigned char *buf = buff; + + ENSURE_BUF_OK(file); + + if (file->do_not_buffer) + return file->write(file, (void *)buff, len); + + for (;;) { + size_t space_left = file->buf_size - file->buf_pos; + + /* cache if it's small */ + if (space_left > len) { + add_to_cache(file, buf, len); + return 0; + } + + add_to_cache(file, buf, space_left); + if (flush_buffer(file) < 0) + return -1; + + len -= space_left; + buf += space_left; + } +} + +int git_filebuf_reserve(git_filebuf *file, void **buffer, size_t len) +{ + size_t space_left = file->buf_size - file->buf_pos; + + *buffer = NULL; + + ENSURE_BUF_OK(file); + + if (len > file->buf_size) { + file->last_error = BUFERR_MEM; + return -1; + } + + if (space_left <= len) { + if (flush_buffer(file) < 0) + return -1; + } + + *buffer = (file->buffer + file->buf_pos); + file->buf_pos += len; + + return 0; +} + +int git_filebuf_printf(git_filebuf *file, const char *format, ...) +{ + va_list arglist; + size_t space_left, len, alloclen; + int written, res; + char *tmp_buffer; + + ENSURE_BUF_OK(file); + + space_left = file->buf_size - file->buf_pos; + + do { + va_start(arglist, format); + written = p_vsnprintf((char *)file->buffer + file->buf_pos, space_left, format, arglist); + va_end(arglist); + + if (written < 0) { + file->last_error = BUFERR_MEM; + return -1; + } + + len = written; + if (len + 1 <= space_left) { + file->buf_pos += len; + return 0; + } + + if (flush_buffer(file) < 0) + return -1; + + space_left = file->buf_size - file->buf_pos; + + } while (len + 1 <= space_left); + + if (GIT_ADD_SIZET_OVERFLOW(&alloclen, len, 1) || + !(tmp_buffer = git__malloc(alloclen))) { + file->last_error = BUFERR_MEM; + return -1; + } + + va_start(arglist, format); + written = p_vsnprintf(tmp_buffer, len + 1, format, arglist); + va_end(arglist); + + if (written < 0) { + git__free(tmp_buffer); + file->last_error = BUFERR_MEM; + return -1; + } + + res = git_filebuf_write(file, tmp_buffer, len); + git__free(tmp_buffer); + + return res; +} + +int git_filebuf_stats(time_t *mtime, size_t *size, git_filebuf *file) +{ + int res; + struct stat st; + + if (file->fd_is_open) + res = p_fstat(file->fd, &st); + else + res = p_stat(file->path_original, &st); + + if (res < 0) { + git_error_set(GIT_ERROR_OS, "could not get stat info for '%s'", + file->path_original); + return res; + } + + if (mtime) + *mtime = st.st_mtime; + if (size) + *size = (size_t)st.st_size; + + return 0; +} diff --git a/vendor/libgit2/src/filebuf.h b/vendor/libgit2/src/util/filebuf.h similarity index 81% rename from vendor/libgit2/src/filebuf.h rename to vendor/libgit2/src/util/filebuf.h index adbb1993..e23b9ed2 100644 --- a/vendor/libgit2/src/filebuf.h +++ b/vendor/libgit2/src/util/filebuf.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_filebuf_h__ #define INCLUDE_filebuf_h__ -#include "common.h" +#include "git2_util.h" #include "futils.h" #include "hash.h" @@ -17,13 +17,14 @@ # define GIT_FILEBUF_THREADS #endif -#define GIT_FILEBUF_HASH_CONTENTS (1 << 0) -#define GIT_FILEBUF_APPEND (1 << 2) +#define GIT_FILEBUF_HASH_SHA1 (1 << 0) +#define GIT_FILEBUF_HASH_SHA256 (1 << 1) +#define GIT_FILEBUF_APPEND (1 << 2) #define GIT_FILEBUF_CREATE_LEADING_DIRS (1 << 3) -#define GIT_FILEBUF_TEMPORARY (1 << 4) -#define GIT_FILEBUF_DO_NOT_BUFFER (1 << 5) -#define GIT_FILEBUF_FSYNC (1 << 6) -#define GIT_FILEBUF_DEFLATE_SHIFT (7) +#define GIT_FILEBUF_TEMPORARY (1 << 4) +#define GIT_FILEBUF_DO_NOT_BUFFER (1 << 5) +#define GIT_FILEBUF_FSYNC (1 << 6) +#define GIT_FILEBUF_DEFLATE_SHIFT (7) #define GIT_FILELOCK_EXTENSION ".lock\0" #define GIT_FILELOCK_EXTLENGTH 6 @@ -91,4 +92,16 @@ int git_filebuf_hash(unsigned char *out, git_filebuf *file); int git_filebuf_flush(git_filebuf *file); int git_filebuf_stats(time_t *mtime, size_t *size, git_filebuf *file); +GIT_INLINE(int) git_filebuf_hash_flags(git_hash_algorithm_t algorithm) +{ + switch (algorithm) { + case GIT_HASH_ALGORITHM_SHA1: + return GIT_FILEBUF_HASH_SHA1; + case GIT_HASH_ALGORITHM_SHA256: + return GIT_FILEBUF_HASH_SHA256; + default: + return 0; + } +} + #endif diff --git a/vendor/libgit2/src/fs_path.c b/vendor/libgit2/src/util/fs_path.c similarity index 91% rename from vendor/libgit2/src/fs_path.c rename to vendor/libgit2/src/util/fs_path.c index a67617ec..5b00b1b4 100644 --- a/vendor/libgit2/src/fs_path.c +++ b/vendor/libgit2/src/util/fs_path.c @@ -7,8 +7,9 @@ #include "fs_path.h" +#include "git2_util.h" +#include "futils.h" #include "posix.h" -#include "repository.h" #ifdef GIT_WIN32 #include "win32/posix.h" #include "win32/w32_buffer.h" @@ -21,6 +22,13 @@ #include #include +#define ensure_error_set(code) do { \ + const git_error *e = git_error_last(); \ + if (!e || !e->message) \ + git_error_set(e ? e->klass : GIT_ERROR_CALLBACK, \ + "filesystem callback returned %d", code); \ + } while(0) + static int dos_drive_prefix_length(const char *path) { int i; @@ -101,7 +109,7 @@ int git_fs_path_basename_r(git_str *buffer, const char *path) /* Empty or NULL string gets treated as "." */ if (path == NULL || *path == '\0') { startp = "."; - len = 1; + len = 1; goto Exit; } @@ -113,7 +121,7 @@ int git_fs_path_basename_r(git_str *buffer, const char *path) /* All slashes becomes "/" */ if (endp == path && *endp == '/') { startp = "/"; - len = 1; + len = 1; goto Exit; } @@ -185,8 +193,7 @@ int git_fs_path_dirname_r(git_str *buffer, const char *path) if (endp - path + 1 > INT_MAX) { git_error_set(GIT_ERROR_INVALID, "path too long"); - len = -1; - goto Exit; + return -1; } if ((len = win32_prefix_length(path, (int)(endp - path + 1))) > 0) { @@ -211,8 +218,7 @@ int git_fs_path_dirname_r(git_str *buffer, const char *path) if (endp - path + 1 > INT_MAX) { git_error_set(GIT_ERROR_INVALID, "path too long"); - len = -1; - goto Exit; + return -1; } if ((len = win32_prefix_length(path, (int)(endp - path + 1))) > 0) { @@ -413,6 +419,16 @@ int git_fs_path_to_dir(git_str *path) return git_str_oom(path) ? -1 : 0; } +size_t git_fs_path_dirlen(const char *path) +{ + size_t len = strlen(path); + + while (len > 1 && path[len - 1] == '/') + len--; + + return len; +} + void git_fs_path_string_to_dir(char *path, size_t size) { size_t end = strlen(path); @@ -530,7 +546,7 @@ int git_fs_path_walk_up( if (!scan) { error = cb(data, ""); if (error) - git_error_set_after_callback(error); + ensure_error_set(error); return error; } @@ -543,7 +559,7 @@ int git_fs_path_walk_up( iter.ptr[scan] = oldc; if (error) { - git_error_set_after_callback(error); + ensure_error_set(error); break; } @@ -563,7 +579,7 @@ int git_fs_path_walk_up( if (!error && stop == 0 && iter.ptr[0] != '/') { error = cb(data, ""); if (error) - git_error_set_after_callback(error); + ensure_error_set(error); } return error; @@ -595,6 +611,37 @@ bool git_fs_path_isfile(const char *path) return S_ISREG(st.st_mode) != 0; } +#ifdef GIT_WIN32 + +bool git_fs_path_isexecutable(const char *path) +{ + struct stat st; + + GIT_ASSERT_ARG_WITH_RETVAL(path, false); + + if (git__suffixcmp_icase(path, ".exe") != 0 && + git__suffixcmp_icase(path, ".cmd") != 0) + return false; + + return (p_stat(path, &st) == 0); +} + +#else + +bool git_fs_path_isexecutable(const char *path) +{ + struct stat st; + + GIT_ASSERT_ARG_WITH_RETVAL(path, false); + if (p_stat(path, &st) < 0) + return false; + + return S_ISREG(st.st_mode) != 0 && + ((st.st_mode & S_IXUSR) != 0); +} + +#endif + bool git_fs_path_islink(const char *path) { struct stat st; @@ -1167,7 +1214,7 @@ int git_fs_path_direach( /* Only set our own error if the callback did not set one already */ if (error != 0) { if (!git_error_last()) - git_error_set_after_callback(error); + ensure_error_set(error); break; } @@ -1779,9 +1826,9 @@ bool git_fs_path_supports_symlinks(const char *dir) return supported; } -static git_fs_path__mock_owner_t mock_owner = GIT_FS_PATH_MOCK_OWNER_NONE; +static git_fs_path_owner_t mock_owner = GIT_FS_PATH_OWNER_NONE; -void git_fs_path__set_owner(git_fs_path__mock_owner_t owner) +void git_fs_path__set_owner(git_fs_path_owner_t owner) { mock_owner = owner; } @@ -1849,7 +1896,7 @@ static int file_owner_sid(PSID *out, const char *path) PSECURITY_DESCRIPTOR descriptor = NULL; PSID owner_sid; DWORD ret; - int error = -1; + int error = GIT_EINVALID; if (git_win32_path_from_utf8(path_w32, path) < 0) return -1; @@ -1873,89 +1920,92 @@ static int file_owner_sid(PSID *out, const char *path) return error; } -int git_fs_path_owner_is_current_user(bool *out, const char *path) +int git_fs_path_owner_is( + bool *out, + const char *path, + git_fs_path_owner_t owner_type) { PSID owner_sid = NULL, user_sid = NULL; - int error = -1; + BOOL is_admin, admin_owned; + int error; if (mock_owner) { - *out = (mock_owner == GIT_FS_PATH_MOCK_OWNER_CURRENT_USER); + *out = ((mock_owner & owner_type) != 0); return 0; } - if ((error = file_owner_sid(&owner_sid, path)) < 0 || - (error = current_user_sid(&user_sid)) < 0) + if ((error = file_owner_sid(&owner_sid, path)) < 0) goto done; - *out = EqualSid(owner_sid, user_sid); - error = 0; + if ((owner_type & GIT_FS_PATH_OWNER_CURRENT_USER) != 0) { + if ((error = current_user_sid(&user_sid)) < 0) + goto done; -done: - git__free(owner_sid); - git__free(user_sid); - return error; -} + if (EqualSid(owner_sid, user_sid)) { + *out = true; + goto done; + } + } -int git_fs_path_owner_is_system(bool *out, const char *path) -{ - PSID owner_sid; + admin_owned = + IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) || + IsWellKnownSid(owner_sid, WinLocalSystemSid); - if (mock_owner) { - *out = (mock_owner == GIT_FS_PATH_MOCK_OWNER_SYSTEM); - return 0; + if (admin_owned && + (owner_type & GIT_FS_PATH_OWNER_ADMINISTRATOR) != 0) { + *out = true; + goto done; } - if (file_owner_sid(&owner_sid, path) < 0) - return -1; + if (admin_owned && + (owner_type & GIT_FS_PATH_USER_IS_ADMINISTRATOR) != 0 && + CheckTokenMembership(NULL, owner_sid, &is_admin) && + is_admin) { + *out = true; + goto done; + } - *out = IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) || - IsWellKnownSid(owner_sid, WinLocalSystemSid); + *out = false; +done: git__free(owner_sid); - return 0; + git__free(user_sid); + return error; } -int git_fs_path_owner_is_system_or_current_user(bool *out, const char *path) +#else + +static int sudo_uid_lookup(uid_t *out) { - PSID owner_sid = NULL, user_sid = NULL; + git_str uid_str = GIT_STR_INIT; + int64_t uid; int error = -1; - if (mock_owner) { - *out = (mock_owner == GIT_FS_PATH_MOCK_OWNER_SYSTEM || - mock_owner == GIT_FS_PATH_MOCK_OWNER_CURRENT_USER); - return 0; - } - - if (file_owner_sid(&owner_sid, path) < 0) - goto done; - - if (IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) || - IsWellKnownSid(owner_sid, WinLocalSystemSid)) { - *out = 1; + if (git__getenv(&uid_str, "SUDO_UID") == 0 && + git__strntol64(&uid, uid_str.ptr, uid_str.size, NULL, 10) == 0 && + uid == (int64_t)((uid_t)uid)) { + *out = (uid_t)uid; error = 0; - goto done; } - if (current_user_sid(&user_sid) < 0) - goto done; - - *out = EqualSid(owner_sid, user_sid); - error = 0; - -done: - git__free(owner_sid); - git__free(user_sid); + git_str_dispose(&uid_str); return error; } -#else - -static int fs_path_owner_is(bool *out, const char *path, uid_t *uids, size_t uids_len) +int git_fs_path_owner_is( + bool *out, + const char *path, + git_fs_path_owner_t owner_type) { struct stat st; - size_t i; + uid_t euid, sudo_uid; - *out = false; + if (mock_owner) { + *out = ((mock_owner & owner_type) != 0); + return 0; + } + + euid = geteuid(); if (p_lstat(path, &st) != 0) { if (errno == ENOENT) @@ -1965,62 +2015,50 @@ static int fs_path_owner_is(bool *out, const char *path, uid_t *uids, size_t uid return -1; } - for (i = 0; i < uids_len; i++) { - if (uids[i] == st.st_uid) { - *out = true; - break; - } + if ((owner_type & GIT_FS_PATH_OWNER_CURRENT_USER) != 0 && + st.st_uid == euid) { + *out = true; + return 0; } - return 0; -} - -int git_fs_path_owner_is_current_user(bool *out, const char *path) -{ - uid_t userid = geteuid(); - - if (mock_owner) { - *out = (mock_owner == GIT_FS_PATH_MOCK_OWNER_CURRENT_USER); + if ((owner_type & GIT_FS_PATH_OWNER_ADMINISTRATOR) != 0 && + st.st_uid == 0) { + *out = true; return 0; } - return fs_path_owner_is(out, path, &userid, 1); -} - -int git_fs_path_owner_is_system(bool *out, const char *path) -{ - uid_t userid = 0; - - if (mock_owner) { - *out = (mock_owner == GIT_FS_PATH_MOCK_OWNER_SYSTEM); + if ((owner_type & GIT_FS_PATH_OWNER_RUNNING_SUDO) != 0 && + euid == 0 && + sudo_uid_lookup(&sudo_uid) == 0 && + st.st_uid == sudo_uid) { + *out = true; return 0; } - return fs_path_owner_is(out, path, &userid, 1); + *out = false; + return 0; } -int git_fs_path_owner_is_system_or_current_user(bool *out, const char *path) -{ - uid_t userids[2] = { geteuid(), 0 }; +#endif - if (mock_owner) { - *out = (mock_owner == GIT_FS_PATH_MOCK_OWNER_SYSTEM || - mock_owner == GIT_FS_PATH_MOCK_OWNER_CURRENT_USER); - return 0; - } +int git_fs_path_owner_is_current_user(bool *out, const char *path) +{ + return git_fs_path_owner_is(out, path, GIT_FS_PATH_OWNER_CURRENT_USER); +} - return fs_path_owner_is(out, path, userids, 2); +int git_fs_path_owner_is_system(bool *out, const char *path) +{ + return git_fs_path_owner_is(out, path, GIT_FS_PATH_OWNER_ADMINISTRATOR); } -#endif +#ifdef GIT_WIN32 -int git_fs_path_find_executable(git_str *fullpath, const char *executable) +static int find_executable(git_str *fullpath, const char *executable) { -#ifdef GIT_WIN32 git_win32_path fullpath_w, executable_w; int error; - if (git__utf8_to_16(executable_w, GIT_WIN_PATH_MAX, executable) < 0) + if (git_utf8_to_16(executable_w, GIT_WIN_PATH_MAX, executable) < 0) return -1; error = git_win32_path_find_executable(fullpath_w, executable_w); @@ -2029,9 +2067,15 @@ int git_fs_path_find_executable(git_str *fullpath, const char *executable) error = git_str_put_w(fullpath, fullpath_w, wcslen(fullpath_w)); return error; +} + #else + +static int find_executable(git_str *fullpath, const char *executable) +{ git_str path = GIT_STR_INIT; const char *current_dir, *term; + size_t current_dirlen; bool found = false; if (git__getenv(&path, "PATH") < 0) @@ -2043,20 +2087,28 @@ int git_fs_path_find_executable(git_str *fullpath, const char *executable) if (! (term = strchr(current_dir, GIT_PATH_LIST_SEPARATOR))) term = strchr(current_dir, '\0'); + current_dirlen = term - current_dir; git_str_clear(fullpath); - if (git_str_put(fullpath, current_dir, (term - current_dir)) < 0 || - git_str_putc(fullpath, '/') < 0 || + + /* An empty path segment is treated as '.' */ + if (current_dirlen == 0 && git_str_putc(fullpath, '.')) + return -1; + else if (current_dirlen != 0 && + git_str_put(fullpath, current_dir, current_dirlen) < 0) + return -1; + + if (git_str_putc(fullpath, '/') < 0 || git_str_puts(fullpath, executable) < 0) return -1; - if (git_fs_path_isfile(fullpath->ptr)) { + if (git_fs_path_isexecutable(fullpath->ptr)) { found = true; break; } current_dir = term; - while (*current_dir == GIT_PATH_LIST_SEPARATOR) + if (*current_dir == GIT_PATH_LIST_SEPARATOR) current_dir++; } @@ -2067,5 +2119,19 @@ int git_fs_path_find_executable(git_str *fullpath, const char *executable) git_str_clear(fullpath); return GIT_ENOTFOUND; +} + #endif + +int git_fs_path_find_executable(git_str *fullpath, const char *executable) +{ + /* For qualified paths we do not look in PATH */ + if (strchr(executable, '/') != NULL) { + if (!git_fs_path_isexecutable(executable)) + return GIT_ENOTFOUND; + + return git_str_puts(fullpath, executable); + } + + return find_executable(fullpath, executable); } diff --git a/vendor/libgit2/src/fs_path.h b/vendor/libgit2/src/util/fs_path.h similarity index 92% rename from vendor/libgit2/src/fs_path.h rename to vendor/libgit2/src/util/fs_path.h index 7e6a22d4..82baf9bf 100644 --- a/vendor/libgit2/src/fs_path.h +++ b/vendor/libgit2/src/util/fs_path.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_fs_path_h__ #define INCLUDE_fs_path_h__ -#include "common.h" +#include "git2_util.h" #include "posix.h" #include "str.h" @@ -86,6 +86,29 @@ extern int git_fs_path_to_dir(git_str *path); */ extern void git_fs_path_string_to_dir(char *path, size_t size); +/** + * Provides the length of the given path string with no trailing + * slashes. + */ +size_t git_fs_path_dirlen(const char *path); + +/** + * Returns nonzero if the given path is a filesystem root; on Windows, this + * means a drive letter (eg `A:/`, `C:\`). On POSIX this is `/`. + */ +GIT_INLINE(int) git_fs_path_is_root(const char *name) +{ +#ifdef GIT_WIN32 + if (((name[0] >= 'A' && name[0] <= 'Z') || (name[0] >= 'a' && name[0] <= 'z')) && + name[1] == ':' && + (name[2] == '/' || name[2] == '\\') && + name[3] == '\0') + return 1; +#endif + + return (name[0] == '/' && name[1] == '\0'); +} + /** * Taken from git.git; returns nonzero if the given path is "." or "..". */ @@ -181,6 +204,12 @@ extern bool git_fs_path_isdir(const char *path); */ extern bool git_fs_path_isfile(const char *path); +/** + * Check if the given path points to an executable. + * @return true or false + */ +extern bool git_fs_path_isexecutable(const char *path); + /** * Check if the given path points to a symbolic link. * @return true or false @@ -732,18 +761,42 @@ int git_fs_path_normalize_slashes(git_str *out, const char *path); bool git_fs_path_supports_symlinks(const char *dir); typedef enum { - GIT_FS_PATH_MOCK_OWNER_NONE = 0, /* do filesystem lookups as normal */ - GIT_FS_PATH_MOCK_OWNER_SYSTEM = 1, - GIT_FS_PATH_MOCK_OWNER_CURRENT_USER = 2, - GIT_FS_PATH_MOCK_OWNER_OTHER = 3 -} git_fs_path__mock_owner_t; + GIT_FS_PATH_OWNER_NONE = 0, + + /** The file must be owned by the current user. */ + GIT_FS_PATH_OWNER_CURRENT_USER = (1 << 0), + + /** The file must be owned by the system account. */ + GIT_FS_PATH_OWNER_ADMINISTRATOR = (1 << 1), + + /** + * The file may be owned by a system account if the current + * user is in an administrator group. Windows only; this is + * a noop on non-Windows systems. + */ + GIT_FS_PATH_USER_IS_ADMINISTRATOR = (1 << 2), + + /** + * The file is owned by the current user, who is running `sudo`. + */ + GIT_FS_PATH_OWNER_RUNNING_SUDO = (1 << 3), + + /** The file may be owned by another user. */ + GIT_FS_PATH_OWNER_OTHER = (1 << 4) +} git_fs_path_owner_t; /** * Sets the mock ownership for files; subsequent calls to - * `git_fs_path_owner_is_*` functions will return this data until cleared - * with `GIT_FS_PATH_MOCK_OWNER_NONE`. + * `git_fs_path_owner_is_*` functions will return this data until + * cleared with `GIT_FS_PATH_OWNER_NONE`. */ -void git_fs_path__set_owner(git_fs_path__mock_owner_t owner); +void git_fs_path__set_owner(git_fs_path_owner_t owner); + +/** Verify that the file in question is owned by the given owner. */ +int git_fs_path_owner_is( + bool *out, + const char *path, + git_fs_path_owner_t owner_type); /** * Verify that the file in question is owned by an administrator or system @@ -757,12 +810,6 @@ int git_fs_path_owner_is_system(bool *out, const char *path); int git_fs_path_owner_is_current_user(bool *out, const char *path); -/** - * Verify that the file in question is owned by an administrator or system - * account _or_ the current user; - */ -int git_fs_path_owner_is_system_or_current_user(bool *out, const char *path); - /** * Search the current PATH for the given executable, returning the full * path if it is found. diff --git a/vendor/libgit2/src/util/futils.c b/vendor/libgit2/src/util/futils.c new file mode 100644 index 00000000..7b5a24b3 --- /dev/null +++ b/vendor/libgit2/src/util/futils.c @@ -0,0 +1,1236 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "futils.h" + +#include "runtime.h" +#include "strmap.h" +#include "hash.h" +#include "rand.h" + +#include + +#define GIT_FILEMODE_DEFAULT 0100666 + +int git_futils_mkpath2file(const char *file_path, const mode_t mode) +{ + return git_futils_mkdir( + file_path, mode, + GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST | GIT_MKDIR_VERIFY_DIR); +} + +int git_futils_mktmp(git_str *path_out, const char *filename, mode_t mode) +{ + const int open_flags = O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC; + unsigned int tries = 32; + int fd; + + while (tries--) { + uint64_t rand = git_rand_next(); + + git_str_sets(path_out, filename); + git_str_puts(path_out, "_git2_"); + git_str_encode_hexstr(path_out, (void *)&rand, sizeof(uint64_t)); + + if (git_str_oom(path_out)) + return -1; + + /* Note that we open with O_CREAT | O_EXCL */ + if ((fd = p_open(path_out->ptr, open_flags, mode)) >= 0) + return fd; + } + + git_error_set(GIT_ERROR_OS, + "failed to create temporary file '%s'", path_out->ptr); + git_str_dispose(path_out); + return -1; +} + +int git_futils_creat_withpath(const char *path, const mode_t dirmode, const mode_t mode) +{ + int fd; + + if (git_futils_mkpath2file(path, dirmode) < 0) + return -1; + + fd = p_creat(path, mode); + if (fd < 0) { + git_error_set(GIT_ERROR_OS, "failed to create file '%s'", path); + return -1; + } + + return fd; +} + +int git_futils_creat_locked(const char *path, const mode_t mode) +{ + int fd = p_open(path, O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, + mode); + + if (fd < 0) { + int error = errno; + git_error_set(GIT_ERROR_OS, "failed to create locked file '%s'", path); + switch (error) { + case EEXIST: + return GIT_ELOCKED; + case ENOENT: + return GIT_ENOTFOUND; + default: + return -1; + } + } + + return fd; +} + +int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, const mode_t mode) +{ + if (git_futils_mkpath2file(path, dirmode) < 0) + return -1; + + return git_futils_creat_locked(path, mode); +} + +int git_futils_open_ro(const char *path) +{ + int fd = p_open(path, O_RDONLY); + if (fd < 0) + return git_fs_path_set_error(errno, path, "open"); + return fd; +} + +int git_futils_truncate(const char *path, int mode) +{ + int fd = p_open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode); + if (fd < 0) + return git_fs_path_set_error(errno, path, "open"); + + close(fd); + return 0; +} + +int git_futils_filesize(uint64_t *out, git_file fd) +{ + struct stat sb; + + if (p_fstat(fd, &sb)) { + git_error_set(GIT_ERROR_OS, "failed to stat file descriptor"); + return -1; + } + + if (sb.st_size < 0) { + git_error_set(GIT_ERROR_INVALID, "invalid file size"); + return -1; + } + + *out = sb.st_size; + return 0; +} + +mode_t git_futils_canonical_mode(mode_t raw_mode) +{ + if (S_ISREG(raw_mode)) + return S_IFREG | GIT_PERMS_CANONICAL(raw_mode); + else if (S_ISLNK(raw_mode)) + return S_IFLNK; + else if (S_ISGITLINK(raw_mode)) + return S_IFGITLINK; + else if (S_ISDIR(raw_mode)) + return S_IFDIR; + else + return 0; +} + +int git_futils_readbuffer_fd(git_str *buf, git_file fd, size_t len) +{ + ssize_t read_size = 0; + size_t alloc_len; + + git_str_clear(buf); + + if (!git__is_ssizet(len)) { + git_error_set(GIT_ERROR_INVALID, "read too large"); + return -1; + } + + GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, len, 1); + if (git_str_grow(buf, alloc_len) < 0) + return -1; + + /* p_read loops internally to read len bytes */ + read_size = p_read(fd, buf->ptr, len); + + if (read_size < 0) { + git_error_set(GIT_ERROR_OS, "failed to read descriptor"); + git_str_dispose(buf); + return -1; + } + + if ((size_t)read_size != len) { + git_error_set(GIT_ERROR_FILESYSTEM, "could not read (expected %" PRIuZ " bytes, read %" PRIuZ ")", len, (size_t)read_size); + git_str_dispose(buf); + return -1; + } + + buf->ptr[read_size] = '\0'; + buf->size = read_size; + + return 0; +} + +int git_futils_readbuffer_fd_full(git_str *buf, git_file fd) +{ + static size_t blocksize = 10240; + size_t alloc_len = 0, total_size = 0; + ssize_t read_size = 0; + + git_str_clear(buf); + + while (true) { + GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, blocksize); + + if (git_str_grow(buf, alloc_len) < 0) + return -1; + + /* p_read loops internally to read blocksize bytes */ + read_size = p_read(fd, buf->ptr, blocksize); + + if (read_size < 0) { + git_error_set(GIT_ERROR_OS, "failed to read descriptor"); + git_str_dispose(buf); + return -1; + } + + total_size += read_size; + + if ((size_t)read_size < blocksize) { + break; + } + } + + buf->ptr[total_size] = '\0'; + buf->size = total_size; + + return 0; +} + +int git_futils_readbuffer_updated( + git_str *out, + const char *path, + unsigned char checksum[GIT_HASH_SHA256_SIZE], + int *updated) +{ + int error; + git_file fd; + struct stat st; + git_str buf = GIT_STR_INIT; + unsigned char checksum_new[GIT_HASH_SHA256_SIZE]; + + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(path && *path); + + if (updated != NULL) + *updated = 0; + + if (p_stat(path, &st) < 0) + return git_fs_path_set_error(errno, path, "stat"); + + + if (S_ISDIR(st.st_mode)) { + git_error_set(GIT_ERROR_INVALID, "requested file is a directory"); + return GIT_ENOTFOUND; + } + + if (!git__is_sizet(st.st_size+1)) { + git_error_set(GIT_ERROR_OS, "invalid regular file stat for '%s'", path); + return -1; + } + + if ((fd = git_futils_open_ro(path)) < 0) + return fd; + + if (git_futils_readbuffer_fd(&buf, fd, (size_t)st.st_size) < 0) { + p_close(fd); + return -1; + } + + p_close(fd); + + if (checksum) { + error = git_hash_buf(checksum_new, buf.ptr, + buf.size, GIT_HASH_ALGORITHM_SHA256); + + if (error < 0) { + git_str_dispose(&buf); + return error; + } + + /* + * If we were given a checksum, we only want to use it if it's different + */ + if (!memcmp(checksum, checksum_new, GIT_HASH_SHA256_SIZE)) { + git_str_dispose(&buf); + if (updated) + *updated = 0; + + return 0; + } + + memcpy(checksum, checksum_new, GIT_HASH_SHA256_SIZE); + } + + /* + * If we're here, the file did change, or the user didn't have an old version + */ + if (updated != NULL) + *updated = 1; + + git_str_swap(out, &buf); + git_str_dispose(&buf); + + return 0; +} + +int git_futils_readbuffer(git_str *buf, const char *path) +{ + return git_futils_readbuffer_updated(buf, path, NULL, NULL); +} + +int git_futils_writebuffer( + const git_str *buf, const char *path, int flags, mode_t mode) +{ + int fd, do_fsync = 0, error = 0; + + if (!flags) + flags = O_CREAT | O_TRUNC | O_WRONLY; + + if ((flags & O_FSYNC) != 0) + do_fsync = 1; + + flags &= ~O_FSYNC; + + if (!mode) + mode = GIT_FILEMODE_DEFAULT; + + if ((fd = p_open(path, flags, mode)) < 0) { + git_error_set(GIT_ERROR_OS, "could not open '%s' for writing", path); + return fd; + } + + if ((error = p_write(fd, git_str_cstr(buf), git_str_len(buf))) < 0) { + git_error_set(GIT_ERROR_OS, "could not write to '%s'", path); + (void)p_close(fd); + return error; + } + + if (do_fsync && (error = p_fsync(fd)) < 0) { + git_error_set(GIT_ERROR_OS, "could not fsync '%s'", path); + p_close(fd); + return error; + } + + if ((error = p_close(fd)) < 0) { + git_error_set(GIT_ERROR_OS, "error while closing '%s'", path); + return error; + } + + if (do_fsync && (flags & O_CREAT)) + error = git_futils_fsync_parent(path); + + return error; +} + +int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode) +{ + if (git_futils_mkpath2file(to, dirmode) < 0) + return -1; + + if (p_rename(from, to) < 0) { + git_error_set(GIT_ERROR_OS, "failed to rename '%s' to '%s'", from, to); + return -1; + } + + return 0; +} + +int git_futils_mmap_ro(git_map *out, git_file fd, off64_t begin, size_t len) +{ + return p_mmap(out, len, GIT_PROT_READ, GIT_MAP_SHARED, fd, begin); +} + +int git_futils_mmap_ro_file(git_map *out, const char *path) +{ + git_file fd = git_futils_open_ro(path); + uint64_t len; + int result; + + if (fd < 0) + return fd; + + if ((result = git_futils_filesize(&len, fd)) < 0) + goto out; + + if (!git__is_sizet(len)) { + git_error_set(GIT_ERROR_OS, "file `%s` too large to mmap", path); + result = -1; + goto out; + } + + result = git_futils_mmap_ro(out, fd, 0, (size_t)len); +out: + p_close(fd); + return result; +} + +void git_futils_mmap_free(git_map *out) +{ + p_munmap(out); +} + +GIT_INLINE(int) mkdir_validate_dir( + const char *path, + struct stat *st, + mode_t mode, + uint32_t flags, + struct git_futils_mkdir_options *opts) +{ + /* with exclusive create, existing dir is an error */ + if ((flags & GIT_MKDIR_EXCL) != 0) { + git_error_set(GIT_ERROR_FILESYSTEM, + "failed to make directory '%s': directory exists", path); + return GIT_EEXISTS; + } + + if ((S_ISREG(st->st_mode) && (flags & GIT_MKDIR_REMOVE_FILES)) || + (S_ISLNK(st->st_mode) && (flags & GIT_MKDIR_REMOVE_SYMLINKS))) { + if (p_unlink(path) < 0) { + git_error_set(GIT_ERROR_OS, "failed to remove %s '%s'", + S_ISLNK(st->st_mode) ? "symlink" : "file", path); + return GIT_EEXISTS; + } + + opts->perfdata.mkdir_calls++; + + if (p_mkdir(path, mode) < 0) { + git_error_set(GIT_ERROR_OS, "failed to make directory '%s'", path); + return GIT_EEXISTS; + } + } + + else if (S_ISLNK(st->st_mode)) { + /* Re-stat the target, make sure it's a directory */ + opts->perfdata.stat_calls++; + + if (p_stat(path, st) < 0) { + git_error_set(GIT_ERROR_OS, "failed to make directory '%s'", path); + return GIT_EEXISTS; + } + } + + else if (!S_ISDIR(st->st_mode)) { + git_error_set(GIT_ERROR_FILESYSTEM, + "failed to make directory '%s': directory exists", path); + return GIT_EEXISTS; + } + + return 0; +} + +GIT_INLINE(int) mkdir_validate_mode( + const char *path, + struct stat *st, + bool terminal_path, + mode_t mode, + uint32_t flags, + struct git_futils_mkdir_options *opts) +{ + if (((terminal_path && (flags & GIT_MKDIR_CHMOD) != 0) || + (flags & GIT_MKDIR_CHMOD_PATH) != 0) && st->st_mode != mode) { + + opts->perfdata.chmod_calls++; + + if (p_chmod(path, mode) < 0) { + git_error_set(GIT_ERROR_OS, "failed to set permissions on '%s'", path); + return -1; + } + } + + return 0; +} + +GIT_INLINE(int) mkdir_canonicalize( + git_str *path, + uint32_t flags) +{ + ssize_t root_len; + + if (path->size == 0) { + git_error_set(GIT_ERROR_OS, "attempt to create empty path"); + return -1; + } + + /* Trim trailing slashes (except the root) */ + if ((root_len = git_fs_path_root(path->ptr)) < 0) + root_len = 0; + else + root_len++; + + while (path->size > (size_t)root_len && path->ptr[path->size - 1] == '/') + path->ptr[--path->size] = '\0'; + + /* if we are not supposed to made the last element, truncate it */ + if ((flags & GIT_MKDIR_SKIP_LAST2) != 0) { + git_fs_path_dirname_r(path, path->ptr); + flags |= GIT_MKDIR_SKIP_LAST; + } + if ((flags & GIT_MKDIR_SKIP_LAST) != 0) { + git_fs_path_dirname_r(path, path->ptr); + } + + /* We were either given the root path (or trimmed it to + * the root), we don't have anything to do. + */ + if (path->size <= (size_t)root_len) + git_str_clear(path); + + return 0; +} + +int git_futils_mkdir( + const char *path, + mode_t mode, + uint32_t flags) +{ + git_str make_path = GIT_STR_INIT, parent_path = GIT_STR_INIT; + const char *relative; + struct git_futils_mkdir_options opts = { 0 }; + struct stat st; + size_t depth = 0; + int len = 0, root_len, error; + + if ((error = git_str_puts(&make_path, path)) < 0 || + (error = mkdir_canonicalize(&make_path, flags)) < 0 || + (error = git_str_puts(&parent_path, make_path.ptr)) < 0 || + make_path.size == 0) + goto done; + + root_len = git_fs_path_root(make_path.ptr); + + /* find the first parent directory that exists. this will be used + * as the base to dirname_relative. + */ + for (relative = make_path.ptr; parent_path.size; ) { + error = p_lstat(parent_path.ptr, &st); + + if (error == 0) { + break; + } else if (errno != ENOENT) { + git_error_set(GIT_ERROR_OS, "failed to stat '%s'", parent_path.ptr); + error = -1; + goto done; + } + + depth++; + + /* examine the parent of the current path */ + if ((len = git_fs_path_dirname_r(&parent_path, parent_path.ptr)) < 0) { + error = len; + goto done; + } + + GIT_ASSERT(len); + + /* + * We've walked all the given path's parents and it's either relative + * (the parent is simply '.') or rooted (the length is less than or + * equal to length of the root path). The path may be less than the + * root path length on Windows, where `C:` == `C:/`. + */ + if ((len == 1 && parent_path.ptr[0] == '.') || + (len == 1 && parent_path.ptr[0] == '/') || + len <= root_len) { + relative = make_path.ptr; + break; + } + + relative = make_path.ptr + len + 1; + + /* not recursive? just make this directory relative to its parent. */ + if ((flags & GIT_MKDIR_PATH) == 0) + break; + } + + /* we found an item at the location we're trying to create, + * validate it. + */ + if (depth == 0) { + error = mkdir_validate_dir(make_path.ptr, &st, mode, flags, &opts); + + if (!error) + error = mkdir_validate_mode( + make_path.ptr, &st, true, mode, flags, &opts); + + goto done; + } + + /* we already took `SKIP_LAST` and `SKIP_LAST2` into account when + * canonicalizing `make_path`. + */ + flags &= ~(GIT_MKDIR_SKIP_LAST2 | GIT_MKDIR_SKIP_LAST); + + error = git_futils_mkdir_relative(relative, + parent_path.size ? parent_path.ptr : NULL, mode, flags, &opts); + +done: + git_str_dispose(&make_path); + git_str_dispose(&parent_path); + return error; +} + +int git_futils_mkdir_r(const char *path, const mode_t mode) +{ + return git_futils_mkdir(path, mode, GIT_MKDIR_PATH); +} + +int git_futils_mkdir_relative( + const char *relative_path, + const char *base, + mode_t mode, + uint32_t flags, + struct git_futils_mkdir_options *opts) +{ + git_str make_path = GIT_STR_INIT; + ssize_t root = 0, min_root_len; + char lastch = '/', *tail; + struct stat st; + struct git_futils_mkdir_options empty_opts = {0}; + int error; + + if (!opts) + opts = &empty_opts; + + /* build path and find "root" where we should start calling mkdir */ + if (git_fs_path_join_unrooted(&make_path, relative_path, base, &root) < 0) + return -1; + + if ((error = mkdir_canonicalize(&make_path, flags)) < 0 || + make_path.size == 0) + goto done; + + /* if we are not supposed to make the whole path, reset root */ + if ((flags & GIT_MKDIR_PATH) == 0) + root = git_str_rfind(&make_path, '/'); + + /* advance root past drive name or network mount prefix */ + min_root_len = git_fs_path_root(make_path.ptr); + if (root < min_root_len) + root = min_root_len; + while (root >= 0 && make_path.ptr[root] == '/') + ++root; + + /* clip root to make_path length */ + if (root > (ssize_t)make_path.size) + root = (ssize_t)make_path.size; /* i.e. NUL byte of string */ + if (root < 0) + root = 0; + + /* walk down tail of path making each directory */ + for (tail = &make_path.ptr[root]; *tail; *tail = lastch) { + bool mkdir_attempted = false; + + /* advance tail to include next path component */ + while (*tail == '/') + tail++; + while (*tail && *tail != '/') + tail++; + + /* truncate path at next component */ + lastch = *tail; + *tail = '\0'; + st.st_mode = 0; + + if (opts->dir_map && git_strmap_exists(opts->dir_map, make_path.ptr)) + continue; + + /* See what's going on with this path component */ + opts->perfdata.stat_calls++; + +retry_lstat: + if (p_lstat(make_path.ptr, &st) < 0) { + if (mkdir_attempted || errno != ENOENT) { + git_error_set(GIT_ERROR_OS, "cannot access component in path '%s'", make_path.ptr); + error = -1; + goto done; + } + + git_error_clear(); + opts->perfdata.mkdir_calls++; + mkdir_attempted = true; + if (p_mkdir(make_path.ptr, mode) < 0) { + if (errno == EEXIST) + goto retry_lstat; + git_error_set(GIT_ERROR_OS, "failed to make directory '%s'", make_path.ptr); + error = -1; + goto done; + } + } else { + if ((error = mkdir_validate_dir( + make_path.ptr, &st, mode, flags, opts)) < 0) + goto done; + } + + /* chmod if requested and necessary */ + if ((error = mkdir_validate_mode( + make_path.ptr, &st, (lastch == '\0'), mode, flags, opts)) < 0) + goto done; + + if (opts->dir_map && opts->pool) { + char *cache_path; + size_t alloc_size; + + GIT_ERROR_CHECK_ALLOC_ADD(&alloc_size, make_path.size, 1); + cache_path = git_pool_malloc(opts->pool, alloc_size); + GIT_ERROR_CHECK_ALLOC(cache_path); + + memcpy(cache_path, make_path.ptr, make_path.size + 1); + + if ((error = git_strmap_set(opts->dir_map, cache_path, cache_path)) < 0) + goto done; + } + } + + error = 0; + + /* check that full path really is a directory if requested & needed */ + if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 && + lastch != '\0') { + opts->perfdata.stat_calls++; + + if (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode)) { + git_error_set(GIT_ERROR_OS, "path is not a directory '%s'", + make_path.ptr); + error = GIT_ENOTFOUND; + } + } + +done: + git_str_dispose(&make_path); + return error; +} + +typedef struct { + const char *base; + size_t baselen; + uint32_t flags; + int depth; +} futils__rmdir_data; + +#define FUTILS_MAX_DEPTH 100 + +static int futils__error_cannot_rmdir(const char *path, const char *filemsg) +{ + if (filemsg) + git_error_set(GIT_ERROR_OS, "could not remove directory '%s': %s", + path, filemsg); + else + git_error_set(GIT_ERROR_OS, "could not remove directory '%s'", path); + + return -1; +} + +static int futils__rm_first_parent(git_str *path, const char *ceiling) +{ + int error = GIT_ENOTFOUND; + struct stat st; + + while (error == GIT_ENOTFOUND) { + git_str_rtruncate_at_char(path, '/'); + + if (!path->size || git__prefixcmp(path->ptr, ceiling) != 0) + error = 0; + else if (p_lstat_posixly(path->ptr, &st) == 0) { + if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) + error = p_unlink(path->ptr); + else if (!S_ISDIR(st.st_mode)) + error = -1; /* fail to remove non-regular file */ + } else if (errno != ENOTDIR) + error = -1; + } + + if (error) + futils__error_cannot_rmdir(path->ptr, "cannot remove parent"); + + return error; +} + +static int futils__rmdir_recurs_foreach(void *opaque, git_str *path) +{ + int error = 0; + futils__rmdir_data *data = opaque; + struct stat st; + + if (data->depth > FUTILS_MAX_DEPTH) + error = futils__error_cannot_rmdir( + path->ptr, "directory nesting too deep"); + + else if ((error = p_lstat_posixly(path->ptr, &st)) < 0) { + if (errno == ENOENT) + error = 0; + else if (errno == ENOTDIR) { + /* asked to remove a/b/c/d/e and a/b is a normal file */ + if ((data->flags & GIT_RMDIR_REMOVE_BLOCKERS) != 0) + error = futils__rm_first_parent(path, data->base); + else + futils__error_cannot_rmdir( + path->ptr, "parent is not directory"); + } + else + error = git_fs_path_set_error(errno, path->ptr, "rmdir"); + } + + else if (S_ISDIR(st.st_mode)) { + data->depth++; + + error = git_fs_path_direach(path, 0, futils__rmdir_recurs_foreach, data); + + data->depth--; + + if (error < 0) + return error; + + if (data->depth == 0 && (data->flags & GIT_RMDIR_SKIP_ROOT) != 0) + return error; + + if ((error = p_rmdir(path->ptr)) < 0) { + if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) != 0 && + (errno == ENOTEMPTY || errno == EEXIST || errno == EBUSY)) + error = 0; + else + error = git_fs_path_set_error(errno, path->ptr, "rmdir"); + } + } + + else if ((data->flags & GIT_RMDIR_REMOVE_FILES) != 0) { + if (p_unlink(path->ptr) < 0) + error = git_fs_path_set_error(errno, path->ptr, "remove"); + } + + else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0) + error = futils__error_cannot_rmdir(path->ptr, "still present"); + + return error; +} + +static int futils__rmdir_empty_parent(void *opaque, const char *path) +{ + futils__rmdir_data *data = opaque; + int error = 0; + + if (strlen(path) <= data->baselen) + error = GIT_ITEROVER; + + else if (p_rmdir(path) < 0) { + int en = errno; + + if (en == ENOENT || en == ENOTDIR) { + /* do nothing */ + } else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0 && + en == EBUSY) { + error = git_fs_path_set_error(errno, path, "rmdir"); + } else if (en == ENOTEMPTY || en == EEXIST || en == EBUSY) { + error = GIT_ITEROVER; + } else { + error = git_fs_path_set_error(errno, path, "rmdir"); + } + } + + return error; +} + +int git_futils_rmdir_r( + const char *path, const char *base, uint32_t flags) +{ + int error; + git_str fullpath = GIT_STR_INIT; + futils__rmdir_data data; + + /* build path and find "root" where we should start calling mkdir */ + if (git_fs_path_join_unrooted(&fullpath, path, base, NULL) < 0) + return -1; + + memset(&data, 0, sizeof(data)); + data.base = base ? base : ""; + data.baselen = base ? strlen(base) : 0; + data.flags = flags; + + error = futils__rmdir_recurs_foreach(&data, &fullpath); + + /* remove now-empty parents if requested */ + if (!error && (flags & GIT_RMDIR_EMPTY_PARENTS) != 0) + error = git_fs_path_walk_up( + &fullpath, base, futils__rmdir_empty_parent, &data); + + if (error == GIT_ITEROVER) { + git_error_clear(); + error = 0; + } + + git_str_dispose(&fullpath); + + return error; +} + +int git_futils_fake_symlink(const char *target, const char *path) +{ + int retcode = GIT_ERROR; + int fd = git_futils_creat_withpath(path, 0755, 0644); + if (fd >= 0) { + retcode = p_write(fd, target, strlen(target)); + p_close(fd); + } + return retcode; +} + +static int cp_by_fd(int ifd, int ofd, bool close_fd_when_done) +{ + int error = 0; + char buffer[GIT_BUFSIZE_FILEIO]; + ssize_t len = 0; + + while (!error && (len = p_read(ifd, buffer, sizeof(buffer))) > 0) + /* p_write() does not have the same semantics as write(). It loops + * internally and will return 0 when it has completed writing. + */ + error = p_write(ofd, buffer, len); + + if (len < 0) { + git_error_set(GIT_ERROR_OS, "read error while copying file"); + error = (int)len; + } + + if (error < 0) + git_error_set(GIT_ERROR_OS, "write error while copying file"); + + if (close_fd_when_done) { + p_close(ifd); + p_close(ofd); + } + + return error; +} + +int git_futils_cp(const char *from, const char *to, mode_t filemode) +{ + int ifd, ofd; + + if ((ifd = git_futils_open_ro(from)) < 0) + return ifd; + + if ((ofd = p_open(to, O_WRONLY | O_CREAT | O_EXCL, filemode)) < 0) { + p_close(ifd); + return git_fs_path_set_error(errno, to, "open for writing"); + } + + return cp_by_fd(ifd, ofd, true); +} + +int git_futils_touch(const char *path, time_t *when) +{ + struct p_timeval times[2]; + int ret; + + times[0].tv_sec = times[1].tv_sec = when ? *when : time(NULL); + times[0].tv_usec = times[1].tv_usec = 0; + + ret = p_utimes(path, times); + + return (ret < 0) ? git_fs_path_set_error(errno, path, "touch") : 0; +} + +static int cp_link(const char *from, const char *to, size_t link_size) +{ + int error = 0; + ssize_t read_len; + char *link_data; + size_t alloc_size; + + GIT_ERROR_CHECK_ALLOC_ADD(&alloc_size, link_size, 1); + link_data = git__malloc(alloc_size); + GIT_ERROR_CHECK_ALLOC(link_data); + + read_len = p_readlink(from, link_data, link_size); + if (read_len != (ssize_t)link_size) { + git_error_set(GIT_ERROR_OS, "failed to read symlink data for '%s'", from); + error = -1; + } + else { + link_data[read_len] = '\0'; + + if (p_symlink(link_data, to) < 0) { + git_error_set(GIT_ERROR_OS, "could not symlink '%s' as '%s'", + link_data, to); + error = -1; + } + } + + git__free(link_data); + return error; +} + +typedef struct { + const char *to_root; + git_str to; + ssize_t from_prefix; + uint32_t flags; + uint32_t mkdir_flags; + mode_t dirmode; +} cp_r_info; + +#define GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT (1u << 10) + +static int _cp_r_mkdir(cp_r_info *info, git_str *from) +{ + int error = 0; + + /* create root directory the first time we need to create a directory */ + if ((info->flags & GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT) == 0) { + error = git_futils_mkdir( + info->to_root, info->dirmode, + (info->flags & GIT_CPDIR_CHMOD_DIRS) ? GIT_MKDIR_CHMOD : 0); + + info->flags |= GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT; + } + + /* create directory with root as base to prevent excess chmods */ + if (!error) + error = git_futils_mkdir_relative( + from->ptr + info->from_prefix, info->to_root, + info->dirmode, info->mkdir_flags, NULL); + + return error; +} + +static int _cp_r_callback(void *ref, git_str *from) +{ + int error = 0; + cp_r_info *info = ref; + struct stat from_st, to_st; + bool exists = false; + + if ((info->flags & GIT_CPDIR_COPY_DOTFILES) == 0 && + from->ptr[git_fs_path_basename_offset(from)] == '.') + return 0; + + if ((error = git_str_joinpath( + &info->to, info->to_root, from->ptr + info->from_prefix)) < 0) + return error; + + if (!(error = git_fs_path_lstat(info->to.ptr, &to_st))) + exists = true; + else if (error != GIT_ENOTFOUND) + return error; + else { + git_error_clear(); + error = 0; + } + + if ((error = git_fs_path_lstat(from->ptr, &from_st)) < 0) + return error; + + if (S_ISDIR(from_st.st_mode)) { + mode_t oldmode = info->dirmode; + + /* if we are not chmod'ing, then overwrite dirmode */ + if ((info->flags & GIT_CPDIR_CHMOD_DIRS) == 0) + info->dirmode = from_st.st_mode; + + /* make directory now if CREATE_EMPTY_DIRS is requested and needed */ + if (!exists && (info->flags & GIT_CPDIR_CREATE_EMPTY_DIRS) != 0) + error = _cp_r_mkdir(info, from); + + /* recurse onto target directory */ + if (!error && (!exists || S_ISDIR(to_st.st_mode))) + error = git_fs_path_direach(from, 0, _cp_r_callback, info); + + if (oldmode != 0) + info->dirmode = oldmode; + + return error; + } + + if (exists) { + if ((info->flags & GIT_CPDIR_OVERWRITE) == 0) + return 0; + + if (p_unlink(info->to.ptr) < 0) { + git_error_set(GIT_ERROR_OS, "cannot overwrite existing file '%s'", + info->to.ptr); + return GIT_EEXISTS; + } + } + + /* Done if this isn't a regular file or a symlink */ + if (!S_ISREG(from_st.st_mode) && + (!S_ISLNK(from_st.st_mode) || + (info->flags & GIT_CPDIR_COPY_SYMLINKS) == 0)) + return 0; + + /* Make container directory on demand if needed */ + if ((info->flags & GIT_CPDIR_CREATE_EMPTY_DIRS) == 0 && + (error = _cp_r_mkdir(info, from)) < 0) + return error; + + /* make symlink or regular file */ + if (info->flags & GIT_CPDIR_LINK_FILES) { + if ((error = p_link(from->ptr, info->to.ptr)) < 0) + git_error_set(GIT_ERROR_OS, "failed to link '%s'", from->ptr); + } else if (S_ISLNK(from_st.st_mode)) { + error = cp_link(from->ptr, info->to.ptr, (size_t)from_st.st_size); + } else { + mode_t usemode = from_st.st_mode; + + if ((info->flags & GIT_CPDIR_SIMPLE_TO_MODE) != 0) + usemode = GIT_PERMS_FOR_WRITE(usemode); + + error = git_futils_cp(from->ptr, info->to.ptr, usemode); + } + + return error; +} + +int git_futils_cp_r( + const char *from, + const char *to, + uint32_t flags, + mode_t dirmode) +{ + int error; + git_str path = GIT_STR_INIT; + cp_r_info info; + + if (git_str_joinpath(&path, from, "") < 0) /* ensure trailing slash */ + return -1; + + memset(&info, 0, sizeof(info)); + info.to_root = to; + info.flags = flags; + info.dirmode = dirmode; + info.from_prefix = path.size; + git_str_init(&info.to, 0); + + /* precalculate mkdir flags */ + if ((flags & GIT_CPDIR_CREATE_EMPTY_DIRS) == 0) { + /* if not creating empty dirs, then use mkdir to create the path on + * demand right before files are copied. + */ + info.mkdir_flags = GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST; + if ((flags & GIT_CPDIR_CHMOD_DIRS) != 0) + info.mkdir_flags |= GIT_MKDIR_CHMOD_PATH; + } else { + /* otherwise, we will do simple mkdir as directories are encountered */ + info.mkdir_flags = + ((flags & GIT_CPDIR_CHMOD_DIRS) != 0) ? GIT_MKDIR_CHMOD : 0; + } + + error = _cp_r_callback(&info, &path); + + git_str_dispose(&path); + git_str_dispose(&info.to); + + return error; +} + +int git_futils_filestamp_check( + git_futils_filestamp *stamp, const char *path) +{ + struct stat st; + + /* if the stamp is NULL, then always reload */ + if (stamp == NULL) + return 1; + + if (p_stat(path, &st) < 0) + return GIT_ENOTFOUND; + + if (stamp->mtime.tv_sec == st.st_mtime && +#if defined(GIT_USE_NSEC) + stamp->mtime.tv_nsec == st.st_mtime_nsec && +#endif + stamp->size == (uint64_t)st.st_size && + stamp->ino == (unsigned int)st.st_ino) + return 0; + + stamp->mtime.tv_sec = st.st_mtime; +#if defined(GIT_USE_NSEC) + stamp->mtime.tv_nsec = st.st_mtime_nsec; +#endif + stamp->size = (uint64_t)st.st_size; + stamp->ino = (unsigned int)st.st_ino; + + return 1; +} + +void git_futils_filestamp_set( + git_futils_filestamp *target, const git_futils_filestamp *source) +{ + if (source) + memcpy(target, source, sizeof(*target)); + else + memset(target, 0, sizeof(*target)); +} + + +void git_futils_filestamp_set_from_stat( + git_futils_filestamp *stamp, struct stat *st) +{ + if (st) { + stamp->mtime.tv_sec = st->st_mtime; +#if defined(GIT_USE_NSEC) + stamp->mtime.tv_nsec = st->st_mtime_nsec; +#else + stamp->mtime.tv_nsec = 0; +#endif + stamp->size = (uint64_t)st->st_size; + stamp->ino = (unsigned int)st->st_ino; + } else { + memset(stamp, 0, sizeof(*stamp)); + } +} + +int git_futils_fsync_dir(const char *path) +{ +#ifdef GIT_WIN32 + GIT_UNUSED(path); + return 0; +#else + int fd, error = -1; + + if ((fd = p_open(path, O_RDONLY)) < 0) { + git_error_set(GIT_ERROR_OS, "failed to open directory '%s' for fsync", path); + return -1; + } + + if ((error = p_fsync(fd)) < 0) + git_error_set(GIT_ERROR_OS, "failed to fsync directory '%s'", path); + + p_close(fd); + return error; +#endif +} + +int git_futils_fsync_parent(const char *path) +{ + char *parent; + int error; + + if ((parent = git_fs_path_dirname(path)) == NULL) + return -1; + + error = git_futils_fsync_dir(parent); + git__free(parent); + return error; +} diff --git a/vendor/libgit2/src/futils.h b/vendor/libgit2/src/util/futils.h similarity index 98% rename from vendor/libgit2/src/futils.h rename to vendor/libgit2/src/util/futils.h index a82ec41c..53bcc551 100644 --- a/vendor/libgit2/src/futils.h +++ b/vendor/libgit2/src/util/futils.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_futils_h__ #define INCLUDE_futils_h__ -#include "common.h" +#include "git2_util.h" #include "map.h" #include "posix.h" @@ -25,8 +25,9 @@ extern int git_futils_readbuffer(git_str *obj, const char *path); extern int git_futils_readbuffer_updated( git_str *obj, const char *path, - unsigned char checksum[GIT_HASH_SHA1_SIZE], + unsigned char checksum[GIT_HASH_SHA256_SIZE], int *updated); +extern int git_futils_readbuffer_fd_full(git_str *obj, git_file fd); extern int git_futils_readbuffer_fd(git_str *obj, git_file fd, size_t len); /* Additional constants for `git_futils_writebuffer`'s `open_flags`. We diff --git a/vendor/libgit2/src/util/git2_features.h.in b/vendor/libgit2/src/util/git2_features.h.in new file mode 100644 index 00000000..52b73284 --- /dev/null +++ b/vendor/libgit2/src/util/git2_features.h.in @@ -0,0 +1,74 @@ +#ifndef INCLUDE_features_h__ +#define INCLUDE_features_h__ + +#cmakedefine GIT_DEBUG_POOL 1 +#cmakedefine GIT_DEBUG_STRICT_ALLOC 1 +#cmakedefine GIT_DEBUG_STRICT_OPEN 1 + +#cmakedefine GIT_THREADS 1 +#cmakedefine GIT_WIN32_LEAKCHECK 1 + +#cmakedefine GIT_ARCH_64 1 +#cmakedefine GIT_ARCH_32 1 + +#cmakedefine GIT_USE_ICONV 1 +#cmakedefine GIT_USE_NSEC 1 +#cmakedefine GIT_USE_STAT_MTIM 1 +#cmakedefine GIT_USE_STAT_MTIMESPEC 1 +#cmakedefine GIT_USE_STAT_MTIME_NSEC 1 +#cmakedefine GIT_USE_FUTIMENS 1 + +#cmakedefine GIT_REGEX_REGCOMP_L +#cmakedefine GIT_REGEX_REGCOMP +#cmakedefine GIT_REGEX_PCRE +#cmakedefine GIT_REGEX_PCRE2 +#cmakedefine GIT_REGEX_BUILTIN 1 + +#cmakedefine GIT_QSORT_BSD +#cmakedefine GIT_QSORT_GNU +#cmakedefine GIT_QSORT_C11 +#cmakedefine GIT_QSORT_MSC + +#cmakedefine GIT_SSH 1 +#cmakedefine GIT_SSH_EXEC 1 +#cmakedefine GIT_SSH_LIBSSH2 1 +#cmakedefine GIT_SSH_LIBSSH2_MEMORY_CREDENTIALS 1 + +#cmakedefine GIT_NTLM 1 +#cmakedefine GIT_GSSAPI 1 +#cmakedefine GIT_GSSFRAMEWORK 1 + +#cmakedefine GIT_WINHTTP 1 +#cmakedefine GIT_HTTPS 1 +#cmakedefine GIT_OPENSSL 1 +#cmakedefine GIT_OPENSSL_DYNAMIC 1 +#cmakedefine GIT_SECURE_TRANSPORT 1 +#cmakedefine GIT_MBEDTLS 1 +#cmakedefine GIT_SCHANNEL 1 + +#cmakedefine GIT_HTTPPARSER_HTTPPARSER 1 +#cmakedefine GIT_HTTPPARSER_LLHTTP 1 +#cmakedefine GIT_HTTPPARSER_BUILTIN 1 + +#cmakedefine GIT_SHA1_COLLISIONDETECT 1 +#cmakedefine GIT_SHA1_WIN32 1 +#cmakedefine GIT_SHA1_COMMON_CRYPTO 1 +#cmakedefine GIT_SHA1_OPENSSL 1 +#cmakedefine GIT_SHA1_OPENSSL_DYNAMIC 1 +#cmakedefine GIT_SHA1_MBEDTLS 1 + +#cmakedefine GIT_SHA256_BUILTIN 1 +#cmakedefine GIT_SHA256_WIN32 1 +#cmakedefine GIT_SHA256_COMMON_CRYPTO 1 +#cmakedefine GIT_SHA256_OPENSSL 1 +#cmakedefine GIT_SHA256_OPENSSL_DYNAMIC 1 +#cmakedefine GIT_SHA256_MBEDTLS 1 + +#cmakedefine GIT_RAND_GETENTROPY 1 +#cmakedefine GIT_RAND_GETLOADAVG 1 + +#cmakedefine GIT_IO_POLL 1 +#cmakedefine GIT_IO_WSAPOLL 1 +#cmakedefine GIT_IO_SELECT 1 + +#endif diff --git a/vendor/libgit2/src/util/git2_util.h b/vendor/libgit2/src/util/git2_util.h new file mode 100644 index 00000000..5bf09819 --- /dev/null +++ b/vendor/libgit2/src/util/git2_util.h @@ -0,0 +1,170 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_git2_util_h__ +#define INCLUDE_git2_util_h__ + +#if !defined(LIBGIT2_NO_FEATURES_H) +# include "git2_features.h" +#endif + +#include "git2/common.h" +#include "git2/sys/errors.h" +#include "cc-compat.h" + +typedef struct git_str git_str; + +/** Declare a function as always inlined. */ +#if defined(_MSC_VER) +# define GIT_INLINE(type) static __inline type +#elif defined(__GNUC__) +# define GIT_INLINE(type) static __inline__ type +#else +# define GIT_INLINE(type) static type +#endif + +/** Support for gcc/clang __has_builtin intrinsic */ +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +/** + * Declare that a function's return value must be used. + * + * Used mostly to guard against potential silent bugs at runtime. This is + * recommended to be added to functions that: + * + * - Allocate / reallocate memory. This prevents memory leaks or errors where + * buffers are expected to have grown to a certain size, but could not be + * resized. + * - Acquire locks. When a lock cannot be acquired, that will almost certainly + * cause a data race / undefined behavior. + */ +#if defined(__GNUC__) +# define GIT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +# define GIT_WARN_UNUSED_RESULT +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef GIT_WIN32 + +# include +# include +# include +# include +# include +# include "win32/msvc-compat.h" +# include "win32/mingw-compat.h" +# include "win32/win32-compat.h" +# include "win32/w32_common.h" +# include "win32/version.h" +# include "win32/error.h" +# ifdef GIT_THREADS +# include "win32/thread.h" +# endif + +#else + +# include +# include +# ifdef GIT_THREADS +# include +# include +# endif + +#define GIT_LIBGIT2_CALL +#define GIT_SYSTEM_CALL + +#ifdef GIT_USE_STAT_ATIMESPEC +# define st_atim st_atimespec +# define st_ctim st_ctimespec +# define st_mtim st_mtimespec +#endif + +# include + +#endif + +#include "git2/types.h" +#include "git2/errors.h" +#include "thread.h" +#include "integer.h" +#include "assert_safe.h" + +#include "posix.h" + +#define GIT_BUFSIZE_DEFAULT 65536 +#define GIT_BUFSIZE_FILEIO GIT_BUFSIZE_DEFAULT +#define GIT_BUFSIZE_FILTERIO GIT_BUFSIZE_DEFAULT +#define GIT_BUFSIZE_NETIO GIT_BUFSIZE_DEFAULT + + +/** + * Check a pointer allocation result, returning -1 if it failed. + */ +#define GIT_ERROR_CHECK_ALLOC(ptr) do { \ + if ((ptr) == NULL) { return -1; } \ + } while(0) + +/** + * Check a buffer allocation result, returning -1 if it failed. + */ +#define GIT_ERROR_CHECK_ALLOC_STR(buf) do { \ + if ((void *)(buf) == NULL || git_str_oom(buf)) { return -1; } \ + } while(0) + +/** + * Check a return value and propagate result if non-zero. + */ +#define GIT_ERROR_CHECK_ERROR(code) \ + do { int _err = (code); if (_err) return _err; } while (0) + + +/** Check for additive overflow, setting an error if would occur. */ +#define GIT_ADD_SIZET_OVERFLOW(out, one, two) \ + (git__add_sizet_overflow(out, one, two) ? (git_error_set_oom(), 1) : 0) + +/** Check for additive overflow, setting an error if would occur. */ +#define GIT_MULTIPLY_SIZET_OVERFLOW(out, nelem, elsize) \ + (git__multiply_sizet_overflow(out, nelem, elsize) ? (git_error_set_oom(), 1) : 0) + +/** Check for additive overflow, failing if it would occur. */ +#define GIT_ERROR_CHECK_ALLOC_ADD(out, one, two) \ + if (GIT_ADD_SIZET_OVERFLOW(out, one, two)) { return -1; } + +#define GIT_ERROR_CHECK_ALLOC_ADD3(out, one, two, three) \ + if (GIT_ADD_SIZET_OVERFLOW(out, one, two) || \ + GIT_ADD_SIZET_OVERFLOW(out, *(out), three)) { return -1; } + +#define GIT_ERROR_CHECK_ALLOC_ADD4(out, one, two, three, four) \ + if (GIT_ADD_SIZET_OVERFLOW(out, one, two) || \ + GIT_ADD_SIZET_OVERFLOW(out, *(out), three) || \ + GIT_ADD_SIZET_OVERFLOW(out, *(out), four)) { return -1; } + +#define GIT_ERROR_CHECK_ALLOC_ADD5(out, one, two, three, four, five) \ + if (GIT_ADD_SIZET_OVERFLOW(out, one, two) || \ + GIT_ADD_SIZET_OVERFLOW(out, *(out), three) || \ + GIT_ADD_SIZET_OVERFLOW(out, *(out), four) || \ + GIT_ADD_SIZET_OVERFLOW(out, *(out), five)) { return -1; } + +/** Check for multiplicative overflow, failing if it would occur. */ +#define GIT_ERROR_CHECK_ALLOC_MULTIPLY(out, nelem, elsize) \ + if (GIT_MULTIPLY_SIZET_OVERFLOW(out, nelem, elsize)) { return -1; } + +#include "util.h" +#include "ctype_compat.h" + +#endif diff --git a/vendor/libgit2/src/util/hash.c b/vendor/libgit2/src/util/hash.c new file mode 100644 index 00000000..ff900cea --- /dev/null +++ b/vendor/libgit2/src/util/hash.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "hash.h" + +int git_hash_global_init(void) +{ + if (git_hash_sha1_global_init() < 0 || + git_hash_sha256_global_init() < 0) + return -1; + + return 0; +} + +int git_hash_ctx_init(git_hash_ctx *ctx, git_hash_algorithm_t algorithm) +{ + int error; + + switch (algorithm) { + case GIT_HASH_ALGORITHM_SHA1: + error = git_hash_sha1_ctx_init(&ctx->ctx.sha1); + break; + case GIT_HASH_ALGORITHM_SHA256: + error = git_hash_sha256_ctx_init(&ctx->ctx.sha256); + break; + default: + git_error_set(GIT_ERROR_INTERNAL, "unknown hash algorithm"); + error = -1; + } + + ctx->algorithm = algorithm; + return error; +} + +void git_hash_ctx_cleanup(git_hash_ctx *ctx) +{ + switch (ctx->algorithm) { + case GIT_HASH_ALGORITHM_SHA1: + git_hash_sha1_ctx_cleanup(&ctx->ctx.sha1); + return; + case GIT_HASH_ALGORITHM_SHA256: + git_hash_sha256_ctx_cleanup(&ctx->ctx.sha256); + return; + default: + /* unreachable */ ; + } +} + +int git_hash_init(git_hash_ctx *ctx) +{ + switch (ctx->algorithm) { + case GIT_HASH_ALGORITHM_SHA1: + return git_hash_sha1_init(&ctx->ctx.sha1); + case GIT_HASH_ALGORITHM_SHA256: + return git_hash_sha256_init(&ctx->ctx.sha256); + default: + /* unreachable */ ; + } + + git_error_set(GIT_ERROR_INTERNAL, "unknown hash algorithm"); + return -1; +} + +int git_hash_update(git_hash_ctx *ctx, const void *data, size_t len) +{ + switch (ctx->algorithm) { + case GIT_HASH_ALGORITHM_SHA1: + return git_hash_sha1_update(&ctx->ctx.sha1, data, len); + case GIT_HASH_ALGORITHM_SHA256: + return git_hash_sha256_update(&ctx->ctx.sha256, data, len); + default: + /* unreachable */ ; + } + + git_error_set(GIT_ERROR_INTERNAL, "unknown hash algorithm"); + return -1; +} + +int git_hash_final(unsigned char *out, git_hash_ctx *ctx) +{ + switch (ctx->algorithm) { + case GIT_HASH_ALGORITHM_SHA1: + return git_hash_sha1_final(out, &ctx->ctx.sha1); + case GIT_HASH_ALGORITHM_SHA256: + return git_hash_sha256_final(out, &ctx->ctx.sha256); + default: + /* unreachable */ ; + } + + git_error_set(GIT_ERROR_INTERNAL, "unknown hash algorithm"); + return -1; +} + +int git_hash_buf( + unsigned char *out, + const void *data, + size_t len, + git_hash_algorithm_t algorithm) +{ + git_hash_ctx ctx; + int error = 0; + + if (git_hash_ctx_init(&ctx, algorithm) < 0) + return -1; + + if ((error = git_hash_update(&ctx, data, len)) >= 0) + error = git_hash_final(out, &ctx); + + git_hash_ctx_cleanup(&ctx); + + return error; +} + +int git_hash_vec( + unsigned char *out, + git_str_vec *vec, + size_t n, + git_hash_algorithm_t algorithm) +{ + git_hash_ctx ctx; + size_t i; + int error = 0; + + if (git_hash_ctx_init(&ctx, algorithm) < 0) + return -1; + + for (i = 0; i < n; i++) { + if ((error = git_hash_update(&ctx, vec[i].data, vec[i].len)) < 0) + goto done; + } + + error = git_hash_final(out, &ctx); + +done: + git_hash_ctx_cleanup(&ctx); + + return error; +} + +int git_hash_fmt(char *out, unsigned char *hash, size_t hash_len) +{ + static char hex[] = "0123456789abcdef"; + char *str = out; + size_t i; + + for (i = 0; i < hash_len; i++) { + *str++ = hex[hash[i] >> 4]; + *str++ = hex[hash[i] & 0x0f]; + } + + *str++ = '\0'; + + return 0; +} diff --git a/vendor/libgit2/src/util/hash.h b/vendor/libgit2/src/util/hash.h new file mode 100644 index 00000000..21fcaf04 --- /dev/null +++ b/vendor/libgit2/src/util/hash.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_hash_h__ +#define INCLUDE_hash_h__ + +#include "git2_util.h" + +#include "hash/sha.h" + +typedef struct { + void *data; + size_t len; +} git_str_vec; + +typedef enum { + GIT_HASH_ALGORITHM_NONE = 0, + GIT_HASH_ALGORITHM_SHA1, + GIT_HASH_ALGORITHM_SHA256 +} git_hash_algorithm_t; + +#define GIT_HASH_MAX_SIZE GIT_HASH_SHA256_SIZE + +typedef struct git_hash_ctx { + union { + git_hash_sha1_ctx sha1; + git_hash_sha256_ctx sha256; + } ctx; + git_hash_algorithm_t algorithm; +} git_hash_ctx; + +int git_hash_global_init(void); + +int git_hash_ctx_init(git_hash_ctx *ctx, git_hash_algorithm_t algorithm); +void git_hash_ctx_cleanup(git_hash_ctx *ctx); + +int git_hash_init(git_hash_ctx *c); +int git_hash_update(git_hash_ctx *c, const void *data, size_t len); +int git_hash_final(unsigned char *out, git_hash_ctx *c); + +int git_hash_buf(unsigned char *out, const void *data, size_t len, git_hash_algorithm_t algorithm); +int git_hash_vec(unsigned char *out, git_str_vec *vec, size_t n, git_hash_algorithm_t algorithm); + +int git_hash_fmt(char *out, unsigned char *hash, size_t hash_len); + +GIT_INLINE(size_t) git_hash_size(git_hash_algorithm_t algorithm) { + switch (algorithm) { + case GIT_HASH_ALGORITHM_SHA1: + return GIT_HASH_SHA1_SIZE; + case GIT_HASH_ALGORITHM_SHA256: + return GIT_HASH_SHA256_SIZE; + default: + return 0; + } +} + +#endif diff --git a/vendor/libgit2/src/util/hash/builtin.c b/vendor/libgit2/src/util/hash/builtin.c new file mode 100644 index 00000000..cc4aa58f --- /dev/null +++ b/vendor/libgit2/src/util/hash/builtin.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "builtin.h" + +int git_hash_sha256_global_init(void) +{ + return 0; +} + +int git_hash_sha256_ctx_init(git_hash_sha256_ctx *ctx) +{ + return git_hash_sha256_init(ctx); +} + +void git_hash_sha256_ctx_cleanup(git_hash_sha256_ctx *ctx) +{ + GIT_UNUSED(ctx); +} + +int git_hash_sha256_init(git_hash_sha256_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + if (SHA256Reset(&ctx->c)) { + git_error_set(GIT_ERROR_SHA, "SHA256 error"); + return -1; + } + return 0; +} + +int git_hash_sha256_update(git_hash_sha256_ctx *ctx, const void *data, size_t len) +{ + GIT_ASSERT_ARG(ctx); + if (SHA256Input(&ctx->c, data, len)) { + git_error_set(GIT_ERROR_SHA, "SHA256 error"); + return -1; + } + return 0; +} + +int git_hash_sha256_final(unsigned char *out, git_hash_sha256_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + if (SHA256Result(&ctx->c, out)) { + git_error_set(GIT_ERROR_SHA, "SHA256 error"); + return -1; + } + return 0; +} diff --git a/vendor/libgit2/src/util/hash/builtin.h b/vendor/libgit2/src/util/hash/builtin.h new file mode 100644 index 00000000..769df1ac --- /dev/null +++ b/vendor/libgit2/src/util/hash/builtin.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_hash_builtin_h__ +#define INCLUDE_hash_builtin_h__ + +#include "hash/sha.h" + +#include "rfc6234/sha.h" + +struct git_hash_sha256_ctx { + SHA256Context c; +}; + +#endif diff --git a/vendor/libgit2/src/hash/sha1/collisiondetect.c b/vendor/libgit2/src/util/hash/collisiondetect.c similarity index 92% rename from vendor/libgit2/src/hash/sha1/collisiondetect.c rename to vendor/libgit2/src/util/hash/collisiondetect.c index ec7059c4..c51a402d 100644 --- a/vendor/libgit2/src/hash/sha1/collisiondetect.c +++ b/vendor/libgit2/src/util/hash/collisiondetect.c @@ -40,7 +40,7 @@ int git_hash_sha1_final(unsigned char *out, git_hash_sha1_ctx *ctx) { GIT_ASSERT_ARG(ctx); if (SHA1DCFinal(out, &ctx->c)) { - git_error_set(GIT_ERROR_SHA1, "SHA1 collision attack detected"); + git_error_set(GIT_ERROR_SHA, "SHA1 collision attack detected"); return -1; } diff --git a/vendor/libgit2/src/util/hash/collisiondetect.h b/vendor/libgit2/src/util/hash/collisiondetect.h new file mode 100644 index 00000000..8de55023 --- /dev/null +++ b/vendor/libgit2/src/util/hash/collisiondetect.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_hash_collisiondetect_h__ +#define INCLUDE_hash_collisiondetect_h__ + +#include "hash/sha.h" + +#include "sha1dc/sha1.h" + +struct git_hash_sha1_ctx { + SHA1_CTX c; +}; + +#endif diff --git a/vendor/libgit2/src/util/hash/common_crypto.c b/vendor/libgit2/src/util/hash/common_crypto.c new file mode 100644 index 00000000..b327ba9e --- /dev/null +++ b/vendor/libgit2/src/util/hash/common_crypto.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "common_crypto.h" + +#define CC_LONG_MAX ((CC_LONG)-1) + +#ifdef GIT_SHA1_COMMON_CRYPTO + +int git_hash_sha1_global_init(void) +{ + return 0; +} + +int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx) +{ + return git_hash_sha1_init(ctx); +} + +void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx) +{ + GIT_UNUSED(ctx); +} + +int git_hash_sha1_init(git_hash_sha1_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + CC_SHA1_Init(&ctx->c); + return 0; +} + +int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *_data, size_t len) +{ + const unsigned char *data = _data; + + GIT_ASSERT_ARG(ctx); + + while (len > 0) { + CC_LONG chunk = (len > CC_LONG_MAX) ? CC_LONG_MAX : (CC_LONG)len; + + CC_SHA1_Update(&ctx->c, data, chunk); + + data += chunk; + len -= chunk; + } + + return 0; +} + +int git_hash_sha1_final(unsigned char *out, git_hash_sha1_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + CC_SHA1_Final(out, &ctx->c); + return 0; +} + +#endif + +#ifdef GIT_SHA256_COMMON_CRYPTO + +int git_hash_sha256_global_init(void) +{ + return 0; +} + +int git_hash_sha256_ctx_init(git_hash_sha256_ctx *ctx) +{ + return git_hash_sha256_init(ctx); +} + +void git_hash_sha256_ctx_cleanup(git_hash_sha256_ctx *ctx) +{ + GIT_UNUSED(ctx); +} + +int git_hash_sha256_init(git_hash_sha256_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + CC_SHA256_Init(&ctx->c); + return 0; +} + +int git_hash_sha256_update(git_hash_sha256_ctx *ctx, const void *_data, size_t len) +{ + const unsigned char *data = _data; + + GIT_ASSERT_ARG(ctx); + + while (len > 0) { + CC_LONG chunk = (len > CC_LONG_MAX) ? CC_LONG_MAX : (CC_LONG)len; + + CC_SHA256_Update(&ctx->c, data, chunk); + + data += chunk; + len -= chunk; + } + + return 0; +} + +int git_hash_sha256_final(unsigned char *out, git_hash_sha256_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + CC_SHA256_Final(out, &ctx->c); + return 0; +} + +#endif diff --git a/vendor/libgit2/src/util/hash/common_crypto.h b/vendor/libgit2/src/util/hash/common_crypto.h new file mode 100644 index 00000000..157712b5 --- /dev/null +++ b/vendor/libgit2/src/util/hash/common_crypto.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_hash_common_crypto_h__ +#define INCLUDE_hash_common_crypto_h__ + +#include "hash/sha.h" + +#include + +#ifdef GIT_SHA1_COMMON_CRYPTO +struct git_hash_sha1_ctx { + CC_SHA1_CTX c; +}; +#endif + +#ifdef GIT_SHA256_COMMON_CRYPTO +struct git_hash_sha256_ctx { + CC_SHA256_CTX c; +}; +#endif + +#endif diff --git a/vendor/libgit2/src/util/hash/mbedtls.c b/vendor/libgit2/src/util/hash/mbedtls.c new file mode 100644 index 00000000..ecdfb787 --- /dev/null +++ b/vendor/libgit2/src/util/hash/mbedtls.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "mbedtls.h" + +#ifdef GIT_SHA1_MBEDTLS + +int git_hash_sha1_global_init(void) +{ + return 0; +} + +int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx) +{ + return git_hash_sha1_init(ctx); +} + +void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx) +{ + if (ctx) + mbedtls_sha1_free(&ctx->c); +} + +int git_hash_sha1_init(git_hash_sha1_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + mbedtls_sha1_init(&ctx->c); + mbedtls_sha1_starts(&ctx->c); + return 0; +} + +int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len) +{ + GIT_ASSERT_ARG(ctx); + mbedtls_sha1_update(&ctx->c, data, len); + return 0; +} + +int git_hash_sha1_final(unsigned char *out, git_hash_sha1_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + mbedtls_sha1_finish(&ctx->c, out); + return 0; +} + +#endif + +#ifdef GIT_SHA256_MBEDTLS + +int git_hash_sha256_global_init(void) +{ + return 0; +} + +int git_hash_sha256_ctx_init(git_hash_sha256_ctx *ctx) +{ + return git_hash_sha256_init(ctx); +} + +void git_hash_sha256_ctx_cleanup(git_hash_sha256_ctx *ctx) +{ + if (ctx) + mbedtls_sha256_free(&ctx->c); +} + +int git_hash_sha256_init(git_hash_sha256_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + mbedtls_sha256_init(&ctx->c); + mbedtls_sha256_starts(&ctx->c, 0); + return 0; +} + +int git_hash_sha256_update(git_hash_sha256_ctx *ctx, const void *data, size_t len) +{ + GIT_ASSERT_ARG(ctx); + mbedtls_sha256_update(&ctx->c, data, len); + return 0; +} + +int git_hash_sha256_final(unsigned char *out, git_hash_sha256_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + mbedtls_sha256_finish(&ctx->c, out); + return 0; +} + +#endif diff --git a/vendor/libgit2/src/util/hash/mbedtls.h b/vendor/libgit2/src/util/hash/mbedtls.h new file mode 100644 index 00000000..05fb38b0 --- /dev/null +++ b/vendor/libgit2/src/util/hash/mbedtls.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_hash_mbedtls_h__ +#define INCLUDE_hash_mbedtls_h__ + +#include "hash/sha.h" + +#ifdef GIT_SHA1_MBEDTLS +# include + +struct git_hash_sha1_ctx { + mbedtls_sha1_context c; +}; +#endif + +#ifdef GIT_SHA256_MBEDTLS +# include + +struct git_hash_sha256_ctx { + mbedtls_sha256_context c; +}; +#endif + +#endif /* INCLUDE_hash_sha1_mbedtls_h__ */ diff --git a/vendor/libgit2/src/util/hash/openssl.c b/vendor/libgit2/src/util/hash/openssl.c new file mode 100644 index 00000000..eaf91e74 --- /dev/null +++ b/vendor/libgit2/src/util/hash/openssl.c @@ -0,0 +1,195 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "openssl.h" + +#ifdef GIT_OPENSSL_DYNAMIC +# include + +static int handle_count; +static void *openssl_handle; + +static int git_hash_openssl_global_shutdown(void) +{ + if (--handle_count == 0) { + dlclose(openssl_handle); + openssl_handle = NULL; + } + + return 0; +} + +static int git_hash_openssl_global_init(void) +{ + if (!handle_count) { + if ((openssl_handle = dlopen("libssl.so.1.1", RTLD_NOW)) == NULL && + (openssl_handle = dlopen("libssl.1.1.dylib", RTLD_NOW)) == NULL && + (openssl_handle = dlopen("libssl.so.1.0.0", RTLD_NOW)) == NULL && + (openssl_handle = dlopen("libssl.1.0.0.dylib", RTLD_NOW)) == NULL && + (openssl_handle = dlopen("libssl.so.10", RTLD_NOW)) == NULL && + (openssl_handle = dlopen("libssl.so.3", RTLD_NOW)) == NULL) { + git_error_set(GIT_ERROR_SSL, "could not load ssl libraries"); + return -1; + } + } + + if (git_hash_openssl_global_shutdown() < 0) + return -1; + + handle_count++; + return 0; +} + +#endif + +#ifdef GIT_SHA1_OPENSSL + +# ifdef GIT_OPENSSL_DYNAMIC +static int (*SHA1_Init)(SHA_CTX *c); +static int (*SHA1_Update)(SHA_CTX *c, const void *data, size_t len); +static int (*SHA1_Final)(unsigned char *md, SHA_CTX *c); +# endif + +int git_hash_sha1_global_init(void) +{ +#ifdef GIT_OPENSSL_DYNAMIC + if (git_hash_openssl_global_init() < 0) + return -1; + + if ((SHA1_Init = dlsym(openssl_handle, "SHA1_Init")) == NULL || + (SHA1_Update = dlsym(openssl_handle, "SHA1_Update")) == NULL || + (SHA1_Final = dlsym(openssl_handle, "SHA1_Final")) == NULL) { + const char *msg = dlerror(); + git_error_set(GIT_ERROR_SSL, "could not load hash function: %s", msg ? msg : "unknown error"); + return -1; + } +#endif + + return 0; +} + +int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx) +{ + return git_hash_sha1_init(ctx); +} + +void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx) +{ + GIT_UNUSED(ctx); +} + +int git_hash_sha1_init(git_hash_sha1_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + + if (SHA1_Init(&ctx->c) != 1) { + git_error_set(GIT_ERROR_SHA, "failed to initialize sha1 context"); + return -1; + } + + return 0; +} + +int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len) +{ + GIT_ASSERT_ARG(ctx); + + if (SHA1_Update(&ctx->c, data, len) != 1) { + git_error_set(GIT_ERROR_SHA, "failed to update sha1"); + return -1; + } + + return 0; +} + +int git_hash_sha1_final(unsigned char *out, git_hash_sha1_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + + if (SHA1_Final(out, &ctx->c) != 1) { + git_error_set(GIT_ERROR_SHA, "failed to finalize sha1"); + return -1; + } + + return 0; +} + +#endif + +#ifdef GIT_SHA256_OPENSSL + +# ifdef GIT_OPENSSL_DYNAMIC +static int (*SHA256_Init)(SHA256_CTX *c); +static int (*SHA256_Update)(SHA256_CTX *c, const void *data, size_t len); +static int (*SHA256_Final)(unsigned char *md, SHA256_CTX *c); +#endif + +int git_hash_sha256_global_init(void) +{ +#ifdef GIT_OPENSSL_DYNAMIC + if (git_hash_openssl_global_init() < 0) + return -1; + + if ((SHA256_Init = dlsym(openssl_handle, "SHA256_Init")) == NULL || + (SHA256_Update = dlsym(openssl_handle, "SHA256_Update")) == NULL || + (SHA256_Final = dlsym(openssl_handle, "SHA256_Final")) == NULL) { + const char *msg = dlerror(); + git_error_set(GIT_ERROR_SSL, "could not load hash function: %s", msg ? msg : "unknown error"); + return -1; + } +#endif + + return 0; +} + +int git_hash_sha256_ctx_init(git_hash_sha256_ctx *ctx) +{ + return git_hash_sha256_init(ctx); +} + +void git_hash_sha256_ctx_cleanup(git_hash_sha256_ctx *ctx) +{ + GIT_UNUSED(ctx); +} + +int git_hash_sha256_init(git_hash_sha256_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + + if (SHA256_Init(&ctx->c) != 1) { + git_error_set(GIT_ERROR_SHA, "failed to initialize sha256 context"); + return -1; + } + + return 0; +} + +int git_hash_sha256_update(git_hash_sha256_ctx *ctx, const void *data, size_t len) +{ + GIT_ASSERT_ARG(ctx); + + if (SHA256_Update(&ctx->c, data, len) != 1) { + git_error_set(GIT_ERROR_SHA, "failed to update sha256"); + return -1; + } + + return 0; +} + +int git_hash_sha256_final(unsigned char *out, git_hash_sha256_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + + if (SHA256_Final(out, &ctx->c) != 1) { + git_error_set(GIT_ERROR_SHA, "failed to finalize sha256"); + return -1; + } + + return 0; +} + +#endif diff --git a/vendor/libgit2/src/util/hash/openssl.h b/vendor/libgit2/src/util/hash/openssl.h new file mode 100644 index 00000000..7cb089ab --- /dev/null +++ b/vendor/libgit2/src/util/hash/openssl.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_hash_openssl_h__ +#define INCLUDE_hash_openssl_h__ + +#include "hash/sha.h" + +#ifndef GIT_OPENSSL_DYNAMIC +# include +#else + +typedef struct { + unsigned int h0, h1, h2, h3, h4; + unsigned int Nl, Nh; + unsigned int data[16]; + unsigned int num; +} SHA_CTX; + +typedef struct { + unsigned int h[8]; + unsigned int Nl, Nh; + unsigned int data[16]; + unsigned int num, md_len; +} SHA256_CTX; + +#endif + +#ifdef GIT_SHA1_OPENSSL +struct git_hash_sha1_ctx { + SHA_CTX c; +}; +#endif + +#ifdef GIT_SHA256_OPENSSL +struct git_hash_sha256_ctx { + SHA256_CTX c; +}; +#endif + +#endif diff --git a/vendor/libgit2/src/util/hash/rfc6234/sha.h b/vendor/libgit2/src/util/hash/rfc6234/sha.h new file mode 100644 index 00000000..0fbcc50d --- /dev/null +++ b/vendor/libgit2/src/util/hash/rfc6234/sha.h @@ -0,0 +1,243 @@ +/**************************** sha.h ****************************/ +/***************** See RFC 6234 for details. *******************/ +/* + Copyright (c) 2011 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, are permitted provided that the following + conditions are met: + + - Redistributions of source code must retain the above + copyright notice, this list of conditions and + the following disclaimer. + + - Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + - Neither the name of Internet Society, IETF or IETF Trust, nor + the names of specific contributors, may be used to endorse or + promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef _SHA_H_ +#define _SHA_H_ + +/* + * Description: + * This file implements the Secure Hash Algorithms + * as defined in the U.S. National Institute of Standards + * and Technology Federal Information Processing Standards + * Publication (FIPS PUB) 180-3 published in October 2008 + * and formerly defined in its predecessors, FIPS PUB 180-1 + * and FIP PUB 180-2. + * + * A combined document showing all algorithms is available at + * http://csrc.nist.gov/publications/fips/ + * fips180-3/fips180-3_final.pdf + * + * The five hashes are defined in these sizes: + * SHA-1 20 byte / 160 bit + * SHA-224 28 byte / 224 bit + * SHA-256 32 byte / 256 bit + * SHA-384 48 byte / 384 bit + * SHA-512 64 byte / 512 bit + * + * Compilation Note: + * These files may be compiled with two options: + * USE_32BIT_ONLY - use 32-bit arithmetic only, for systems + * without 64-bit integers + * + * USE_MODIFIED_MACROS - use alternate form of the SHA_Ch() + * and SHA_Maj() macros that are equivalent + * and potentially faster on many systems + * + */ + +#include +/* + * If you do not have the ISO standard stdint.h header file, then you + * must typedef the following: + * name meaning + * uint64_t unsigned 64-bit integer + * uint32_t unsigned 32-bit integer + * uint8_t unsigned 8-bit integer (i.e., unsigned char) + * int_least16_t integer of >= 16 bits + * + * See stdint-example.h + */ + +#ifndef _SHA_enum_ +#define _SHA_enum_ +/* + * All SHA functions return one of these values. + */ +enum { + shaSuccess = 0, + shaNull, /* Null pointer parameter */ + shaInputTooLong, /* input data too long */ + shaStateError, /* called Input after FinalBits or Result */ + shaBadParam /* passed a bad parameter */ +}; +#endif /* _SHA_enum_ */ + +/* + * These constants hold size information for each of the SHA + * hashing operations + */ +enum { + SHA1_Message_Block_Size = 64, SHA224_Message_Block_Size = 64, + SHA256_Message_Block_Size = 64, SHA384_Message_Block_Size = 128, + SHA512_Message_Block_Size = 128, + USHA_Max_Message_Block_Size = SHA512_Message_Block_Size, + SHA1HashSize = 20, SHA224HashSize = 28, SHA256HashSize = 32, + SHA384HashSize = 48, SHA512HashSize = 64, + USHAMaxHashSize = SHA512HashSize, + + SHA1HashSizeBits = 160, SHA224HashSizeBits = 224, + SHA256HashSizeBits = 256, SHA384HashSizeBits = 384, + SHA512HashSizeBits = 512, USHAMaxHashSizeBits = SHA512HashSizeBits +}; + +/* + * These constants are used in the USHA (Unified SHA) functions. + */ +typedef enum SHAversion { + SHA1, SHA224, SHA256, SHA384, SHA512 +} SHAversion; + +/* + * This structure will hold context information for the SHA-1 + * hashing operation. + */ +typedef struct SHA1Context { + uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ + + uint32_t Length_High; /* Message length in bits */ + uint32_t Length_Low; /* Message length in bits */ + + int_least16_t Message_Block_Index; /* Message_Block array index */ + /* 512-bit message blocks */ + uint8_t Message_Block[SHA1_Message_Block_Size]; + + int Computed; /* Is the hash computed? */ + int Corrupted; /* Cumulative corruption code */ +} SHA1Context; + +/* + * This structure will hold context information for the SHA-256 + * hashing operation. + */ +typedef struct SHA256Context { + uint32_t Intermediate_Hash[SHA256HashSize/4]; /* Message Digest */ + + uint32_t Length_High; /* Message length in bits */ + uint32_t Length_Low; /* Message length in bits */ + + int_least16_t Message_Block_Index; /* Message_Block array index */ + /* 512-bit message blocks */ + uint8_t Message_Block[SHA256_Message_Block_Size]; + + int Computed; /* Is the hash computed? */ + int Corrupted; /* Cumulative corruption code */ +} SHA256Context; + +/* + * This structure will hold context information for the SHA-512 + * hashing operation. + */ +typedef struct SHA512Context { +#ifdef USE_32BIT_ONLY + uint32_t Intermediate_Hash[SHA512HashSize/4]; /* Message Digest */ + uint32_t Length[4]; /* Message length in bits */ +#else /* !USE_32BIT_ONLY */ + uint64_t Intermediate_Hash[SHA512HashSize/8]; /* Message Digest */ + uint64_t Length_High, Length_Low; /* Message length in bits */ +#endif /* USE_32BIT_ONLY */ + + int_least16_t Message_Block_Index; /* Message_Block array index */ + /* 1024-bit message blocks */ + uint8_t Message_Block[SHA512_Message_Block_Size]; + + int Computed; /* Is the hash computed?*/ + int Corrupted; /* Cumulative corruption code */ +} SHA512Context; + +/* + * This structure will hold context information for the SHA-224 + * hashing operation. It uses the SHA-256 structure for computation. + */ +typedef struct SHA256Context SHA224Context; + +/* + * This structure will hold context information for the SHA-384 + * hashing operation. It uses the SHA-512 structure for computation. + */ +typedef struct SHA512Context SHA384Context; + +/* + * Function Prototypes + */ + +/* SHA-1 */ +extern int SHA1Reset(SHA1Context *); +extern int SHA1Input(SHA1Context *, const uint8_t *bytes, + unsigned int bytecount); +extern int SHA1FinalBits(SHA1Context *, uint8_t bits, + unsigned int bit_count); +extern int SHA1Result(SHA1Context *, + uint8_t Message_Digest[SHA1HashSize]); + +/* SHA-224 */ +extern int SHA224Reset(SHA224Context *); +extern int SHA224Input(SHA224Context *, const uint8_t *bytes, + unsigned int bytecount); +extern int SHA224FinalBits(SHA224Context *, uint8_t bits, + unsigned int bit_count); +extern int SHA224Result(SHA224Context *, + uint8_t Message_Digest[SHA224HashSize]); + +/* SHA-256 */ +extern int SHA256Reset(SHA256Context *); +extern int SHA256Input(SHA256Context *, const uint8_t *bytes, + unsigned int bytecount); +extern int SHA256FinalBits(SHA256Context *, uint8_t bits, + unsigned int bit_count); +extern int SHA256Result(SHA256Context *, + uint8_t Message_Digest[SHA256HashSize]); + +/* SHA-384 */ +extern int SHA384Reset(SHA384Context *); +extern int SHA384Input(SHA384Context *, const uint8_t *bytes, + unsigned int bytecount); +extern int SHA384FinalBits(SHA384Context *, uint8_t bits, + unsigned int bit_count); +extern int SHA384Result(SHA384Context *, + uint8_t Message_Digest[SHA384HashSize]); + +/* SHA-512 */ +extern int SHA512Reset(SHA512Context *); +extern int SHA512Input(SHA512Context *, const uint8_t *bytes, + unsigned int bytecount); +extern int SHA512FinalBits(SHA512Context *, uint8_t bits, + unsigned int bit_count); +extern int SHA512Result(SHA512Context *, + uint8_t Message_Digest[SHA512HashSize]); + +#endif /* _SHA_H_ */ diff --git a/vendor/libgit2/src/util/hash/rfc6234/sha224-256.c b/vendor/libgit2/src/util/hash/rfc6234/sha224-256.c new file mode 100644 index 00000000..c8e0cf85 --- /dev/null +++ b/vendor/libgit2/src/util/hash/rfc6234/sha224-256.c @@ -0,0 +1,601 @@ +/************************* sha224-256.c ************************/ +/***************** See RFC 6234 for details. *******************/ +/* Copyright (c) 2011 IETF Trust and the persons identified as */ +/* authors of the code. All rights reserved. */ +/* See sha.h for terms of use and redistribution. */ + +/* + * Description: + * This file implements the Secure Hash Algorithms SHA-224 and + * SHA-256 as defined in the U.S. National Institute of Standards + * and Technology Federal Information Processing Standards + * Publication (FIPS PUB) 180-3 published in October 2008 + * and formerly defined in its predecessors, FIPS PUB 180-1 + * and FIP PUB 180-2. + * + * A combined document showing all algorithms is available at + * http://csrc.nist.gov/publications/fips/ + * fips180-3/fips180-3_final.pdf + * + * The SHA-224 and SHA-256 algorithms produce 224-bit and 256-bit + * message digests for a given data stream. It should take about + * 2**n steps to find a message with the same digest as a given + * message and 2**(n/2) to find any two messages with the same + * digest, when n is the digest size in bits. Therefore, this + * algorithm can serve as a means of providing a + * "fingerprint" for a message. + * + * Portability Issues: + * SHA-224 and SHA-256 are defined in terms of 32-bit "words". + * This code uses (included via "sha.h") to define 32- + * and 8-bit unsigned integer types. If your C compiler does not + * support 32-bit unsigned integers, this code is not + * appropriate. + * + * Caveats: + * SHA-224 and SHA-256 are designed to work with messages less + * than 2^64 bits long. This implementation uses SHA224/256Input() + * to hash the bits that are a multiple of the size of an 8-bit + * octet, and then optionally uses SHA224/256FinalBits() + * to hash the final few bits of the input. + */ + +#include "sha.h" + +/* + * These definitions are defined in FIPS 180-3, section 4.1. + * Ch() and Maj() are defined identically in sections 4.1.1, + * 4.1.2, and 4.1.3. + * + * The definitions used in FIPS 180-3 are as follows: + */ +#ifndef USE_MODIFIED_MACROS +#define SHA_Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define SHA_Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#else /* USE_MODIFIED_MACROS */ +/* + * The following definitions are equivalent and potentially faster. + */ +#define SHA_Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z)) +#define SHA_Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) +#endif /* USE_MODIFIED_MACROS */ + +#define SHA_Parity(x, y, z) ((x) ^ (y) ^ (z)) + +/* Define the SHA shift, rotate left, and rotate right macros */ +#define SHA256_SHR(bits,word) ((word) >> (bits)) +#define SHA256_ROTL(bits,word) \ + (((word) << (bits)) | ((word) >> (32-(bits)))) +#define SHA256_ROTR(bits,word) \ + (((word) >> (bits)) | ((word) << (32-(bits)))) + +/* Define the SHA SIGMA and sigma macros */ +#define SHA256_SIGMA0(word) \ + (SHA256_ROTR( 2,word) ^ SHA256_ROTR(13,word) ^ SHA256_ROTR(22,word)) +#define SHA256_SIGMA1(word) \ + (SHA256_ROTR( 6,word) ^ SHA256_ROTR(11,word) ^ SHA256_ROTR(25,word)) +#define SHA256_sigma0(word) \ + (SHA256_ROTR( 7,word) ^ SHA256_ROTR(18,word) ^ SHA256_SHR( 3,word)) +#define SHA256_sigma1(word) \ + (SHA256_ROTR(17,word) ^ SHA256_ROTR(19,word) ^ SHA256_SHR(10,word)) + +/* + * Add "length" to the length. + * Set Corrupted when overflow has occurred. + */ +static uint32_t addTemp; +#define SHA224_256AddLength(context, length) \ + (addTemp = (context)->Length_Low, (context)->Corrupted = \ + (((context)->Length_Low += (length)) < addTemp) && \ + (++(context)->Length_High == 0) ? shaInputTooLong : \ + (context)->Corrupted ) + +/* Local Function Prototypes */ +static int SHA224_256Reset(SHA256Context *context, uint32_t *H0); +static void SHA224_256ProcessMessageBlock(SHA256Context *context); +static void SHA224_256Finalize(SHA256Context *context, + uint8_t Pad_Byte); +static void SHA224_256PadMessage(SHA256Context *context, + uint8_t Pad_Byte); +static int SHA224_256ResultN(SHA256Context *context, + uint8_t Message_Digest[ ], int HashSize); + +/* Initial Hash Values: FIPS 180-3 section 5.3.2 */ +static uint32_t SHA224_H0[SHA256HashSize/4] = { + 0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939, + 0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4 +}; + +/* Initial Hash Values: FIPS 180-3 section 5.3.3 */ +static uint32_t SHA256_H0[SHA256HashSize/4] = { + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 +}; + +/* + * SHA224Reset + * + * Description: + * This function will initialize the SHA224Context in preparation + * for computing a new SHA224 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + */ +int SHA224Reset(SHA224Context *context) +{ + return SHA224_256Reset(context, SHA224_H0); +} + +/* + * SHA224Input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * message_array[ ]: [in] + * An array of octets representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array. + * + * Returns: + * sha Error Code. + * + */ +int SHA224Input(SHA224Context *context, const uint8_t *message_array, + unsigned int length) +{ + return SHA256Input(context, message_array, length); +} + +/* + * SHA224FinalBits + * + * Description: + * This function will add in any final bits of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * message_bits: [in] + * The final bits of the message, in the upper portion of the + * byte. (Use 0b###00000 instead of 0b00000### to input the + * three bits ###.) + * length: [in] + * The number of bits in message_bits, between 1 and 7. + * + * Returns: + * sha Error Code. + */ +int SHA224FinalBits(SHA224Context *context, + uint8_t message_bits, unsigned int length) +{ + return SHA256FinalBits(context, message_bits, length); +} + +/* + * SHA224Result + * + * Description: + * This function will return the 224-bit message digest + * into the Message_Digest array provided by the caller. + * NOTE: + * The first octet of hash is stored in the element with index 0, + * the last octet of hash in the element with index 27. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA hash. + * Message_Digest[ ]: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + */ +int SHA224Result(SHA224Context *context, + uint8_t Message_Digest[SHA224HashSize]) +{ + return SHA224_256ResultN(context, Message_Digest, SHA224HashSize); +} + +/* + * SHA256Reset + * + * Description: + * This function will initialize the SHA256Context in preparation + * for computing a new SHA256 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + */ +int SHA256Reset(SHA256Context *context) +{ + return SHA224_256Reset(context, SHA256_H0); +} + +/* + * SHA256Input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * message_array[ ]: [in] + * An array of octets representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array. + * + * Returns: + * sha Error Code. + */ +int SHA256Input(SHA256Context *context, const uint8_t *message_array, + unsigned int length) +{ + if (!context) return shaNull; + if (!length) return shaSuccess; + if (!message_array) return shaNull; + if (context->Computed) return context->Corrupted = shaStateError; + if (context->Corrupted) return context->Corrupted; + + while (length--) { + context->Message_Block[context->Message_Block_Index++] = + *message_array; + + if ((SHA224_256AddLength(context, 8) == shaSuccess) && + (context->Message_Block_Index == SHA256_Message_Block_Size)) + SHA224_256ProcessMessageBlock(context); + + message_array++; + } + + return context->Corrupted; + +} + +/* + * SHA256FinalBits + * + * Description: + * This function will add in any final bits of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * message_bits: [in] + * The final bits of the message, in the upper portion of the + * byte. (Use 0b###00000 instead of 0b00000### to input the + * three bits ###.) + * length: [in] + * The number of bits in message_bits, between 1 and 7. + * + * Returns: + * sha Error Code. + */ +int SHA256FinalBits(SHA256Context *context, + uint8_t message_bits, unsigned int length) +{ + static uint8_t masks[8] = { + /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80, + /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0, + /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8, + /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE + }; + static uint8_t markbit[8] = { + /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40, + /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10, + /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04, + /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01 + }; + + if (!context) return shaNull; + if (!length) return shaSuccess; + if (context->Corrupted) return context->Corrupted; + if (context->Computed) return context->Corrupted = shaStateError; + if (length >= 8) return context->Corrupted = shaBadParam; + + SHA224_256AddLength(context, length); + SHA224_256Finalize(context, (uint8_t) + ((message_bits & masks[length]) | markbit[length])); + + return context->Corrupted; +} + +/* + * SHA256Result + * + * Description: + * This function will return the 256-bit message digest + * into the Message_Digest array provided by the caller. + * NOTE: + * The first octet of hash is stored in the element with index 0, + * the last octet of hash in the element with index 31. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA hash. + * Message_Digest[ ]: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + */ +int SHA256Result(SHA256Context *context, + uint8_t Message_Digest[SHA256HashSize]) +{ + return SHA224_256ResultN(context, Message_Digest, SHA256HashSize); +} + +/* + * SHA224_256Reset + * + * Description: + * This helper function will initialize the SHA256Context in + * preparation for computing a new SHA-224 or SHA-256 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * H0[ ]: [in] + * The initial hash value array to use. + * + * Returns: + * sha Error Code. + */ +static int SHA224_256Reset(SHA256Context *context, uint32_t *H0) +{ + if (!context) return shaNull; + + context->Length_High = context->Length_Low = 0; + context->Message_Block_Index = 0; + + context->Intermediate_Hash[0] = H0[0]; + context->Intermediate_Hash[1] = H0[1]; + context->Intermediate_Hash[2] = H0[2]; + context->Intermediate_Hash[3] = H0[3]; + context->Intermediate_Hash[4] = H0[4]; + context->Intermediate_Hash[5] = H0[5]; + context->Intermediate_Hash[6] = H0[6]; + context->Intermediate_Hash[7] = H0[7]; + + context->Computed = 0; + context->Corrupted = shaSuccess; + + return shaSuccess; +} + +/* + * SHA224_256ProcessMessageBlock + * + * Description: + * This helper function will process the next 512 bits of the + * message stored in the Message_Block array. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * + * Returns: + * Nothing. + * + * Comments: + * Many of the variable names in this code, especially the + * single character names, were used because those were the + * names used in the Secure Hash Standard. + */ +static void SHA224_256ProcessMessageBlock(SHA256Context *context) +{ + /* Constants defined in FIPS 180-3, section 4.2.2 */ + static const uint32_t K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, + 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, + 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, + 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, + 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, + 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, + 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, + 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, + 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + int t, t4; /* Loop counter */ + uint32_t temp1, temp2; /* Temporary word value */ + uint32_t W[64]; /* Word sequence */ + uint32_t A, B, C, D, E, F, G, H; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for (t = t4 = 0; t < 16; t++, t4 += 4) + W[t] = (((uint32_t)context->Message_Block[t4]) << 24) | + (((uint32_t)context->Message_Block[t4 + 1]) << 16) | + (((uint32_t)context->Message_Block[t4 + 2]) << 8) | + (((uint32_t)context->Message_Block[t4 + 3])); + + for (t = 16; t < 64; t++) + W[t] = SHA256_sigma1(W[t-2]) + W[t-7] + + SHA256_sigma0(W[t-15]) + W[t-16]; + + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + F = context->Intermediate_Hash[5]; + G = context->Intermediate_Hash[6]; + H = context->Intermediate_Hash[7]; + + for (t = 0; t < 64; t++) { + temp1 = H + SHA256_SIGMA1(E) + SHA_Ch(E,F,G) + K[t] + W[t]; + temp2 = SHA256_SIGMA0(A) + SHA_Maj(A,B,C); + H = G; + G = F; + F = E; + E = D + temp1; + D = C; + C = B; + B = A; + A = temp1 + temp2; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + context->Intermediate_Hash[5] += F; + context->Intermediate_Hash[6] += G; + context->Intermediate_Hash[7] += H; + + context->Message_Block_Index = 0; +} + +/* + * SHA224_256Finalize + * + * Description: + * This helper function finishes off the digest calculations. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * Pad_Byte: [in] + * The last byte to add to the message block before the 0-padding + * and length. This will contain the last bits of the message + * followed by another single bit. If the message was an + * exact multiple of 8-bits long, Pad_Byte will be 0x80. + * + * Returns: + * sha Error Code. + */ +static void SHA224_256Finalize(SHA256Context *context, + uint8_t Pad_Byte) +{ + int i; + SHA224_256PadMessage(context, Pad_Byte); + /* message may be sensitive, so clear it out */ + for (i = 0; i < SHA256_Message_Block_Size; ++i) + context->Message_Block[i] = 0; + context->Length_High = 0; /* and clear length */ + context->Length_Low = 0; + context->Computed = 1; +} + +/* + * SHA224_256PadMessage + * + * Description: + * According to the standard, the message must be padded to the next + * even multiple of 512 bits. The first padding bit must be a '1'. + * The last 64 bits represent the length of the original message. + * All bits in between should be 0. This helper function will pad + * the message according to those rules by filling the + * Message_Block array accordingly. When it returns, it can be + * assumed that the message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad. + * Pad_Byte: [in] + * The last byte to add to the message block before the 0-padding + * and length. This will contain the last bits of the message + * followed by another single bit. If the message was an + * exact multiple of 8-bits long, Pad_Byte will be 0x80. + * + * Returns: + * Nothing. + */ +static void SHA224_256PadMessage(SHA256Context *context, + uint8_t Pad_Byte) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index >= (SHA256_Message_Block_Size-8)) { + context->Message_Block[context->Message_Block_Index++] = Pad_Byte; + while (context->Message_Block_Index < SHA256_Message_Block_Size) + context->Message_Block[context->Message_Block_Index++] = 0; + SHA224_256ProcessMessageBlock(context); + } else + context->Message_Block[context->Message_Block_Index++] = Pad_Byte; + + while (context->Message_Block_Index < (SHA256_Message_Block_Size-8)) + context->Message_Block[context->Message_Block_Index++] = 0; + + /* + * Store the message length as the last 8 octets + */ + context->Message_Block[56] = (uint8_t)(context->Length_High >> 24); + context->Message_Block[57] = (uint8_t)(context->Length_High >> 16); + context->Message_Block[58] = (uint8_t)(context->Length_High >> 8); + context->Message_Block[59] = (uint8_t)(context->Length_High); + context->Message_Block[60] = (uint8_t)(context->Length_Low >> 24); + context->Message_Block[61] = (uint8_t)(context->Length_Low >> 16); + context->Message_Block[62] = (uint8_t)(context->Length_Low >> 8); + context->Message_Block[63] = (uint8_t)(context->Length_Low); + + SHA224_256ProcessMessageBlock(context); +} + +/* + * SHA224_256ResultN + * + * Description: + * This helper function will return the 224-bit or 256-bit message + * digest into the Message_Digest array provided by the caller. + * NOTE: + * The first octet of hash is stored in the element with index 0, + * the last octet of hash in the element with index 27/31. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA hash. + * Message_Digest[ ]: [out] + * Where the digest is returned. + * HashSize: [in] + * The size of the hash, either 28 or 32. + * + * Returns: + * sha Error Code. + */ +static int SHA224_256ResultN(SHA256Context *context, + uint8_t Message_Digest[ ], int HashSize) +{ + int i; + + if (!context) return shaNull; + if (!Message_Digest) return shaNull; + if (context->Corrupted) return context->Corrupted; + + if (!context->Computed) + SHA224_256Finalize(context, 0x80); + + for (i = 0; i < HashSize; ++i) + Message_Digest[i] = (uint8_t) + (context->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) )); + + return shaSuccess; +} + diff --git a/vendor/libgit2/src/util/hash/sha.h b/vendor/libgit2/src/util/hash/sha.h new file mode 100644 index 00000000..4f596234 --- /dev/null +++ b/vendor/libgit2/src/util/hash/sha.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_hash_sha_h__ +#define INCLUDE_hash_sha_h__ + +#include "git2_util.h" + +typedef struct git_hash_sha1_ctx git_hash_sha1_ctx; +typedef struct git_hash_sha256_ctx git_hash_sha256_ctx; + +#if defined(GIT_SHA1_COMMON_CRYPTO) || defined(GIT_SHA256_COMMON_CRYPTO) +# include "common_crypto.h" +#endif + +#if defined(GIT_SHA1_OPENSSL) || defined(GIT_SHA256_OPENSSL) +# include "openssl.h" +#endif + +#if defined(GIT_SHA1_WIN32) || defined(GIT_SHA256_WIN32) +# include "win32.h" +#endif + +#if defined(GIT_SHA1_MBEDTLS) || defined(GIT_SHA256_MBEDTLS) +# include "mbedtls.h" +#endif + +#if defined(GIT_SHA1_COLLISIONDETECT) +# include "collisiondetect.h" +#endif + +#if defined(GIT_SHA256_BUILTIN) +# include "builtin.h" +#endif + +/* + * SHA1 + */ + +#define GIT_HASH_SHA1_SIZE 20 + +int git_hash_sha1_global_init(void); + +int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx); +void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx); + +int git_hash_sha1_init(git_hash_sha1_ctx *c); +int git_hash_sha1_update(git_hash_sha1_ctx *c, const void *data, size_t len); +int git_hash_sha1_final(unsigned char *out, git_hash_sha1_ctx *c); + +/* + * SHA256 + */ + +#define GIT_HASH_SHA256_SIZE 32 + +int git_hash_sha256_global_init(void); + +int git_hash_sha256_ctx_init(git_hash_sha256_ctx *ctx); +void git_hash_sha256_ctx_cleanup(git_hash_sha256_ctx *ctx); + +int git_hash_sha256_init(git_hash_sha256_ctx *c); +int git_hash_sha256_update(git_hash_sha256_ctx *c, const void *data, size_t len); +int git_hash_sha256_final(unsigned char *out, git_hash_sha256_ctx *c); + +#endif diff --git a/vendor/libgit2/src/hash/sha1/sha1dc/sha1.c b/vendor/libgit2/src/util/hash/sha1dc/sha1.c similarity index 100% rename from vendor/libgit2/src/hash/sha1/sha1dc/sha1.c rename to vendor/libgit2/src/util/hash/sha1dc/sha1.c diff --git a/vendor/libgit2/src/hash/sha1/sha1dc/sha1.h b/vendor/libgit2/src/util/hash/sha1dc/sha1.h similarity index 100% rename from vendor/libgit2/src/hash/sha1/sha1dc/sha1.h rename to vendor/libgit2/src/util/hash/sha1dc/sha1.h diff --git a/vendor/libgit2/src/hash/sha1/sha1dc/ubc_check.c b/vendor/libgit2/src/util/hash/sha1dc/ubc_check.c similarity index 100% rename from vendor/libgit2/src/hash/sha1/sha1dc/ubc_check.c rename to vendor/libgit2/src/util/hash/sha1dc/ubc_check.c diff --git a/vendor/libgit2/src/hash/sha1/sha1dc/ubc_check.h b/vendor/libgit2/src/util/hash/sha1dc/ubc_check.h similarity index 100% rename from vendor/libgit2/src/hash/sha1/sha1dc/ubc_check.h rename to vendor/libgit2/src/util/hash/sha1dc/ubc_check.h diff --git a/vendor/libgit2/src/util/hash/win32.c b/vendor/libgit2/src/util/hash/win32.c new file mode 100644 index 00000000..f80c0d5c --- /dev/null +++ b/vendor/libgit2/src/util/hash/win32.c @@ -0,0 +1,549 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "win32.h" + +#include "runtime.h" + +#include +#include + +#define GIT_HASH_CNG_DLL_NAME "bcrypt.dll" + +/* BCRYPT_SHA1_ALGORITHM */ +#define GIT_HASH_CNG_SHA1_TYPE L"SHA1" +#define GIT_HASH_CNG_SHA256_TYPE L"SHA256" + +/* BCRYPT_OBJECT_LENGTH */ +#define GIT_HASH_CNG_HASH_OBJECT_LEN L"ObjectLength" + +/* BCRYPT_HASH_REUSEABLE_FLAGS */ +#define GIT_HASH_CNG_HASH_REUSABLE 0x00000020 + +/* Definitions */ + +/* CryptoAPI is available for hashing on Windows XP and newer. */ +struct cryptoapi_provider { + HCRYPTPROV handle; +}; + +/* + * CNG (bcrypt.dll) is significantly more performant than CryptoAPI and is + * preferred, however it is only available on Windows 2008 and newer and + * must therefore be dynamically loaded, and we must inline constants that + * would not exist when building in pre-Windows 2008 environments. + */ + +/* Function declarations for CNG */ +typedef NTSTATUS (WINAPI *cng_open_algorithm_provider_fn)( + HANDLE /* BCRYPT_ALG_HANDLE */ *phAlgorithm, + LPCWSTR pszAlgId, + LPCWSTR pszImplementation, + DWORD dwFlags); + +typedef NTSTATUS (WINAPI *cng_get_property_fn)( + HANDLE /* BCRYPT_HANDLE */ hObject, + LPCWSTR pszProperty, + PUCHAR pbOutput, + ULONG cbOutput, + ULONG *pcbResult, + ULONG dwFlags); + +typedef NTSTATUS (WINAPI *cng_create_hash_fn)( + HANDLE /* BCRYPT_ALG_HANDLE */ hAlgorithm, + HANDLE /* BCRYPT_HASH_HANDLE */ *phHash, + PUCHAR pbHashObject, ULONG cbHashObject, + PUCHAR pbSecret, + ULONG cbSecret, + ULONG dwFlags); + +typedef NTSTATUS (WINAPI *cng_finish_hash_fn)( + HANDLE /* BCRYPT_HASH_HANDLE */ hHash, + PUCHAR pbOutput, + ULONG cbOutput, + ULONG dwFlags); + +typedef NTSTATUS (WINAPI *cng_hash_data_fn)( + HANDLE /* BCRYPT_HASH_HANDLE */ hHash, + PUCHAR pbInput, + ULONG cbInput, + ULONG dwFlags); + +typedef NTSTATUS (WINAPI *cng_destroy_hash_fn)( + HANDLE /* BCRYPT_HASH_HANDLE */ hHash); + +typedef NTSTATUS (WINAPI *cng_close_algorithm_provider_fn)( + HANDLE /* BCRYPT_ALG_HANDLE */ hAlgorithm, + ULONG dwFlags); + +struct cng_provider { + /* DLL for CNG */ + HINSTANCE dll; + + /* Function pointers for CNG */ + cng_open_algorithm_provider_fn open_algorithm_provider; + cng_get_property_fn get_property; + cng_create_hash_fn create_hash; + cng_finish_hash_fn finish_hash; + cng_hash_data_fn hash_data; + cng_destroy_hash_fn destroy_hash; + cng_close_algorithm_provider_fn close_algorithm_provider; + + HANDLE /* BCRYPT_ALG_HANDLE */ sha1_handle; + DWORD sha1_object_size; + + HANDLE /* BCRYPT_ALG_HANDLE */ sha256_handle; + DWORD sha256_object_size; +}; + +typedef struct { + git_hash_win32_provider_t type; + + union { + struct cryptoapi_provider cryptoapi; + struct cng_provider cng; + } provider; +} hash_win32_provider; + +/* Hash provider definition */ + +static hash_win32_provider hash_provider = {0}; + +/* Hash initialization */ + +/* Initialize CNG, if available */ +GIT_INLINE(int) cng_provider_init(void) +{ + char dll_path[MAX_PATH]; + DWORD dll_path_len, size_len; + + /* Only use CNG on Windows 2008 / Vista SP1 or better (Windows 6.0 SP1) */ + if (!git_has_win32_version(6, 0, 1)) { + git_error_set(GIT_ERROR_SHA, "CryptoNG is not supported on this platform"); + return -1; + } + + /* Load bcrypt.dll explicitly from the system directory */ + if ((dll_path_len = GetSystemDirectory(dll_path, MAX_PATH)) == 0 || + dll_path_len > MAX_PATH || + StringCchCat(dll_path, MAX_PATH, "\\") < 0 || + StringCchCat(dll_path, MAX_PATH, GIT_HASH_CNG_DLL_NAME) < 0 || + (hash_provider.provider.cng.dll = LoadLibrary(dll_path)) == NULL) { + git_error_set(GIT_ERROR_SHA, "CryptoNG library could not be loaded"); + return -1; + } + + /* Load the function addresses */ + if ((hash_provider.provider.cng.open_algorithm_provider = (cng_open_algorithm_provider_fn)((void *)GetProcAddress(hash_provider.provider.cng.dll, "BCryptOpenAlgorithmProvider"))) == NULL || + (hash_provider.provider.cng.get_property = (cng_get_property_fn)((void *)GetProcAddress(hash_provider.provider.cng.dll, "BCryptGetProperty"))) == NULL || + (hash_provider.provider.cng.create_hash = (cng_create_hash_fn)((void *)GetProcAddress(hash_provider.provider.cng.dll, "BCryptCreateHash"))) == NULL || + (hash_provider.provider.cng.finish_hash = (cng_finish_hash_fn)((void *)GetProcAddress(hash_provider.provider.cng.dll, "BCryptFinishHash"))) == NULL || + (hash_provider.provider.cng.hash_data = (cng_hash_data_fn)((void *)GetProcAddress(hash_provider.provider.cng.dll, "BCryptHashData"))) == NULL || + (hash_provider.provider.cng.destroy_hash = (cng_destroy_hash_fn)((void *)GetProcAddress(hash_provider.provider.cng.dll, "BCryptDestroyHash"))) == NULL || + (hash_provider.provider.cng.close_algorithm_provider = (cng_close_algorithm_provider_fn)((void *)GetProcAddress(hash_provider.provider.cng.dll, "BCryptCloseAlgorithmProvider"))) == NULL) { + FreeLibrary(hash_provider.provider.cng.dll); + + git_error_set(GIT_ERROR_OS, "CryptoNG functions could not be loaded"); + return -1; + } + + /* Load the SHA1 algorithm */ + if (hash_provider.provider.cng.open_algorithm_provider(&hash_provider.provider.cng.sha1_handle, GIT_HASH_CNG_SHA1_TYPE, NULL, GIT_HASH_CNG_HASH_REUSABLE) < 0 || + hash_provider.provider.cng.get_property(hash_provider.provider.cng.sha1_handle, GIT_HASH_CNG_HASH_OBJECT_LEN, (PBYTE)&hash_provider.provider.cng.sha1_object_size, sizeof(DWORD), &size_len, 0) < 0) { + git_error_set(GIT_ERROR_OS, "algorithm provider could not be initialized"); + goto on_error; + } + + /* Load the SHA256 algorithm */ + if (hash_provider.provider.cng.open_algorithm_provider(&hash_provider.provider.cng.sha256_handle, GIT_HASH_CNG_SHA256_TYPE, NULL, GIT_HASH_CNG_HASH_REUSABLE) < 0 || + hash_provider.provider.cng.get_property(hash_provider.provider.cng.sha256_handle, GIT_HASH_CNG_HASH_OBJECT_LEN, (PBYTE)&hash_provider.provider.cng.sha256_object_size, sizeof(DWORD), &size_len, 0) < 0) { + git_error_set(GIT_ERROR_OS, "algorithm provider could not be initialized"); + goto on_error; + } + + hash_provider.type = GIT_HASH_WIN32_CNG; + return 0; + +on_error: + if (hash_provider.provider.cng.sha1_handle) + hash_provider.provider.cng.close_algorithm_provider(hash_provider.provider.cng.sha1_handle, 0); + + if (hash_provider.provider.cng.sha256_handle) + hash_provider.provider.cng.close_algorithm_provider(hash_provider.provider.cng.sha256_handle, 0); + + if (hash_provider.provider.cng.dll) + FreeLibrary(hash_provider.provider.cng.dll); + + return -1; +} + +GIT_INLINE(void) cng_provider_shutdown(void) +{ + if (hash_provider.type == GIT_HASH_WIN32_INVALID) + return; + + hash_provider.provider.cng.close_algorithm_provider(hash_provider.provider.cng.sha1_handle, 0); + hash_provider.provider.cng.close_algorithm_provider(hash_provider.provider.cng.sha256_handle, 0); + FreeLibrary(hash_provider.provider.cng.dll); + + hash_provider.type = GIT_HASH_WIN32_INVALID; +} + +/* Initialize CryptoAPI */ +GIT_INLINE(int) cryptoapi_provider_init(void) +{ + if (!CryptAcquireContext(&hash_provider.provider.cryptoapi.handle, NULL, 0, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { + git_error_set(GIT_ERROR_OS, "legacy hash context could not be started"); + return -1; + } + + hash_provider.type = GIT_HASH_WIN32_CRYPTOAPI; + return 0; +} + +GIT_INLINE(void) cryptoapi_provider_shutdown(void) +{ + if (hash_provider.type == GIT_HASH_WIN32_INVALID) + return; + + CryptReleaseContext(hash_provider.provider.cryptoapi.handle, 0); + + hash_provider.type = GIT_HASH_WIN32_INVALID; +} + +static void hash_provider_shutdown(void) +{ + if (hash_provider.type == GIT_HASH_WIN32_CNG) + cng_provider_shutdown(); + else if (hash_provider.type == GIT_HASH_WIN32_CRYPTOAPI) + cryptoapi_provider_shutdown(); +} + +static int hash_provider_init(void) +{ + int error = 0; + + if (hash_provider.type != GIT_HASH_WIN32_INVALID) + return 0; + + if ((error = cng_provider_init()) < 0) + error = cryptoapi_provider_init(); + + if (!error) + error = git_runtime_shutdown_register(hash_provider_shutdown); + + return error; +} + +git_hash_win32_provider_t git_hash_win32_provider(void) +{ + return hash_provider.type; +} + +int git_hash_win32_set_provider(git_hash_win32_provider_t provider) +{ + if (provider == hash_provider.type) + return 0; + + hash_provider_shutdown(); + + if (provider == GIT_HASH_WIN32_CNG) + return cng_provider_init(); + else if (provider == GIT_HASH_WIN32_CRYPTOAPI) + return cryptoapi_provider_init(); + + git_error_set(GIT_ERROR_SHA, "unsupported win32 provider"); + return -1; +} + +/* CryptoAPI: available in Windows XP and newer */ + +GIT_INLINE(int) hash_cryptoapi_init(git_hash_win32_ctx *ctx) +{ + if (ctx->ctx.cryptoapi.valid) + CryptDestroyHash(ctx->ctx.cryptoapi.hash_handle); + + if (!CryptCreateHash(hash_provider.provider.cryptoapi.handle, ctx->algorithm, 0, 0, &ctx->ctx.cryptoapi.hash_handle)) { + ctx->ctx.cryptoapi.valid = 0; + git_error_set(GIT_ERROR_OS, "legacy hash implementation could not be created"); + return -1; + } + + ctx->ctx.cryptoapi.valid = 1; + return 0; +} + +GIT_INLINE(int) hash_cryptoapi_update(git_hash_win32_ctx *ctx, const void *_data, size_t len) +{ + const BYTE *data = (BYTE *)_data; + + GIT_ASSERT(ctx->ctx.cryptoapi.valid); + + while (len > 0) { + DWORD chunk = (len > MAXDWORD) ? MAXDWORD : (DWORD)len; + + if (!CryptHashData(ctx->ctx.cryptoapi.hash_handle, data, chunk, 0)) { + git_error_set(GIT_ERROR_OS, "legacy hash data could not be updated"); + return -1; + } + + data += chunk; + len -= chunk; + } + + return 0; +} + +GIT_INLINE(int) hash_cryptoapi_final(unsigned char *out, git_hash_win32_ctx *ctx) +{ + DWORD len = ctx->algorithm == CALG_SHA_256 ? GIT_HASH_SHA256_SIZE : GIT_HASH_SHA1_SIZE; + int error = 0; + + GIT_ASSERT(ctx->ctx.cryptoapi.valid); + + if (!CryptGetHashParam(ctx->ctx.cryptoapi.hash_handle, HP_HASHVAL, out, &len, 0)) { + git_error_set(GIT_ERROR_OS, "legacy hash data could not be finished"); + error = -1; + } + + CryptDestroyHash(ctx->ctx.cryptoapi.hash_handle); + ctx->ctx.cryptoapi.valid = 0; + + return error; +} + +GIT_INLINE(void) hash_ctx_cryptoapi_cleanup(git_hash_win32_ctx *ctx) +{ + if (ctx->ctx.cryptoapi.valid) + CryptDestroyHash(ctx->ctx.cryptoapi.hash_handle); +} + +GIT_INLINE(int) hash_sha1_cryptoapi_ctx_init_init(git_hash_win32_ctx *ctx) +{ + ctx->algorithm = CALG_SHA1; + return hash_cryptoapi_init(ctx); +} + +GIT_INLINE(int) hash_sha256_cryptoapi_ctx_init(git_hash_win32_ctx *ctx) +{ + ctx->algorithm = CALG_SHA_256; + return hash_cryptoapi_init(ctx); +} + +/* CNG: Available in Windows Server 2008 and newer */ + +GIT_INLINE(int) hash_sha1_cng_ctx_init(git_hash_win32_ctx *ctx) +{ + if ((ctx->ctx.cng.hash_object = git__malloc(hash_provider.provider.cng.sha1_object_size)) == NULL) + return -1; + + if (hash_provider.provider.cng.create_hash(hash_provider.provider.cng.sha1_handle, &ctx->ctx.cng.hash_handle, ctx->ctx.cng.hash_object, hash_provider.provider.cng.sha1_object_size, NULL, 0, 0) < 0) { + git__free(ctx->ctx.cng.hash_object); + + git_error_set(GIT_ERROR_OS, "sha1 implementation could not be created"); + return -1; + } + + ctx->algorithm = CALG_SHA1; + return 0; +} + +GIT_INLINE(int) hash_sha256_cng_ctx_init(git_hash_win32_ctx *ctx) +{ + if ((ctx->ctx.cng.hash_object = git__malloc(hash_provider.provider.cng.sha256_object_size)) == NULL) + return -1; + + if (hash_provider.provider.cng.create_hash(hash_provider.provider.cng.sha256_handle, &ctx->ctx.cng.hash_handle, ctx->ctx.cng.hash_object, hash_provider.provider.cng.sha256_object_size, NULL, 0, 0) < 0) { + git__free(ctx->ctx.cng.hash_object); + + git_error_set(GIT_ERROR_OS, "sha256 implementation could not be created"); + return -1; + } + + ctx->algorithm = CALG_SHA_256; + return 0; +} + +GIT_INLINE(int) hash_cng_init(git_hash_win32_ctx *ctx) +{ + BYTE hash[GIT_HASH_SHA256_SIZE]; + ULONG size = ctx->algorithm == CALG_SHA_256 ? GIT_HASH_SHA256_SIZE : GIT_HASH_SHA1_SIZE; + + if (!ctx->ctx.cng.updated) + return 0; + + /* CNG needs to be finished to restart */ + if (hash_provider.provider.cng.finish_hash(ctx->ctx.cng.hash_handle, hash, size, 0) < 0) { + git_error_set(GIT_ERROR_OS, "hash implementation could not be finished"); + return -1; + } + + ctx->ctx.cng.updated = 0; + + return 0; +} + +GIT_INLINE(int) hash_cng_update(git_hash_win32_ctx *ctx, const void *_data, size_t len) +{ + PBYTE data = (PBYTE)_data; + + while (len > 0) { + ULONG chunk = (len > ULONG_MAX) ? ULONG_MAX : (ULONG)len; + + if (hash_provider.provider.cng.hash_data(ctx->ctx.cng.hash_handle, data, chunk, 0) < 0) { + git_error_set(GIT_ERROR_OS, "hash could not be updated"); + return -1; + } + + data += chunk; + len -= chunk; + } + + return 0; +} + +GIT_INLINE(int) hash_cng_final(unsigned char *out, git_hash_win32_ctx *ctx) +{ + ULONG size = ctx->algorithm == CALG_SHA_256 ? GIT_HASH_SHA256_SIZE : GIT_HASH_SHA1_SIZE; + + if (hash_provider.provider.cng.finish_hash(ctx->ctx.cng.hash_handle, out, size, 0) < 0) { + git_error_set(GIT_ERROR_OS, "hash could not be finished"); + return -1; + } + + ctx->ctx.cng.updated = 0; + + return 0; +} + +GIT_INLINE(void) hash_ctx_cng_cleanup(git_hash_win32_ctx *ctx) +{ + hash_provider.provider.cng.destroy_hash(ctx->ctx.cng.hash_handle); + git__free(ctx->ctx.cng.hash_object); +} + +/* Indirection between CryptoAPI and CNG */ + +GIT_INLINE(int) hash_sha1_win32_ctx_init(git_hash_win32_ctx *ctx) +{ + GIT_ASSERT_ARG(hash_provider.type); + + memset(ctx, 0x0, sizeof(git_hash_win32_ctx)); + return (hash_provider.type == GIT_HASH_WIN32_CNG) ? hash_sha1_cng_ctx_init(ctx) : hash_sha1_cryptoapi_ctx_init_init(ctx); +} + +GIT_INLINE(int) hash_sha256_win32_ctx_init(git_hash_win32_ctx *ctx) +{ + GIT_ASSERT_ARG(hash_provider.type); + + memset(ctx, 0x0, sizeof(git_hash_win32_ctx)); + return (hash_provider.type == GIT_HASH_WIN32_CNG) ? hash_sha256_cng_ctx_init(ctx) : hash_sha256_cryptoapi_ctx_init(ctx); +} + +GIT_INLINE(int) hash_win32_init(git_hash_win32_ctx *ctx) +{ + return (hash_provider.type == GIT_HASH_WIN32_CNG) ? hash_cng_init(ctx) : hash_cryptoapi_init(ctx); +} + +GIT_INLINE(int) hash_win32_update(git_hash_win32_ctx *ctx, const void *data, size_t len) +{ + return (hash_provider.type == GIT_HASH_WIN32_CNG) ? hash_cng_update(ctx, data, len) : hash_cryptoapi_update(ctx, data, len); +} + +GIT_INLINE(int) hash_win32_final(unsigned char *out, git_hash_win32_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + return (hash_provider.type == GIT_HASH_WIN32_CNG) ? hash_cng_final(out, ctx) : hash_cryptoapi_final(out, ctx); +} + +GIT_INLINE(void) hash_win32_cleanup(git_hash_win32_ctx *ctx) +{ + if (hash_provider.type == GIT_HASH_WIN32_CNG) + hash_ctx_cng_cleanup(ctx); + else if(hash_provider.type == GIT_HASH_WIN32_CRYPTOAPI) + hash_ctx_cryptoapi_cleanup(ctx); +} + +#ifdef GIT_SHA1_WIN32 + +int git_hash_sha1_global_init(void) +{ + return hash_provider_init(); +} + +int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + return hash_sha1_win32_ctx_init(&ctx->win32); +} + +int git_hash_sha1_init(git_hash_sha1_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + return hash_win32_init(&ctx->win32); +} + +int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len) +{ + GIT_ASSERT_ARG(ctx); + return hash_win32_update(&ctx->win32, data, len); +} + +int git_hash_sha1_final(unsigned char *out, git_hash_sha1_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + return hash_win32_final(out, &ctx->win32); +} + +void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx) +{ + if (!ctx) + return; + hash_win32_cleanup(&ctx->win32); +} + +#endif + +#ifdef GIT_SHA256_WIN32 + +int git_hash_sha256_global_init(void) +{ + return hash_provider_init(); +} + +int git_hash_sha256_ctx_init(git_hash_sha256_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + return hash_sha256_win32_ctx_init(&ctx->win32); +} + +int git_hash_sha256_init(git_hash_sha256_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + return hash_win32_init(&ctx->win32); +} + +int git_hash_sha256_update(git_hash_sha256_ctx *ctx, const void *data, size_t len) +{ + GIT_ASSERT_ARG(ctx); + return hash_win32_update(&ctx->win32, data, len); +} + +int git_hash_sha256_final(unsigned char *out, git_hash_sha256_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + return hash_win32_final(out, &ctx->win32); +} + +void git_hash_sha256_ctx_cleanup(git_hash_sha256_ctx *ctx) +{ + if (!ctx) + return; + hash_win32_cleanup(&ctx->win32); +} + +#endif diff --git a/vendor/libgit2/src/util/hash/win32.h b/vendor/libgit2/src/util/hash/win32.h new file mode 100644 index 00000000..a9fb87ae --- /dev/null +++ b/vendor/libgit2/src/util/hash/win32.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_hash_win32_h__ +#define INCLUDE_hash_win32_h__ + +#include "hash/sha.h" + +#include + +typedef enum { + GIT_HASH_WIN32_INVALID = 0, + GIT_HASH_WIN32_CRYPTOAPI, + GIT_HASH_WIN32_CNG +} git_hash_win32_provider_t; + +struct git_hash_win32_cryptoapi_ctx { + bool valid; + HCRYPTHASH hash_handle; +}; + +struct git_hash_win32_cng_ctx { + bool updated; + HANDLE /* BCRYPT_HASH_HANDLE */ hash_handle; + PBYTE hash_object; +}; + +typedef struct { + ALG_ID algorithm; + + union { + struct git_hash_win32_cryptoapi_ctx cryptoapi; + struct git_hash_win32_cng_ctx cng; + } ctx; +} git_hash_win32_ctx; + +/* + * Gets/sets the current hash provider (cng or cryptoapi). This is only + * for testing purposes. + */ +git_hash_win32_provider_t git_hash_win32_provider(void); +int git_hash_win32_set_provider(git_hash_win32_provider_t provider); + +#ifdef GIT_SHA1_WIN32 +struct git_hash_sha1_ctx { + git_hash_win32_ctx win32; +}; +#endif + +#ifdef GIT_SHA256_WIN32 +struct git_hash_sha256_ctx { + git_hash_win32_ctx win32; +}; +#endif + +#endif diff --git a/vendor/libgit2/src/integer.h b/vendor/libgit2/src/util/integer.h similarity index 98% rename from vendor/libgit2/src/integer.h rename to vendor/libgit2/src/util/integer.h index 63277177..a9e416cc 100644 --- a/vendor/libgit2/src/integer.h +++ b/vendor/libgit2/src/util/integer.h @@ -89,7 +89,9 @@ GIT_INLINE(int) git__is_int(int64_t p) /* Use Microsoft's safe integer handling functions where available */ #elif defined(_MSC_VER) -# define ENABLE_INTSAFE_SIGNED_FUNCTIONS +# if !defined(ENABLE_INTSAFE_SIGNED_FUNCTIONS) +# define ENABLE_INTSAFE_SIGNED_FUNCTIONS +# endif # include # define git__add_sizet_overflow(out, one, two) \ diff --git a/vendor/libgit2/src/khash.h b/vendor/libgit2/src/util/khash.h similarity index 100% rename from vendor/libgit2/src/khash.h rename to vendor/libgit2/src/util/khash.h diff --git a/vendor/libgit2/src/map.h b/vendor/libgit2/src/util/map.h similarity index 98% rename from vendor/libgit2/src/map.h rename to vendor/libgit2/src/util/map.h index 01931d19..c101e46f 100644 --- a/vendor/libgit2/src/map.h +++ b/vendor/libgit2/src/util/map.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_map_h__ #define INCLUDE_map_h__ -#include "common.h" +#include "git2_util.h" /* p_mmap() prot values */ diff --git a/vendor/libgit2/src/util/net.c b/vendor/libgit2/src/util/net.c new file mode 100644 index 00000000..dede784c --- /dev/null +++ b/vendor/libgit2/src/util/net.c @@ -0,0 +1,1153 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "net.h" + +#include + +#include "posix.h" +#include "str.h" +#include "runtime.h" + +#define DEFAULT_PORT_HTTP "80" +#define DEFAULT_PORT_HTTPS "443" +#define DEFAULT_PORT_GIT "9418" +#define DEFAULT_PORT_SSH "22" + +#define GIT_NET_URL_PARSER_INIT { 0 } + +typedef struct { + unsigned int hierarchical : 1; + + const char *scheme; + const char *user; + const char *password; + const char *host; + const char *port; + const char *path; + const char *query; + const char *fragment; + + size_t scheme_len; + size_t user_len; + size_t password_len; + size_t host_len; + size_t port_len; + size_t path_len; + size_t query_len; + size_t fragment_len; +} git_net_url_parser; + +bool git_net_hostname_matches_cert( + const char *hostname, + const char *pattern) +{ + for (;;) { + char c = git__tolower(*pattern++); + + if (c == '\0') + return *hostname ? false : true; + + if (c == '*') { + c = *pattern; + + /* '*' at the end matches everything left */ + if (c == '\0') + return true; + + /* + * We've found a pattern, so move towards the + * next matching char. The '.' is handled + * specially because wildcards aren't allowed + * to cross subdomains. + */ + while(*hostname) { + char h = git__tolower(*hostname); + + if (h == c) + return git_net_hostname_matches_cert(hostname++, pattern); + else if (h == '.') + return git_net_hostname_matches_cert(hostname, pattern); + + hostname++; + } + + return false; + } + + if (c != git__tolower(*hostname++)) + return false; + } + + return false; +} + +#define is_valid_scheme_char(c) \ + (((c) >= 'a' && (c) <= 'z') || \ + ((c) >= 'A' && (c) <= 'Z') || \ + ((c) >= '0' && (c) <= '9') || \ + (c) == '+' || (c) == '-' || (c) == '.') + +bool git_net_str_is_url(const char *str) +{ + const char *c; + + for (c = str; *c; c++) { + if (*c == ':' && *(c+1) == '/' && *(c+2) == '/') + return true; + + if (!is_valid_scheme_char(*c)) + break; + } + + return false; +} + +static const char *default_port_for_scheme(const char *scheme) +{ + if (strcmp(scheme, "http") == 0) + return DEFAULT_PORT_HTTP; + else if (strcmp(scheme, "https") == 0) + return DEFAULT_PORT_HTTPS; + else if (strcmp(scheme, "git") == 0) + return DEFAULT_PORT_GIT; + else if (strcmp(scheme, "ssh") == 0 || + strcmp(scheme, "ssh+git") == 0 || + strcmp(scheme, "git+ssh") == 0) + return DEFAULT_PORT_SSH; + + return NULL; +} + +static bool is_ssh_scheme(const char *scheme, size_t scheme_len) +{ + if (!scheme_len) + return false; + + return strncasecmp(scheme, "ssh", scheme_len) == 0 || + strncasecmp(scheme, "ssh+git", scheme_len) == 0 || + strncasecmp(scheme, "git+ssh", scheme_len) == 0; +} + +int git_net_url_dup(git_net_url *out, git_net_url *in) +{ + if (in->scheme) { + out->scheme = git__strdup(in->scheme); + GIT_ERROR_CHECK_ALLOC(out->scheme); + } + + if (in->host) { + out->host = git__strdup(in->host); + GIT_ERROR_CHECK_ALLOC(out->host); + } + + if (in->port) { + out->port = git__strdup(in->port); + GIT_ERROR_CHECK_ALLOC(out->port); + } + + if (in->path) { + out->path = git__strdup(in->path); + GIT_ERROR_CHECK_ALLOC(out->path); + } + + if (in->query) { + out->query = git__strdup(in->query); + GIT_ERROR_CHECK_ALLOC(out->query); + } + + if (in->username) { + out->username = git__strdup(in->username); + GIT_ERROR_CHECK_ALLOC(out->username); + } + + if (in->password) { + out->password = git__strdup(in->password); + GIT_ERROR_CHECK_ALLOC(out->password); + } + + return 0; +} + +static int url_invalid(const char *message) +{ + git_error_set(GIT_ERROR_NET, "invalid url: %s", message); + return GIT_EINVALIDSPEC; +} + +static int url_parse_authority( + git_net_url_parser *parser, + const char *authority, + size_t len) +{ + const char *c, *hostport_end, *host_end = NULL, + *userpass_end, *user_end = NULL; + + enum { + HOSTPORT, HOST, IPV6, HOST_END, USERPASS, USER + } state = HOSTPORT; + + if (len == 0) + return 0; + + /* + * walk the authority backwards so that we can parse google code's + * ssh urls that are not rfc compliant and allow @ in the username + */ + for (hostport_end = authority + len, c = hostport_end - 1; + c >= authority && !user_end; + c--) { + switch (state) { + case HOSTPORT: + if (*c == ':') { + parser->port = c + 1; + parser->port_len = hostport_end - parser->port; + host_end = c; + state = HOST; + break; + } + + /* + * if we've only seen digits then we don't know + * if we're parsing just a host or a host and port. + * if we see a non-digit, then we're in a host, + * otherwise, fall through to possibly match the + * "@" (user/host separator). + */ + + if (*c < '0' || *c > '9') { + host_end = hostport_end; + state = HOST; + } + + /* fall through */ + + case HOST: + if (*c == ']' && host_end == c + 1) { + host_end = c; + state = IPV6; + } + + else if (*c == '@') { + parser->host = c + 1; + parser->host_len = host_end ? + host_end - parser->host : + hostport_end - parser->host; + userpass_end = c; + state = USERPASS; + } + + else if (*c == '[' || *c == ']' || *c == ':') { + return url_invalid("malformed hostname"); + } + + break; + + case IPV6: + if (*c == '[') { + parser->host = c + 1; + parser->host_len = host_end - parser->host; + state = HOST_END; + } + + else if ((*c < '0' || *c > '9') && + (*c < 'a' || *c > 'f') && + (*c < 'A' || *c > 'F') && + (*c != ':')) { + return url_invalid("malformed hostname"); + } + + break; + + case HOST_END: + if (*c == '@') { + userpass_end = c; + state = USERPASS; + break; + } + + return url_invalid("malformed hostname"); + + case USERPASS: + if (*c == '@' && + !is_ssh_scheme(parser->scheme, parser->scheme_len)) + return url_invalid("malformed hostname"); + + if (*c == ':') { + parser->password = c + 1; + parser->password_len = userpass_end - parser->password; + user_end = c; + state = USER; + break; + } + + break; + + default: + GIT_ASSERT(!"unhandled state"); + } + } + + switch (state) { + case HOSTPORT: + parser->host = authority; + parser->host_len = (hostport_end - parser->host); + break; + case HOST: + parser->host = authority; + parser->host_len = (host_end - parser->host); + break; + case IPV6: + return url_invalid("malformed hostname"); + case HOST_END: + break; + case USERPASS: + parser->user = authority; + parser->user_len = (userpass_end - parser->user); + break; + case USER: + parser->user = authority; + parser->user_len = (user_end - parser->user); + break; + default: + GIT_ASSERT(!"unhandled state"); + } + + return 0; +} + +static int url_parse_path( + git_net_url_parser *parser, + const char *path, + size_t len) +{ + const char *c, *end; + + enum { PATH, QUERY, FRAGMENT } state = PATH; + + parser->path = path; + end = path + len; + + for (c = path; c < end; c++) { + switch (state) { + case PATH: + switch (*c) { + case '?': + parser->path_len = (c - parser->path); + parser->query = c + 1; + state = QUERY; + break; + case '#': + parser->path_len = (c - parser->path); + parser->fragment = c + 1; + state = FRAGMENT; + break; + } + break; + + case QUERY: + if (*c == '#') { + parser->query_len = (c - parser->query); + parser->fragment = c + 1; + state = FRAGMENT; + } + break; + + case FRAGMENT: + break; + + default: + GIT_ASSERT(!"unhandled state"); + } + } + + switch (state) { + case PATH: + parser->path_len = (c - parser->path); + break; + case QUERY: + parser->query_len = (c - parser->query); + break; + case FRAGMENT: + parser->fragment_len = (c - parser->fragment); + break; + } + + return 0; +} + +static int url_parse_finalize(git_net_url *url, git_net_url_parser *parser) +{ + git_str scheme = GIT_STR_INIT, user = GIT_STR_INIT, + password = GIT_STR_INIT, host = GIT_STR_INIT, + port = GIT_STR_INIT, path = GIT_STR_INIT, + query = GIT_STR_INIT, fragment = GIT_STR_INIT; + const char *default_port; + int error = 0; + + if (parser->scheme_len) { + if ((error = git_str_put(&scheme, parser->scheme, parser->scheme_len)) < 0) + goto done; + + git__strntolower(scheme.ptr, scheme.size); + } + + if (parser->user_len && + (error = git_str_decode_percent(&user, parser->user, parser->user_len)) < 0) + goto done; + + if (parser->password_len && + (error = git_str_decode_percent(&password, parser->password, parser->password_len)) < 0) + goto done; + + if (parser->host_len && + (error = git_str_decode_percent(&host, parser->host, parser->host_len)) < 0) + goto done; + + if (parser->port_len) + error = git_str_put(&port, parser->port, parser->port_len); + else if (parser->scheme_len && (default_port = default_port_for_scheme(scheme.ptr)) != NULL) + error = git_str_puts(&port, default_port); + + if (error < 0) + goto done; + + if (parser->path_len) + error = git_str_put(&path, parser->path, parser->path_len); + else if (parser->hierarchical) + error = git_str_puts(&path, "/"); + + if (error < 0) + goto done; + + if (parser->query_len && + (error = git_str_decode_percent(&query, parser->query, parser->query_len)) < 0) + goto done; + + if (parser->fragment_len && + (error = git_str_decode_percent(&fragment, parser->fragment, parser->fragment_len)) < 0) + goto done; + + url->scheme = git_str_detach(&scheme); + url->host = git_str_detach(&host); + url->port = git_str_detach(&port); + url->path = git_str_detach(&path); + url->query = git_str_detach(&query); + url->fragment = git_str_detach(&fragment); + url->username = git_str_detach(&user); + url->password = git_str_detach(&password); + + error = 0; + +done: + git_str_dispose(&scheme); + git_str_dispose(&user); + git_str_dispose(&password); + git_str_dispose(&host); + git_str_dispose(&port); + git_str_dispose(&path); + git_str_dispose(&query); + git_str_dispose(&fragment); + + return error; +} + +int git_net_url_parse(git_net_url *url, const char *given) +{ + git_net_url_parser parser = GIT_NET_URL_PARSER_INIT; + const char *c, *authority, *path; + size_t authority_len = 0, path_len = 0; + int error = 0; + + enum { + SCHEME_START, SCHEME, + AUTHORITY_START, AUTHORITY, + PATH_START, PATH + } state = SCHEME_START; + + memset(url, 0, sizeof(git_net_url)); + + for (c = given; *c; c++) { + switch (state) { + case SCHEME_START: + parser.scheme = c; + state = SCHEME; + + /* fall through */ + + case SCHEME: + if (*c == ':') { + parser.scheme_len = (c - parser.scheme); + + if (parser.scheme_len && + *(c+1) == '/' && *(c+2) == '/') { + c += 2; + parser.hierarchical = 1; + state = AUTHORITY_START; + } else { + state = PATH_START; + } + } else if (!is_valid_scheme_char(*c)) { + /* + * an illegal scheme character means that we + * were just given a relative path + */ + path = given; + state = PATH; + break; + } + break; + + case AUTHORITY_START: + authority = c; + state = AUTHORITY; + + /* fall through */ + case AUTHORITY: + if (*c != '/') + break; + + authority_len = (c - authority); + + /* fall through */ + case PATH_START: + path = c; + state = PATH; + break; + + case PATH: + break; + + default: + GIT_ASSERT(!"unhandled state"); + } + } + + switch (state) { + case SCHEME: + /* + * if we never saw a ':' then we were given a relative + * path, not a bare scheme + */ + path = given; + path_len = (c - path); + break; + case AUTHORITY_START: + break; + case AUTHORITY: + authority_len = (c - authority); + break; + case PATH_START: + break; + case PATH: + path_len = (c - path); + break; + default: + GIT_ASSERT(!"unhandled state"); + } + + if (authority_len && + (error = url_parse_authority(&parser, authority, authority_len)) < 0) + goto done; + + if (path_len && + (error = url_parse_path(&parser, path, path_len)) < 0) + goto done; + + error = url_parse_finalize(url, &parser); + +done: + return error; +} + +int git_net_url_parse_http( + git_net_url *url, + const char *given) +{ + git_net_url_parser parser = GIT_NET_URL_PARSER_INIT; + const char *c, *authority, *path = NULL; + size_t authority_len = 0, path_len = 0; + int error; + + /* Hopefully this is a proper URL with a scheme. */ + if (git_net_str_is_url(given)) + return git_net_url_parse(url, given); + + memset(url, 0, sizeof(git_net_url)); + + /* Without a scheme, we are in the host (authority) section. */ + for (c = authority = given; *c; c++) { + if (!path && *c == '/') { + authority_len = (c - authority); + path = c; + } + } + + if (path) + path_len = (c - path); + else + authority_len = (c - authority); + + parser.scheme = "http"; + parser.scheme_len = 4; + parser.hierarchical = 1; + + if (authority_len && + (error = url_parse_authority(&parser, authority, authority_len)) < 0) + return error; + + if (path_len && + (error = url_parse_path(&parser, path, path_len)) < 0) + return error; + + return url_parse_finalize(url, &parser); +} + +static int scp_invalid(const char *message) +{ + git_error_set(GIT_ERROR_NET, "invalid scp-style path: %s", message); + return GIT_EINVALIDSPEC; +} + +static bool is_ipv6(const char *str) +{ + const char *c; + size_t colons = 0; + + if (*str++ != '[') + return false; + + for (c = str; *c; c++) { + if (*c == ':') + colons++; + + if (*c == ']') + return (colons > 1); + + if (*c != ':' && + (*c < '0' || *c > '9') && + (*c < 'a' || *c > 'f') && + (*c < 'A' || *c > 'F')) + return false; + } + + return false; +} + +static bool has_at(const char *str) +{ + const char *c; + + for (c = str; *c; c++) { + if (*c == '@') + return true; + + if (*c == ':') + break; + } + + return false; +} + +int git_net_url_parse_scp(git_net_url *url, const char *given) +{ + const char *default_port = default_port_for_scheme("ssh"); + const char *c, *user, *host, *port = NULL, *path = NULL; + size_t user_len = 0, host_len = 0, port_len = 0; + unsigned short bracket = 0; + + enum { + NONE, + USER, + HOST_START, HOST, HOST_END, + IPV6, IPV6_END, + PORT_START, PORT, PORT_END, + PATH_START + } state = NONE; + + memset(url, 0, sizeof(git_net_url)); + + for (c = given; *c && !path; c++) { + switch (state) { + case NONE: + switch (*c) { + case '@': + return scp_invalid("unexpected '@'"); + case ':': + return scp_invalid("unexpected ':'"); + case '[': + if (is_ipv6(c)) { + state = IPV6; + host = c; + } else if (bracket++ > 1) { + return scp_invalid("unexpected '['"); + } + break; + default: + if (has_at(c)) { + state = USER; + user = c; + } else { + state = HOST; + host = c; + } + break; + } + break; + + case USER: + if (*c == '@') { + user_len = (c - user); + state = HOST_START; + } + break; + + case HOST_START: + state = (*c == '[') ? IPV6 : HOST; + host = c; + break; + + case HOST: + if (*c == ':') { + host_len = (c - host); + state = bracket ? PORT_START : PATH_START; + } else if (*c == ']') { + if (bracket-- == 0) + return scp_invalid("unexpected ']'"); + + host_len = (c - host); + state = HOST_END; + } + break; + + case HOST_END: + if (*c != ':') + return scp_invalid("unexpected character after hostname"); + state = PATH_START; + break; + + case IPV6: + if (*c == ']') + state = IPV6_END; + break; + + case IPV6_END: + if (*c != ':') + return scp_invalid("unexpected character after ipv6 address"); + + host_len = (c - host); + state = bracket ? PORT_START : PATH_START; + break; + + case PORT_START: + port = c; + state = PORT; + break; + + case PORT: + if (*c == ']') { + if (bracket-- == 0) + return scp_invalid("unexpected ']'"); + + port_len = c - port; + state = PORT_END; + } + break; + + case PORT_END: + if (*c != ':') + return scp_invalid("unexpected character after ipv6 address"); + + state = PATH_START; + break; + + case PATH_START: + path = c; + break; + + default: + GIT_ASSERT(!"unhandled state"); + } + } + + if (!path) + return scp_invalid("path is required"); + + GIT_ERROR_CHECK_ALLOC(url->scheme = git__strdup("ssh")); + + if (user_len) + GIT_ERROR_CHECK_ALLOC(url->username = git__strndup(user, user_len)); + + GIT_ASSERT(host_len); + GIT_ERROR_CHECK_ALLOC(url->host = git__strndup(host, host_len)); + + if (port_len) + GIT_ERROR_CHECK_ALLOC(url->port = git__strndup(port, port_len)); + else + GIT_ERROR_CHECK_ALLOC(url->port = git__strdup(default_port)); + + GIT_ASSERT(path); + GIT_ERROR_CHECK_ALLOC(url->path = git__strdup(path)); + + return 0; +} + +int git_net_url_parse_standard_or_scp(git_net_url *url, const char *given) +{ + return git_net_str_is_url(given) ? + git_net_url_parse(url, given) : + git_net_url_parse_scp(url, given); +} + +int git_net_url_joinpath( + git_net_url *out, + git_net_url *one, + const char *two) +{ + git_str path = GIT_STR_INIT; + const char *query; + size_t one_len, two_len; + + git_net_url_dispose(out); + + if ((query = strchr(two, '?')) != NULL) { + two_len = query - two; + + if (*(++query) != '\0') { + out->query = git__strdup(query); + GIT_ERROR_CHECK_ALLOC(out->query); + } + } else { + two_len = strlen(two); + } + + /* Strip all trailing `/`s from the first path */ + one_len = one->path ? strlen(one->path) : 0; + while (one_len && one->path[one_len - 1] == '/') + one_len--; + + /* Strip all leading `/`s from the second path */ + while (*two == '/') { + two++; + two_len--; + } + + git_str_put(&path, one->path, one_len); + git_str_putc(&path, '/'); + git_str_put(&path, two, two_len); + + if (git_str_oom(&path)) + return -1; + + out->path = git_str_detach(&path); + + if (one->scheme) { + out->scheme = git__strdup(one->scheme); + GIT_ERROR_CHECK_ALLOC(out->scheme); + } + + if (one->host) { + out->host = git__strdup(one->host); + GIT_ERROR_CHECK_ALLOC(out->host); + } + + if (one->port) { + out->port = git__strdup(one->port); + GIT_ERROR_CHECK_ALLOC(out->port); + } + + if (one->username) { + out->username = git__strdup(one->username); + GIT_ERROR_CHECK_ALLOC(out->username); + } + + if (one->password) { + out->password = git__strdup(one->password); + GIT_ERROR_CHECK_ALLOC(out->password); + } + + return 0; +} + +/* + * Some servers strip the query parameters from the Location header + * when sending a redirect. Others leave it in place. + * Check for both, starting with the stripped case first, + * since it appears to be more common. + */ +static void remove_service_suffix( + git_net_url *url, + const char *service_suffix) +{ + const char *service_query = strchr(service_suffix, '?'); + size_t full_suffix_len = strlen(service_suffix); + size_t suffix_len = service_query ? + (size_t)(service_query - service_suffix) : full_suffix_len; + size_t path_len = strlen(url->path); + ssize_t truncate = -1; + + /* + * Check for a redirect without query parameters, + * like "/newloc/info/refs"' + */ + if (suffix_len && path_len >= suffix_len) { + size_t suffix_offset = path_len - suffix_len; + + if (git__strncmp(url->path + suffix_offset, service_suffix, suffix_len) == 0 && + (!service_query || git__strcmp(url->query, service_query + 1) == 0)) { + truncate = suffix_offset; + } + } + + /* + * If we haven't already found where to truncate to remove the + * suffix, check for a redirect with query parameters, like + * "/newloc/info/refs?service=git-upload-pack" + */ + if (truncate < 0 && git__suffixcmp(url->path, service_suffix) == 0) + truncate = path_len - full_suffix_len; + + /* Ensure we leave a minimum of '/' as the path */ + if (truncate == 0) + truncate++; + + if (truncate > 0) { + url->path[truncate] = '\0'; + + git__free(url->query); + url->query = NULL; + } +} + +int git_net_url_apply_redirect( + git_net_url *url, + const char *redirect_location, + bool allow_offsite, + const char *service_suffix) +{ + git_net_url tmp = GIT_NET_URL_INIT; + int error = 0; + + GIT_ASSERT(url); + GIT_ASSERT(redirect_location); + + if (redirect_location[0] == '/') { + git__free(url->path); + + if ((url->path = git__strdup(redirect_location)) == NULL) { + error = -1; + goto done; + } + } else { + git_net_url *original = url; + + if ((error = git_net_url_parse(&tmp, redirect_location)) < 0) + goto done; + + /* Validate that this is a legal redirection */ + + if (original->scheme && + strcmp(original->scheme, tmp.scheme) != 0 && + strcmp(tmp.scheme, "https") != 0) { + git_error_set(GIT_ERROR_NET, "cannot redirect from '%s' to '%s'", + original->scheme, tmp.scheme); + + error = -1; + goto done; + } + + if (original->host && + !allow_offsite && + git__strcasecmp(original->host, tmp.host) != 0) { + git_error_set(GIT_ERROR_NET, "cannot redirect from '%s' to '%s'", + original->host, tmp.host); + + error = -1; + goto done; + } + + git_net_url_swap(url, &tmp); + } + + /* Remove the service suffix if it was given to us */ + if (service_suffix) + remove_service_suffix(url, service_suffix); + +done: + git_net_url_dispose(&tmp); + return error; +} + +bool git_net_url_valid(git_net_url *url) +{ + return (url->host && url->port && url->path); +} + +bool git_net_url_is_default_port(git_net_url *url) +{ + const char *default_port; + + if (url->scheme && (default_port = default_port_for_scheme(url->scheme)) != NULL) + return (strcmp(url->port, default_port) == 0); + else + return false; +} + +bool git_net_url_is_ipv6(git_net_url *url) +{ + return (strchr(url->host, ':') != NULL); +} + +void git_net_url_swap(git_net_url *a, git_net_url *b) +{ + git_net_url tmp = GIT_NET_URL_INIT; + + memcpy(&tmp, a, sizeof(git_net_url)); + memcpy(a, b, sizeof(git_net_url)); + memcpy(b, &tmp, sizeof(git_net_url)); +} + +int git_net_url_fmt(git_str *buf, git_net_url *url) +{ + GIT_ASSERT_ARG(url); + GIT_ASSERT_ARG(url->scheme); + GIT_ASSERT_ARG(url->host); + + git_str_puts(buf, url->scheme); + git_str_puts(buf, "://"); + + if (url->username) { + git_str_puts(buf, url->username); + + if (url->password) { + git_str_puts(buf, ":"); + git_str_puts(buf, url->password); + } + + git_str_putc(buf, '@'); + } + + git_str_puts(buf, url->host); + + if (url->port && !git_net_url_is_default_port(url)) { + git_str_putc(buf, ':'); + git_str_puts(buf, url->port); + } + + git_str_puts(buf, url->path ? url->path : "/"); + + if (url->query) { + git_str_putc(buf, '?'); + git_str_puts(buf, url->query); + } + + return git_str_oom(buf) ? -1 : 0; +} + +int git_net_url_fmt_path(git_str *buf, git_net_url *url) +{ + git_str_puts(buf, url->path ? url->path : "/"); + + if (url->query) { + git_str_putc(buf, '?'); + git_str_puts(buf, url->query); + } + + return git_str_oom(buf) ? -1 : 0; +} + +static bool matches_pattern( + git_net_url *url, + const char *pattern, + size_t pattern_len) +{ + const char *domain, *port = NULL, *colon; + size_t host_len, domain_len, port_len = 0, wildcard = 0; + + GIT_UNUSED(url); + GIT_UNUSED(pattern); + + if (!pattern_len) + return false; + else if (pattern_len == 1 && pattern[0] == '*') + return true; + else if (pattern_len > 1 && pattern[0] == '*' && pattern[1] == '.') + wildcard = 2; + else if (pattern[0] == '.') + wildcard = 1; + + domain = pattern + wildcard; + domain_len = pattern_len - wildcard; + + if ((colon = memchr(domain, ':', domain_len)) != NULL) { + domain_len = colon - domain; + port = colon + 1; + port_len = pattern_len - wildcard - domain_len - 1; + } + + /* A pattern's port *must* match if it's specified */ + if (port_len && git__strlcmp(url->port, port, port_len) != 0) + return false; + + /* No wildcard? Host must match exactly. */ + if (!wildcard) + return !git__strlcmp(url->host, domain, domain_len); + + /* Wildcard: ensure there's (at least) a suffix match */ + if ((host_len = strlen(url->host)) < domain_len || + memcmp(url->host + (host_len - domain_len), domain, domain_len)) + return false; + + /* The pattern is *.domain and the host is simply domain */ + if (host_len == domain_len) + return true; + + /* The pattern is *.domain and the host is foo.domain */ + return (url->host[host_len - domain_len - 1] == '.'); +} + +bool git_net_url_matches_pattern(git_net_url *url, const char *pattern) +{ + return matches_pattern(url, pattern, strlen(pattern)); +} + +bool git_net_url_matches_pattern_list( + git_net_url *url, + const char *pattern_list) +{ + const char *pattern, *pattern_end, *sep; + + for (pattern = pattern_list; + pattern && *pattern; + pattern = sep ? sep + 1 : NULL) { + sep = strchr(pattern, ','); + pattern_end = sep ? sep : strchr(pattern, '\0'); + + if (matches_pattern(url, pattern, (pattern_end - pattern))) + return true; + } + + return false; +} + +void git_net_url_dispose(git_net_url *url) +{ + if (url->username) + git__memzero(url->username, strlen(url->username)); + + if (url->password) + git__memzero(url->password, strlen(url->password)); + + git__free(url->scheme); url->scheme = NULL; + git__free(url->host); url->host = NULL; + git__free(url->port); url->port = NULL; + git__free(url->path); url->path = NULL; + git__free(url->query); url->query = NULL; + git__free(url->fragment); url->fragment = NULL; + git__free(url->username); url->username = NULL; + git__free(url->password); url->password = NULL; +} diff --git a/vendor/libgit2/src/util/net.h b/vendor/libgit2/src/util/net.h new file mode 100644 index 00000000..8024956a --- /dev/null +++ b/vendor/libgit2/src/util/net.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_net_h__ +#define INCLUDE_net_h__ + +#include "git2_util.h" + +/* + * Hostname handling + */ + +/* + * See if a given hostname matches a certificate name pattern, according + * to RFC2818 rules (which specifies HTTP over TLS). Mainly, an asterisk + * matches anything, but is limited to a single url component. + */ +extern bool git_net_hostname_matches_cert( + const char *hostname, + const char *pattern); + +/* + * URL handling + */ + +typedef struct git_net_url { + char *scheme; + char *host; + char *port; + char *path; + char *query; + char *fragment; + char *username; + char *password; +} git_net_url; + +#define GIT_NET_URL_INIT { NULL } + +/** Is a given string a url? */ +extern bool git_net_str_is_url(const char *str); + +/** Duplicate a URL */ +extern int git_net_url_dup(git_net_url *out, git_net_url *in); + +/** Parses a string containing a URL into a structure. */ +extern int git_net_url_parse(git_net_url *url, const char *str); + +/** Parses a string containing an SCP style path into a URL structure. */ +extern int git_net_url_parse_scp(git_net_url *url, const char *str); + +/** + * Parses a string containing a standard URL or an SCP style path into + * a URL structure. + */ +extern int git_net_url_parse_standard_or_scp(git_net_url *url, const char *str); + +/** + * Parses a string containing an HTTP endpoint that may not be a + * well-formed URL. For example, "localhost" or "localhost:port". + */ +extern int git_net_url_parse_http( + git_net_url *url, + const char *str); + +/** Appends a path and/or query string to the given URL */ +extern int git_net_url_joinpath( + git_net_url *out, + git_net_url *in, + const char *path); + +/** Ensures that a URL is minimally valid (contains a host, port and path) */ +extern bool git_net_url_valid(git_net_url *url); + +/** Returns true if the URL is on the default port. */ +extern bool git_net_url_is_default_port(git_net_url *url); + +/** Returns true if the host portion of the URL is an ipv6 address. */ +extern bool git_net_url_is_ipv6(git_net_url *url); + +/* Applies a redirect to the URL with a git-aware service suffix. */ +extern int git_net_url_apply_redirect( + git_net_url *url, + const char *redirect_location, + bool allow_offsite, + const char *service_suffix); + +/** Swaps the contents of one URL for another. */ +extern void git_net_url_swap(git_net_url *a, git_net_url *b); + +/** Places the URL into the given buffer. */ +extern int git_net_url_fmt(git_str *out, git_net_url *url); + +/** Place the path and query string into the given buffer. */ +extern int git_net_url_fmt_path(git_str *buf, git_net_url *url); + +/** Determines if the url matches given pattern or pattern list */ +extern bool git_net_url_matches_pattern( + git_net_url *url, + const char *pattern); +extern bool git_net_url_matches_pattern_list( + git_net_url *url, + const char *pattern_list); + +/** Disposes the contents of the structure. */ +extern void git_net_url_dispose(git_net_url *url); + +#endif diff --git a/vendor/libgit2/src/pool.c b/vendor/libgit2/src/util/pool.c similarity index 100% rename from vendor/libgit2/src/pool.c rename to vendor/libgit2/src/util/pool.c diff --git a/vendor/libgit2/src/pool.h b/vendor/libgit2/src/util/pool.h similarity index 99% rename from vendor/libgit2/src/pool.h rename to vendor/libgit2/src/util/pool.h index cecb8466..0238431b 100644 --- a/vendor/libgit2/src/pool.h +++ b/vendor/libgit2/src/util/pool.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_pool_h__ #define INCLUDE_pool_h__ -#include "common.h" +#include "git2_util.h" #include "vector.h" diff --git a/vendor/libgit2/src/util/posix.c b/vendor/libgit2/src/util/posix.c new file mode 100644 index 00000000..cfc0e075 --- /dev/null +++ b/vendor/libgit2/src/util/posix.c @@ -0,0 +1,357 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "posix.h" + +#include "fs_path.h" +#include +#include + +size_t p_fsync__cnt = 0; + +#ifndef GIT_WIN32 + +#ifdef NO_ADDRINFO + +int p_getaddrinfo( + const char *host, + const char *port, + struct addrinfo *hints, + struct addrinfo **info) +{ + struct addrinfo *ainfo, *ai; + int p = 0; + + GIT_UNUSED(hints); + + if ((ainfo = git__malloc(sizeof(struct addrinfo))) == NULL) + return -1; + + if ((ainfo->ai_hostent = gethostbyname(host)) == NULL) { + git__free(ainfo); + return -2; + } + + ainfo->ai_servent = getservbyname(port, 0); + + if (ainfo->ai_servent) + ainfo->ai_port = ainfo->ai_servent->s_port; + else + ainfo->ai_port = htons(atol(port)); + + memcpy(&ainfo->ai_addr_in.sin_addr, + ainfo->ai_hostent->h_addr_list[0], + ainfo->ai_hostent->h_length); + + ainfo->ai_protocol = 0; + ainfo->ai_socktype = hints->ai_socktype; + ainfo->ai_family = ainfo->ai_hostent->h_addrtype; + ainfo->ai_addr_in.sin_family = ainfo->ai_family; + ainfo->ai_addr_in.sin_port = ainfo->ai_port; + ainfo->ai_addr = (struct addrinfo *)&ainfo->ai_addr_in; + ainfo->ai_addrlen = sizeof(struct sockaddr_in); + + *info = ainfo; + + if (ainfo->ai_hostent->h_addr_list[1] == NULL) { + ainfo->ai_next = NULL; + return 0; + } + + ai = ainfo; + + for (p = 1; ainfo->ai_hostent->h_addr_list[p] != NULL; p++) { + if (!(ai->ai_next = git__malloc(sizeof(struct addrinfo)))) { + p_freeaddrinfo(ainfo); + return -1; + } + memcpy(ai->ai_next, ainfo, sizeof(struct addrinfo)); + memcpy(&ai->ai_next->ai_addr_in.sin_addr, + ainfo->ai_hostent->h_addr_list[p], + ainfo->ai_hostent->h_length); + ai->ai_next->ai_addr = (struct addrinfo *)&ai->ai_next->ai_addr_in; + ai = ai->ai_next; + } + + ai->ai_next = NULL; + return 0; +} + +void p_freeaddrinfo(struct addrinfo *info) +{ + struct addrinfo *p, *next; + + p = info; + + while(p != NULL) { + next = p->ai_next; + git__free(p); + p = next; + } +} + +const char *p_gai_strerror(int ret) +{ + switch(ret) { + case -1: return "Out of memory"; break; + case -2: return "Address lookup failed"; break; + default: return "Unknown error"; break; + } +} + +#endif /* NO_ADDRINFO */ + +int p_open(const char *path, volatile int flags, ...) +{ + mode_t mode = 0; + + #ifdef GIT_DEBUG_STRICT_OPEN + if (strstr(path, "//") != NULL) { + errno = EACCES; + return -1; + } + #endif + + if (flags & O_CREAT) { + va_list arg_list; + + va_start(arg_list, flags); + mode = (mode_t)va_arg(arg_list, int); + va_end(arg_list); + } + + return open(path, flags | O_BINARY | O_CLOEXEC, mode); +} + +int p_creat(const char *path, mode_t mode) +{ + return open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC, mode); +} + +int p_getcwd(char *buffer_out, size_t size) +{ + char *cwd_buffer; + + GIT_ASSERT_ARG(buffer_out); + GIT_ASSERT_ARG(size > 0); + + cwd_buffer = getcwd(buffer_out, size); + + if (cwd_buffer == NULL) + return -1; + + git_fs_path_mkposix(buffer_out); + git_fs_path_string_to_dir(buffer_out, size); /* append trailing slash */ + + return 0; +} + +int p_rename(const char *from, const char *to) +{ + if (!link(from, to)) { + p_unlink(from); + return 0; + } + + if (!rename(from, to)) + return 0; + + return -1; +} + +#endif /* GIT_WIN32 */ + +ssize_t p_read(git_file fd, void *buf, size_t cnt) +{ + char *b = buf; + + if (!git__is_ssizet(cnt)) { +#ifdef GIT_WIN32 + SetLastError(ERROR_INVALID_PARAMETER); +#endif + errno = EINVAL; + return -1; + } + + while (cnt) { + ssize_t r; +#ifdef GIT_WIN32 + r = read(fd, b, cnt > INT_MAX ? INT_MAX : (unsigned int)cnt); +#else + r = read(fd, b, cnt); +#endif + if (r < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + return -1; + } + if (!r) + break; + cnt -= r; + b += r; + } + return (b - (char *)buf); +} + +int p_write(git_file fd, const void *buf, size_t cnt) +{ + const char *b = buf; + + while (cnt) { + ssize_t r; +#ifdef GIT_WIN32 + GIT_ASSERT((size_t)((unsigned int)cnt) == cnt); + r = write(fd, b, (unsigned int)cnt); +#else + r = write(fd, b, cnt); +#endif + if (r < 0) { + if (errno == EINTR || GIT_ISBLOCKED(errno)) + continue; + return -1; + } + if (!r) { + errno = EPIPE; + return -1; + } + cnt -= r; + b += r; + } + return 0; +} + +#ifdef NO_MMAP + +#include "map.h" + +int git__page_size(size_t *page_size) +{ + /* dummy; here we don't need any alignment anyway */ + *page_size = 4096; + return 0; +} + +int git__mmap_alignment(size_t *alignment) +{ + /* dummy; here we don't need any alignment anyway */ + *alignment = 4096; + return 0; +} + + +int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset) +{ + const char *ptr; + size_t remaining_len; + + GIT_MMAP_VALIDATE(out, len, prot, flags); + + /* writes cannot be emulated without handling pagefaults since write happens by + * writing to mapped memory */ + if (prot & GIT_PROT_WRITE) { + git_error_set(GIT_ERROR_OS, "trying to map %s-writeable", + ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED) ? "shared": "private"); + return -1; + } + + if (!git__is_ssizet(len)) { + errno = EINVAL; + return -1; + } + + out->len = 0; + out->data = git__malloc(len); + GIT_ERROR_CHECK_ALLOC(out->data); + + remaining_len = len; + ptr = (const char *)out->data; + while (remaining_len > 0) { + ssize_t nb; + HANDLE_EINTR(nb, p_pread(fd, (void *)ptr, remaining_len, offset)); + if (nb <= 0) { + git_error_set(GIT_ERROR_OS, "mmap emulation failed"); + git__free(out->data); + out->data = NULL; + return -1; + } + + ptr += nb; + offset += nb; + remaining_len -= nb; + } + + out->len = len; + return 0; +} + +int p_munmap(git_map *map) +{ + GIT_ASSERT_ARG(map); + git__free(map->data); + + /* Initializing will help debug use-after-free */ + map->len = 0; + map->data = NULL; + + return 0; +} + +#endif + +#if defined(GIT_IO_POLL) || defined(GIT_IO_WSAPOLL) + +/* Handled by posix.h; this test simplifies the final else */ + +#elif defined(GIT_IO_SELECT) + +int p_poll(struct pollfd *fds, unsigned int nfds, int timeout_ms) +{ + fd_set read_fds, write_fds, except_fds; + struct timeval timeout = { 0, 0 }; + unsigned int i; + int max_fd = -1, ret; + + FD_ZERO(&read_fds); + FD_ZERO(&write_fds); + FD_ZERO(&except_fds); + + for (i = 0; i < nfds; i++) { + if ((fds[i].events & POLLIN)) + FD_SET(fds[i].fd, &read_fds); + + if ((fds[i].events & POLLOUT)) + FD_SET(fds[i].fd, &write_fds); + + if ((fds[i].events & POLLPRI)) + FD_SET(fds[i].fd, &except_fds); + + max_fd = MAX(max_fd, fds[i].fd); + } + + if (timeout_ms > 0) { + timeout.tv_sec = timeout_ms / 1000; + timeout.tv_usec = (timeout_ms % 1000) * 1000; + } + + if ((ret = select(max_fd + 1, &read_fds, &write_fds, &except_fds, + timeout_ms < 0 ? NULL : &timeout)) < 0) + goto done; + + for (i = 0; i < nfds; i++) { + fds[i].revents = 0 | + FD_ISSET(fds[i].fd, &read_fds) ? POLLIN : 0 | + FD_ISSET(fds[i].fd, &write_fds) ? POLLOUT : 0 | + FD_ISSET(fds[i].fd, &except_fds) ? POLLPRI : 0; + } + +done: + return ret; +} + +#else +# error no poll compatible implementation +#endif diff --git a/vendor/libgit2/src/util/posix.h b/vendor/libgit2/src/util/posix.h new file mode 100644 index 00000000..74707453 --- /dev/null +++ b/vendor/libgit2/src/util/posix.h @@ -0,0 +1,220 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_posix_h__ +#define INCLUDE_posix_h__ + +#include "git2_util.h" + +#include +#include +#include + +/* stat: file mode type testing macros */ +#ifndef S_IFGITLINK +#define S_IFGITLINK 0160000 +#define S_ISGITLINK(m) (((m) & S_IFMT) == S_IFGITLINK) +#endif + +#ifndef S_IFLNK +#define S_IFLNK 0120000 +#undef _S_IFLNK +#define _S_IFLNK S_IFLNK +#endif + +#ifndef S_IWUSR +#define S_IWUSR 00200 +#endif + +#ifndef S_IXUSR +#define S_IXUSR 00100 +#endif + +#ifndef S_ISLNK +#define S_ISLNK(m) (((m) & _S_IFMT) == _S_IFLNK) +#endif + +#ifndef S_ISDIR +#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR) +#endif + +#ifndef S_ISREG +#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG) +#endif + +#ifndef S_ISFIFO +#define S_ISFIFO(m) (((m) & _S_IFMT) == _S_IFIFO) +#endif + +/* if S_ISGID is not defined, then don't try to set it */ +#ifndef S_ISGID +#define S_ISGID 0 +#endif + +#ifndef O_BINARY +#define O_BINARY 0 +#endif +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif +#ifndef SOCK_CLOEXEC +#define SOCK_CLOEXEC 0 +#endif + +/* access() mode parameter #defines */ +#ifndef F_OK +#define F_OK 0 /* existence check */ +#endif +#ifndef W_OK +#define W_OK 2 /* write mode check */ +#endif +#ifndef R_OK +#define R_OK 4 /* read mode check */ +#endif + +/* Determine whether an errno value indicates that a read or write failed + * because the descriptor is blocked. + */ +#if defined(EWOULDBLOCK) +#define GIT_ISBLOCKED(e) ((e) == EAGAIN || (e) == EWOULDBLOCK) +#else +#define GIT_ISBLOCKED(e) ((e) == EAGAIN) +#endif + +/* define some standard errnos that the runtime may be missing. for example, + * mingw lacks EAFNOSUPPORT. */ +#ifndef EAFNOSUPPORT +#define EAFNOSUPPORT (INT_MAX-1) +#endif + +/* Compiler independent macro to handle signal interrpted system calls */ +#define HANDLE_EINTR(result, x) do { \ + result = (x); \ + } while (result == -1 && errno == EINTR); + + +/* Provide a 64-bit size for offsets. */ + +#if defined(_MSC_VER) +typedef __int64 off64_t; +#elif defined(__HAIKU__) +typedef __haiku_std_int64 off64_t; +#elif defined(__APPLE__) +typedef __int64_t off64_t; +#elif defined(_AIX) +typedef long long off64_t; +#else +typedef int64_t off64_t; +#endif + +typedef int git_file; + +/** + * Standard POSIX Methods + * + * All the methods starting with the `p_` prefix are + * direct ports of the standard POSIX methods. + * + * Some of the methods are slightly wrapped to provide + * saner defaults. Some of these methods are emulated + * in Windows platforms. + * + * Use your manpages to check the docs on these. + */ + +extern ssize_t p_read(git_file fd, void *buf, size_t cnt); +extern int p_write(git_file fd, const void *buf, size_t cnt); + +extern ssize_t p_pread(int fd, void *data, size_t size, off64_t offset); +extern ssize_t p_pwrite(int fd, const void *data, size_t size, off64_t offset); + +#define p_close(fd) close(fd) +#define p_umask(m) umask(m) + +extern int p_open(const char *path, int flags, ...); +extern int p_creat(const char *path, mode_t mode); +extern int p_getcwd(char *buffer_out, size_t size); +extern int p_rename(const char *from, const char *to); + +extern int git__page_size(size_t *page_size); +extern int git__mmap_alignment(size_t *page_size); + +/* The number of times `p_fsync` has been called. Note that this is for + * test code only; it it not necessarily thread-safe and should not be + * relied upon in production. + */ +extern size_t p_fsync__cnt; + +/** + * Platform-dependent methods + */ +#ifdef GIT_WIN32 +# include "win32/posix.h" +#else +# include "unix/posix.h" +#endif + +#include "strnlen.h" + +#ifdef NO_READDIR_R +GIT_INLINE(int) p_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) +{ + GIT_UNUSED(entry); + *result = readdir(dirp); + return 0; +} +#else /* NO_READDIR_R */ +# define p_readdir_r(d,e,r) readdir_r(d,e,r) +#endif + +#ifdef NO_ADDRINFO +# include +struct addrinfo { + struct hostent *ai_hostent; + struct servent *ai_servent; + struct sockaddr_in ai_addr_in; + struct sockaddr *ai_addr; + size_t ai_addrlen; + int ai_family; + int ai_socktype; + int ai_protocol; + long ai_port; + struct addrinfo *ai_next; +}; + +extern int p_getaddrinfo(const char *host, const char *port, + struct addrinfo *hints, struct addrinfo **info); +extern void p_freeaddrinfo(struct addrinfo *info); +extern const char *p_gai_strerror(int ret); +#else +# define p_getaddrinfo(a, b, c, d) getaddrinfo(a, b, c, d) +# define p_freeaddrinfo(a) freeaddrinfo(a) +# define p_gai_strerror(c) gai_strerror(c) +#endif /* NO_ADDRINFO */ + +#ifdef GIT_IO_POLL +# include +# define p_poll poll +#elif GIT_IO_WSAPOLL +# include +# define p_poll WSAPoll +#else +# define POLLIN 0x01 +# define POLLPRI 0x02 +# define POLLOUT 0x04 +# define POLLERR 0x08 +# define POLLHUP 0x10 + +struct pollfd { + int fd; + short events; + short revents; +}; + +extern int p_poll(struct pollfd *fds, unsigned int nfds, int timeout); +#endif + +#endif diff --git a/vendor/libgit2/src/pqueue.c b/vendor/libgit2/src/util/pqueue.c similarity index 100% rename from vendor/libgit2/src/pqueue.c rename to vendor/libgit2/src/util/pqueue.c diff --git a/vendor/libgit2/src/pqueue.h b/vendor/libgit2/src/util/pqueue.h similarity index 98% rename from vendor/libgit2/src/pqueue.h rename to vendor/libgit2/src/util/pqueue.h index 4db74ea0..97232b4a 100644 --- a/vendor/libgit2/src/pqueue.h +++ b/vendor/libgit2/src/util/pqueue.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_pqueue_h__ #define INCLUDE_pqueue_h__ -#include "common.h" +#include "git2_util.h" #include "vector.h" diff --git a/vendor/libgit2/src/util/process.h b/vendor/libgit2/src/util/process.h new file mode 100644 index 00000000..a3804ec7 --- /dev/null +++ b/vendor/libgit2/src/util/process.h @@ -0,0 +1,223 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_process_h__ +#define INCLUDE_process_h__ + +typedef struct git_process git_process; + +typedef struct { + unsigned int use_shell : 1, + capture_in : 1, + capture_out : 1, + capture_err : 1, + exclude_env : 1; + + char *cwd; +} git_process_options; + +typedef enum { + GIT_PROCESS_STATUS_NONE, + GIT_PROCESS_STATUS_NORMAL, + GIT_PROCESS_STATUS_ERROR +} git_process_result_status; + +#define GIT_PROCESS_RESULT_INIT { GIT_PROCESS_STATUS_NONE } + +typedef struct { + git_process_result_status status; + int exitcode; + int signal; +} git_process_result; + +#define GIT_PROCESS_OPTIONS_INIT { 0 } + +#ifdef GIT_WIN32 +# define p_pid_t DWORD +#else +# define p_pid_t pid_t +#endif + +/** + * Create a new process. The command to run should be specified as the + * element of the `arg` array, execv-style. This should be the full path + * to the command to run, the PATH is not obeyed. + * + * This function will add the given environment variables (in `env`) + * to the current environment. Operations on environment variables + * are not thread safe, so you may not modify the environment during + * this call. You can avoid this by setting `exclude_env` in the + * options and providing the entire environment yourself. + * + * @param out location to store the process + * @param args the command (with arguments) to run + * @param args_len the length of the args array + * @param env environment variables to add (or NULL) + * @param env_len the length of the env len + * @param opts the options for creating the process + * @return 0 or an error code + */ +extern int git_process_new( + git_process **out, + const char **args, + size_t args_len, + const char **env, + size_t env_len, + git_process_options *opts); + +/** + * Create a new process. The command to run should be specified as the + * `cmdline` option - which is the full text of the command line as it + * would be specified or run by a user. The command to run will be + * looked up in the PATH. + * + * On Unix, this will be executed by the system's shell (`/bin/sh`) + * and may contain _Bourne-style_ shell quoting rules. On Windows, + * this will be passed to `CreateProcess`, and similarly, may + * contain _Windows-style_ shell quoting rules. + * + * This function will add the given environment variables (in `env`) + * to the current environment. Operations on environment variables + * are not thread safe, so you may not modify the environment during + * this call. You can avoid this by setting `exclude_env` in the + * options and providing the entire environment yourself. + */ +extern int git_process_new_from_cmdline( + git_process **out, + const char *cmdline, + const char **env, + size_t env_len, + git_process_options *opts); + +#ifdef GIT_WIN32 + +extern int git_process__appname( + git_str *out, + const char *cmdline); + +/* Windows path parsing is tricky; this helper function is for testing. */ +extern int git_process__cmdline( + git_str *out, + const char **in, + size_t in_len); + +#endif + +/* + * Whether the given string looks like a command line option (starts + * with a dash). This is useful for examining strings that will become + * cmdline arguments to ensure that they are not erroneously treated + * as an option. For example, arguments to `ssh`. + */ +GIT_INLINE(bool) git_process__is_cmdline_option(const char *str) +{ + return (str && str[0] == '-'); +} + +/** + * Start the process. + * + * @param process the process to start + * @return 0 or an error code + */ +extern int git_process_start(git_process *process); + +/** + * Returns the process id of the process. + * + * @param out pointer to a pid_t to store the process id + * @param process the process to query + * @return 0 or an error code + */ +extern int git_process_id(p_pid_t *out, git_process *process); + +/** + * Read from the process's stdout. The process must have been created with + * `capture_out` set to true. + * + * @param process the process to read from + * @param buf the buf to read into + * @param count maximum number of bytes to read + * @return number of bytes read or an error code + */ +extern ssize_t git_process_read(git_process *process, void *buf, size_t count); + +/** + * Read from the process's stderr. The process must have been created with + * `capture_err` set to true. + * + * @param process the process to read from + * @param buf the buf to read into + * @param count maximum number of bytes to read + * @return number of bytes read or an error code + */ +extern ssize_t git_process_read_err(git_process *process, void *buf, size_t count); + +/** + * Write to the process's stdin. The process must have been created with + * `capture_in` set to true. + * + * @param process the process to write to + * @param buf the buf to write + * @param count maximum number of bytes to write + * @return number of bytes written or an error code + */ +extern ssize_t git_process_write(git_process *process, const void *buf, size_t count); + +/** + * Wait for the process to finish. + * + * @param result the result of the process or NULL + * @param process the process to wait on + */ +extern int git_process_wait(git_process_result *result, git_process *process); + +/** + * Close the input pipe from the child. + * + * @param process the process to close the pipe on + */ +extern int git_process_close_in(git_process *process); + +/** + * Close the output pipe from the child. + * + * @param process the process to close the pipe on + */ +extern int git_process_close_out(git_process *process); + +/** + * Close the error pipe from the child. + * + * @param process the process to close the pipe on + */ +extern int git_process_close_err(git_process *process); + +/** + * Close all resources that are used by the process. This does not + * wait for the process to complete. + * + * @parma process the process to close + */ +extern int git_process_close(git_process *process); + +/** + * Place a human-readable error message in the given git buffer. + * + * @param msg the buffer to store the message + * @param result the process result that produced an error + */ +extern int git_process_result_msg(git_str *msg, git_process_result *result); + +/** + * Free a process structure + * + * @param process the process to free + */ +extern void git_process_free(git_process *process); + +#endif diff --git a/vendor/libgit2/src/rand.c b/vendor/libgit2/src/util/rand.c similarity index 96% rename from vendor/libgit2/src/rand.c rename to vendor/libgit2/src/util/rand.c index 0a208134..2b137a57 100644 --- a/vendor/libgit2/src/rand.c +++ b/vendor/libgit2/src/util/rand.c @@ -6,12 +6,12 @@ worldwide. This software is distributed without any warranty. See . */ -#include "common.h" +#include "git2_util.h" #include "rand.h" #include "runtime.h" -#if defined(GIT_RAND_GETENTROPY) -# include +#if defined(GIT_WIN32) +# include #endif static uint64_t state[4]; @@ -28,7 +28,6 @@ GIT_INLINE(int) getseed(uint64_t *seed) HCRYPTPROV provider; SYSTEMTIME systemtime; FILETIME filetime, idletime, kerneltime, usertime; - bits convert; if (CryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) { @@ -63,7 +62,7 @@ GIT_INLINE(int) getseed(uint64_t *seed) *seed ^= ((uint64_t)GetCurrentProcessId() << 32); *seed ^= ((uint64_t)GetCurrentThreadId() << 48); - convert.f = git__timer(); *seed ^= (convert.d); + *seed ^= git_time_monotonic(); /* Mix in the addresses of some functions and variables */ *seed ^= (((uint64_t)((uintptr_t)seed) << 32)); @@ -77,9 +76,12 @@ GIT_INLINE(int) getseed(uint64_t *seed) GIT_INLINE(int) getseed(uint64_t *seed) { struct timeval tv; + int fd; + +# if defined(GIT_RAND_GETLOADAVG) double loadavg[3]; bits convert; - int fd; +# endif # if defined(GIT_RAND_GETENTROPY) GIT_UNUSED((fd = 0)); @@ -106,8 +108,6 @@ GIT_INLINE(int) getseed(uint64_t *seed) return -1; } - getloadavg(loadavg, 3); - *seed = 0; *seed |= ((uint64_t)tv.tv_usec << 40); *seed |= ((uint64_t)tv.tv_sec); @@ -119,11 +119,15 @@ GIT_INLINE(int) getseed(uint64_t *seed) *seed ^= ((uint64_t)getuid() << 8); *seed ^= ((uint64_t)getgid()); +# if defined(GIT_RAND_GETLOADAVG) + getloadavg(loadavg, 3); + convert.f = loadavg[0]; *seed ^= (convert.d >> 36); convert.f = loadavg[1]; *seed ^= (convert.d); convert.f = loadavg[2]; *seed ^= (convert.d >> 16); +# endif - convert.f = git__timer(); *seed ^= (convert.d); + *seed ^= git_time_monotonic(); /* Mix in the addresses of some variables */ *seed ^= ((uint64_t)((size_t)((void *)seed)) << 32); diff --git a/vendor/libgit2/src/rand.h b/vendor/libgit2/src/util/rand.h similarity index 97% rename from vendor/libgit2/src/rand.h rename to vendor/libgit2/src/util/rand.h index 2e60561e..fa0619aa 100644 --- a/vendor/libgit2/src/rand.h +++ b/vendor/libgit2/src/util/rand.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_rand_h__ #define INCLUDE_rand_h__ -#include "common.h" +#include "git2_util.h" /** * Initialize the random number generation subsystem. This will diff --git a/vendor/libgit2/src/util/regexp.c b/vendor/libgit2/src/util/regexp.c new file mode 100644 index 00000000..eb458224 --- /dev/null +++ b/vendor/libgit2/src/util/regexp.c @@ -0,0 +1,221 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "regexp.h" + +#if defined(GIT_REGEX_BUILTIN) || defined(GIT_REGEX_PCRE) + +int git_regexp_compile(git_regexp *r, const char *pattern, int flags) +{ + int erroffset, cflags = 0; + const char *error = NULL; + + if (flags & GIT_REGEXP_ICASE) + cflags |= PCRE_CASELESS; + + if ((*r = pcre_compile(pattern, cflags, &error, &erroffset, NULL)) == NULL) { + git_error_set_str(GIT_ERROR_REGEX, error); + return GIT_EINVALIDSPEC; + } + + return 0; +} + +void git_regexp_dispose(git_regexp *r) +{ + pcre_free(*r); + *r = NULL; +} + +int git_regexp_match(const git_regexp *r, const char *string) +{ + int error; + if ((error = pcre_exec(*r, NULL, string, (int) strlen(string), 0, 0, NULL, 0)) < 0) + return (error == PCRE_ERROR_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC; + return 0; +} + +int git_regexp_search(const git_regexp *r, const char *string, size_t nmatches, git_regmatch *matches) +{ + int static_ovec[9] = {0}, *ovec; + int error; + size_t i; + + /* The ovec array always needs to be a multiple of three */ + if (nmatches <= ARRAY_SIZE(static_ovec) / 3) + ovec = static_ovec; + else + ovec = git__calloc(nmatches * 3, sizeof(*ovec)); + GIT_ERROR_CHECK_ALLOC(ovec); + + if ((error = pcre_exec(*r, NULL, string, (int) strlen(string), 0, 0, ovec, (int) nmatches * 3)) < 0) + goto out; + + if (error == 0) + error = (int) nmatches; + + for (i = 0; i < (unsigned int) error; i++) { + matches[i].start = (ovec[i * 2] < 0) ? -1 : ovec[i * 2]; + matches[i].end = (ovec[i * 2 + 1] < 0) ? -1 : ovec[i * 2 + 1]; + } + for (i = (unsigned int) error; i < nmatches; i++) + matches[i].start = matches[i].end = -1; + +out: + if (nmatches > ARRAY_SIZE(static_ovec) / 3) + git__free(ovec); + if (error < 0) + return (error == PCRE_ERROR_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC; + return 0; +} + +#elif defined(GIT_REGEX_PCRE2) + +int git_regexp_compile(git_regexp *r, const char *pattern, int flags) +{ + unsigned char errmsg[1024]; + PCRE2_SIZE erroff; + int error, cflags = 0; + + if (flags & GIT_REGEXP_ICASE) + cflags |= PCRE2_CASELESS; + + if ((*r = pcre2_compile((const unsigned char *) pattern, PCRE2_ZERO_TERMINATED, + cflags, &error, &erroff, NULL)) == NULL) { + pcre2_get_error_message(error, errmsg, sizeof(errmsg)); + git_error_set_str(GIT_ERROR_REGEX, (char *) errmsg); + return GIT_EINVALIDSPEC; + } + + return 0; +} + +void git_regexp_dispose(git_regexp *r) +{ + pcre2_code_free(*r); + *r = NULL; +} + +int git_regexp_match(const git_regexp *r, const char *string) +{ + pcre2_match_data *data; + int error; + + data = pcre2_match_data_create(1, NULL); + GIT_ERROR_CHECK_ALLOC(data); + + error = pcre2_match(*r, (const unsigned char *) string, strlen(string), 0, 0, data, NULL); + pcre2_match_data_free(data); + if (error < 0) + return (error == PCRE2_ERROR_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC; + + return 0; +} + +int git_regexp_search(const git_regexp *r, const char *string, size_t nmatches, git_regmatch *matches) +{ + pcre2_match_data *data = NULL; + PCRE2_SIZE *ovec; + int error; + size_t i; + + if ((data = pcre2_match_data_create(nmatches, NULL)) == NULL) { + git_error_set_oom(); + return -1; + } + + if ((error = pcre2_match(*r, (const unsigned char *) string, strlen(string), + 0, 0, data, NULL)) < 0) + goto out; + + if (error == 0 || (unsigned int) error > nmatches) + error = nmatches; + ovec = pcre2_get_ovector_pointer(data); + + for (i = 0; i < (unsigned int) error; i++) { + matches[i].start = (ovec[i * 2] == PCRE2_UNSET) ? -1 : (ssize_t) ovec[i * 2]; + matches[i].end = (ovec[i * 2 + 1] == PCRE2_UNSET) ? -1 : (ssize_t) ovec[i * 2 + 1]; + } + for (i = (unsigned int) error; i < nmatches; i++) + matches[i].start = matches[i].end = -1; + +out: + pcre2_match_data_free(data); + if (error < 0) + return (error == PCRE2_ERROR_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC; + return 0; +} + +#elif defined(GIT_REGEX_REGCOMP) || defined(GIT_REGEX_REGCOMP_L) + +#if defined(GIT_REGEX_REGCOMP_L) +# include +#endif + +int git_regexp_compile(git_regexp *r, const char *pattern, int flags) +{ + int cflags = REG_EXTENDED, error; + char errmsg[1024]; + + if (flags & GIT_REGEXP_ICASE) + cflags |= REG_ICASE; + +# if defined(GIT_REGEX_REGCOMP) + if ((error = regcomp(r, pattern, cflags)) != 0) +# else + if ((error = regcomp_l(r, pattern, cflags, (locale_t) 0)) != 0) +# endif + { + regerror(error, r, errmsg, sizeof(errmsg)); + git_error_set_str(GIT_ERROR_REGEX, errmsg); + return GIT_EINVALIDSPEC; + } + + return 0; +} + +void git_regexp_dispose(git_regexp *r) +{ + regfree(r); +} + +int git_regexp_match(const git_regexp *r, const char *string) +{ + int error; + if ((error = regexec(r, string, 0, NULL, 0)) != 0) + return (error == REG_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC; + return 0; +} + +int git_regexp_search(const git_regexp *r, const char *string, size_t nmatches, git_regmatch *matches) +{ + regmatch_t static_m[3], *m; + int error; + size_t i; + + if (nmatches <= ARRAY_SIZE(static_m)) + m = static_m; + else + m = git__calloc(nmatches, sizeof(*m)); + + if ((error = regexec(r, string, nmatches, m, 0)) != 0) + goto out; + + for (i = 0; i < nmatches; i++) { + matches[i].start = (m[i].rm_so < 0) ? -1 : m[i].rm_so; + matches[i].end = (m[i].rm_eo < 0) ? -1 : m[i].rm_eo; + } + +out: + if (nmatches > ARRAY_SIZE(static_m)) + git__free(m); + if (error) + return (error == REG_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC; + return 0; +} + +#endif diff --git a/vendor/libgit2/src/regexp.h b/vendor/libgit2/src/util/regexp.h similarity index 99% rename from vendor/libgit2/src/regexp.h rename to vendor/libgit2/src/util/regexp.h index 2592ef38..d0862b10 100644 --- a/vendor/libgit2/src/regexp.h +++ b/vendor/libgit2/src/util/regexp.h @@ -8,7 +8,7 @@ #ifndef INCLUDE_regexp_h__ #define INCLUDE_regexp_h__ -#include "common.h" +#include "git2_util.h" #if defined(GIT_REGEX_BUILTIN) || defined(GIT_REGEX_PCRE) # include "pcre.h" diff --git a/vendor/libgit2/src/runtime.c b/vendor/libgit2/src/util/runtime.c similarity index 99% rename from vendor/libgit2/src/runtime.c rename to vendor/libgit2/src/util/runtime.c index c05dee8b..a7711ffc 100644 --- a/vendor/libgit2/src/runtime.c +++ b/vendor/libgit2/src/util/runtime.c @@ -5,7 +5,7 @@ * a Linking Exception. For full terms see the included COPYING file. */ -#include "common.h" +#include "git2_util.h" #include "runtime.h" static git_runtime_shutdown_fn shutdown_callback[32]; diff --git a/vendor/libgit2/src/runtime.h b/vendor/libgit2/src/util/runtime.h similarity index 98% rename from vendor/libgit2/src/runtime.h rename to vendor/libgit2/src/util/runtime.h index 24ac58ee..6cbfd604 100644 --- a/vendor/libgit2/src/runtime.h +++ b/vendor/libgit2/src/util/runtime.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_runtime_h__ #define INCLUDE_runtime_h__ -#include "common.h" +#include "git2_util.h" typedef int (*git_runtime_init_fn)(void); typedef void (*git_runtime_shutdown_fn)(void); diff --git a/vendor/libgit2/src/sortedcache.c b/vendor/libgit2/src/util/sortedcache.c similarity index 100% rename from vendor/libgit2/src/sortedcache.c rename to vendor/libgit2/src/util/sortedcache.c diff --git a/vendor/libgit2/src/sortedcache.h b/vendor/libgit2/src/util/sortedcache.h similarity index 99% rename from vendor/libgit2/src/sortedcache.h rename to vendor/libgit2/src/util/sortedcache.h index ef260a09..3eee4659 100644 --- a/vendor/libgit2/src/sortedcache.h +++ b/vendor/libgit2/src/util/sortedcache.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_sorted_cache_h__ #define INCLUDE_sorted_cache_h__ -#include "common.h" +#include "git2_util.h" #include "util.h" #include "futils.h" diff --git a/vendor/libgit2/src/util/staticstr.h b/vendor/libgit2/src/util/staticstr.h new file mode 100644 index 00000000..b7d0790c --- /dev/null +++ b/vendor/libgit2/src/util/staticstr.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_stackstr_h__ +#define INCLUDE_stackstr_h__ + +#include "git2_util.h" + +typedef struct { + /* Length of / number of bytes used by `data`. */ + size_t len; + + /* Size of the allocated `data` buffer. */ + size_t size; + + /* The actual string buffer data. */ + char data[GIT_FLEX_ARRAY]; +} git_staticstr; + +#define git_staticstr_with_size(__size) \ + struct { \ + size_t len; \ + size_t size; \ + char data[__size]; \ + } + +#define git_staticstr_init(__str, __size) \ + do { \ + (__str)->len = 0; \ + (__str)->size = __size; \ + (__str)->data[0] = '\0'; \ + } while(0) + +#define git_staticstr_offset(__str) \ + ((__str)->data + (__str)->len) + +#define git_staticstr_remain(__str) \ + ((__str)->len > (__str)->size ? 0 : ((__str)->size - (__str)->len)) + +#define git_staticstr_increase(__str, __len) \ + do { ((__str)->len += __len); } while(0) + +#define git_staticstr_consume_bytes(__str, __len) \ + do { git_staticstr_consume(__str, (__str)->data + __len); } while(0) + +#define git_staticstr_consume(__str, __end) \ + do { \ + if (__end > (__str)->data && \ + __end <= (__str)->data + (__str)->len) { \ + size_t __consumed = __end - (__str)->data; \ + memmove((__str)->data, __end, (__str)->len - __consumed); \ + (__str)->len -= __consumed; \ + (__str)->data[(__str)->len] = '\0'; \ + } \ + } while(0) + +#define git_staticstr_clear(__str) \ + do { \ + (__str)->len = 0; \ + (__str)->data[0] = 0; \ + } while(0) + +#endif diff --git a/vendor/libgit2/src/str.c b/vendor/libgit2/src/util/str.c similarity index 97% rename from vendor/libgit2/src/str.c rename to vendor/libgit2/src/util/str.c index 0d405bfd..7b8d99bc 100644 --- a/vendor/libgit2/src/str.c +++ b/vendor/libgit2/src/util/str.c @@ -485,8 +485,8 @@ int git_str_decode_percent( for (str_pos = 0; str_pos < str_len; buf->size++, str_pos++) { if (str[str_pos] == '%' && str_len > str_pos + 2 && - isxdigit(str[str_pos + 1]) && - isxdigit(str[str_pos + 2])) { + git__isxdigit(str[str_pos + 1]) && + git__isxdigit(str[str_pos + 2])) { buf->ptr[buf->size] = (HEX_DECODE(str[str_pos + 1]) << 4) + HEX_DECODE(str[str_pos + 2]); str_pos += 2; @@ -1065,10 +1065,13 @@ int git_str_puts_escaped( git_str *buf, const char *string, const char *esc_chars, - const char *esc_with) + const char *esc_prefix, + const char *esc_suffix) { const char *scan; - size_t total = 0, esc_len = strlen(esc_with), count, alloclen; + size_t total = 0, count, alloclen; + size_t esc_prefix_len = esc_prefix ? strlen(esc_prefix) : 0; + size_t esc_suffix_len = esc_suffix ? strlen(esc_suffix) : 0; if (!string) return 0; @@ -1080,7 +1083,7 @@ int git_str_puts_escaped( scan += count; /* count run of escaped characters */ count = strspn(scan, esc_chars); - total += count * (esc_len + 1); + total += count * (esc_prefix_len + esc_suffix_len + 1); scan += count; } @@ -1096,13 +1099,22 @@ int git_str_puts_escaped( buf->size += count; for (count = strspn(scan, esc_chars); count > 0; --count) { - /* copy escape sequence */ - memmove(buf->ptr + buf->size, esc_with, esc_len); - buf->size += esc_len; + /* copy escape prefix sequence */ + if (esc_prefix) { + memmove(buf->ptr + buf->size, esc_prefix, esc_prefix_len); + buf->size += esc_prefix_len; + } + /* copy character to be escaped */ buf->ptr[buf->size] = *scan; buf->size++; scan++; + + /* copy escape suffix sequence */ + if (esc_suffix) { + memmove(buf->ptr + buf->size, esc_suffix, esc_suffix_len); + buf->size += esc_suffix_len; + } } } diff --git a/vendor/libgit2/src/str.h b/vendor/libgit2/src/util/str.h similarity index 98% rename from vendor/libgit2/src/str.h rename to vendor/libgit2/src/util/str.h index ef769ce2..ad9b892c 100644 --- a/vendor/libgit2/src/str.h +++ b/vendor/libgit2/src/util/str.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_str_h__ #define INCLUDE_str_h__ -#include "common.h" +#include "git2_util.h" struct git_str { char *ptr; @@ -268,21 +268,23 @@ int git_str_splice( * @param str String buffer to append data to * @param string String to escape and append * @param esc_chars Characters to be escaped - * @param esc_with String to insert in from of each found character + * @param esc_prefix String to insert as prefix of each found character + * @param esc_suffix String to insert as suffix of each found character * @return 0 on success, <0 on failure (probably allocation problem) */ extern int git_str_puts_escaped( git_str *str, const char *string, const char *esc_chars, - const char *esc_with); + const char *esc_prefix, + const char *esc_suffix); /** * Append string escaping characters that are regex special */ GIT_INLINE(int) git_str_puts_escape_regex(git_str *str, const char *string) { - return git_str_puts_escaped(str, string, "^.[]$()|*+?{}\\", "\\"); + return git_str_puts_escaped(str, string, "^.[]$()|*+?{}\\", "\\", NULL); } /** diff --git a/vendor/libgit2/src/util/strlist.c b/vendor/libgit2/src/util/strlist.c new file mode 100644 index 00000000..df5640c2 --- /dev/null +++ b/vendor/libgit2/src/util/strlist.c @@ -0,0 +1,108 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include + +#include "git2_util.h" +#include "vector.h" +#include "strlist.h" + +int git_strlist_copy(char ***out, const char **in, size_t len) +{ + char **dup; + size_t i; + + dup = git__calloc(len, sizeof(char *)); + GIT_ERROR_CHECK_ALLOC(dup); + + for (i = 0; i < len; i++) { + dup[i] = git__strdup(in[i]); + GIT_ERROR_CHECK_ALLOC(dup[i]); + } + + *out = dup; + return 0; +} + +int git_strlist_copy_with_null(char ***out, const char **in, size_t len) +{ + char **dup; + size_t new_len, i; + + GIT_ERROR_CHECK_ALLOC_ADD(&new_len, len, 1); + + dup = git__calloc(new_len, sizeof(char *)); + GIT_ERROR_CHECK_ALLOC(dup); + + for (i = 0; i < len; i++) { + dup[i] = git__strdup(in[i]); + GIT_ERROR_CHECK_ALLOC(dup[i]); + } + + *out = dup; + return 0; +} + +bool git_strlist_contains_prefix( + const char **strings, + size_t len, + const char *str, + size_t n) +{ + size_t i; + + for (i = 0; i < len; i++) { + if (strncmp(strings[i], str, n) == 0) + return true; + } + + return false; +} + +bool git_strlist_contains_key( + const char **strings, + size_t len, + const char *key, + char delimiter) +{ + const char *c; + + for (c = key; *c; c++) { + if (*c == delimiter) + break; + } + + return *c ? + git_strlist_contains_prefix(strings, len, key, (c - key)) : + false; +} + +void git_strlist_free(char **strings, size_t len) +{ + size_t i; + + if (!strings) + return; + + for (i = 0; i < len; i++) + git__free(strings[i]); + + git__free(strings); +} + +void git_strlist_free_with_null(char **strings) +{ + char **s; + + if (!strings) + return; + + for (s = strings; *s; s++) + git__free(*s); + + git__free(strings); +} diff --git a/vendor/libgit2/src/util/strlist.h b/vendor/libgit2/src/util/strlist.h new file mode 100644 index 00000000..68fbf8fb --- /dev/null +++ b/vendor/libgit2/src/util/strlist.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_runtime_h__ +#define INCLUDE_runtime_h__ + +#include "git2_util.h" + +extern int git_strlist_copy(char ***out, const char **in, size_t len); + +extern int git_strlist_copy_with_null( + char ***out, + const char **in, + size_t len); + +extern bool git_strlist_contains_prefix( + const char **strings, + size_t len, + const char *str, + size_t n); + +extern bool git_strlist_contains_key( + const char **strings, + size_t len, + const char *key, + char delimiter); + +extern void git_strlist_free(char **strings, size_t len); + +extern void git_strlist_free_with_null(char **strings); + +#endif diff --git a/vendor/libgit2/src/strmap.c b/vendor/libgit2/src/util/strmap.c similarity index 100% rename from vendor/libgit2/src/strmap.c rename to vendor/libgit2/src/util/strmap.c diff --git a/vendor/libgit2/src/strmap.h b/vendor/libgit2/src/util/strmap.h similarity index 99% rename from vendor/libgit2/src/strmap.h rename to vendor/libgit2/src/util/strmap.h index 9f5e4cc8..b64d3dcb 100644 --- a/vendor/libgit2/src/strmap.h +++ b/vendor/libgit2/src/util/strmap.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_strmap_h__ #define INCLUDE_strmap_h__ -#include "common.h" +#include "git2_util.h" /** A map with C strings as key. */ typedef struct kh_str_s git_strmap; diff --git a/vendor/libgit2/src/strnlen.h b/vendor/libgit2/src/util/strnlen.h similarity index 100% rename from vendor/libgit2/src/strnlen.h rename to vendor/libgit2/src/util/strnlen.h diff --git a/vendor/libgit2/src/thread.c b/vendor/libgit2/src/util/thread.c similarity index 99% rename from vendor/libgit2/src/thread.c rename to vendor/libgit2/src/util/thread.c index 3171771d..bc7364f8 100644 --- a/vendor/libgit2/src/thread.c +++ b/vendor/libgit2/src/util/thread.c @@ -5,7 +5,7 @@ * a Linking Exception. For full terms see the included COPYING file. */ -#include "common.h" +#include "git2_util.h" #if !defined(GIT_THREADS) diff --git a/vendor/libgit2/src/util/thread.h b/vendor/libgit2/src/util/thread.h new file mode 100644 index 00000000..c32554bf --- /dev/null +++ b/vendor/libgit2/src/util/thread.h @@ -0,0 +1,480 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_thread_h__ +#define INCLUDE_thread_h__ + +#if defined(GIT_THREADS) + +#if defined(__clang__) + +# if (__clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 1)) +# error Atomic primitives do not exist on this version of clang; configure libgit2 with -DUSE_THREADS=OFF +# else +# define GIT_BUILTIN_ATOMIC +# endif + +#elif defined(__GNUC__) + +# if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1)) +# error Atomic primitives do not exist on this version of gcc; configure libgit2 with -DUSE_THREADS=OFF +# elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) +# define GIT_BUILTIN_ATOMIC +# else +# define GIT_BUILTIN_SYNC +# endif + +#endif + +#endif /* GIT_THREADS */ + +/* Common operations even if threading has been disabled */ +typedef struct { +#if defined(GIT_WIN32) + volatile long val; +#else + volatile int val; +#endif +} git_atomic32; + +#ifdef GIT_ARCH_64 + +typedef struct { +#if defined(GIT_WIN32) + volatile __int64 val; +#else + volatile int64_t val; +#endif +} git_atomic64; + +typedef git_atomic64 git_atomic_ssize; + +#define git_atomic_ssize_set git_atomic64_set +#define git_atomic_ssize_add git_atomic64_add +#define git_atomic_ssize_get git_atomic64_get + +#else + +typedef git_atomic32 git_atomic_ssize; + +#define git_atomic_ssize_set git_atomic32_set +#define git_atomic_ssize_add git_atomic32_add +#define git_atomic_ssize_get git_atomic32_get + +#endif + +#ifdef GIT_THREADS + +#ifdef GIT_WIN32 +# include "win32/thread.h" +#else +# include "unix/pthread.h" +#endif + +/* + * Atomically sets the contents of *a to be val. + */ +GIT_INLINE(void) git_atomic32_set(git_atomic32 *a, int val) +{ +#if defined(GIT_WIN32) + InterlockedExchange(&a->val, (LONG)val); +#elif defined(GIT_BUILTIN_ATOMIC) + __atomic_store_n(&a->val, val, __ATOMIC_SEQ_CST); +#elif defined(GIT_BUILTIN_SYNC) + __sync_lock_test_and_set(&a->val, val); +#else +# error "Unsupported architecture for atomic operations" +#endif +} + +/* + * Atomically increments the contents of *a by 1, and stores the result back into *a. + * @return the result of the operation. + */ +GIT_INLINE(int) git_atomic32_inc(git_atomic32 *a) +{ +#if defined(GIT_WIN32) + return InterlockedIncrement(&a->val); +#elif defined(GIT_BUILTIN_ATOMIC) + return __atomic_add_fetch(&a->val, 1, __ATOMIC_SEQ_CST); +#elif defined(GIT_BUILTIN_SYNC) + return __sync_add_and_fetch(&a->val, 1); +#else +# error "Unsupported architecture for atomic operations" +#endif +} + +/* + * Atomically adds the contents of *a and addend, and stores the result back into *a. + * @return the result of the operation. + */ +GIT_INLINE(int) git_atomic32_add(git_atomic32 *a, int32_t addend) +{ +#if defined(GIT_WIN32) + return InterlockedAdd(&a->val, addend); +#elif defined(GIT_BUILTIN_ATOMIC) + return __atomic_add_fetch(&a->val, addend, __ATOMIC_SEQ_CST); +#elif defined(GIT_BUILTIN_SYNC) + return __sync_add_and_fetch(&a->val, addend); +#else +# error "Unsupported architecture for atomic operations" +#endif +} + +/* + * Atomically decrements the contents of *a by 1, and stores the result back into *a. + * @return the result of the operation. + */ +GIT_INLINE(int) git_atomic32_dec(git_atomic32 *a) +{ +#if defined(GIT_WIN32) + return InterlockedDecrement(&a->val); +#elif defined(GIT_BUILTIN_ATOMIC) + return __atomic_sub_fetch(&a->val, 1, __ATOMIC_SEQ_CST); +#elif defined(GIT_BUILTIN_SYNC) + return __sync_sub_and_fetch(&a->val, 1); +#else +# error "Unsupported architecture for atomic operations" +#endif +} + +/* + * Atomically gets the contents of *a. + * @return the contents of *a. + */ +GIT_INLINE(int) git_atomic32_get(git_atomic32 *a) +{ +#if defined(GIT_WIN32) + return (int)InterlockedCompareExchange(&a->val, 0, 0); +#elif defined(GIT_BUILTIN_ATOMIC) + return __atomic_load_n(&a->val, __ATOMIC_SEQ_CST); +#elif defined(GIT_BUILTIN_SYNC) + return __sync_val_compare_and_swap(&a->val, 0, 0); +#else +# error "Unsupported architecture for atomic operations" +#endif +} + +GIT_INLINE(void *) git_atomic__compare_and_swap( + void * volatile *ptr, void *oldval, void *newval) +{ +#if defined(GIT_WIN32) + return InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval); +#elif defined(GIT_BUILTIN_ATOMIC) + void *foundval = oldval; + __atomic_compare_exchange(ptr, &foundval, &newval, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + return foundval; +#elif defined(GIT_BUILTIN_SYNC) + return __sync_val_compare_and_swap(ptr, oldval, newval); +#else +# error "Unsupported architecture for atomic operations" +#endif +} + +GIT_INLINE(volatile void *) git_atomic__swap( + void * volatile *ptr, void *newval) +{ +#if defined(GIT_WIN32) + return InterlockedExchangePointer(ptr, newval); +#elif defined(GIT_BUILTIN_ATOMIC) + void * foundval = NULL; + __atomic_exchange(ptr, &newval, &foundval, __ATOMIC_SEQ_CST); + return foundval; +#elif defined(GIT_BUILTIN_SYNC) + return (volatile void *)__sync_lock_test_and_set(ptr, newval); +#else +# error "Unsupported architecture for atomic operations" +#endif +} + +GIT_INLINE(volatile void *) git_atomic__load(void * volatile *ptr) +{ +#if defined(GIT_WIN32) + void *newval = NULL, *oldval = NULL; + return (volatile void *)InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval); +#elif defined(GIT_BUILTIN_ATOMIC) + return (volatile void *)__atomic_load_n(ptr, __ATOMIC_SEQ_CST); +#elif defined(GIT_BUILTIN_SYNC) + return (volatile void *)__sync_val_compare_and_swap(ptr, 0, 0); +#else +# error "Unsupported architecture for atomic operations" +#endif +} + +#ifdef GIT_ARCH_64 + +/* + * Atomically adds the contents of *a and addend, and stores the result back into *a. + * @return the result of the operation. + */ +GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend) +{ +#if defined(GIT_WIN32) + return InterlockedAdd64(&a->val, addend); +#elif defined(GIT_BUILTIN_ATOMIC) + return __atomic_add_fetch(&a->val, addend, __ATOMIC_SEQ_CST); +#elif defined(GIT_BUILTIN_SYNC) + return __sync_add_and_fetch(&a->val, addend); +#else +# error "Unsupported architecture for atomic operations" +#endif +} + +/* + * Atomically sets the contents of *a to be val. + */ +GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val) +{ +#if defined(GIT_WIN32) + InterlockedExchange64(&a->val, val); +#elif defined(GIT_BUILTIN_ATOMIC) + __atomic_store_n(&a->val, val, __ATOMIC_SEQ_CST); +#elif defined(GIT_BUILTIN_SYNC) + __sync_lock_test_and_set(&a->val, val); +#else +# error "Unsupported architecture for atomic operations" +#endif +} + +/* + * Atomically gets the contents of *a. + * @return the contents of *a. + */ +GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a) +{ +#if defined(GIT_WIN32) + return (int64_t)InterlockedCompareExchange64(&a->val, 0, 0); +#elif defined(GIT_BUILTIN_ATOMIC) + return __atomic_load_n(&a->val, __ATOMIC_SEQ_CST); +#elif defined(GIT_BUILTIN_SYNC) + return __sync_val_compare_and_swap(&a->val, 0, 0); +#else +# error "Unsupported architecture for atomic operations" +#endif +} + +#endif + +#else + +#define git_threads_global_init git__noop + +#define git_thread unsigned int +#define git_thread_create(t, s, a) git__noop(t, s, a) +#define git_thread_join(i, s) git__noop_args(i, s) + +/* Pthreads Mutex */ +#define git_mutex unsigned int +#define git_mutex_init(a) git__noop_args(a) +#define git_mutex_init(a) git__noop_args(a) +#define git_mutex_lock(a) git__noop_args(a) +#define git_mutex_unlock(a) git__noop_args(a) +#define git_mutex_free(a) git__noop_args(a) + +/* Pthreads condition vars */ +#define git_cond unsigned int +#define git_cond_init(c) git__noop_args(c) +#define git_cond_free(c) git__noop_args(c) +#define git_cond_wait(c, l) git__noop_args(c, l) +#define git_cond_signal(c) git__noop_args(c) +#define git_cond_broadcast(c) git__noop_args(c) + +/* Pthreads rwlock */ +#define git_rwlock unsigned int +#define git_rwlock_init(a) git__noop_args(a) +#define git_rwlock_rdlock(a) git__noop_args(a) +#define git_rwlock_rdunlock(a) git__noop_args(a) +#define git_rwlock_wrlock(a) git__noop_args(a) +#define git_rwlock_wrunlock(a) git__noop_args(a) +#define git_rwlock_free(a) git__noop_args(a) + +#define GIT_RWLOCK_STATIC_INIT 0 + + +GIT_INLINE(void) git_atomic32_set(git_atomic32 *a, int val) +{ + a->val = val; +} + +GIT_INLINE(int) git_atomic32_inc(git_atomic32 *a) +{ + return ++a->val; +} + +GIT_INLINE(int) git_atomic32_add(git_atomic32 *a, int32_t addend) +{ + a->val += addend; + return a->val; +} + +GIT_INLINE(int) git_atomic32_dec(git_atomic32 *a) +{ + return --a->val; +} + +GIT_INLINE(int) git_atomic32_get(git_atomic32 *a) +{ + return (int)a->val; +} + +GIT_INLINE(void *) git_atomic__compare_and_swap( + void * volatile *ptr, void *oldval, void *newval) +{ + void *foundval = *ptr; + if (foundval == oldval) + *ptr = newval; + return foundval; +} + +GIT_INLINE(volatile void *) git_atomic__swap( + void * volatile *ptr, void *newval) +{ + volatile void *old = *ptr; + *ptr = newval; + return old; +} + +GIT_INLINE(volatile void *) git_atomic__load(void * volatile *ptr) +{ + return *ptr; +} + +#ifdef GIT_ARCH_64 + +GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend) +{ + a->val += addend; + return a->val; +} + +GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val) +{ + a->val = val; +} + +GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a) +{ + return (int64_t)a->val; +} + +#endif + +#endif + +/* + * Atomically replace the contents of *ptr (if they are equal to oldval) with + * newval. ptr must point to a pointer or a value that is the same size as a + * pointer. This is semantically compatible with: + * + * #define git_atomic_compare_and_swap(ptr, oldval, newval) \ + * ({ \ + * void *foundval = *ptr; \ + * if (foundval == oldval) \ + * *ptr = newval; \ + * foundval; \ + * }) + * + * @return the original contents of *ptr. + */ +#define git_atomic_compare_and_swap(ptr, oldval, newval) \ + git_atomic__compare_and_swap((void * volatile *)ptr, oldval, newval) + +/* + * Atomically replace the contents of v with newval. v must be the same size as + * a pointer. This is semantically compatible with: + * + * #define git_atomic_swap(v, newval) \ + * ({ \ + * volatile void *old = v; \ + * v = newval; \ + * old; \ + * }) + * + * @return the original contents of v. + */ +#define git_atomic_swap(v, newval) \ + (void *)git_atomic__swap((void * volatile *)&(v), newval) + +/* + * Atomically reads the contents of v. v must be the same size as a pointer. + * This is semantically compatible with: + * + * #define git_atomic_load(v) v + * + * @return the contents of v. + */ +#define git_atomic_load(v) \ + (void *)git_atomic__load((void * volatile *)&(v)) + +#if defined(GIT_THREADS) + +# if defined(GIT_WIN32) +# define GIT_MEMORY_BARRIER MemoryBarrier() +# elif defined(GIT_BUILTIN_ATOMIC) +# define GIT_MEMORY_BARRIER __atomic_thread_fence(__ATOMIC_SEQ_CST) +# elif defined(GIT_BUILTIN_SYNC) +# define GIT_MEMORY_BARRIER __sync_synchronize() +# endif + +#else + +# define GIT_MEMORY_BARRIER /* noop */ + +#endif + +/* Thread-local data */ + +#if !defined(GIT_THREADS) +# define git_tlsdata_key int +#elif defined(GIT_WIN32) +# define git_tlsdata_key DWORD +#elif defined(_POSIX_THREADS) +# define git_tlsdata_key pthread_key_t +#else +# error unknown threading model +#endif + +/** + * Create a thread-local data key. The destroy function will be + * called upon thread exit. On some platforms, it may be called + * when all threads have deleted their keys. + * + * Note that the tlsdata functions do not set an error message on + * failure; this is because the error handling in libgit2 is itself + * handled by thread-local data storage. + * + * @param key the tlsdata key + * @param destroy_fn function pointer called upon thread exit + * @return 0 on success, non-zero on failure + */ +int git_tlsdata_init(git_tlsdata_key *key, void (GIT_SYSTEM_CALL *destroy_fn)(void *)); + +/** + * Set a the thread-local value for the given key. + * + * @param key the tlsdata key to store data on + * @param value the pointer to store + * @return 0 on success, non-zero on failure + */ +int git_tlsdata_set(git_tlsdata_key key, void *value); + +/** + * Get the thread-local value for the given key. + * + * @param key the tlsdata key to retrieve the value of + * @return the pointer stored with git_tlsdata_set + */ +void *git_tlsdata_get(git_tlsdata_key key); + +/** + * Delete the given thread-local key. + * + * @param key the tlsdata key to dispose + * @return 0 on success, non-zero on failure + */ +int git_tlsdata_dispose(git_tlsdata_key key); + +#endif diff --git a/vendor/libgit2/src/tsort.c b/vendor/libgit2/src/util/tsort.c similarity index 99% rename from vendor/libgit2/src/tsort.c rename to vendor/libgit2/src/util/tsort.c index 045efad2..2ef03d03 100644 --- a/vendor/libgit2/src/tsort.c +++ b/vendor/libgit2/src/util/tsort.c @@ -5,7 +5,7 @@ * a Linking Exception. For full terms see the included COPYING file. */ -#include "common.h" +#include "git2_util.h" /** * An array-of-pointers implementation of Python's Timsort diff --git a/vendor/libgit2/src/util/unix/map.c b/vendor/libgit2/src/util/unix/map.c new file mode 100644 index 00000000..93307768 --- /dev/null +++ b/vendor/libgit2/src/util/unix/map.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "git2_util.h" + +#if !defined(GIT_WIN32) && !defined(NO_MMAP) + +#include "map.h" +#include +#include +#include + +int git__page_size(size_t *page_size) +{ + long sc_page_size = sysconf(_SC_PAGE_SIZE); + if (sc_page_size < 0) { + git_error_set(GIT_ERROR_OS, "can't determine system page size"); + return -1; + } + *page_size = (size_t) sc_page_size; + return 0; +} + +int git__mmap_alignment(size_t *alignment) +{ + return git__page_size(alignment); +} + +int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset) +{ + int mprot = PROT_READ; + int mflag = 0; + + GIT_MMAP_VALIDATE(out, len, prot, flags); + + out->data = NULL; + out->len = 0; + + if (prot & GIT_PROT_WRITE) + mprot |= PROT_WRITE; + + if ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED) + mflag = MAP_SHARED; + else if ((flags & GIT_MAP_TYPE) == GIT_MAP_PRIVATE) + mflag = MAP_PRIVATE; + else + mflag = MAP_SHARED; + + out->data = mmap(NULL, len, mprot, mflag, fd, offset); + + if (!out->data || out->data == MAP_FAILED) { + git_error_set(GIT_ERROR_OS, "failed to mmap. Could not write data"); + return -1; + } + + out->len = len; + + return 0; +} + +int p_munmap(git_map *map) +{ + GIT_ASSERT_ARG(map); + munmap(map->data, map->len); + map->data = NULL; + map->len = 0; + + return 0; +} + +#endif + diff --git a/vendor/libgit2/src/util/unix/posix.h b/vendor/libgit2/src/util/unix/posix.h new file mode 100644 index 00000000..60f27d3d --- /dev/null +++ b/vendor/libgit2/src/util/unix/posix.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_unix_posix_h__ +#define INCLUDE_unix_posix_h__ + +#include "git2_util.h" + +#include +#include +#include +#include +#include + +typedef int GIT_SOCKET; +#define INVALID_SOCKET -1 + +#define p_lseek(f,n,w) lseek(f, n, w) +#define p_fstat(f,b) fstat(f, b) +#define p_lstat(p,b) lstat(p,b) +#define p_stat(p,b) stat(p, b) + +#if defined(GIT_USE_STAT_MTIMESPEC) +# define st_atime_nsec st_atimespec.tv_nsec +# define st_mtime_nsec st_mtimespec.tv_nsec +# define st_ctime_nsec st_ctimespec.tv_nsec +#elif defined(GIT_USE_STAT_MTIM) +# define st_atime_nsec st_atim.tv_nsec +# define st_mtime_nsec st_mtim.tv_nsec +# define st_ctime_nsec st_ctim.tv_nsec +#elif !defined(GIT_USE_STAT_MTIME_NSEC) && defined(GIT_USE_NSEC) +# error GIT_USE_NSEC defined but unknown struct stat nanosecond type +#endif + +#define p_utimes(f, t) utimes(f, t) + +#define p_readlink(a, b, c) readlink(a, b, c) +#define p_symlink(o,n) symlink(o, n) +#define p_link(o,n) link(o, n) +#define p_unlink(p) unlink(p) +#define p_mkdir(p,m) mkdir(p, m) +extern char *p_realpath(const char *, char *); + +GIT_INLINE(int) p_fsync(int fd) +{ + p_fsync__cnt++; + return fsync(fd); +} + +#define p_recv(s,b,l,f) recv(s,b,l,f) +#define p_send(s,b,l,f) send(s,b,l,f) +#define p_inet_pton(a, b, c) inet_pton(a, b, c) + +#define p_vsnprintf(b, c, f, a) vsnprintf(b, c, f, a) +#define p_snprintf snprintf +#define p_chdir(p) chdir(p) +#define p_rmdir(p) rmdir(p) +#define p_access(p,m) access(p,m) +#define p_ftruncate(fd, sz) ftruncate(fd, sz) + +/* + * Pre-Android 5 did not implement a virtual filesystem atop FAT + * partitions for Unix permissions, which causes chmod to fail. However, + * Unix permissions have no effect on Android anyway as file permissions + * are not actually managed this way, so treating it as a no-op across + * all Android is safe. + */ +#ifdef __ANDROID__ +# define p_chmod(p,m) 0 +#else +# define p_chmod(p,m) chmod(p, m) +#endif + +/* see win32/posix.h for explanation about why this exists */ +#define p_lstat_posixly(p,b) lstat(p,b) + +#define p_localtime_r(c, r) localtime_r(c, r) +#define p_gmtime_r(c, r) gmtime_r(c, r) + +#define p_timeval timeval + +#ifdef GIT_USE_FUTIMENS +GIT_INLINE(int) p_futimes(int f, const struct p_timeval t[2]) +{ + struct timespec s[2]; + s[0].tv_sec = t[0].tv_sec; + s[0].tv_nsec = t[0].tv_usec * 1000; + s[1].tv_sec = t[1].tv_sec; + s[1].tv_nsec = t[1].tv_usec * 1000; + return futimens(f, s); +} +#else +# define p_futimes futimes +#endif + +#define p_pread(f, d, s, o) pread(f, d, s, o) +#define p_pwrite(f, d, s, o) pwrite(f, d, s, o) + +#endif diff --git a/vendor/libgit2/src/util/unix/process.c b/vendor/libgit2/src/util/unix/process.c new file mode 100644 index 00000000..296007e6 --- /dev/null +++ b/vendor/libgit2/src/util/unix/process.c @@ -0,0 +1,706 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include +#include +#include + +#include "git2_util.h" +#include "vector.h" +#include "futils.h" +#include "process.h" +#include "strlist.h" + +#ifdef __APPLE__ + #include + #define environ (*_NSGetEnviron()) +#else + extern char **environ; +#endif + +struct git_process { + char **args; + char **env; + + char *cwd; + + unsigned int use_shell : 1, + capture_in : 1, + capture_out : 1, + capture_err : 1; + + pid_t pid; + + int child_in; + int child_out; + int child_err; + git_process_result_status status; +}; + +GIT_INLINE(bool) is_delete_env(const char *env) +{ + char *c = strchr(env, '='); + + if (c == NULL) + return false; + + return *(c+1) == '\0'; +} + +GIT_INLINE(int) insert_dup(git_vector *v, const char *s) +{ + char *dup = git__strdup(s); + + GIT_ERROR_CHECK_ALLOC(dup); + + return git_vector_insert(v, dup); +} + +static int setup_args( + char ***out, + const char **args, + size_t args_len, + bool use_shell) +{ + git_vector prefixed = GIT_VECTOR_INIT; + git_str first = GIT_STR_INIT; + size_t cnt; + + GIT_ASSERT(args && args_len); + + if (use_shell) { + if (git_str_puts(&first, args[0]) < 0 || + git_str_puts(&first, " \"$@\"") < 0 || + insert_dup(&prefixed, "/bin/sh") < 0 || + insert_dup(&prefixed, "-c") < 0 || + git_vector_insert(&prefixed, git_str_detach(&first)) < 0) + goto on_error; + } + + for (cnt = 0; args && cnt < args_len; cnt++) { + if (insert_dup(&prefixed, args[cnt]) < 0) + goto on_error; + } + + git_vector_insert(&prefixed, NULL); + + *out = (char **)prefixed.contents; + + return 0; + +on_error: + git_str_dispose(&first); + git_vector_free_deep(&prefixed); + return -1; +} + +static int merge_env( + char ***out, + const char **env, + size_t env_len, + bool exclude_env) +{ + git_vector merged = GIT_VECTOR_INIT; + char **kv; + size_t max, cnt; + int error = 0; + + for (max = env_len, kv = environ; !exclude_env && *kv; kv++) + max++; + + if ((error = git_vector_init(&merged, max, NULL)) < 0) + goto on_error; + + for (cnt = 0; env && cnt < env_len; cnt++) { + if (is_delete_env(env[cnt])) + continue; + + if (insert_dup(&merged, env[cnt]) < 0) + goto on_error; + } + + if (!exclude_env) { + for (kv = environ; *kv; kv++) { + if (env && git_strlist_contains_key(env, env_len, *kv, '=')) + continue; + + if (insert_dup(&merged, *kv) < 0) + goto on_error; + } + } + + if (merged.length == 0) { + *out = NULL; + error = 0; + goto on_error; + } + + git_vector_insert(&merged, NULL); + + *out = (char **)merged.contents; + + return 0; + +on_error: + git_vector_free_deep(&merged); + return error; +} + +int git_process_new( + git_process **out, + const char **args, + size_t args_len, + const char **env, + size_t env_len, + git_process_options *opts) +{ + git_process *process; + + GIT_ASSERT_ARG(out && args && args_len > 0); + + *out = NULL; + + process = git__calloc(sizeof(git_process), 1); + GIT_ERROR_CHECK_ALLOC(process); + + if (setup_args(&process->args, args, args_len, opts ? opts->use_shell : false) < 0 || + merge_env(&process->env, env, env_len, opts ? opts->exclude_env : false) < 0) { + git_process_free(process); + return -1; + } + + if (opts) { + process->use_shell = opts->use_shell; + process->capture_in = opts->capture_in; + process->capture_out = opts->capture_out; + process->capture_err = opts->capture_err; + + if (opts->cwd) { + process->cwd = git__strdup(opts->cwd); + GIT_ERROR_CHECK_ALLOC(process->cwd); + } + } + + process->child_in = -1; + process->child_out = -1; + process->child_err = -1; + process->status = -1; + + *out = process; + return 0; +} + +extern int git_process_new_from_cmdline( + git_process **out, + const char *cmdline, + const char **env, + size_t env_len, + git_process_options *opts) +{ + git_process_options merged_opts = {0}; + + memcpy(&merged_opts, opts, sizeof(git_process_options)); + merged_opts.use_shell = 1; + + return git_process_new(out, &cmdline, 1, env, env_len, &merged_opts); +} + +#define CLOSE_FD(fd) \ + if (fd >= 0) { \ + close(fd); \ + fd = -1; \ + } + +static int try_read_status(size_t *out, int fd, void *buf, size_t len) +{ + size_t read_len = 0; + int ret = -1; + + while (ret && read_len < len) { + ret = read(fd, buf + read_len, len - read_len); + + if (ret < 0 && errno != EAGAIN && errno != EINTR) { + git_error_set(GIT_ERROR_OS, "could not read child status"); + return -1; + } + + read_len += ret; + } + + *out = read_len; + return 0; +} + + +static int read_status(int fd) +{ + size_t status_len = sizeof(int) * 3, read_len = 0; + char buffer[status_len], fn[128]; + int error, fn_error, os_error, fn_len = 0; + + if ((error = try_read_status(&read_len, fd, buffer, status_len)) < 0) + return error; + + /* Immediate EOF indicates the exec succeeded. */ + if (read_len == 0) + return 0; + + if (read_len < status_len) { + git_error_set(GIT_ERROR_INVALID, "child status truncated"); + return -1; + } + + memcpy(&fn_error, &buffer[0], sizeof(int)); + memcpy(&os_error, &buffer[sizeof(int)], sizeof(int)); + memcpy(&fn_len, &buffer[sizeof(int) * 2], sizeof(int)); + + if (fn_len > 0) { + fn_len = min(fn_len, (int)(ARRAY_SIZE(fn) - 1)); + + if ((error = try_read_status(&read_len, fd, fn, fn_len)) < 0) + return error; + + fn[fn_len] = '\0'; + } else { + fn[0] = '\0'; + } + + if (fn_error) { + errno = os_error; + git_error_set(GIT_ERROR_OS, "could not %s", fn[0] ? fn : "(unknown)"); + } + + return fn_error; +} + +static bool try_write_status(int fd, const void *buf, size_t len) +{ + size_t write_len; + int ret; + + for (write_len = 0; write_len < len; ) { + ret = write(fd, buf + write_len, len - write_len); + + if (ret <= 0) + break; + + write_len += ret; + } + + return (len == write_len); +} + +static void write_status(int fd, const char *fn, int error, int os_error) +{ + size_t status_len = sizeof(int) * 3, fn_len; + char buffer[status_len]; + + fn_len = strlen(fn); + + if (fn_len > INT_MAX) + fn_len = INT_MAX; + + memcpy(&buffer[0], &error, sizeof(int)); + memcpy(&buffer[sizeof(int)], &os_error, sizeof(int)); + memcpy(&buffer[sizeof(int) * 2], &fn_len, sizeof(int)); + + /* Do our best effort to write all the status. */ + if (!try_write_status(fd, buffer, status_len)) + return; + + if (fn_len) + try_write_status(fd, fn, fn_len); +} + +static int resolve_path(git_process *process) +{ + git_str full_path = GIT_STR_INIT; + int error = 0; + + /* The shell will resolve the path for us */ + if (process->use_shell) + goto done; + + error = git_fs_path_find_executable(&full_path, process->args[0]); + + if (error == GIT_ENOTFOUND) { + git_error_set(GIT_ERROR_SSH, "cannot run %s: No such file or directory", process->args[0]); + error = -1; + } + + if (error) + goto done; + + git__free(process->args[0]); + process->args[0] = git_str_detach(&full_path); + +done: + git_str_dispose(&full_path); + return error; +} + +int git_process_start(git_process *process) +{ + int in[2] = { -1, -1 }, out[2] = { -1, -1 }, + err[2] = { -1, -1 }, status[2] = { -1, -1 }; + int fdflags, state, error; + pid_t pid; + + /* Locate the path (unless we're letting the shell do it for us) */ + if ((error = resolve_path(process)) < 0) + goto on_error; + + /* Set up the pipes to read from/write to the process */ + if ((process->capture_in && pipe(in) < 0) || + (process->capture_out && pipe(out) < 0) || + (process->capture_err && pipe(err) < 0)) { + git_error_set(GIT_ERROR_OS, "could not create pipe"); + goto on_error; + } + + /* Set up a self-pipe for status from the forked process. */ + if (pipe(status) < 0 || + (fdflags = fcntl(status[1], F_GETFD)) < 0 || + fcntl(status[1], F_SETFD, fdflags | FD_CLOEXEC) < 0) { + git_error_set(GIT_ERROR_OS, "could not create pipe"); + goto on_error; + } + + switch (pid = fork()) { + case -1: + git_error_set(GIT_ERROR_OS, "could not fork"); + goto on_error; + + /* Child: start the process. */ + case 0: + /* Close the opposing side of the pipes */ + CLOSE_FD(status[0]); + + if (process->capture_in) { + CLOSE_FD(in[1]); + dup2(in[0], STDIN_FILENO); + } + + if (process->capture_out) { + CLOSE_FD(out[0]); + dup2(out[1], STDOUT_FILENO); + } + + if (process->capture_err) { + CLOSE_FD(err[0]); + dup2(err[1], STDERR_FILENO); + } + + if (process->cwd && (error = chdir(process->cwd)) < 0) { + write_status(status[1], "chdir", error, errno); + exit(0); + } + + /* + * Exec the process and write the results back if the + * call fails. If it succeeds, we'll close the status + * pipe (via CLOEXEC) and the parent will know. + */ + error = execve(process->args[0], + process->args, + process->env); + + write_status(status[1], "execve", error, errno); + exit(0); + + /* Parent: make sure the child process exec'd correctly. */ + default: + /* Close the opposing side of the pipes */ + CLOSE_FD(status[1]); + + if (process->capture_in) { + CLOSE_FD(in[0]); + process->child_in = in[1]; + } + + if (process->capture_out) { + CLOSE_FD(out[1]); + process->child_out = out[0]; + } + + if (process->capture_err) { + CLOSE_FD(err[1]); + process->child_err = err[0]; + } + + /* Try to read the status */ + process->status = status[0]; + if ((error = read_status(status[0])) < 0) { + waitpid(process->pid, &state, 0); + goto on_error; + } + + process->pid = pid; + return 0; + } + +on_error: + CLOSE_FD(in[0]); CLOSE_FD(in[1]); + CLOSE_FD(out[0]); CLOSE_FD(out[1]); + CLOSE_FD(err[0]); CLOSE_FD(err[1]); + CLOSE_FD(status[0]); CLOSE_FD(status[1]); + return -1; +} + +int git_process_id(p_pid_t *out, git_process *process) +{ + GIT_ASSERT(out && process); + + if (!process->pid) { + git_error_set(GIT_ERROR_INVALID, "process not running"); + return -1; + } + + *out = process->pid; + return 0; +} + +static ssize_t process_read(int fd, void *buf, size_t count) +{ + ssize_t ret; + + if (count > SSIZE_MAX) + count = SSIZE_MAX; + + if ((ret = read(fd, buf, count)) < 0) { + git_error_set(GIT_ERROR_OS, "could not read from child process"); + return -1; + } + + return ret; +} + +ssize_t git_process_read(git_process *process, void *buf, size_t count) +{ + GIT_ASSERT_ARG(process); + GIT_ASSERT(process->capture_out); + + return process_read(process->child_out, buf, count); +} + +ssize_t git_process_read_err(git_process *process, void *buf, size_t count) +{ + GIT_ASSERT_ARG(process); + GIT_ASSERT(process->capture_err); + + return process_read(process->child_err, buf, count); +} + +#ifdef GIT_THREADS + +# define signal_state sigset_t + +/* + * Since signal-handling is process-wide, we cannot simply use + * SIG_IGN to avoid SIGPIPE. Instead: http://www.microhowto.info:80/howto/ignore_sigpipe_without_affecting_other_threads_in_a_process.html + */ + +GIT_INLINE(int) disable_signals(sigset_t *saved_mask) +{ + sigset_t sigpipe_mask; + + sigemptyset(&sigpipe_mask); + sigaddset(&sigpipe_mask, SIGPIPE); + + if (pthread_sigmask(SIG_BLOCK, &sigpipe_mask, saved_mask) < 0) { + git_error_set(GIT_ERROR_OS, "could not configure signal mask"); + return -1; + } + + return 0; +} + +GIT_INLINE(int) restore_signals(sigset_t *saved_mask) +{ + sigset_t sigpipe_mask, pending; + int signal; + + sigemptyset(&sigpipe_mask); + sigaddset(&sigpipe_mask, SIGPIPE); + + if (sigpending(&pending) < 0) { + git_error_set(GIT_ERROR_OS, "could not examine pending signals"); + return -1; + } + + if (sigismember(&pending, SIGPIPE) == 1 && + sigwait(&sigpipe_mask, &signal) < 0) { + git_error_set(GIT_ERROR_OS, "could not wait for (blocking) signal delivery"); + return -1; + } + + if (pthread_sigmask(SIG_SETMASK, saved_mask, 0) < 0) { + git_error_set(GIT_ERROR_OS, "could not configure signal mask"); + return -1; + } + + return 0; +} + +#else + +# define signal_state struct sigaction + +GIT_INLINE(int) disable_signals(struct sigaction *saved_handler) +{ + struct sigaction ign_handler = { 0 }; + + ign_handler.sa_handler = SIG_IGN; + + if (sigaction(SIGPIPE, &ign_handler, saved_handler) < 0) { + git_error_set(GIT_ERROR_OS, "could not configure signal handler"); + return -1; + } + + return 0; +} + +GIT_INLINE(int) restore_signals(struct sigaction *saved_handler) +{ + if (sigaction(SIGPIPE, saved_handler, NULL) < 0) { + git_error_set(GIT_ERROR_OS, "could not configure signal handler"); + return -1; + } + + return 0; +} + +#endif + +ssize_t git_process_write(git_process *process, const void *buf, size_t count) +{ + signal_state saved_signal; + ssize_t ret; + + GIT_ASSERT_ARG(process); + GIT_ASSERT(process->capture_in); + + if (count > SSIZE_MAX) + count = SSIZE_MAX; + + if (disable_signals(&saved_signal) < 0) + return -1; + + if ((ret = write(process->child_in, buf, count)) < 0) + git_error_set(GIT_ERROR_OS, "could not write to child process"); + + if (restore_signals(&saved_signal) < 0) + return -1; + + return (ret < 0) ? -1 : ret; +} + +int git_process_close_in(git_process *process) +{ + if (!process->capture_in) { + git_error_set(GIT_ERROR_INVALID, "input is not open"); + return -1; + } + + CLOSE_FD(process->child_in); + return 0; +} + +int git_process_close_out(git_process *process) +{ + if (!process->capture_out) { + git_error_set(GIT_ERROR_INVALID, "output is not open"); + return -1; + } + + CLOSE_FD(process->child_out); + return 0; +} + +int git_process_close_err(git_process *process) +{ + if (!process->capture_err) { + git_error_set(GIT_ERROR_INVALID, "error is not open"); + return -1; + } + + CLOSE_FD(process->child_err); + return 0; +} + +int git_process_close(git_process *process) +{ + CLOSE_FD(process->child_in); + CLOSE_FD(process->child_out); + CLOSE_FD(process->child_err); + + return 0; +} + +int git_process_wait(git_process_result *result, git_process *process) +{ + int state; + + if (result) + memset(result, 0, sizeof(git_process_result)); + + if (!process->pid) { + git_error_set(GIT_ERROR_INVALID, "process is stopped"); + return -1; + } + + if (waitpid(process->pid, &state, 0) < 0) { + git_error_set(GIT_ERROR_OS, "could not wait for child"); + return -1; + } + + process->pid = 0; + + if (result) { + if (WIFEXITED(state)) { + result->status = GIT_PROCESS_STATUS_NORMAL; + result->exitcode = WEXITSTATUS(state); + } else if (WIFSIGNALED(state)) { + result->status = GIT_PROCESS_STATUS_ERROR; + result->signal = WTERMSIG(state); + } else { + result->status = GIT_PROCESS_STATUS_ERROR; + } + } + + return 0; +} + +int git_process_result_msg(git_str *out, git_process_result *result) +{ + if (result->status == GIT_PROCESS_STATUS_NONE) { + return git_str_puts(out, "process not started"); + } else if (result->status == GIT_PROCESS_STATUS_NORMAL) { + return git_str_printf(out, "process exited with code %d", + result->exitcode); + } else if (result->signal) { + return git_str_printf(out, "process exited on signal %d", + result->signal); + } + + return git_str_puts(out, "unknown error"); +} + +void git_process_free(git_process *process) +{ + if (!process) + return; + + if (process->pid) + git_process_close(process); + + git__free(process->cwd); + git_strlist_free_with_null(process->args); + git_strlist_free_with_null(process->env); + git__free(process); +} diff --git a/vendor/libgit2/src/unix/pthread.h b/vendor/libgit2/src/util/unix/pthread.h similarity index 100% rename from vendor/libgit2/src/unix/pthread.h rename to vendor/libgit2/src/util/unix/pthread.h diff --git a/vendor/libgit2/src/util/unix/realpath.c b/vendor/libgit2/src/util/unix/realpath.c new file mode 100644 index 00000000..e1d2adb8 --- /dev/null +++ b/vendor/libgit2/src/util/unix/realpath.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "git2_util.h" + +#ifndef GIT_WIN32 + +#include +#include +#include +#include + +char *p_realpath(const char *pathname, char *resolved) +{ + char *result; + + if ((result = realpath(pathname, resolved)) == NULL) + return NULL; + +#ifdef __OpenBSD__ + /* The OpenBSD realpath function behaves differently, + * figure out if the file exists */ + if (access(ret, F_OK) < 0) { + if (!resolved) + free(result); + + return NULL; + } +#endif + + /* + * If resolved == NULL, the system has allocated the result + * string. We need to strdup this into _our_ allocator pool + * so that callers can free it with git__free. + */ + if (!resolved) { + char *dup = git__strdup(result); + free(result); + + result = dup; + } + + return result; +} + +#endif diff --git a/vendor/libgit2/src/util/utf8.c b/vendor/libgit2/src/util/utf8.c new file mode 100644 index 00000000..c566fdf2 --- /dev/null +++ b/vendor/libgit2/src/util/utf8.c @@ -0,0 +1,150 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "utf8.h" + +#include "git2_util.h" + +/* + * git_utf8_iterate is taken from the utf8proc project, + * http://www.public-software-group.org/utf8proc + * + * Copyright (c) 2009 Public Software Group e. V., Berlin, Germany + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the ""Software""), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +static const uint8_t utf8proc_utf8class[256] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static int utf8_charlen(const uint8_t *str, size_t str_len) +{ + uint8_t length; + size_t i; + + length = utf8proc_utf8class[str[0]]; + if (!length) + return -1; + + if (str_len > 0 && length > str_len) + return -1; + + for (i = 1; i < length; i++) { + if ((str[i] & 0xC0) != 0x80) + return -1; + } + + return (int)length; +} + +int git_utf8_iterate(uint32_t *out, const char *_str, size_t str_len) +{ + const uint8_t *str = (const uint8_t *)_str; + uint32_t uc = 0; + int length; + + *out = 0; + + if ((length = utf8_charlen(str, str_len)) < 0) + return -1; + + switch (length) { + case 1: + uc = str[0]; + break; + case 2: + uc = ((str[0] & 0x1F) << 6) + (str[1] & 0x3F); + if (uc < 0x80) uc = -1; + break; + case 3: + uc = ((str[0] & 0x0F) << 12) + ((str[1] & 0x3F) << 6) + + (str[2] & 0x3F); + if (uc < 0x800 || (uc >= 0xD800 && uc < 0xE000) || + (uc >= 0xFDD0 && uc < 0xFDF0)) uc = -1; + break; + case 4: + uc = ((str[0] & 0x07) << 18) + ((str[1] & 0x3F) << 12) + + ((str[2] & 0x3F) << 6) + (str[3] & 0x3F); + if (uc < 0x10000 || uc >= 0x110000) uc = -1; + break; + default: + return -1; + } + + if ((uc & 0xFFFF) >= 0xFFFE) + return -1; + + *out = uc; + return length; +} + +size_t git_utf8_char_length(const char *_str, size_t str_len) +{ + const uint8_t *str = (const uint8_t *)_str; + size_t offset = 0, count = 0; + + while (offset < str_len) { + int length = utf8_charlen(str + offset, str_len - offset); + + if (length < 0) + length = 1; + + offset += length; + count++; + } + + return count; +} + +size_t git_utf8_valid_buf_length(const char *_str, size_t str_len) +{ + const uint8_t *str = (const uint8_t *)_str; + size_t offset = 0; + + while (offset < str_len) { + int length = utf8_charlen(str + offset, str_len - offset); + + if (length < 0) + break; + + offset += length; + } + + return offset; +} diff --git a/vendor/libgit2/src/utf8.h b/vendor/libgit2/src/util/utf8.h similarity index 98% rename from vendor/libgit2/src/utf8.h rename to vendor/libgit2/src/util/utf8.h index dff91b29..753ab07e 100644 --- a/vendor/libgit2/src/utf8.h +++ b/vendor/libgit2/src/util/utf8.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_utf8_h__ #define INCLUDE_utf8_h__ -#include "common.h" +#include "git2_util.h" /* * Iterate through an UTF-8 string, yielding one codepoint at a time. diff --git a/vendor/libgit2/src/util.c b/vendor/libgit2/src/util/util.c similarity index 95% rename from vendor/libgit2/src/util.c rename to vendor/libgit2/src/util/util.c index e06d4ca0..3e4d9344 100644 --- a/vendor/libgit2/src/util.c +++ b/vendor/libgit2/src/util/util.c @@ -7,7 +7,7 @@ #include "util.h" -#include "common.h" +#include "git2_util.h" #ifdef GIT_WIN32 # include "win32/utf-conv.h" @@ -18,7 +18,7 @@ # endif # include -# ifdef GIT_QSORT_S +# ifdef GIT_QSORT_MSC # include # endif #endif @@ -269,13 +269,26 @@ int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix) return prefixcmp(str, str_n, prefix, true); } -int git__suffixcmp(const char *str, const char *suffix) +static int suffixcmp(const char *str, const char *suffix, bool icase) { size_t a = strlen(str); size_t b = strlen(suffix); + if (a < b) return -1; - return strcmp(str + (a - b), suffix); + + return icase ? strcasecmp(str + (a - b), suffix) : + strcmp(str + (a - b), suffix); +} + +int git__suffixcmp(const char *str, const char *suffix) +{ + return suffixcmp(str, suffix, false); +} + +int git__suffixcmp_icase(const char *str, const char *suffix) +{ + return suffixcmp(str, suffix, true); } char *git__strtok(char **end, const char *sep) @@ -623,12 +636,12 @@ int git__bsearch_r( */ int git__strcmp_cb(const void *a, const void *b) { - return strcmp((const char *)a, (const char *)b); + return git__strcmp((const char *)a, (const char *)b); } int git__strcasecmp_cb(const void *a, const void *b) { - return strcasecmp((const char *)a, (const char *)b); + return git__strcasecmp((const char *)a, (const char *)b); } int git__parse_bool(int *out, const char *value) @@ -673,7 +686,7 @@ size_t git__unescape(char *str) return (pos - str); } -#if defined(GIT_QSORT_S) || defined(GIT_QSORT_R_BSD) +#if defined(GIT_QSORT_MSC) || defined(GIT_QSORT_BSD) typedef struct { git__sort_r_cmp cmp; void *payload; @@ -688,9 +701,11 @@ static int GIT_LIBGIT2_CALL git__qsort_r_glue_cmp( #endif -#if !defined(GIT_QSORT_R_BSD) && \ - !defined(GIT_QSORT_R_GNU) && \ - !defined(GIT_QSORT_S) +#if !defined(GIT_QSORT_BSD) && \ + !defined(GIT_QSORT_GNU) && \ + !defined(GIT_QSORT_C11) && \ + !defined(GIT_QSORT_MSC) + static void swap(uint8_t *a, uint8_t *b, size_t elsize) { char tmp[256]; @@ -716,17 +731,20 @@ static void insertsort( for (j = i; j > base && cmp(j, j - elsize, payload) < 0; j -= elsize) swap(j, j - elsize, elsize); } + #endif void git__qsort_r( void *els, size_t nel, size_t elsize, git__sort_r_cmp cmp, void *payload) { -#if defined(GIT_QSORT_R_BSD) +#if defined(GIT_QSORT_GNU) + qsort_r(els, nel, elsize, cmp, payload); +#elif defined(GIT_QSORT_C11) + qsort_s(els, nel, elsize, cmp, payload); +#elif defined(GIT_QSORT_BSD) git__qsort_r_glue glue = { cmp, payload }; qsort_r(els, nel, elsize, &glue, git__qsort_r_glue_cmp); -#elif defined(GIT_QSORT_R_GNU) - qsort_r(els, nel, elsize, cmp, payload); -#elif defined(GIT_QSORT_S) +#elif defined(GIT_QSORT_MSC) git__qsort_r_glue glue = { cmp, payload }; qsort_s(els, nel, elsize, git__qsort_r_glue_cmp, &glue); #else @@ -743,7 +761,7 @@ int git__getenv(git_str *out, const char *name) git_str_clear(out); - if (git__utf8_to_16_alloc(&wide_name, name) < 0) + if (git_utf8_to_16_alloc(&wide_name, name) < 0) return -1; if ((value_len = GetEnvironmentVariableW(wide_name, NULL, 0)) > 0) { diff --git a/vendor/libgit2/src/util.h b/vendor/libgit2/src/util/util.h similarity index 86% rename from vendor/libgit2/src/util.h rename to vendor/libgit2/src/util/util.h index 141779ad..1f22f470 100644 --- a/vendor/libgit2/src/util.h +++ b/vendor/libgit2/src/util/util.h @@ -12,7 +12,7 @@ #endif #include "str.h" -#include "common.h" +#include "git2_util.h" #include "strnlen.h" #include "thread.h" @@ -57,6 +57,7 @@ extern int git__prefixcmp_icase(const char *str, const char *prefix); extern int git__prefixncmp(const char *str, size_t str_n, const char *prefix); extern int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix); extern int git__suffixcmp(const char *str, const char *suffix); +extern int git__suffixcmp_icase(const char *str, const char *suffix); GIT_INLINE(int) git__signum(int val) { @@ -83,15 +84,6 @@ extern char *git__strsep(char **end, const char *sep); extern void git__strntolower(char *str, size_t len); extern void git__strtolower(char *str); -#ifdef GIT_WIN32 -GIT_INLINE(int) git__tolower(int c) -{ - return (c >= 'A' && c <= 'Z') ? (c + 32) : c; -} -#else -# define git__tolower(a) tolower(a) -#endif - extern size_t git__linenlen(const char *buffer, size_t buffer_len); GIT_INLINE(const char *) git__next_line(const char *s) @@ -249,26 +241,6 @@ GIT_INLINE(size_t) git__size_t_powerof2(size_t v) return git__size_t_bitmask(v) + 1; } -GIT_INLINE(bool) git__isupper(int c) -{ - return (c >= 'A' && c <= 'Z'); -} - -GIT_INLINE(bool) git__isalpha(int c) -{ - return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')); -} - -GIT_INLINE(bool) git__isdigit(int c) -{ - return (c >= '0' && c <= '9'); -} - -GIT_INLINE(bool) git__isspace(int c) -{ - return (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r' || c == '\v'); -} - GIT_INLINE(bool) git__isspace_nonlf(int c) { return (c == ' ' || c == '\t' || c == '\f' || c == '\r' || c == '\v'); @@ -279,11 +251,6 @@ GIT_INLINE(bool) git__iswildcard(int c) return (c == '*' || c == '?' || c == '['); } -GIT_INLINE(bool) git__isxdigit(int c) -{ - return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); -} - /* * Parse a string value as a boolean, just like Core Git does. * @@ -319,59 +286,67 @@ GIT_INLINE(void) git__memzero(void *data, size_t size) #ifdef GIT_WIN32 -GIT_INLINE(double) git__timer(void) +GIT_INLINE(uint64_t) git_time_monotonic(void) { /* GetTickCount64 returns the number of milliseconds that have * elapsed since the system was started. */ - return (double) GetTickCount64() / (double) 1000; + return GetTickCount64(); } #elif __APPLE__ #include +#include -GIT_INLINE(double) git__timer(void) +GIT_INLINE(uint64_t) git_time_monotonic(void) { - uint64_t time = mach_absolute_time(); - static double scaling_factor = 0; + static double scaling_factor = 0; - if (scaling_factor == 0) { - mach_timebase_info_data_t info; - (void)mach_timebase_info(&info); - scaling_factor = (double)info.numer / (double)info.denom; - } + if (scaling_factor == 0) { + mach_timebase_info_data_t info; + + scaling_factor = mach_timebase_info(&info) == KERN_SUCCESS ? + ((double)info.numer / (double)info.denom) / 1.0E6 : + -1; + } else if (scaling_factor < 0) { + struct timeval tv; + + /* mach_timebase_info failed; fall back to gettimeofday */ + gettimeofday(&tv, NULL); + return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); + } - return (double)time * scaling_factor / 1.0E9; + return (uint64_t)(mach_absolute_time() * scaling_factor); } #elif defined(__amigaos4__) #include -GIT_INLINE(double) git__timer(void) +GIT_INLINE(uint64_t) git_time_monotonic(void) { struct TimeVal tv; ITimer->GetUpTime(&tv); - return (double)tv.Seconds + (double)tv.Microseconds / 1.0E6; + return (tv.Seconds * 1000) + (tv.Microseconds / 1000); } #else #include -GIT_INLINE(double) git__timer(void) +GIT_INLINE(uint64_t) git_time_monotonic(void) { struct timeval tv; #ifdef CLOCK_MONOTONIC struct timespec tp; if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) - return (double) tp.tv_sec + (double) tp.tv_nsec / 1.0E9; + return (tp.tv_sec * 1000) + (tp.tv_nsec / 1.0E6); #endif /* Fall back to using gettimeofday */ gettimeofday(&tv, NULL); - return (double)tv.tv_sec + (double)tv.tv_usec / 1.0E6; + return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); } #endif @@ -381,6 +356,7 @@ extern int git__getenv(git_str *out, const char *name); extern int git__online_cpus(void); GIT_INLINE(int) git__noop(void) { return 0; } +GIT_INLINE(int) git__noop_args(void *a, ...) { GIT_UNUSED(a); return 0; } #include "alloc.h" diff --git a/vendor/libgit2/src/varint.c b/vendor/libgit2/src/util/varint.c similarity index 100% rename from vendor/libgit2/src/varint.c rename to vendor/libgit2/src/util/varint.c diff --git a/vendor/libgit2/src/varint.h b/vendor/libgit2/src/util/varint.h similarity index 94% rename from vendor/libgit2/src/varint.h rename to vendor/libgit2/src/util/varint.h index 652e2248..79b8f554 100644 --- a/vendor/libgit2/src/varint.h +++ b/vendor/libgit2/src/util/varint.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_varint_h__ #define INCLUDE_varint_h__ -#include "common.h" +#include "git2_util.h" #include diff --git a/vendor/libgit2/src/vector.c b/vendor/libgit2/src/util/vector.c similarity index 100% rename from vendor/libgit2/src/vector.c rename to vendor/libgit2/src/util/vector.c diff --git a/vendor/libgit2/src/vector.h b/vendor/libgit2/src/util/vector.h similarity index 99% rename from vendor/libgit2/src/vector.h rename to vendor/libgit2/src/util/vector.h index ae3c79a4..e50cdfef 100644 --- a/vendor/libgit2/src/vector.h +++ b/vendor/libgit2/src/util/vector.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_vector_h__ #define INCLUDE_vector_h__ -#include "common.h" +#include "git2_util.h" typedef int (*git_vector_cmp)(const void *, const void *); diff --git a/vendor/libgit2/src/wildmatch.c b/vendor/libgit2/src/util/wildmatch.c similarity index 100% rename from vendor/libgit2/src/wildmatch.c rename to vendor/libgit2/src/util/wildmatch.c diff --git a/vendor/libgit2/src/wildmatch.h b/vendor/libgit2/src/util/wildmatch.h similarity index 95% rename from vendor/libgit2/src/wildmatch.h rename to vendor/libgit2/src/util/wildmatch.h index 44bb575a..f2064050 100644 --- a/vendor/libgit2/src/wildmatch.h +++ b/vendor/libgit2/src/util/wildmatch.h @@ -8,7 +8,7 @@ #ifndef INCLUDE_wildmatch_h__ #define INCLUDE_wildmatch_h__ -#include "common.h" +#include "git2_util.h" #define WM_CASEFOLD 1 #define WM_PATHNAME 2 diff --git a/vendor/libgit2/src/win32/dir.c b/vendor/libgit2/src/util/win32/dir.c similarity index 100% rename from vendor/libgit2/src/win32/dir.c rename to vendor/libgit2/src/util/win32/dir.c diff --git a/vendor/libgit2/src/win32/dir.h b/vendor/libgit2/src/util/win32/dir.h similarity index 97% rename from vendor/libgit2/src/win32/dir.h rename to vendor/libgit2/src/util/win32/dir.h index acd64729..81011153 100644 --- a/vendor/libgit2/src/win32/dir.h +++ b/vendor/libgit2/src/util/win32/dir.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_win32_dir_h__ #define INCLUDE_win32_dir_h__ -#include "common.h" +#include "git2_util.h" #include "w32_util.h" diff --git a/vendor/libgit2/src/win32/error.c b/vendor/libgit2/src/util/win32/error.c similarity index 95% rename from vendor/libgit2/src/win32/error.c rename to vendor/libgit2/src/util/win32/error.c index 3a52fb5a..dfd6fa1e 100644 --- a/vendor/libgit2/src/win32/error.c +++ b/vendor/libgit2/src/util/win32/error.c @@ -43,7 +43,7 @@ char *git_win32_get_error_message(DWORD error_code) (LPWSTR)&lpMsgBuf, 0, NULL)) { /* Convert the message to UTF-8. If this fails, we will * return NULL, which is a condition expected by the caller */ - if (git__utf16_to_8_alloc(&utf8_msg, lpMsgBuf) < 0) + if (git_utf8_from_16_alloc(&utf8_msg, lpMsgBuf) < 0) utf8_msg = NULL; LocalFree(lpMsgBuf); diff --git a/vendor/libgit2/src/util/win32/error.h b/vendor/libgit2/src/util/win32/error.h new file mode 100644 index 00000000..fd53b7f9 --- /dev/null +++ b/vendor/libgit2/src/util/win32/error.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_win32_error_h__ +#define INCLUDE_win32_error_h__ + +#include "git2_util.h" + +extern char *git_win32_get_error_message(DWORD error_code); + +#endif diff --git a/vendor/libgit2/src/util/win32/map.c b/vendor/libgit2/src/util/win32/map.c new file mode 100644 index 00000000..52e1363e --- /dev/null +++ b/vendor/libgit2/src/util/win32/map.c @@ -0,0 +1,141 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "git2_util.h" + +#include "map.h" +#include + +#ifndef NO_MMAP + +static DWORD get_page_size(void) +{ + static DWORD page_size; + SYSTEM_INFO sys; + + if (!page_size) { + GetSystemInfo(&sys); + page_size = sys.dwPageSize; + } + + return page_size; +} + +static DWORD get_allocation_granularity(void) +{ + static DWORD granularity; + SYSTEM_INFO sys; + + if (!granularity) { + GetSystemInfo(&sys); + granularity = sys.dwAllocationGranularity; + } + + return granularity; +} + +int git__page_size(size_t *page_size) +{ + *page_size = get_page_size(); + return 0; +} + +int git__mmap_alignment(size_t *page_size) +{ + *page_size = get_allocation_granularity(); + return 0; +} + +int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset) +{ + HANDLE fh = (HANDLE)_get_osfhandle(fd); + DWORD alignment = get_allocation_granularity(); + DWORD fmap_prot = 0; + DWORD view_prot = 0; + DWORD off_low = 0; + DWORD off_hi = 0; + off64_t page_start; + off64_t page_offset; + + GIT_MMAP_VALIDATE(out, len, prot, flags); + + out->data = NULL; + out->len = 0; + out->fmh = NULL; + + if (fh == INVALID_HANDLE_VALUE) { + errno = EBADF; + git_error_set(GIT_ERROR_OS, "failed to mmap. Invalid handle value"); + return -1; + } + + if (prot & GIT_PROT_WRITE) + fmap_prot |= PAGE_READWRITE; + else if (prot & GIT_PROT_READ) + fmap_prot |= PAGE_READONLY; + + if (prot & GIT_PROT_WRITE) + view_prot |= FILE_MAP_WRITE; + if (prot & GIT_PROT_READ) + view_prot |= FILE_MAP_READ; + + page_start = (offset / alignment) * alignment; + page_offset = offset - page_start; + + if (page_offset != 0) { /* offset must be multiple of the allocation granularity */ + errno = EINVAL; + git_error_set(GIT_ERROR_OS, "failed to mmap. Offset must be multiple of allocation granularity"); + return -1; + } + + out->fmh = CreateFileMapping(fh, NULL, fmap_prot, 0, 0, NULL); + if (!out->fmh || out->fmh == INVALID_HANDLE_VALUE) { + git_error_set(GIT_ERROR_OS, "failed to mmap. Invalid handle value"); + out->fmh = NULL; + return -1; + } + + off_low = (DWORD)(page_start); + off_hi = (DWORD)(page_start >> 32); + out->data = MapViewOfFile(out->fmh, view_prot, off_hi, off_low, len); + if (!out->data) { + git_error_set(GIT_ERROR_OS, "failed to mmap. No data written"); + CloseHandle(out->fmh); + out->fmh = NULL; + return -1; + } + out->len = len; + + return 0; +} + +int p_munmap(git_map *map) +{ + int error = 0; + + GIT_ASSERT_ARG(map); + + if (map->data) { + if (!UnmapViewOfFile(map->data)) { + git_error_set(GIT_ERROR_OS, "failed to munmap. Could not unmap view of file"); + error = -1; + } + map->data = NULL; + } + + if (map->fmh) { + if (!CloseHandle(map->fmh)) { + git_error_set(GIT_ERROR_OS, "failed to munmap. Could not close handle"); + error = -1; + } + map->fmh = NULL; + } + + return error; +} + +#endif diff --git a/vendor/libgit2/src/win32/mingw-compat.h b/vendor/libgit2/src/util/win32/mingw-compat.h similarity index 100% rename from vendor/libgit2/src/win32/mingw-compat.h rename to vendor/libgit2/src/util/win32/mingw-compat.h diff --git a/vendor/libgit2/src/win32/msvc-compat.h b/vendor/libgit2/src/util/win32/msvc-compat.h similarity index 100% rename from vendor/libgit2/src/win32/msvc-compat.h rename to vendor/libgit2/src/util/win32/msvc-compat.h diff --git a/vendor/libgit2/src/win32/path_w32.c b/vendor/libgit2/src/util/win32/path_w32.c similarity index 85% rename from vendor/libgit2/src/win32/path_w32.c rename to vendor/libgit2/src/util/win32/path_w32.c index d9fc8292..2714efbb 100644 --- a/vendor/libgit2/src/win32/path_w32.c +++ b/vendor/libgit2/src/util/win32/path_w32.c @@ -153,6 +153,7 @@ int git_win32_path_canonicalize(git_win32_path path) static int git_win32_path_join( git_win32_path dest, + size_t *dest_len, const wchar_t *one, size_t one_len, const wchar_t *two, @@ -176,6 +177,9 @@ static int git_win32_path_join( memcpy(dest + one_len + backslash, two, two_len * sizeof(wchar_t)); dest[one_len + backslash + two_len] = L'\0'; + if (dest_len) + *dest_len = one_len + backslash + two_len; + return 0; } @@ -253,21 +257,92 @@ static void win32_path_iter_dispose(struct win32_path_iter *iter) iter->current_dir = NULL; } +struct executable_suffix { + const wchar_t *suffix; + size_t len; +}; + +static struct executable_suffix suffixes[] = { { NULL, 0 }, { L".exe", 4 }, { L".cmd", 4 } }; + +static bool has_executable_suffix(wchar_t *exe, size_t exe_len) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(suffixes); i++) { + struct executable_suffix *suffix = &suffixes[i]; + + if (!suffix->len) + continue; + + if (exe_len < suffix->len) + continue; + + if (memcmp(&exe[exe_len - suffix->len], suffix->suffix, suffix->len) == 0) + return true; + } + + return false; +} + +static int is_executable(git_win32_path path, size_t path_len, bool suffixed) +{ + size_t i; + + /* + * if the given name has an executable suffix, then try looking for it + * directly. in all cases, append executable extensions + * (".exe", ".cmd"...) + */ + for (i = suffixed ? 0 : 1; i < ARRAY_SIZE(suffixes); i++) { + struct executable_suffix *suffix = &suffixes[i]; + + if (suffix->len) { + if (path_len + suffix->len > MAX_PATH) + continue; + + wcscat(path, suffix->suffix); + } + + if (_waccess(path, 0) == 0) + return true; + + path[path_len] = L'\0'; + } + + return false; +} + int git_win32_path_find_executable(git_win32_path fullpath, wchar_t *exe) { struct win32_path_iter path_iter; const wchar_t *dir; - size_t dir_len, exe_len = wcslen(exe); - bool found = false; + size_t dir_len, exe_len, fullpath_len; + bool suffixed = false, found = false; + + if ((exe_len = wcslen(exe)) > MAX_PATH) + goto done; + + /* see if the given executable has an executable suffix; if so we will + * look for the explicit name directly, as well as with added suffixes. + */ + suffixed = has_executable_suffix(exe, exe_len); + + /* For fully-qualified paths we do not look in PATH */ + if (wcschr(exe, L'\\') != NULL || wcschr(exe, L'/') != NULL) { + if ((found = is_executable(exe, exe_len, suffixed))) + wcscpy(fullpath, exe); + + goto done; + } if (win32_path_iter_init(&path_iter) < 0) return -1; - while (win32_path_iter_next(&dir, &dir_len, &path_iter) != GIT_ITEROVER) { - if (git_win32_path_join(fullpath, dir, dir_len, exe, exe_len) < 0) + while (win32_path_iter_next(&dir, &dir_len, &path_iter) != GIT_ITEROVER && !found) { + if (git_win32_path_join(fullpath, &fullpath_len, dir, dir_len, exe, exe_len) < 0) continue; - if (_waccess(fullpath, 0) == 0) { + if (is_executable(fullpath, fullpath_len, suffixed)) { found = true; break; } @@ -275,6 +350,7 @@ int git_win32_path_find_executable(git_win32_path fullpath, wchar_t *exe) win32_path_iter_dispose(&path_iter); +done: if (found) return 0; @@ -336,13 +412,13 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src) /* See if this is an absolute path (beginning with a drive letter) */ if (git_fs_path_is_absolute(src)) { - if (git__utf8_to_16(dest, GIT_WIN_PATH_MAX, src) < 0) + if (git_utf8_to_16(dest, GIT_WIN_PATH_MAX, src) < 0) goto on_error; } /* File-prefixed NT-style paths beginning with \\?\ */ else if (path__is_nt_namespace(src)) { /* Skip the NT prefix, the destination already contains it */ - if (git__utf8_to_16(dest, GIT_WIN_PATH_MAX, src + PATH__NT_NAMESPACE_LEN) < 0) + if (git_utf8_to_16(dest, GIT_WIN_PATH_MAX, src + PATH__NT_NAMESPACE_LEN) < 0) goto on_error; } /* UNC paths */ @@ -351,7 +427,7 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src) dest += 4; /* Skip the leading "\\" */ - if (git__utf8_to_16(dest, GIT_WIN_PATH_MAX - 2, src + 2) < 0) + if (git_utf8_to_16(dest, GIT_WIN_PATH_MAX - 2, src + 2) < 0) goto on_error; } /* Absolute paths omitting the drive letter */ @@ -365,7 +441,7 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src) } /* Skip the drive letter specification ("C:") */ - if (git__utf8_to_16(dest + 2, GIT_WIN_PATH_MAX - 2, src) < 0) + if (git_utf8_to_16(dest + 2, GIT_WIN_PATH_MAX - 2, src) < 0) goto on_error; } /* Relative paths */ @@ -377,7 +453,7 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src) dest[cwd_len++] = L'\\'; - if (git__utf8_to_16(dest + cwd_len, GIT_WIN_PATH_MAX - cwd_len, src) < 0) + if (git_utf8_to_16(dest + cwd_len, GIT_WIN_PATH_MAX - cwd_len, src) < 0) goto on_error; } @@ -404,7 +480,7 @@ int git_win32_path_relative_from_utf8(git_win32_path out, const char *src) return git_win32_path_from_utf8(out, src); } - if ((len = git__utf8_to_16(dest, GIT_WIN_PATH_MAX, src)) < 0) + if ((len = git_utf8_to_16(dest, GIT_WIN_PATH_MAX, src)) < 0) return -1; for (p = dest; p < (dest + len); p++) { @@ -433,7 +509,7 @@ int git_win32_path_to_utf8(git_win32_utf8_path dest, const wchar_t *src) } } - if ((len = git__utf16_to_8(out, GIT_WIN_PATH_UTF8, src)) < 0) + if ((len = git_utf8_from_16(out, GIT_WIN_PATH_UTF8, src)) < 0) return len; git_fs_path_mkposix(dest); @@ -471,7 +547,7 @@ char *git_win32_path_8dot3_name(const char *path) if (namelen > 12 || (shortname = git__malloc(namelen + 1)) == NULL) return NULL; - if ((len = git__utf16_to_8(shortname, namelen + 1, start)) < 0) + if ((len = git_utf8_from_16(shortname, namelen + 1, start)) < 0) return NULL; return shortname; diff --git a/vendor/libgit2/src/win32/path_w32.h b/vendor/libgit2/src/util/win32/path_w32.h similarity index 99% rename from vendor/libgit2/src/win32/path_w32.h rename to vendor/libgit2/src/util/win32/path_w32.h index 837b11eb..b241d5c8 100644 --- a/vendor/libgit2/src/win32/path_w32.h +++ b/vendor/libgit2/src/util/win32/path_w32.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_win32_path_w32_h__ #define INCLUDE_win32_path_w32_h__ -#include "common.h" +#include "git2_util.h" /** * Create a Win32 path (in UCS-2 format) from a UTF-8 string. If the given diff --git a/vendor/libgit2/src/util/win32/posix.h b/vendor/libgit2/src/util/win32/posix.h new file mode 100644 index 00000000..03fa2ac5 --- /dev/null +++ b/vendor/libgit2/src/util/win32/posix.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_win32_posix_h__ +#define INCLUDE_win32_posix_h__ + +#include "git2_util.h" +#include "../posix.h" +#include "win32-compat.h" +#include "path_w32.h" +#include "utf-conv.h" +#include "dir.h" + +extern unsigned long git_win32__createfile_sharemode; +extern int git_win32__retries; + +typedef SOCKET GIT_SOCKET; + +#define p_lseek(f,n,w) _lseeki64(f, n, w) + +extern int p_fstat(int fd, struct stat *buf); +extern int p_lstat(const char *file_name, struct stat *buf); +extern int p_stat(const char *path, struct stat *buf); + +extern int p_utimes(const char *filename, const struct p_timeval times[2]); +extern int p_futimes(int fd, const struct p_timeval times[2]); + +extern int p_readlink(const char *path, char *buf, size_t bufsiz); +extern int p_symlink(const char *old, const char *new); +extern int p_link(const char *old, const char *new); +extern int p_unlink(const char *path); +extern int p_mkdir(const char *path, mode_t mode); +extern int p_fsync(int fd); +extern char *p_realpath(const char *orig_path, char *buffer); + +extern int p_recv(GIT_SOCKET socket, void *buffer, size_t length, int flags); +extern int p_send(GIT_SOCKET socket, const void *buffer, size_t length, int flags); +extern int p_inet_pton(int af, const char *src, void* dst); + +extern int p_vsnprintf(char *buffer, size_t count, const char *format, va_list argptr); +extern int p_snprintf(char *buffer, size_t count, const char *format, ...) GIT_FORMAT_PRINTF(3, 4); +extern int p_chdir(const char *path); +extern int p_chmod(const char *path, mode_t mode); +extern int p_rmdir(const char *path); +extern int p_access(const char *path, mode_t mode); +extern int p_ftruncate(int fd, off64_t size); + +/* p_lstat is almost but not quite POSIX correct. Specifically, the use of + * ENOTDIR is wrong, in that it does not mean precisely that a non-directory + * entry was encountered. Making it correct is potentially expensive, + * however, so this is a separate version of p_lstat to use when correct + * POSIX ENOTDIR semantics is required. + */ +extern int p_lstat_posixly(const char *filename, struct stat *buf); + +extern struct tm * p_localtime_r(const time_t *timer, struct tm *result); +extern struct tm * p_gmtime_r(const time_t *timer, struct tm *result); + +#endif diff --git a/vendor/libgit2/src/win32/posix_w32.c b/vendor/libgit2/src/util/win32/posix_w32.c similarity index 96% rename from vendor/libgit2/src/win32/posix_w32.c rename to vendor/libgit2/src/util/win32/posix_w32.c index 5f7cd0c2..ace23200 100644 --- a/vendor/libgit2/src/win32/posix_w32.c +++ b/vendor/libgit2/src/util/win32/posix_w32.c @@ -5,7 +5,7 @@ * a Linking Exception. For full terms see the included COPYING file. */ -#include "common.h" +#include "git2_util.h" #include "../posix.h" #include "../futils.h" @@ -649,7 +649,7 @@ int p_getcwd(char *buffer_out, size_t size) git_win32_path_remove_namespace(cwd, wcslen(cwd)); /* Convert the working directory back to UTF-8 */ - if (git__utf16_to_8(buffer_out, size, cwd) < 0) { + if (git_utf8_from_16(buffer_out, size, cwd) < 0) { DWORD code = GetLastError(); if (code == ERROR_INSUFFICIENT_BUFFER) @@ -787,13 +787,19 @@ int p_rmdir(const char *path) char *p_realpath(const char *orig_path, char *buffer) { git_win32_path orig_path_w, buffer_w; + DWORD long_len; if (git_win32_path_from_utf8(orig_path_w, orig_path) < 0) return NULL; - /* Note that if the path provided is a relative path, then the current directory + /* + * POSIX realpath performs two functions: first, it turns relative + * paths into absolute paths. For this, we need GetFullPathName. + * + * Note that if the path provided is a relative path, then the current directory * is used to resolve the path -- which is a concurrency issue because the current - * directory is a process-wide variable. */ + * directory is a process-wide variable. + */ if (!GetFullPathNameW(orig_path_w, GIT_WIN_PATH_UTF16, buffer_w, NULL)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) errno = ENAMETOOLONG; @@ -803,9 +809,26 @@ char *p_realpath(const char *orig_path, char *buffer) return NULL; } - /* The path must exist. */ - if (GetFileAttributesW(buffer_w) == INVALID_FILE_ATTRIBUTES) { - errno = ENOENT; + /* + * Then, the path is canonicalized. eg, on macOS, + * "/TMP" -> "/private/tmp". For this, we need GetLongPathName. + */ + if ((long_len = GetLongPathNameW(buffer_w, buffer_w, GIT_WIN_PATH_UTF16)) == 0) { + DWORD error = GetLastError(); + + if (error == ERROR_FILE_NOT_FOUND || + error == ERROR_PATH_NOT_FOUND) + errno = ENOENT; + else if (error == ERROR_ACCESS_DENIED) + errno = EPERM; + else + errno = EINVAL; + + return NULL; + } + + if (long_len > GIT_WIN_PATH_UTF16) { + errno = ENAMETOOLONG; return NULL; } @@ -821,7 +844,6 @@ char *p_realpath(const char *orig_path, char *buffer) return NULL; git_fs_path_mkposix(buffer); - return buffer; } diff --git a/vendor/libgit2/tests/precompiled.c b/vendor/libgit2/src/util/win32/precompiled.c similarity index 100% rename from vendor/libgit2/tests/precompiled.c rename to vendor/libgit2/src/util/win32/precompiled.c diff --git a/vendor/libgit2/src/util/win32/precompiled.h b/vendor/libgit2/src/util/win32/precompiled.h new file mode 100644 index 00000000..1163c3d6 --- /dev/null +++ b/vendor/libgit2/src/util/win32/precompiled.h @@ -0,0 +1,21 @@ +#include "git2_util.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#ifdef GIT_THREADS + #include "win32/thread.h" +#endif + +#include "git2.h" diff --git a/vendor/libgit2/src/util/win32/process.c b/vendor/libgit2/src/util/win32/process.c new file mode 100644 index 00000000..ad4ae896 --- /dev/null +++ b/vendor/libgit2/src/util/win32/process.c @@ -0,0 +1,522 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include +#include + +#include "git2_util.h" +#include "process.h" +#include "strlist.h" +#include "fs_path.h" + +#ifndef DWORD_MAX +# define DWORD_MAX INT32_MAX +#endif + +#define ENV_MAX 32767 + +struct git_process { + char *app_name; + wchar_t *app_path; + wchar_t *cmdline; + wchar_t *env; + + wchar_t *cwd; + + unsigned int capture_in : 1, + capture_out : 1, + capture_err : 1; + + PROCESS_INFORMATION process_info; + + HANDLE child_in; + HANDLE child_out; + HANDLE child_err; + + git_process_result_status status; +}; + +/* + * Windows processes have a single command-line that is split by the + * invoked application into arguments (instead of an array of + * command-line arguments). This command-line is split by space or + * tab delimiters, unless that whitespace is within a double quote. + * Literal double-quotes themselves can be escaped by a backslash, + * but only when not within double quotes. Literal backslashes can + * be escaped by a backslash. + * + * Effectively, this means that instead of thinking about quoting + * individual strings, think about double quotes as an escaping + * mechanism for whitespace. + * + * In other words (using ` as a string boundary): + * [ `foo`, `bar` ] => `foo bar` + * [ `foo bar` ] => `foo" "bar` + * [ `foo bar`, `foo bar` ] => `foo" "bar foo" "bar` + * [ `foo "bar" foo` ] => `foo" "\"bar\"" "foo` + */ +int git_process__cmdline( + git_str *out, + const char **in, + size_t in_len) +{ + bool quoted = false; + const char *c; + size_t i; + + for (i = 0; i < in_len; i++) { + /* Arguments are delimited by an unquoted space */ + if (i) + git_str_putc(out, ' '); + + for (c = in[i]; *c; c++) { + /* Start or stop quoting spaces within an argument */ + if ((*c == ' ' || *c == '\t') && !quoted) { + git_str_putc(out, '"'); + quoted = true; + } else if (*c != ' ' && *c != '\t' && quoted) { + git_str_putc(out, '"'); + quoted = false; + } + + /* Escape double-quotes and backslashes */ + if (*c == '"' || *c == '\\') + git_str_putc(out, '\\'); + + git_str_putc(out, *c); + } + } + + return git_str_oom(out) ? -1 : 0; +} + +GIT_INLINE(bool) is_delete_env(const char *env) +{ + char *c = strchr(env, '='); + + if (c == NULL) + return false; + + return *(c+1) == '\0'; +} + +static int merge_env(wchar_t **out, const char **in, size_t in_len, bool exclude_env) +{ + git_str merged = GIT_STR_INIT; + wchar_t *in16 = NULL, *env = NULL, *e; + char *e8 = NULL; + size_t e_len; + int ret = 0; + size_t i; + + *out = NULL; + + in16 = git__malloc(ENV_MAX * sizeof(wchar_t)); + GIT_ERROR_CHECK_ALLOC(in16); + + e8 = git__malloc(ENV_MAX); + GIT_ERROR_CHECK_ALLOC(e8); + + for (i = 0; in && i < in_len; i++) { + if (is_delete_env(in[i])) + continue; + + if ((ret = git_utf8_to_16(in16, ENV_MAX, in[i])) < 0) + goto done; + + git_str_put(&merged, (const char *)in16, ret * 2); + git_str_put(&merged, "\0\0", 2); + } + + if (!exclude_env) { + env = GetEnvironmentStringsW(); + + for (e = env; *e; e += (e_len + 1)) { + e_len = wcslen(e); + + if ((ret = git_utf8_from_16(e8, ENV_MAX, e)) < 0) + goto done; + + if (git_strlist_contains_key(in, in_len, e8, '=')) + continue; + + git_str_put(&merged, (const char *)e, e_len * 2); + git_str_put(&merged, "\0\0", 2); + } + } + + git_str_put(&merged, "\0\0", 2); + + *out = (wchar_t *)git_str_detach(&merged); + +done: + if (env) + FreeEnvironmentStringsW(env); + + git_str_dispose(&merged); + git__free(e8); + git__free(in16); + + return ret < 0 ? -1 : 0; +} + +static int process_new( + git_process **out, + const char *appname, + const char *cmdline, + const char **env, + size_t env_len, + git_process_options *opts) +{ + git_process *process; + int error = 0; + + *out = NULL; + + process = git__calloc(1, sizeof(git_process)); + GIT_ERROR_CHECK_ALLOC(process); + + if (appname && (process->app_name = git__strdup(appname)) == NULL) { + error = -1; + goto done; + } + + if (git_utf8_to_16_alloc(&process->cmdline, cmdline) < 0) { + error = -1; + goto done; + } + + if (opts && opts->cwd && + git_utf8_to_16_alloc(&process->cwd, opts->cwd) < 0) { + error = -1; + goto done; + } + + if (env && (error = merge_env(&process->env, env, env_len, opts && opts->exclude_env) < 0)) + goto done; + + if (opts) { + process->capture_in = opts->capture_in; + process->capture_out = opts->capture_out; + process->capture_err = opts->capture_err; + } + +done: + if (error) + git_process_free(process); + else + *out = process; + + return error; +} + +int git_process_new_from_cmdline( + git_process **out, + const char *cmdline, + const char **env, + size_t env_len, + git_process_options *opts) +{ + GIT_ASSERT_ARG(out && cmdline); + + return process_new(out, NULL, cmdline, env, env_len, opts); +} + +int git_process_new( + git_process **out, + const char **args, + size_t args_len, + const char **env, + size_t env_len, + git_process_options *opts) +{ + git_str cmd_path = GIT_STR_INIT, cmdline = GIT_STR_INIT; + int error; + + GIT_ASSERT_ARG(out && args && args_len > 0); + + if ((error = git_process__cmdline(&cmdline, args, args_len)) < 0) + goto done; + + error = process_new(out, args[0], cmdline.ptr, env, env_len, opts); + +done: + git_str_dispose(&cmd_path); + git_str_dispose(&cmdline); + return error; +} + +#define CLOSE_HANDLE(h) do { if ((h) != NULL) CloseHandle(h); } while(0) + +int git_process_start(git_process *process) +{ + STARTUPINFOW startup_info; + SECURITY_ATTRIBUTES security_attrs; + DWORD flags = CREATE_UNICODE_ENVIRONMENT; + HANDLE in[2] = { NULL, NULL }, + out[2] = { NULL, NULL }, + err[2] = { NULL, NULL }; + + if (process->app_name) { + git_str cmd_path = GIT_STR_INIT; + int error; + + if ((error = git_fs_path_find_executable(&cmd_path, process->app_name)) == 0) + error = git_utf8_to_16_alloc(&process->app_path, cmd_path.ptr); + + git_str_dispose(&cmd_path); + + if (error < 0) + goto on_error; + } + + memset(&security_attrs, 0, sizeof(SECURITY_ATTRIBUTES)); + security_attrs.bInheritHandle = TRUE; + + memset(&startup_info, 0, sizeof(STARTUPINFOW)); + startup_info.cb = sizeof(STARTUPINFOW); + startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + startup_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); + + if (process->capture_in) { + if (!CreatePipe(&in[0], &in[1], &security_attrs, 0) || + !SetHandleInformation(in[1], HANDLE_FLAG_INHERIT, 0)) { + git_error_set(GIT_ERROR_OS, "could not create pipe"); + goto on_error; + } + + startup_info.hStdInput = in[0]; + startup_info.dwFlags |= STARTF_USESTDHANDLES; + } + + if (process->capture_out) { + if (!CreatePipe(&out[0], &out[1], &security_attrs, 0) || + !SetHandleInformation(out[0], HANDLE_FLAG_INHERIT, 0)) { + git_error_set(GIT_ERROR_OS, "could not create pipe"); + goto on_error; + } + + startup_info.hStdOutput = out[1]; + startup_info.dwFlags |= STARTF_USESTDHANDLES; + } + + if (process->capture_err) { + if (!CreatePipe(&err[0], &err[1], &security_attrs, 0) || + !SetHandleInformation(err[0], HANDLE_FLAG_INHERIT, 0)) { + git_error_set(GIT_ERROR_OS, "could not create pipe"); + goto on_error; + } + + startup_info.hStdError = err[1]; + startup_info.dwFlags |= STARTF_USESTDHANDLES; + } + + memset(&process->process_info, 0, sizeof(PROCESS_INFORMATION)); + + if (!CreateProcessW(process->app_path, process->cmdline, + NULL, NULL, TRUE, flags, process->env, + process->cwd, + &startup_info, + &process->process_info)) { + git_error_set(GIT_ERROR_OS, "could not create process"); + goto on_error; + } + + CLOSE_HANDLE(in[0]); process->child_in = in[1]; + CLOSE_HANDLE(out[1]); process->child_out = out[0]; + CLOSE_HANDLE(err[1]); process->child_err = err[0]; + + return 0; + +on_error: + CLOSE_HANDLE(in[0]); CLOSE_HANDLE(in[1]); + CLOSE_HANDLE(out[0]); CLOSE_HANDLE(out[1]); + CLOSE_HANDLE(err[0]); CLOSE_HANDLE(err[1]); + return -1; +} + +int git_process_id(p_pid_t *out, git_process *process) +{ + GIT_ASSERT(out && process); + + if (!process->process_info.dwProcessId) { + git_error_set(GIT_ERROR_INVALID, "process not running"); + return -1; + } + + *out = process->process_info.dwProcessId; + return 0; +} + +ssize_t git_process_read(git_process *process, void *buf, size_t count) +{ + DWORD ret; + + if (count > DWORD_MAX) + count = DWORD_MAX; + if (count > SSIZE_MAX) + count = SSIZE_MAX; + + if (!ReadFile(process->child_out, buf, (DWORD)count, &ret, NULL)) { + if (GetLastError() == ERROR_BROKEN_PIPE) + return 0; + + git_error_set(GIT_ERROR_OS, "could not read"); + return -1; + } + + return ret; +} + +ssize_t git_process_write(git_process *process, const void *buf, size_t count) +{ + DWORD ret; + + if (count > DWORD_MAX) + count = DWORD_MAX; + if (count > SSIZE_MAX) + count = SSIZE_MAX; + + if (!WriteFile(process->child_in, buf, (DWORD)count, &ret, NULL)) { + git_error_set(GIT_ERROR_OS, "could not write"); + return -1; + } + + return ret; +} + +int git_process_close_in(git_process *process) +{ + if (!process->capture_in) { + git_error_set(GIT_ERROR_INVALID, "input is not open"); + return -1; + } + + if (process->child_in) { + CloseHandle(process->child_in); + process->child_in = NULL; + } + + return 0; +} + +int git_process_close_out(git_process *process) +{ + if (!process->capture_out) { + git_error_set(GIT_ERROR_INVALID, "output is not open"); + return -1; + } + + if (process->child_out) { + CloseHandle(process->child_out); + process->child_out = NULL; + } + + return 0; +} + +int git_process_close_err(git_process *process) +{ + if (!process->capture_err) { + git_error_set(GIT_ERROR_INVALID, "error is not open"); + return -1; + } + + if (process->child_err) { + CloseHandle(process->child_err); + process->child_err = NULL; + } + + return 0; +} + +int git_process_close(git_process *process) +{ + if (process->child_in) { + CloseHandle(process->child_in); + process->child_in = NULL; + } + + if (process->child_out) { + CloseHandle(process->child_out); + process->child_out = NULL; + } + + if (process->child_err) { + CloseHandle(process->child_err); + process->child_err = NULL; + } + + CloseHandle(process->process_info.hProcess); + process->process_info.hProcess = NULL; + + CloseHandle(process->process_info.hThread); + process->process_info.hThread = NULL; + + return 0; +} + +int git_process_wait(git_process_result *result, git_process *process) +{ + DWORD exitcode; + + if (result) + memset(result, 0, sizeof(git_process_result)); + + if (!process->process_info.dwProcessId) { + git_error_set(GIT_ERROR_INVALID, "process is stopped"); + return -1; + } + + if (WaitForSingleObject(process->process_info.hProcess, INFINITE) == WAIT_FAILED) { + git_error_set(GIT_ERROR_OS, "could not wait for process"); + return -1; + } + + if (!GetExitCodeProcess(process->process_info.hProcess, &exitcode)) { + git_error_set(GIT_ERROR_OS, "could not get process exit code"); + return -1; + } + + result->status = GIT_PROCESS_STATUS_NORMAL; + result->exitcode = exitcode; + + memset(&process->process_info, 0, sizeof(PROCESS_INFORMATION)); + return 0; +} + +int git_process_result_msg(git_str *out, git_process_result *result) +{ + if (result->status == GIT_PROCESS_STATUS_NONE) { + return git_str_puts(out, "process not started"); + } else if (result->status == GIT_PROCESS_STATUS_NORMAL) { + return git_str_printf(out, "process exited with code %d", + result->exitcode); + } else if (result->signal) { + return git_str_printf(out, "process exited on signal %d", + result->signal); + } + + return git_str_puts(out, "unknown error"); +} + +void git_process_free(git_process *process) +{ + if (!process) + return; + + if (process->process_info.hProcess) + git_process_close(process); + + git__free(process->env); + git__free(process->cwd); + git__free(process->cmdline); + git__free(process->app_path); + git__free(process->app_name); + git__free(process); +} diff --git a/vendor/libgit2/src/win32/reparse.h b/vendor/libgit2/src/util/win32/reparse.h similarity index 100% rename from vendor/libgit2/src/win32/reparse.h rename to vendor/libgit2/src/util/win32/reparse.h diff --git a/vendor/libgit2/src/win32/thread.c b/vendor/libgit2/src/util/win32/thread.c similarity index 100% rename from vendor/libgit2/src/win32/thread.c rename to vendor/libgit2/src/util/win32/thread.c diff --git a/vendor/libgit2/src/util/win32/thread.h b/vendor/libgit2/src/util/win32/thread.h new file mode 100644 index 00000000..184762e2 --- /dev/null +++ b/vendor/libgit2/src/util/win32/thread.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_win32_thread_h__ +#define INCLUDE_win32_thread_h__ + +#include "git2_util.h" + +#if defined (_MSC_VER) +# define GIT_RESTRICT __restrict +#else +# define GIT_RESTRICT __restrict__ +#endif + +typedef struct { + HANDLE thread; + void *(*proc)(void *); + void *param; + void *result; +} git_thread; + +typedef CRITICAL_SECTION git_mutex; +typedef HANDLE git_cond; + +typedef struct { void *Ptr; } GIT_SRWLOCK; + +typedef struct { + union { + GIT_SRWLOCK srwl; + CRITICAL_SECTION csec; + } native; +} git_rwlock; + +int git_threads_global_init(void); + +int git_thread_create(git_thread *GIT_RESTRICT, + void *(*) (void *), + void *GIT_RESTRICT); +int git_thread_join(git_thread *, void **); +size_t git_thread_currentid(void); +void git_thread_exit(void *); + +int git_mutex_init(git_mutex *GIT_RESTRICT mutex); +int git_mutex_free(git_mutex *); +int git_mutex_lock(git_mutex *); +int git_mutex_unlock(git_mutex *); + +int git_cond_init(git_cond *); +int git_cond_free(git_cond *); +int git_cond_wait(git_cond *, git_mutex *); +int git_cond_signal(git_cond *); + +int git_rwlock_init(git_rwlock *GIT_RESTRICT lock); +int git_rwlock_rdlock(git_rwlock *); +int git_rwlock_rdunlock(git_rwlock *); +int git_rwlock_wrlock(git_rwlock *); +int git_rwlock_wrunlock(git_rwlock *); +int git_rwlock_free(git_rwlock *); + +#endif diff --git a/vendor/libgit2/src/util/win32/utf-conv.c b/vendor/libgit2/src/util/win32/utf-conv.c new file mode 100644 index 00000000..ad35c0c3 --- /dev/null +++ b/vendor/libgit2/src/util/win32/utf-conv.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "utf-conv.h" + +GIT_INLINE(void) git__set_errno(void) +{ + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) + errno = ENAMETOOLONG; + else + errno = EINVAL; +} + +int git_utf8_to_16(wchar_t *dest, size_t dest_size, const char *src) +{ + /* Length of -1 indicates NULL termination of the input string. */ + return git_utf8_to_16_with_len(dest, dest_size, src, -1); +} + +int git_utf8_to_16_with_len( + wchar_t *dest, + size_t _dest_size, + const char *src, + int src_len) +{ + int dest_size = (int)min(_dest_size, INT_MAX); + int len; + + /* + * Subtract 1 from the result to turn 0 into -1 (an error code) and + * to not count the NULL terminator as part of the string's length. + * MultiByteToWideChar never returns int's minvalue, so underflow + * is not possible. + */ + len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + src, src_len, dest, dest_size) - 1; + + if (len < 0) + git__set_errno(); + + return len; +} + +int git_utf8_from_16(char *dest, size_t dest_size, const wchar_t *src) +{ + /* Length of -1 indicates NULL termination of the input string. */ + return git_utf8_from_16_with_len(dest, dest_size, src, -1); +} + +int git_utf8_from_16_with_len( + char *dest, + size_t _dest_size, + const wchar_t *src, + int src_len) +{ + int dest_size = (int)min(_dest_size, INT_MAX); + int len; + + /* + * Subtract 1 from the result to turn 0 into -1 (an error code) and + * to not count the NULL terminator as part of the string's length. + * WideCharToMultiByte never returns int's minvalue, so underflow + * is not possible. + */ + len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, + src, src_len, dest, dest_size, NULL, NULL) - 1; + + if (len < 0) + git__set_errno(); + + return len; +} + +int git_utf8_to_16_alloc(wchar_t **dest, const char *src) +{ + /* Length of -1 indicates NULL termination of the input string. */ + return git_utf8_to_16_alloc_with_len(dest, src, -1); +} + +int git_utf8_to_16_alloc_with_len(wchar_t **dest, const char *src, int src_len) +{ + int utf16_size; + + *dest = NULL; + + utf16_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + src, src_len, NULL, 0); + + if (!utf16_size) { + git__set_errno(); + return -1; + } + + *dest = git__mallocarray(utf16_size, sizeof(wchar_t)); + GIT_ERROR_CHECK_ALLOC(*dest); + + utf16_size = git_utf8_to_16_with_len(*dest, (size_t)utf16_size, + src, src_len); + + if (utf16_size < 0) { + git__free(*dest); + *dest = NULL; + } + + return utf16_size; +} + +int git_utf8_from_16_alloc(char **dest, const wchar_t *src) +{ + /* Length of -1 indicates NULL termination of the input string. */ + return git_utf8_from_16_alloc_with_len(dest, src, -1); +} + +int git_utf8_from_16_alloc_with_len(char **dest, const wchar_t *src, int src_len) +{ + int utf8_size; + + *dest = NULL; + + utf8_size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, + src, src_len, NULL, 0, NULL, NULL); + + if (!utf8_size) { + git__set_errno(); + return -1; + } + + *dest = git__malloc(utf8_size); + GIT_ERROR_CHECK_ALLOC(*dest); + + utf8_size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, + src, src_len, *dest, utf8_size, NULL, NULL); + + if (utf8_size < 0) { + git__free(*dest); + *dest = NULL; + } + + return utf8_size; +} diff --git a/vendor/libgit2/src/util/win32/utf-conv.h b/vendor/libgit2/src/util/win32/utf-conv.h new file mode 100644 index 00000000..301f5a6d --- /dev/null +++ b/vendor/libgit2/src/util/win32/utf-conv.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_win32_utf_conv_h__ +#define INCLUDE_win32_utf_conv_h__ + +#include "git2_util.h" + +#include + +#ifndef WC_ERR_INVALID_CHARS +# define WC_ERR_INVALID_CHARS 0x80 +#endif + +/** + * Converts a NUL-terminated UTF-8 string to wide characters. This is a + * convenience function for `git_utf8_to_16_with_len`. + * + * @param dest The buffer to receive the wide string. + * @param dest_size The size of the buffer, in characters. + * @param src The UTF-8 string to convert. + * @return The length of the wide string, in characters + * (not counting the NULL terminator), or < 0 for failure + */ +int git_utf8_to_16(wchar_t *dest, size_t dest_size, const char *src); + +/** + * Converts a UTF-8 string to wide characters. + * + * @param dest The buffer to receive the wide string. + * @param dest_size The size of the buffer, in characters. + * @param src The UTF-8 string to convert. + * @param src_len The length of the string to convert. + * @return The length of the wide string, in characters + * (not counting the NULL terminator), or < 0 for failure + */ +int git_utf8_to_16_with_len( + wchar_t *dest, + size_t dest_size, + const char *src, + int src_len); + +/** + * Converts a NUL-terminated wide string to UTF-8. This is a convenience + * function for `git_utf8_from_16_with_len`. + * + * @param dest The buffer to receive the UTF-8 string. + * @param dest_size The size of the buffer, in bytes. + * @param src The wide string to convert. + * @param src_len The length of the string to convert. + * @return The length of the UTF-8 string, in bytes + * (not counting the NULL terminator), or < 0 for failure + */ +int git_utf8_from_16(char *dest, size_t dest_size, const wchar_t *src); + +/** + * Converts a wide string to UTF-8. + * + * @param dest The buffer to receive the UTF-8 string. + * @param dest_size The size of the buffer, in bytes. + * @param src The wide string to convert. + * @param src_len The length of the string to convert. + * @return The length of the UTF-8 string, in bytes + * (not counting the NULL terminator), or < 0 for failure + */ +int git_utf8_from_16_with_len(char *dest, size_t dest_size, const wchar_t *src, int src_len); + +/** + * Converts a UTF-8 string to wide characters. Memory is allocated to hold + * the converted string. The caller is responsible for freeing the string + * with git__free. + * + * @param dest Receives a pointer to the wide string. + * @param src The UTF-8 string to convert. + * @return The length of the wide string, in characters + * (not counting the NULL terminator), or < 0 for failure + */ +int git_utf8_to_16_alloc(wchar_t **dest, const char *src); + +/** + * Converts a UTF-8 string to wide characters. Memory is allocated to hold + * the converted string. The caller is responsible for freeing the string + * with git__free. + * + * @param dest Receives a pointer to the wide string. + * @param src The UTF-8 string to convert. + * @param src_len The length of the string. + * @return The length of the wide string, in characters + * (not counting the NULL terminator), or < 0 for failure + */ +int git_utf8_to_16_alloc_with_len( + wchar_t **dest, + const char *src, + int src_len); + +/** + * Converts a wide string to UTF-8. Memory is allocated to hold the + * converted string. The caller is responsible for freeing the string + * with git__free. + * + * @param dest Receives a pointer to the UTF-8 string. + * @param src The wide string to convert. + * @return The length of the UTF-8 string, in bytes + * (not counting the NULL terminator), or < 0 for failure + */ +int git_utf8_from_16_alloc(char **dest, const wchar_t *src); + +/** + * Converts a wide string to UTF-8. Memory is allocated to hold the + * converted string. The caller is responsible for freeing the string + * with git__free. + * + * @param dest Receives a pointer to the UTF-8 string. + * @param src The wide string to convert. + * @param src_len The length of the wide string. + * @return The length of the UTF-8 string, in bytes + * (not counting the NULL terminator), or < 0 for failure + */ +int git_utf8_from_16_alloc_with_len( + char **dest, + const wchar_t *src, + int src_len); + +#endif diff --git a/vendor/libgit2/src/win32/version.h b/vendor/libgit2/src/util/win32/version.h similarity index 100% rename from vendor/libgit2/src/win32/version.h rename to vendor/libgit2/src/util/win32/version.h diff --git a/vendor/libgit2/src/win32/w32_buffer.c b/vendor/libgit2/src/util/win32/w32_buffer.c similarity index 100% rename from vendor/libgit2/src/win32/w32_buffer.c rename to vendor/libgit2/src/util/win32/w32_buffer.c diff --git a/vendor/libgit2/src/win32/w32_buffer.h b/vendor/libgit2/src/util/win32/w32_buffer.h similarity index 95% rename from vendor/libgit2/src/win32/w32_buffer.h rename to vendor/libgit2/src/util/win32/w32_buffer.h index 4227296d..68ea9603 100644 --- a/vendor/libgit2/src/win32/w32_buffer.h +++ b/vendor/libgit2/src/util/win32/w32_buffer.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_win32_w32_buffer_h__ #define INCLUDE_win32_w32_buffer_h__ -#include "common.h" +#include "git2_util.h" #include "str.h" /** diff --git a/vendor/libgit2/src/win32/w32_common.h b/vendor/libgit2/src/util/win32/w32_common.h similarity index 100% rename from vendor/libgit2/src/win32/w32_common.h rename to vendor/libgit2/src/util/win32/w32_common.h diff --git a/vendor/libgit2/src/win32/w32_leakcheck.c b/vendor/libgit2/src/util/win32/w32_leakcheck.c similarity index 100% rename from vendor/libgit2/src/win32/w32_leakcheck.c rename to vendor/libgit2/src/util/win32/w32_leakcheck.c diff --git a/vendor/libgit2/src/win32/w32_leakcheck.h b/vendor/libgit2/src/util/win32/w32_leakcheck.h similarity index 99% rename from vendor/libgit2/src/win32/w32_leakcheck.h rename to vendor/libgit2/src/util/win32/w32_leakcheck.h index cb45e367..82d86385 100644 --- a/vendor/libgit2/src/win32/w32_leakcheck.h +++ b/vendor/libgit2/src/util/win32/w32_leakcheck.h @@ -8,7 +8,7 @@ #ifndef INCLUDE_win32_leakcheck_h__ #define INCLUDE_win32_leakcheck_h__ -#include "common.h" +#include "git2_util.h" /* Initialize the win32 leak checking system. */ int git_win32_leakcheck_global_init(void); diff --git a/vendor/libgit2/src/win32/w32_util.c b/vendor/libgit2/src/util/win32/w32_util.c similarity index 98% rename from vendor/libgit2/src/win32/w32_util.c rename to vendor/libgit2/src/util/win32/w32_util.c index fe4b75ba..f5b006a1 100644 --- a/vendor/libgit2/src/win32/w32_util.c +++ b/vendor/libgit2/src/util/win32/w32_util.c @@ -115,7 +115,7 @@ int git_win32__file_attribute_to_stat( /* st_size gets the UTF-8 length of the target name, in bytes, * not counting the NULL terminator */ - if ((st->st_size = git__utf16_to_8(NULL, 0, target)) < 0) { + if ((st->st_size = git_utf8_from_16(NULL, 0, target)) < 0) { git_error_set(GIT_ERROR_OS, "could not convert reparse point name for '%ls'", path); return -1; } diff --git a/vendor/libgit2/src/win32/w32_util.h b/vendor/libgit2/src/util/win32/w32_util.h similarity index 99% rename from vendor/libgit2/src/win32/w32_util.h rename to vendor/libgit2/src/util/win32/w32_util.h index 1321d30e..51966372 100644 --- a/vendor/libgit2/src/win32/w32_util.h +++ b/vendor/libgit2/src/util/win32/w32_util.h @@ -8,7 +8,7 @@ #ifndef INCLUDE_win32_w32_util_h__ #define INCLUDE_win32_w32_util_h__ -#include "common.h" +#include "git2_util.h" #include "utf-conv.h" #include "posix.h" diff --git a/vendor/libgit2/src/win32/win32-compat.h b/vendor/libgit2/src/util/win32/win32-compat.h similarity index 100% rename from vendor/libgit2/src/win32/win32-compat.h rename to vendor/libgit2/src/util/win32/win32-compat.h diff --git a/vendor/libgit2/src/zstream.c b/vendor/libgit2/src/util/zstream.c similarity index 100% rename from vendor/libgit2/src/zstream.c rename to vendor/libgit2/src/util/zstream.c diff --git a/vendor/libgit2/src/zstream.h b/vendor/libgit2/src/util/zstream.h similarity index 98% rename from vendor/libgit2/src/zstream.h rename to vendor/libgit2/src/util/zstream.h index 3f8b1c72..d78b1129 100644 --- a/vendor/libgit2/src/zstream.h +++ b/vendor/libgit2/src/util/zstream.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_zstream_h__ #define INCLUDE_zstream_h__ -#include "common.h" +#include "git2_util.h" #include diff --git a/vendor/libgit2/src/win32/error.h b/vendor/libgit2/src/win32/error.h deleted file mode 100644 index 9e81141c..00000000 --- a/vendor/libgit2/src/win32/error.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#ifndef INCLUDE_win32_error_h__ -#define INCLUDE_win32_error_h__ - -#include "common.h" - -extern char *git_win32_get_error_message(DWORD error_code); - -#endif diff --git a/vendor/libgit2/src/win32/findfile.c b/vendor/libgit2/src/win32/findfile.c deleted file mode 100644 index 725a9016..00000000 --- a/vendor/libgit2/src/win32/findfile.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "findfile.h" - -#include "path_w32.h" -#include "utf-conv.h" -#include "fs_path.h" - -#define REG_GITFORWINDOWS_KEY L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1" -#define REG_GITFORWINDOWS_KEY_WOW64 L"SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1" - -static int git_win32__expand_path(git_win32_path dest, const wchar_t *src) -{ - DWORD len = ExpandEnvironmentStringsW(src, dest, GIT_WIN_PATH_UTF16); - - if (!len || len > GIT_WIN_PATH_UTF16) - return -1; - - return 0; -} - -static int win32_path_to_8(git_str *dest, const wchar_t *src) -{ - git_win32_utf8_path utf8_path; - - if (git_win32_path_to_utf8(utf8_path, src) < 0) { - git_error_set(GIT_ERROR_OS, "unable to convert path to UTF-8"); - return -1; - } - - /* Convert backslashes to forward slashes */ - git_fs_path_mkposix(utf8_path); - - return git_str_sets(dest, utf8_path); -} - -static git_win32_path mock_registry; -static bool mock_registry_set; - -extern int git_win32__set_registry_system_dir(const wchar_t *mock_sysdir) -{ - if (!mock_sysdir) { - mock_registry[0] = L'\0'; - mock_registry_set = false; - } else { - size_t len = wcslen(mock_sysdir); - - if (len > GIT_WIN_PATH_MAX) { - git_error_set(GIT_ERROR_INVALID, "mock path too long"); - return -1; - } - - wcscpy(mock_registry, mock_sysdir); - mock_registry_set = true; - } - - return 0; -} - -static int lookup_registry_key( - git_win32_path out, - const HKEY hive, - const wchar_t* key, - const wchar_t *value) -{ - HKEY hkey; - DWORD type, size; - int error = GIT_ENOTFOUND; - - /* - * Registry data may not be NUL terminated, provide room to do - * it ourselves. - */ - size = (DWORD)((sizeof(git_win32_path) - 1) * sizeof(wchar_t)); - - if (RegOpenKeyExW(hive, key, 0, KEY_READ, &hkey) != 0) - return GIT_ENOTFOUND; - - if (RegQueryValueExW(hkey, value, NULL, &type, (LPBYTE)out, &size) == 0 && - type == REG_SZ && - size > 0 && - size < sizeof(git_win32_path)) { - size_t wsize = size / sizeof(wchar_t); - size_t len = wsize - 1; - - if (out[wsize - 1] != L'\0') { - len = wsize; - out[wsize] = L'\0'; - } - - if (out[len - 1] == L'\\') - out[len - 1] = L'\0'; - - if (_waccess(out, F_OK) == 0) - error = 0; - } - - RegCloseKey(hkey); - return error; -} - -static int find_sysdir_in_registry(git_win32_path out) -{ - if (mock_registry_set) { - if (mock_registry[0] == L'\0') - return GIT_ENOTFOUND; - - wcscpy(out, mock_registry); - return 0; - } - - if (lookup_registry_key(out, HKEY_CURRENT_USER, REG_GITFORWINDOWS_KEY, L"InstallLocation") == 0 || - lookup_registry_key(out, HKEY_CURRENT_USER, REG_GITFORWINDOWS_KEY_WOW64, L"InstallLocation") == 0 || - lookup_registry_key(out, HKEY_LOCAL_MACHINE, REG_GITFORWINDOWS_KEY, L"InstallLocation") == 0 || - lookup_registry_key(out, HKEY_LOCAL_MACHINE, REG_GITFORWINDOWS_KEY_WOW64, L"InstallLocation") == 0) - return 0; - - return GIT_ENOTFOUND; -} - -static int find_sysdir_in_path(git_win32_path out) -{ - size_t out_len; - - if (git_win32_path_find_executable(out, L"git.exe") < 0 && - git_win32_path_find_executable(out, L"git.cmd") < 0) - return GIT_ENOTFOUND; - - out_len = wcslen(out); - - /* Trim the file name */ - if (out_len <= CONST_STRLEN(L"git.exe")) - return GIT_ENOTFOUND; - - out_len -= CONST_STRLEN(L"git.exe"); - - if (out_len && out[out_len - 1] == L'\\') - out_len--; - - /* - * Git for Windows usually places the command in a 'bin' or - * 'cmd' directory, trim that. - */ - if (out_len >= CONST_STRLEN(L"\\bin") && - wcsncmp(&out[out_len - CONST_STRLEN(L"\\bin")], L"\\bin", CONST_STRLEN(L"\\bin")) == 0) - out_len -= CONST_STRLEN(L"\\bin"); - else if (out_len >= CONST_STRLEN(L"\\cmd") && - wcsncmp(&out[out_len - CONST_STRLEN(L"\\cmd")], L"\\cmd", CONST_STRLEN(L"\\cmd")) == 0) - out_len -= CONST_STRLEN(L"\\cmd"); - - if (!out_len) - return GIT_ENOTFOUND; - - out[out_len] = L'\0'; - return 0; -} - -static int win32_find_existing_dirs( - git_str* out, - const wchar_t* tmpl[]) -{ - git_win32_path path16; - git_str buf = GIT_STR_INIT; - - git_str_clear(out); - - for (; *tmpl != NULL; tmpl++) { - if (!git_win32__expand_path(path16, *tmpl) && - path16[0] != L'%' && - !_waccess(path16, F_OK)) { - win32_path_to_8(&buf, path16); - - if (buf.size) - git_str_join(out, GIT_PATH_LIST_SEPARATOR, out->ptr, buf.ptr); - } - } - - git_str_dispose(&buf); - - return (git_str_oom(out) ? -1 : 0); -} - -static int append_subdir(git_str *out, git_str *path, const char *subdir) -{ - static const char* architecture_roots[] = { - "", - "mingw64", - "mingw32", - NULL - }; - const char **root; - size_t orig_path_len = path->size; - - for (root = architecture_roots; *root; root++) { - if ((*root[0] && git_str_joinpath(path, path->ptr, *root) < 0) || - git_str_joinpath(path, path->ptr, subdir) < 0) - return -1; - - if (git_fs_path_exists(path->ptr) && - git_str_join(out, GIT_PATH_LIST_SEPARATOR, out->ptr, path->ptr) < 0) - return -1; - - git_str_truncate(path, orig_path_len); - } - - return 0; -} - -int git_win32__find_system_dirs(git_str *out, const char *subdir) -{ - git_win32_path pathdir, regdir; - git_str path8 = GIT_STR_INIT; - bool has_pathdir, has_regdir; - int error; - - has_pathdir = (find_sysdir_in_path(pathdir) == 0); - has_regdir = (find_sysdir_in_registry(regdir) == 0); - - if (!has_pathdir && !has_regdir) - return 0; - - /* - * Usually the git in the path is the same git in the registry, - * in this case there's no need to duplicate the paths. - */ - if (has_pathdir && has_regdir && wcscmp(pathdir, regdir) == 0) - has_regdir = false; - - if (has_pathdir) { - if ((error = win32_path_to_8(&path8, pathdir)) < 0 || - (error = append_subdir(out, &path8, subdir)) < 0) - goto done; - } - - if (has_regdir) { - if ((error = win32_path_to_8(&path8, regdir)) < 0 || - (error = append_subdir(out, &path8, subdir)) < 0) - goto done; - } - -done: - git_str_dispose(&path8); - return error; -} - -int git_win32__find_global_dirs(git_str *out) -{ - static const wchar_t *global_tmpls[4] = { - L"%HOME%\\", - L"%HOMEDRIVE%%HOMEPATH%\\", - L"%USERPROFILE%\\", - NULL, - }; - - return win32_find_existing_dirs(out, global_tmpls); -} - -int git_win32__find_xdg_dirs(git_str *out) -{ - static const wchar_t *global_tmpls[7] = { - L"%XDG_CONFIG_HOME%\\git", - L"%APPDATA%\\git", - L"%LOCALAPPDATA%\\git", - L"%HOME%\\.config\\git", - L"%HOMEDRIVE%%HOMEPATH%\\.config\\git", - L"%USERPROFILE%\\.config\\git", - NULL, - }; - - return win32_find_existing_dirs(out, global_tmpls); -} - -int git_win32__find_programdata_dirs(git_str *out) -{ - static const wchar_t *programdata_tmpls[2] = { - L"%PROGRAMDATA%\\Git", - NULL, - }; - - return win32_find_existing_dirs(out, programdata_tmpls); -} diff --git a/vendor/libgit2/src/win32/findfile.h b/vendor/libgit2/src/win32/findfile.h deleted file mode 100644 index 61fb7dba..00000000 --- a/vendor/libgit2/src/win32/findfile.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#ifndef INCLUDE_win32_findfile_h__ -#define INCLUDE_win32_findfile_h__ - -#include "common.h" - -/** Sets the mock registry root for Git for Windows for testing. */ -extern int git_win32__set_registry_system_dir(const wchar_t *mock_sysdir); - -extern int git_win32__find_system_dirs(git_str *out, const char *subpath); -extern int git_win32__find_global_dirs(git_str *out); -extern int git_win32__find_xdg_dirs(git_str *out); -extern int git_win32__find_programdata_dirs(git_str *out); - -#endif - diff --git a/vendor/libgit2/src/win32/map.c b/vendor/libgit2/src/win32/map.c deleted file mode 100644 index 2aabc9b1..00000000 --- a/vendor/libgit2/src/win32/map.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "common.h" - -#include "map.h" -#include - -#ifndef NO_MMAP - -static DWORD get_page_size(void) -{ - static DWORD page_size; - SYSTEM_INFO sys; - - if (!page_size) { - GetSystemInfo(&sys); - page_size = sys.dwPageSize; - } - - return page_size; -} - -static DWORD get_allocation_granularity(void) -{ - static DWORD granularity; - SYSTEM_INFO sys; - - if (!granularity) { - GetSystemInfo(&sys); - granularity = sys.dwAllocationGranularity; - } - - return granularity; -} - -int git__page_size(size_t *page_size) -{ - *page_size = get_page_size(); - return 0; -} - -int git__mmap_alignment(size_t *page_size) -{ - *page_size = get_allocation_granularity(); - return 0; -} - -int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset) -{ - HANDLE fh = (HANDLE)_get_osfhandle(fd); - DWORD alignment = get_allocation_granularity(); - DWORD fmap_prot = 0; - DWORD view_prot = 0; - DWORD off_low = 0; - DWORD off_hi = 0; - off64_t page_start; - off64_t page_offset; - - GIT_MMAP_VALIDATE(out, len, prot, flags); - - out->data = NULL; - out->len = 0; - out->fmh = NULL; - - if (fh == INVALID_HANDLE_VALUE) { - errno = EBADF; - git_error_set(GIT_ERROR_OS, "failed to mmap. Invalid handle value"); - return -1; - } - - if (prot & GIT_PROT_WRITE) - fmap_prot |= PAGE_READWRITE; - else if (prot & GIT_PROT_READ) - fmap_prot |= PAGE_READONLY; - - if (prot & GIT_PROT_WRITE) - view_prot |= FILE_MAP_WRITE; - if (prot & GIT_PROT_READ) - view_prot |= FILE_MAP_READ; - - page_start = (offset / alignment) * alignment; - page_offset = offset - page_start; - - if (page_offset != 0) { /* offset must be multiple of the allocation granularity */ - errno = EINVAL; - git_error_set(GIT_ERROR_OS, "failed to mmap. Offset must be multiple of allocation granularity"); - return -1; - } - - out->fmh = CreateFileMapping(fh, NULL, fmap_prot, 0, 0, NULL); - if (!out->fmh || out->fmh == INVALID_HANDLE_VALUE) { - git_error_set(GIT_ERROR_OS, "failed to mmap. Invalid handle value"); - out->fmh = NULL; - return -1; - } - - off_low = (DWORD)(page_start); - off_hi = (DWORD)(page_start >> 32); - out->data = MapViewOfFile(out->fmh, view_prot, off_hi, off_low, len); - if (!out->data) { - git_error_set(GIT_ERROR_OS, "failed to mmap. No data written"); - CloseHandle(out->fmh); - out->fmh = NULL; - return -1; - } - out->len = len; - - return 0; -} - -int p_munmap(git_map *map) -{ - int error = 0; - - GIT_ASSERT_ARG(map); - - if (map->data) { - if (!UnmapViewOfFile(map->data)) { - git_error_set(GIT_ERROR_OS, "failed to munmap. Could not unmap view of file"); - error = -1; - } - map->data = NULL; - } - - if (map->fmh) { - if (!CloseHandle(map->fmh)) { - git_error_set(GIT_ERROR_OS, "failed to munmap. Could not close handle"); - error = -1; - } - map->fmh = NULL; - } - - return error; -} - -#endif diff --git a/vendor/libgit2/src/win32/posix.h b/vendor/libgit2/src/win32/posix.h deleted file mode 100644 index 578347f1..00000000 --- a/vendor/libgit2/src/win32/posix.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_win32_posix_h__ -#define INCLUDE_win32_posix_h__ - -#include "common.h" -#include "../posix.h" -#include "win32-compat.h" -#include "path_w32.h" -#include "utf-conv.h" -#include "dir.h" - -extern unsigned long git_win32__createfile_sharemode; -extern int git_win32__retries; - -typedef SOCKET GIT_SOCKET; - -#define p_lseek(f,n,w) _lseeki64(f, n, w) - -extern int p_fstat(int fd, struct stat *buf); -extern int p_lstat(const char *file_name, struct stat *buf); -extern int p_stat(const char *path, struct stat *buf); - -extern int p_utimes(const char *filename, const struct p_timeval times[2]); -extern int p_futimes(int fd, const struct p_timeval times[2]); - -extern int p_readlink(const char *path, char *buf, size_t bufsiz); -extern int p_symlink(const char *old, const char *new); -extern int p_link(const char *old, const char *new); -extern int p_unlink(const char *path); -extern int p_mkdir(const char *path, mode_t mode); -extern int p_fsync(int fd); -extern char *p_realpath(const char *orig_path, char *buffer); - -extern int p_recv(GIT_SOCKET socket, void *buffer, size_t length, int flags); -extern int p_send(GIT_SOCKET socket, const void *buffer, size_t length, int flags); -extern int p_inet_pton(int af, const char *src, void* dst); - -extern int p_vsnprintf(char *buffer, size_t count, const char *format, va_list argptr); -extern int p_snprintf(char *buffer, size_t count, const char *format, ...) GIT_FORMAT_PRINTF(3, 4); -extern int p_chdir(const char *path); -extern int p_chmod(const char *path, mode_t mode); -extern int p_rmdir(const char *path); -extern int p_access(const char *path, mode_t mode); -extern int p_ftruncate(int fd, off64_t size); - -/* p_lstat is almost but not quite POSIX correct. Specifically, the use of - * ENOTDIR is wrong, in that it does not mean precisely that a non-directory - * entry was encountered. Making it correct is potentially expensive, - * however, so this is a separate version of p_lstat to use when correct - * POSIX ENOTDIR semantics is required. - */ -extern int p_lstat_posixly(const char *filename, struct stat *buf); - -extern struct tm * p_localtime_r(const time_t *timer, struct tm *result); -extern struct tm * p_gmtime_r(const time_t *timer, struct tm *result); - -#endif diff --git a/vendor/libgit2/src/win32/precompiled.h b/vendor/libgit2/src/win32/precompiled.h deleted file mode 100644 index 806b1698..00000000 --- a/vendor/libgit2/src/win32/precompiled.h +++ /dev/null @@ -1,21 +0,0 @@ -#include "common.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#ifdef GIT_THREADS - #include "win32/thread.h" -#endif - -#include "git2.h" diff --git a/vendor/libgit2/src/win32/thread.h b/vendor/libgit2/src/win32/thread.h deleted file mode 100644 index 8305036b..00000000 --- a/vendor/libgit2/src/win32/thread.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#ifndef INCLUDE_win32_thread_h__ -#define INCLUDE_win32_thread_h__ - -#include "common.h" - -#if defined (_MSC_VER) -# define GIT_RESTRICT __restrict -#else -# define GIT_RESTRICT __restrict__ -#endif - -typedef struct { - HANDLE thread; - void *(*proc)(void *); - void *param; - void *result; -} git_thread; - -typedef CRITICAL_SECTION git_mutex; -typedef HANDLE git_cond; - -typedef struct { void *Ptr; } GIT_SRWLOCK; - -typedef struct { - union { - GIT_SRWLOCK srwl; - CRITICAL_SECTION csec; - } native; -} git_rwlock; - -int git_threads_global_init(void); - -int git_thread_create(git_thread *GIT_RESTRICT, - void *(*) (void *), - void *GIT_RESTRICT); -int git_thread_join(git_thread *, void **); -size_t git_thread_currentid(void); -void git_thread_exit(void *); - -int git_mutex_init(git_mutex *GIT_RESTRICT mutex); -int git_mutex_free(git_mutex *); -int git_mutex_lock(git_mutex *); -int git_mutex_unlock(git_mutex *); - -int git_cond_init(git_cond *); -int git_cond_free(git_cond *); -int git_cond_wait(git_cond *, git_mutex *); -int git_cond_signal(git_cond *); - -int git_rwlock_init(git_rwlock *GIT_RESTRICT lock); -int git_rwlock_rdlock(git_rwlock *); -int git_rwlock_rdunlock(git_rwlock *); -int git_rwlock_wrlock(git_rwlock *); -int git_rwlock_wrunlock(git_rwlock *); -int git_rwlock_free(git_rwlock *); - -#endif diff --git a/vendor/libgit2/src/win32/utf-conv.c b/vendor/libgit2/src/win32/utf-conv.c deleted file mode 100644 index 4bde3023..00000000 --- a/vendor/libgit2/src/win32/utf-conv.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "utf-conv.h" - -GIT_INLINE(void) git__set_errno(void) -{ - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) - errno = ENAMETOOLONG; - else - errno = EINVAL; -} - -/** - * Converts a UTF-8 string to wide characters. - * - * @param dest The buffer to receive the wide string. - * @param dest_size The size of the buffer, in characters. - * @param src The UTF-8 string to convert. - * @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure - */ -int git__utf8_to_16(wchar_t *dest, size_t dest_size, const char *src) -{ - int len; - - /* Length of -1 indicates NULL termination of the input string. Subtract 1 from the result to - * turn 0 into -1 (an error code) and to not count the NULL terminator as part of the string's - * length. MultiByteToWideChar never returns int's minvalue, so underflow is not possible */ - if ((len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, dest, (int)dest_size) - 1) < 0) - git__set_errno(); - - return len; -} - -/** - * Converts a wide string to UTF-8. - * - * @param dest The buffer to receive the UTF-8 string. - * @param dest_size The size of the buffer, in bytes. - * @param src The wide string to convert. - * @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure - */ -int git__utf16_to_8(char *dest, size_t dest_size, const wchar_t *src) -{ - int len; - - /* Length of -1 indicates NULL termination of the input string. Subtract 1 from the result to - * turn 0 into -1 (an error code) and to not count the NULL terminator as part of the string's - * length. WideCharToMultiByte never returns int's minvalue, so underflow is not possible */ - if ((len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, dest, (int)dest_size, NULL, NULL) - 1) < 0) - git__set_errno(); - - return len; -} - -/** - * Converts a UTF-8 string to wide characters. - * Memory is allocated to hold the converted string. - * The caller is responsible for freeing the string with git__free. - * - * @param dest Receives a pointer to the wide string. - * @param src The UTF-8 string to convert. - * @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure - */ -int git__utf8_to_16_alloc(wchar_t **dest, const char *src) -{ - int utf16_size; - - *dest = NULL; - - /* Length of -1 indicates NULL termination of the input string */ - utf16_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, NULL, 0); - - if (!utf16_size) { - git__set_errno(); - return -1; - } - - if (!(*dest = git__mallocarray(utf16_size, sizeof(wchar_t)))) { - errno = ENOMEM; - return -1; - } - - utf16_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, *dest, utf16_size); - - if (!utf16_size) { - git__set_errno(); - - git__free(*dest); - *dest = NULL; - } - - /* Subtract 1 from the result to turn 0 into -1 (an error code) and to not count the NULL - * terminator as part of the string's length. MultiByteToWideChar never returns int's minvalue, - * so underflow is not possible */ - return utf16_size - 1; -} - -/** - * Converts a wide string to UTF-8. - * Memory is allocated to hold the converted string. - * The caller is responsible for freeing the string with git__free. - * - * @param dest Receives a pointer to the UTF-8 string. - * @param src The wide string to convert. - * @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure - */ -int git__utf16_to_8_alloc(char **dest, const wchar_t *src) -{ - int utf8_size; - - *dest = NULL; - - /* Length of -1 indicates NULL termination of the input string */ - utf8_size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, NULL, 0, NULL, NULL); - - if (!utf8_size) { - git__set_errno(); - return -1; - } - - *dest = git__malloc(utf8_size); - - if (!*dest) { - errno = ENOMEM; - return -1; - } - - utf8_size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, *dest, utf8_size, NULL, NULL); - - if (!utf8_size) { - git__set_errno(); - - git__free(*dest); - *dest = NULL; - } - - /* Subtract 1 from the result to turn 0 into -1 (an error code) and to not count the NULL - * terminator as part of the string's length. MultiByteToWideChar never returns int's minvalue, - * so underflow is not possible */ - return utf8_size - 1; -} diff --git a/vendor/libgit2/src/win32/utf-conv.h b/vendor/libgit2/src/win32/utf-conv.h deleted file mode 100644 index 6090a4b3..00000000 --- a/vendor/libgit2/src/win32/utf-conv.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_win32_utf_conv_h__ -#define INCLUDE_win32_utf_conv_h__ - -#include "common.h" - -#include - -#ifndef WC_ERR_INVALID_CHARS -# define WC_ERR_INVALID_CHARS 0x80 -#endif - -/** - * Converts a UTF-8 string to wide characters. - * - * @param dest The buffer to receive the wide string. - * @param dest_size The size of the buffer, in characters. - * @param src The UTF-8 string to convert. - * @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure - */ -int git__utf8_to_16(wchar_t *dest, size_t dest_size, const char *src); - -/** - * Converts a wide string to UTF-8. - * - * @param dest The buffer to receive the UTF-8 string. - * @param dest_size The size of the buffer, in bytes. - * @param src The wide string to convert. - * @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure - */ -int git__utf16_to_8(char *dest, size_t dest_size, const wchar_t *src); - -/** - * Converts a UTF-8 string to wide characters. - * Memory is allocated to hold the converted string. - * The caller is responsible for freeing the string with git__free. - * - * @param dest Receives a pointer to the wide string. - * @param src The UTF-8 string to convert. - * @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure - */ -int git__utf8_to_16_alloc(wchar_t **dest, const char *src); - -/** - * Converts a wide string to UTF-8. - * Memory is allocated to hold the converted string. - * The caller is responsible for freeing the string with git__free. - * - * @param dest Receives a pointer to the UTF-8 string. - * @param src The wide string to convert. - * @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure - */ -int git__utf16_to_8_alloc(char **dest, const wchar_t *src); - -#endif diff --git a/vendor/libgit2/src/worktree.c b/vendor/libgit2/src/worktree.c deleted file mode 100644 index 2ac2274f..00000000 --- a/vendor/libgit2/src/worktree.c +++ /dev/null @@ -1,652 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "worktree.h" - -#include "buf.h" -#include "repository.h" -#include "path.h" - -#include "git2/branch.h" -#include "git2/commit.h" -#include "git2/worktree.h" - -static bool is_worktree_dir(const char *dir) -{ - git_str buf = GIT_STR_INIT; - int error; - - if (git_str_sets(&buf, dir) < 0) - return -1; - - error = git_fs_path_contains_file(&buf, "commondir") - && git_fs_path_contains_file(&buf, "gitdir") - && git_fs_path_contains_file(&buf, "HEAD"); - - git_str_dispose(&buf); - return error; -} - -int git_worktree_list(git_strarray *wts, git_repository *repo) -{ - git_vector worktrees = GIT_VECTOR_INIT; - git_str path = GIT_STR_INIT; - char *worktree; - size_t i, len; - int error; - - GIT_ASSERT_ARG(wts); - GIT_ASSERT_ARG(repo); - - wts->count = 0; - wts->strings = NULL; - - if ((error = git_str_joinpath(&path, repo->commondir, "worktrees/")) < 0) - goto exit; - if (!git_fs_path_exists(path.ptr) || git_fs_path_is_empty_dir(path.ptr)) - goto exit; - if ((error = git_fs_path_dirload(&worktrees, path.ptr, path.size, 0x0)) < 0) - goto exit; - - len = path.size; - - git_vector_foreach(&worktrees, i, worktree) { - git_str_truncate(&path, len); - git_str_puts(&path, worktree); - - if (!is_worktree_dir(path.ptr)) { - git_vector_remove(&worktrees, i); - git__free(worktree); - } - } - - wts->strings = (char **)git_vector_detach(&wts->count, NULL, &worktrees); - -exit: - git_str_dispose(&path); - - return error; -} - -char *git_worktree__read_link(const char *base, const char *file) -{ - git_str path = GIT_STR_INIT, buf = GIT_STR_INIT; - - GIT_ASSERT_ARG_WITH_RETVAL(base, NULL); - GIT_ASSERT_ARG_WITH_RETVAL(file, NULL); - - if (git_str_joinpath(&path, base, file) < 0) - goto err; - if (git_futils_readbuffer(&buf, path.ptr) < 0) - goto err; - git_str_dispose(&path); - - git_str_rtrim(&buf); - - if (!git_fs_path_is_relative(buf.ptr)) - return git_str_detach(&buf); - - if (git_str_sets(&path, base) < 0) - goto err; - if (git_fs_path_apply_relative(&path, buf.ptr) < 0) - goto err; - git_str_dispose(&buf); - - return git_str_detach(&path); - -err: - git_str_dispose(&buf); - git_str_dispose(&path); - - return NULL; -} - -static int write_wtfile(const char *base, const char *file, const git_str *buf) -{ - git_str path = GIT_STR_INIT; - int err; - - GIT_ASSERT_ARG(base); - GIT_ASSERT_ARG(file); - GIT_ASSERT_ARG(buf); - - if ((err = git_str_joinpath(&path, base, file)) < 0) - goto out; - - if ((err = git_futils_writebuffer(buf, path.ptr, O_CREAT|O_EXCL|O_WRONLY, 0644)) < 0) - goto out; - -out: - git_str_dispose(&path); - - return err; -} - -static int open_worktree_dir(git_worktree **out, const char *parent, const char *dir, const char *name) -{ - git_str gitdir = GIT_STR_INIT; - git_worktree *wt = NULL; - int error = 0; - - if (!is_worktree_dir(dir)) { - error = -1; - goto out; - } - - if ((error = git_path_validate_length(NULL, dir)) < 0) - goto out; - - if ((wt = git__calloc(1, sizeof(*wt))) == NULL) { - error = -1; - goto out; - } - - if ((wt->name = git__strdup(name)) == NULL || - (wt->commondir_path = git_worktree__read_link(dir, "commondir")) == NULL || - (wt->gitlink_path = git_worktree__read_link(dir, "gitdir")) == NULL || - (parent && (wt->parent_path = git__strdup(parent)) == NULL) || - (wt->worktree_path = git_fs_path_dirname(wt->gitlink_path)) == NULL) { - error = -1; - goto out; - } - - if ((error = git_fs_path_prettify_dir(&gitdir, dir, NULL)) < 0) - goto out; - wt->gitdir_path = git_str_detach(&gitdir); - - if ((error = git_worktree_is_locked(NULL, wt)) < 0) - goto out; - wt->locked = !!error; - error = 0; - - *out = wt; - -out: - if (error) - git_worktree_free(wt); - git_str_dispose(&gitdir); - - return error; -} - -int git_worktree_lookup(git_worktree **out, git_repository *repo, const char *name) -{ - git_str path = GIT_STR_INIT; - git_worktree *wt = NULL; - int error; - - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(name); - - *out = NULL; - - if ((error = git_str_join3(&path, '/', repo->commondir, "worktrees", name)) < 0) - goto out; - - if ((error = (open_worktree_dir(out, git_repository_workdir(repo), path.ptr, name))) < 0) - goto out; - -out: - git_str_dispose(&path); - - if (error) - git_worktree_free(wt); - - return error; -} - -int git_worktree_open_from_repository(git_worktree **out, git_repository *repo) -{ - git_str parent = GIT_STR_INIT; - const char *gitdir, *commondir; - char *name = NULL; - int error = 0; - - if (!git_repository_is_worktree(repo)) { - git_error_set(GIT_ERROR_WORKTREE, "cannot open worktree of a non-worktree repo"); - error = -1; - goto out; - } - - gitdir = git_repository_path(repo); - commondir = git_repository_commondir(repo); - - if ((error = git_fs_path_prettify_dir(&parent, "..", commondir)) < 0) - goto out; - - /* The name is defined by the last component in '.git/worktree/%s' */ - name = git_fs_path_basename(gitdir); - - if ((error = open_worktree_dir(out, parent.ptr, gitdir, name)) < 0) - goto out; - -out: - git__free(name); - git_str_dispose(&parent); - - return error; -} - -void git_worktree_free(git_worktree *wt) -{ - if (!wt) - return; - - git__free(wt->commondir_path); - git__free(wt->worktree_path); - git__free(wt->gitlink_path); - git__free(wt->gitdir_path); - git__free(wt->parent_path); - git__free(wt->name); - git__free(wt); -} - -int git_worktree_validate(const git_worktree *wt) -{ - GIT_ASSERT_ARG(wt); - - if (!is_worktree_dir(wt->gitdir_path)) { - git_error_set(GIT_ERROR_WORKTREE, - "worktree gitdir ('%s') is not valid", - wt->gitlink_path); - return GIT_ERROR; - } - - if (wt->parent_path && !git_fs_path_exists(wt->parent_path)) { - git_error_set(GIT_ERROR_WORKTREE, - "worktree parent directory ('%s') does not exist ", - wt->parent_path); - return GIT_ERROR; - } - - if (!git_fs_path_exists(wt->commondir_path)) { - git_error_set(GIT_ERROR_WORKTREE, - "worktree common directory ('%s') does not exist ", - wt->commondir_path); - return GIT_ERROR; - } - - if (!git_fs_path_exists(wt->worktree_path)) { - git_error_set(GIT_ERROR_WORKTREE, - "worktree directory '%s' does not exist", - wt->worktree_path); - return GIT_ERROR; - } - - return 0; -} - -int git_worktree_add_options_init(git_worktree_add_options *opts, - unsigned int version) -{ - GIT_INIT_STRUCTURE_FROM_TEMPLATE(opts, version, - git_worktree_add_options, GIT_WORKTREE_ADD_OPTIONS_INIT); - return 0; -} - -#ifndef GIT_DEPRECATE_HARD -int git_worktree_add_init_options(git_worktree_add_options *opts, - unsigned int version) -{ - return git_worktree_add_options_init(opts, version); -} -#endif - -int git_worktree_add(git_worktree **out, git_repository *repo, - const char *name, const char *worktree, - const git_worktree_add_options *opts) -{ - git_str gitdir = GIT_STR_INIT, wddir = GIT_STR_INIT, buf = GIT_STR_INIT; - git_reference *ref = NULL, *head = NULL; - git_commit *commit = NULL; - git_repository *wt = NULL; - git_checkout_options coopts; - git_worktree_add_options wtopts = GIT_WORKTREE_ADD_OPTIONS_INIT; - int err; - - GIT_ERROR_CHECK_VERSION( - opts, GIT_WORKTREE_ADD_OPTIONS_VERSION, "git_worktree_add_options"); - - GIT_ASSERT_ARG(out); - GIT_ASSERT_ARG(repo); - GIT_ASSERT_ARG(name); - GIT_ASSERT_ARG(worktree); - - *out = NULL; - - if (opts) - memcpy(&wtopts, opts, sizeof(wtopts)); - - memcpy(&coopts, &wtopts.checkout_options, sizeof(coopts)); - - if (wtopts.ref) { - if (!git_reference_is_branch(wtopts.ref)) { - git_error_set(GIT_ERROR_WORKTREE, "reference is not a branch"); - err = -1; - goto out; - } - - if (git_branch_is_checked_out(wtopts.ref)) { - git_error_set(GIT_ERROR_WORKTREE, "reference is already checked out"); - err = -1; - goto out; - } - } - - /* Create gitdir directory ".git/worktrees/" */ - if ((err = git_str_joinpath(&gitdir, repo->commondir, "worktrees")) < 0) - goto out; - if (!git_fs_path_exists(gitdir.ptr)) - if ((err = git_futils_mkdir(gitdir.ptr, 0755, GIT_MKDIR_EXCL)) < 0) - goto out; - if ((err = git_str_joinpath(&gitdir, gitdir.ptr, name)) < 0) - goto out; - if ((err = git_futils_mkdir(gitdir.ptr, 0755, GIT_MKDIR_EXCL)) < 0) - goto out; - if ((err = git_fs_path_prettify_dir(&gitdir, gitdir.ptr, NULL)) < 0) - goto out; - - /* Create worktree work dir */ - if ((err = git_futils_mkdir(worktree, 0755, GIT_MKDIR_EXCL)) < 0) - goto out; - if ((err = git_fs_path_prettify_dir(&wddir, worktree, NULL)) < 0) - goto out; - - if (wtopts.lock) { - int fd; - - if ((err = git_str_joinpath(&buf, gitdir.ptr, "locked")) < 0) - goto out; - - if ((fd = p_creat(buf.ptr, 0644)) < 0) { - err = fd; - goto out; - } - - p_close(fd); - git_str_clear(&buf); - } - - /* Create worktree .git file */ - if ((err = git_str_printf(&buf, "gitdir: %s\n", gitdir.ptr)) < 0) - goto out; - if ((err = write_wtfile(wddir.ptr, ".git", &buf)) < 0) - goto out; - - /* Create gitdir files */ - if ((err = git_fs_path_prettify_dir(&buf, repo->commondir, NULL) < 0) - || (err = git_str_putc(&buf, '\n')) < 0 - || (err = write_wtfile(gitdir.ptr, "commondir", &buf)) < 0) - goto out; - if ((err = git_str_joinpath(&buf, wddir.ptr, ".git")) < 0 - || (err = git_str_putc(&buf, '\n')) < 0 - || (err = write_wtfile(gitdir.ptr, "gitdir", &buf)) < 0) - goto out; - - /* Set up worktree reference */ - if (wtopts.ref) { - if ((err = git_reference_dup(&ref, wtopts.ref)) < 0) - goto out; - } else { - if ((err = git_repository_head(&head, repo)) < 0) - goto out; - if ((err = git_commit_lookup(&commit, repo, &head->target.oid)) < 0) - goto out; - if ((err = git_branch_create(&ref, repo, name, commit, false)) < 0) - goto out; - } - - /* Set worktree's HEAD */ - if ((err = git_repository_create_head(gitdir.ptr, git_reference_name(ref))) < 0) - goto out; - if ((err = git_repository_open(&wt, wddir.ptr)) < 0) - goto out; - - /* Checkout worktree's HEAD */ - if ((err = git_checkout_head(wt, &coopts)) < 0) - goto out; - - /* Load result */ - if ((err = git_worktree_lookup(out, repo, name)) < 0) - goto out; - -out: - git_str_dispose(&gitdir); - git_str_dispose(&wddir); - git_str_dispose(&buf); - git_reference_free(ref); - git_reference_free(head); - git_commit_free(commit); - git_repository_free(wt); - - return err; -} - -int git_worktree_lock(git_worktree *wt, const char *reason) -{ - git_str buf = GIT_STR_INIT, path = GIT_STR_INIT; - int error; - - GIT_ASSERT_ARG(wt); - - if ((error = git_worktree_is_locked(NULL, wt)) < 0) - goto out; - if (error) { - error = GIT_ELOCKED; - goto out; - } - - if ((error = git_str_joinpath(&path, wt->gitdir_path, "locked")) < 0) - goto out; - - if (reason) - git_str_attach_notowned(&buf, reason, strlen(reason)); - - if ((error = git_futils_writebuffer(&buf, path.ptr, O_CREAT|O_EXCL|O_WRONLY, 0644)) < 0) - goto out; - - wt->locked = 1; - -out: - git_str_dispose(&path); - - return error; -} - -int git_worktree_unlock(git_worktree *wt) -{ - git_str path = GIT_STR_INIT; - int error; - - GIT_ASSERT_ARG(wt); - - if ((error = git_worktree_is_locked(NULL, wt)) < 0) - return error; - if (!error) - return 1; - - if (git_str_joinpath(&path, wt->gitdir_path, "locked") < 0) - return -1; - - if (p_unlink(path.ptr) != 0) { - git_str_dispose(&path); - return -1; - } - - wt->locked = 0; - - git_str_dispose(&path); - - return 0; -} - -static int git_worktree__is_locked(git_str *reason, const git_worktree *wt) -{ - git_str path = GIT_STR_INIT; - int error, locked; - - GIT_ASSERT_ARG(wt); - - if (reason) - git_str_clear(reason); - - if ((error = git_str_joinpath(&path, wt->gitdir_path, "locked")) < 0) - goto out; - locked = git_fs_path_exists(path.ptr); - if (locked && reason && - (error = git_futils_readbuffer(reason, path.ptr)) < 0) - goto out; - - error = locked; -out: - git_str_dispose(&path); - - return error; -} - -int git_worktree_is_locked(git_buf *reason, const git_worktree *wt) -{ - git_str str = GIT_STR_INIT; - int error = 0; - - if (reason && (error = git_buf_tostr(&str, reason)) < 0) - return error; - - error = git_worktree__is_locked(reason ? &str : NULL, wt); - - if (error >= 0 && reason) { - if (git_buf_fromstr(reason, &str) < 0) - error = -1; - } - - git_str_dispose(&str); - return error; -} - -const char *git_worktree_name(const git_worktree *wt) -{ - GIT_ASSERT_ARG_WITH_RETVAL(wt, NULL); - return wt->name; -} - -const char *git_worktree_path(const git_worktree *wt) -{ - GIT_ASSERT_ARG_WITH_RETVAL(wt, NULL); - return wt->worktree_path; -} - -int git_worktree_prune_options_init( - git_worktree_prune_options *opts, - unsigned int version) -{ - GIT_INIT_STRUCTURE_FROM_TEMPLATE(opts, version, - git_worktree_prune_options, GIT_WORKTREE_PRUNE_OPTIONS_INIT); - return 0; -} - -#ifndef GIT_DEPRECATE_HARD -int git_worktree_prune_init_options(git_worktree_prune_options *opts, - unsigned int version) -{ - return git_worktree_prune_options_init(opts, version); -} -#endif - -int git_worktree_is_prunable(git_worktree *wt, - git_worktree_prune_options *opts) -{ - git_worktree_prune_options popts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; - - GIT_ERROR_CHECK_VERSION( - opts, GIT_WORKTREE_PRUNE_OPTIONS_VERSION, - "git_worktree_prune_options"); - - if (opts) - memcpy(&popts, opts, sizeof(popts)); - - if ((popts.flags & GIT_WORKTREE_PRUNE_LOCKED) == 0) { - git_str reason = GIT_STR_INIT; - int error; - - if ((error = git_worktree__is_locked(&reason, wt)) < 0) - return error; - - if (error) { - if (!reason.size) - git_str_attach_notowned(&reason, "no reason given", 15); - git_error_set(GIT_ERROR_WORKTREE, "not pruning locked working tree: '%s'", reason.ptr); - git_str_dispose(&reason); - return 0; - } - } - - if ((popts.flags & GIT_WORKTREE_PRUNE_VALID) == 0 && - git_worktree_validate(wt) == 0) { - git_error_set(GIT_ERROR_WORKTREE, "not pruning valid working tree"); - return 0; - } - - return 1; -} - -int git_worktree_prune(git_worktree *wt, - git_worktree_prune_options *opts) -{ - git_worktree_prune_options popts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; - git_str path = GIT_STR_INIT; - char *wtpath; - int err; - - GIT_ERROR_CHECK_VERSION( - opts, GIT_WORKTREE_PRUNE_OPTIONS_VERSION, - "git_worktree_prune_options"); - - if (opts) - memcpy(&popts, opts, sizeof(popts)); - - if (!git_worktree_is_prunable(wt, &popts)) { - err = -1; - goto out; - } - - /* Delete gitdir in parent repository */ - if ((err = git_str_join3(&path, '/', wt->commondir_path, "worktrees", wt->name)) < 0) - goto out; - if (!git_fs_path_exists(path.ptr)) - { - git_error_set(GIT_ERROR_WORKTREE, "worktree gitdir '%s' does not exist", path.ptr); - err = -1; - goto out; - } - if ((err = git_futils_rmdir_r(path.ptr, NULL, GIT_RMDIR_REMOVE_FILES)) < 0) - goto out; - - /* Skip deletion of the actual working tree if it does - * not exist or deletion was not requested */ - if ((popts.flags & GIT_WORKTREE_PRUNE_WORKING_TREE) == 0 || - !git_fs_path_exists(wt->gitlink_path)) - { - goto out; - } - - if ((wtpath = git_fs_path_dirname(wt->gitlink_path)) == NULL) - goto out; - git_str_attach(&path, wtpath, 0); - if (!git_fs_path_exists(path.ptr)) - { - git_error_set(GIT_ERROR_WORKTREE, "working tree '%s' does not exist", path.ptr); - err = -1; - goto out; - } - if ((err = git_futils_rmdir_r(path.ptr, NULL, GIT_RMDIR_REMOVE_FILES)) < 0) - goto out; - -out: - git_str_dispose(&path); - - return err; -} diff --git a/vendor/libgit2/src/xdiff/xmacros.h b/vendor/libgit2/src/xdiff/xmacros.h deleted file mode 100644 index 2809a28c..00000000 --- a/vendor/libgit2/src/xdiff/xmacros.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * LibXDiff by Davide Libenzi ( File Differential Library ) - * Copyright (C) 2003 Davide Libenzi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - * - * Davide Libenzi - * - */ - -#if !defined(XMACROS_H) -#define XMACROS_H - - - - -#define XDL_MIN(a, b) ((a) < (b) ? (a): (b)) -#define XDL_MAX(a, b) ((a) > (b) ? (a): (b)) -#define XDL_ABS(v) ((v) >= 0 ? (v): -(v)) -#define XDL_ISDIGIT(c) ((c) >= '0' && (c) <= '9') -#define XDL_ISSPACE(c) (isspace((unsigned char)(c))) -#define XDL_ADDBITS(v,b) ((v) + ((v) >> (b))) -#define XDL_MASKBITS(b) ((1UL << (b)) - 1) -#define XDL_HASHLONG(v,b) (XDL_ADDBITS((unsigned long)(v), b) & XDL_MASKBITS(b)) -#define XDL_PTRFREE(p) do { if (p) { xdl_free(p); (p) = NULL; } } while (0) -#define XDL_LE32_PUT(p, v) \ -do { \ - unsigned char *__p = (unsigned char *) (p); \ - *__p++ = (unsigned char) (v); \ - *__p++ = (unsigned char) ((v) >> 8); \ - *__p++ = (unsigned char) ((v) >> 16); \ - *__p = (unsigned char) ((v) >> 24); \ -} while (0) -#define XDL_LE32_GET(p, v) \ -do { \ - unsigned char const *__p = (unsigned char const *) (p); \ - (v) = (unsigned long) __p[0] | ((unsigned long) __p[1]) << 8 | \ - ((unsigned long) __p[2]) << 16 | ((unsigned long) __p[3]) << 24; \ -} while (0) - - -#endif /* #if !defined(XMACROS_H) */ diff --git a/vendor/libgit2/tests/CMakeLists.txt b/vendor/libgit2/tests/CMakeLists.txt index f293c158..df100e98 100644 --- a/vendor/libgit2/tests/CMakeLists.txt +++ b/vendor/libgit2/tests/CMakeLists.txt @@ -1,96 +1,6 @@ -set(Python_ADDITIONAL_VERSIONS 3 2.7) -find_package(PythonInterp) +# The main libgit2 tests tree: this CMakeLists.txt includes the +# subprojects that make up core libgit2 support. -if(NOT PYTHONINTERP_FOUND) - message(FATAL_ERROR "Could not find a python interpreter, which is needed to build the tests. " - "Make sure python is available, or pass -DBUILD_TESTS=OFF to skip building the tests") -ENDIF() - -set(CLAR_FIXTURES "${CMAKE_CURRENT_SOURCE_DIR}/resources/") -set(CLAR_PATH "${CMAKE_CURRENT_SOURCE_DIR}") -add_definitions(-DCLAR_FIXTURE_PATH=\"${CLAR_FIXTURES}\") -add_definitions(-DCLAR_TMPDIR=\"libgit2_tests\") -add_definitions(-DCLAR_WIN32_LONGPATHS) -add_definitions(-D_FILE_OFFSET_BITS=64) - -# Ensure that we do not use deprecated functions internally -add_definitions(-DGIT_DEPRECATE_HARD) - -set(TEST_INCLUDES "${CLAR_PATH}" "${CMAKE_CURRENT_BINARY_DIR}") -file(GLOB_RECURSE SRC_TEST ${CLAR_PATH}/*/*.c ${CLAR_PATH}/*/*.h) -set(SRC_CLAR "main.c" "clar_libgit2.c" "clar_libgit2_trace.c" "clar_libgit2_timer.c" "clar.c") - -if(MSVC_IDE) - list(APPEND SRC_CLAR "precompiled.c") -endif() - -add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/clar.suite ${CMAKE_CURRENT_BINARY_DIR}/clar_suite.h - COMMAND ${PYTHON_EXECUTABLE} generate.py -o "${CMAKE_CURRENT_BINARY_DIR}" -f -xonline -xstress -xperf . - DEPENDS ${SRC_TEST} - WORKING_DIRECTORY ${CLAR_PATH} -) - -set_source_files_properties( - ${CLAR_PATH}/clar.c - PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/clar.suite) - -add_executable(libgit2_tests ${SRC_CLAR} ${SRC_TEST} ${LIBGIT2_OBJECTS}) - -set_target_properties(libgit2_tests PROPERTIES C_STANDARD 90) -set_target_properties(libgit2_tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) - -target_include_directories(libgit2_tests PRIVATE ${TEST_INCLUDES} ${LIBGIT2_INCLUDES} ${LIBGIT2_DEPENDENCY_INCLUDES}) -target_include_directories(libgit2_tests SYSTEM PRIVATE ${LIBGIT2_SYSTEM_INCLUDES}) -target_link_libraries(libgit2_tests ${LIBGIT2_SYSTEM_LIBS}) - -ide_split_sources(libgit2_tests) - -# -# Old versions of gcc require us to declare our test functions; don't do -# this on newer compilers to avoid unnecessary recompilation. -# -if(CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0) - target_compile_options(libgit2_tests PRIVATE -include "clar_suite.h") -endif() - -if(MSVC_IDE) - # Precompiled headers - set_target_properties(libgit2_tests PROPERTIES COMPILE_FLAGS "/Yuprecompiled.h /FIprecompiled.h") - set_source_files_properties("precompiled.c" COMPILE_FLAGS "/Ycprecompiled.h") -endif() - -function(ADD_CLAR_TEST name) - if(NOT USE_LEAK_CHECKER STREQUAL "OFF") - add_test(${name} "${PROJECT_SOURCE_DIR}/script/${USE_LEAK_CHECKER}.sh" "${PROJECT_BINARY_DIR}/libgit2_tests" ${ARGN}) - else() - add_test(${name} "${PROJECT_BINARY_DIR}/libgit2_tests" ${ARGN}) - endif() -endfunction(ADD_CLAR_TEST) - -add_clar_test(offline -v -xonline) -add_clar_test(invasive -v -score::ftruncate -sfilter::stream::bigfile -sodb::largefiles -siterator::workdir::filesystem_gunk -srepo::init -srepo::init::at_filesystem_root) -add_clar_test(online -v -sonline -xonline::customcert) -add_clar_test(online_customcert -v -sonline::customcert) -add_clar_test(gitdaemon -v -sonline::push) -add_clar_test(ssh -v -sonline::push -sonline::clone::ssh_cert -sonline::clone::ssh_with_paths -sonline::clone::path_whitespace_ssh) -add_clar_test(proxy -v -sonline::clone::proxy) -add_clar_test(auth_clone -v -sonline::clone::cred) -add_clar_test(auth_clone_and_push -v -sonline::clone::push -sonline::push) - -# -# Header file validation project: ensure that we do not publish any sloppy -# definitions in our headers and that a consumer can include -# even when they have aggressive C90 warnings enabled. -# - -add_executable(headertest headertest.c) -set_target_properties(headertest PROPERTIES C_STANDARD 90) -set_target_properties(headertest PROPERTIES C_EXTENSIONS OFF) -target_include_directories(headertest PRIVATE ${LIBGIT2_INCLUDES}) - -if (MSVC) - target_compile_options(headertest PUBLIC /W4 /WX) -else() - target_compile_options(headertest PUBLIC -Wall -Wextra -pedantic -Werror) -endif() +add_subdirectory(headertest) +add_subdirectory(libgit2) +add_subdirectory(util) diff --git a/vendor/libgit2/tests/README.md b/vendor/libgit2/tests/README.md index 4369a8f3..460e045e 100644 --- a/vendor/libgit2/tests/README.md +++ b/vendor/libgit2/tests/README.md @@ -1,33 +1,58 @@ -Writing Clar tests for libgit2 -============================== - -For information on the Clar testing framework and a detailed introduction -please visit: - -https://github.com/vmg/clar - - -* Write your modules and tests. Use good, meaningful names. - -* Make sure you actually build the tests by setting: - - cmake -DBUILD_TESTS=ON build/ - -* Test: - - ./build/libgit2_tests - -* Make sure everything is fine. - -* Send your pull request. That's it. - - -Memory leak checks ------------------- +# libgit2 tests + +These are the unit and integration tests for the libgit2 projects. + +* `benchmarks` + These are benchmark tests that excercise the CLI. +* `clar` + This is [clar](https://github.com/clar-test/clar) the common test framework. +* `headertest` + This is a simple project that ensures that our public headers are + compatible with extremely strict compilation options. +* `libgit2` + These tests exercise the core git functionality in libgit2 itself. +* `resources` + These are the resources for the tests, including files and git + repositories. +* `util` + These are tests of the common utility library. + +## Writing tests for libgit2 + +libgit2 uses the [clar test framework](http://github.com/clar-test/clar), a +C testing framework. + +The best resources for learning clar are [clar itself](https://github.com/clar-test/clar) +and the existing tests within libgit2. In general: + +* If you place a `.c` file into a test directory, it is eligible to contain +test cases. +* The function name for your test is important; test function names begin + with `test_`, followed by the folder path (underscore separated), two + underscores as a delimiter, then the test name. For example, a file + `merge/analysis.c` may contain a test `uptodate`: + + ``` + void test_merge_analysis__uptodate(void) + { + ... + } + ``` + +* You can run an individual test by passing `-s` to the test runner. Tests + are referred to by their function names; for example, the function + `test_merge_analysis__uptodate` is referred to as `merge::analysis::uptodate`. + To run only that function you can use the `-s` option on the test runner: + + ``` + libgit2_tests -smerge::analysis::uptodate + ``` + +## Memory leak checking These are automatically run as part of CI, but if you want to check locally: -#### Linux +### Linux Uses [`valgrind`](http://www.valgrind.org/): @@ -38,7 +63,7 @@ $ valgrind --leak-check=full --show-reachable=yes --num-callers=50 --suppression ./libgit2_tests ``` -#### macOS +### macOS Uses [`leaks`](https://developer.apple.com/library/archive/documentation/Performance/Conceptual/ManagingMemory/Articles/FindingLeaks.html), which requires XCode installed: @@ -46,3 +71,13 @@ Uses [`leaks`](https://developer.apple.com/library/archive/documentation/Perform $ MallocStackLogging=1 MallocScribble=1 MallocLogFile=/dev/null CLAR_AT_EXIT="leaks -quiet \$PPID" \ ./libgit2_tests ``` + +### Windows + +Build with the `WIN32_LEAKCHECK` option: + +```console +$ cmake -DBUILD_TESTS=ON -DWIN32_LEAKCHECK=ON .. +$ cmake --build . +$ ./libgit2_tests +``` diff --git a/vendor/libgit2/tests/apply/index.c b/vendor/libgit2/tests/apply/index.c deleted file mode 100644 index 9c9094cc..00000000 --- a/vendor/libgit2/tests/apply/index.c +++ /dev/null @@ -1,321 +0,0 @@ -#include "clar_libgit2.h" -#include "apply_helpers.h" - -static git_repository *repo; - -#define TEST_REPO_PATH "merge-recursive" - -void test_apply_index__initialize(void) -{ - git_oid oid; - git_commit *commit; - - repo = cl_git_sandbox_init(TEST_REPO_PATH); - - git_oid_fromstr(&oid, "539bd011c4822c560c1d17cab095006b7a10f707"); - cl_git_pass(git_commit_lookup(&commit, repo, &oid)); - cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL)); - git_commit_free(commit); -} - -void test_apply_index__cleanup(void) -{ - cl_git_sandbox_cleanup(); -} - -void test_apply_index__generate_diff(void) -{ - git_oid a_oid, b_oid; - git_commit *a_commit, *b_commit; - git_tree *a_tree, *b_tree; - git_diff *diff; - git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; - - struct merge_index_entry index_expected[] = { - { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, - }; - size_t index_expected_cnt = sizeof(index_expected) / - sizeof(struct merge_index_entry); - - git_oid_fromstr(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707"); - git_oid_fromstr(&b_oid, "7c7bf85e978f1d18c0566f702d2cb7766b9c8d4f"); - cl_git_pass(git_commit_lookup(&a_commit, repo, &a_oid)); - cl_git_pass(git_commit_lookup(&b_commit, repo, &b_oid)); - - cl_git_pass(git_commit_tree(&a_tree, a_commit)); - cl_git_pass(git_commit_tree(&b_tree, b_commit)); - - cl_git_pass(git_diff_tree_to_tree(&diff, repo, a_tree, b_tree, &diff_opts)); - cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); - - validate_apply_index(repo, index_expected, index_expected_cnt); - validate_workdir_unchanged(repo); - - git_diff_free(diff); - git_tree_free(a_tree); - git_tree_free(b_tree); - git_commit_free(a_commit); - git_commit_free(b_commit); -} - -void test_apply_index__parsed_diff(void) -{ - git_diff *diff; - - struct merge_index_entry index_expected[] = { - { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, - }; - size_t index_expected_cnt = sizeof(index_expected) / - sizeof(struct merge_index_entry); - - cl_git_pass(git_diff_from_buffer(&diff, - DIFF_MODIFY_TWO_FILES, strlen(DIFF_MODIFY_TWO_FILES))); - cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); - - validate_apply_index(repo, index_expected, index_expected_cnt); - validate_workdir_unchanged(repo); - - git_diff_free(diff); -} - -void test_apply_index__removes_file(void) -{ - git_diff *diff; - - struct merge_index_entry index_expected[] = { - { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, - }; - size_t index_expected_cnt = sizeof(index_expected) / - sizeof(struct merge_index_entry); - - cl_git_pass(git_diff_from_buffer(&diff, DIFF_DELETE_FILE, - strlen(DIFF_DELETE_FILE))); - cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); - - validate_apply_index(repo, index_expected, index_expected_cnt); - validate_workdir_unchanged(repo); - - git_diff_free(diff); -} - -void test_apply_index__adds_file(void) -{ - git_diff *diff; - - struct merge_index_entry index_expected[] = { - { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "6370543fcfedb3e6516ec53b06158f3687dc1447", 0, "newfile.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, - }; - size_t index_expected_cnt = sizeof(index_expected) / - sizeof(struct merge_index_entry); - - cl_git_pass(git_diff_from_buffer(&diff, - DIFF_ADD_FILE, strlen(DIFF_ADD_FILE))); - cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); - - validate_apply_index(repo, index_expected, index_expected_cnt); - validate_workdir_unchanged(repo); - - git_diff_free(diff); -} - -void test_apply_index__modified_workdir_with_unmodified_index_is_ok(void) -{ - git_diff *diff; - - const char *diff_file = DIFF_MODIFY_TWO_FILES; - - struct merge_index_entry index_expected[] = { - { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, - }; - size_t index_expected_cnt = sizeof(index_expected) / - sizeof(struct merge_index_entry); - - struct merge_index_entry workdir_expected[] = { - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "f75ba05f340c51065cbea2e1fdbfe5fe13144c97", 0, "veal.txt" } - }; - size_t workdir_expected_cnt = sizeof(workdir_expected) / - sizeof(struct merge_index_entry); - - /* mutate the workdir and leave the index matching HEAD */ - cl_git_rmfile("merge-recursive/asparagus.txt"); - cl_git_rewritefile("merge-recursive/veal.txt", "Hello, world.\n"); - - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); - cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); - - validate_apply_index(repo, index_expected, index_expected_cnt); - validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); - - git_diff_free(diff); -} - -void test_apply_index__application_failure_leaves_index_unmodified(void) -{ - git_diff *diff; - git_index *index; - - const char *diff_file = DIFF_MODIFY_TWO_FILES; - - struct merge_index_entry index_expected[] = { - { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - }; - size_t index_expected_cnt = sizeof(index_expected) / - sizeof(struct merge_index_entry); - - /* mutate the index */ - cl_git_pass(git_repository_index(&index, repo)); - cl_git_pass(git_index_remove(index, "veal.txt", 0)); - cl_git_pass(git_index_write(index)); - git_index_free(index); - - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); - cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); - - validate_apply_index(repo, index_expected, index_expected_cnt); - - git_diff_free(diff); -} - -void test_apply_index__keeps_nonconflicting_changes(void) -{ - git_diff *diff; - git_index *index; - git_index_entry idx_entry; - - const char *diff_file = DIFF_MODIFY_TWO_FILES; - - struct merge_index_entry index_expected[] = { - { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, - { 0100644, "898d12687fb35be271c27c795a6b32c8b51da79e", 0, "beef.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, - }; - size_t index_expected_cnt = sizeof(index_expected) / - sizeof(struct merge_index_entry); - - /* mutate the index */ - cl_git_pass(git_repository_index(&index, repo)); - - memset(&idx_entry, 0, sizeof(git_index_entry)); - idx_entry.mode = 0100644; - idx_entry.path = "beef.txt"; - cl_git_pass(git_oid_fromstr(&idx_entry.id, "898d12687fb35be271c27c795a6b32c8b51da79e")); - cl_git_pass(git_index_add(index, &idx_entry)); - - cl_git_pass(git_index_remove(index, "bouilli.txt", 0)); - cl_git_pass(git_index_write(index)); - git_index_free(index); - - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); - cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); - - validate_apply_index(repo, index_expected, index_expected_cnt); - validate_workdir_unchanged(repo); - - git_diff_free(diff); -} - -void test_apply_index__can_apply_nonconflicting_file_changes(void) -{ - git_diff *diff; - git_index *index; - git_index_entry idx_entry; - - const char *diff_file = DIFF_MODIFY_TWO_FILES; - - struct merge_index_entry index_expected[] = { - { 0100644, "4f2d1645dee99ced096877911de540c65ade2ef8", 0, "asparagus.txt" }, - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, - }; - size_t index_expected_cnt = sizeof(index_expected) / - sizeof(struct merge_index_entry); - - /* - * Replace the index entry with a version that is different than - * HEAD but such that the patch still applies cleanly. This item - * has a new line appended. - */ - - cl_git_pass(git_repository_index(&index, repo)); - - memset(&idx_entry, 0, sizeof(git_index_entry)); - idx_entry.mode = 0100644; - idx_entry.path = "asparagus.txt"; - cl_git_pass(git_oid_fromstr(&idx_entry.id, "06d3fefb8726ab1099acc76e02dfb85e034b2538")); - cl_git_pass(git_index_add(index, &idx_entry)); - - cl_git_pass(git_index_write(index)); - git_index_free(index); - - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); - cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); - - validate_apply_index(repo, index_expected, index_expected_cnt); - validate_workdir_unchanged(repo); - - git_diff_free(diff); -} - -void test_apply_index__change_mode(void) -{ - git_diff *diff; - - const char *diff_file = DIFF_EXECUTABLE_FILE; - - struct merge_index_entry index_expected[] = { - { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, - { 0100755, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, - }; - size_t index_expected_cnt = sizeof(index_expected) / - sizeof(struct merge_index_entry); - - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); - cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); - - validate_apply_index(repo, index_expected, index_expected_cnt); - validate_workdir_unchanged(repo); - - git_diff_free(diff); -} diff --git a/vendor/libgit2/tests/apply/tree.c b/vendor/libgit2/tests/apply/tree.c deleted file mode 100644 index 5154f134..00000000 --- a/vendor/libgit2/tests/apply/tree.c +++ /dev/null @@ -1,94 +0,0 @@ -#include "clar_libgit2.h" -#include "apply_helpers.h" -#include "../merge/merge_helpers.h" - -static git_repository *repo; - -#define TEST_REPO_PATH "merge-recursive" - - -void test_apply_tree__initialize(void) -{ - repo = cl_git_sandbox_init(TEST_REPO_PATH); -} - -void test_apply_tree__cleanup(void) -{ - cl_git_sandbox_cleanup(); -} - -void test_apply_tree__one(void) -{ - git_oid a_oid, b_oid; - git_commit *a_commit, *b_commit; - git_tree *a_tree, *b_tree; - git_diff *diff; - git_index *index = NULL; - git_diff_options opts = GIT_DIFF_OPTIONS_INIT; - - struct merge_index_entry expected[] = { - { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, - }; - - git_oid_fromstr(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707"); - git_oid_fromstr(&b_oid, "7c7bf85e978f1d18c0566f702d2cb7766b9c8d4f"); - - cl_git_pass(git_commit_lookup(&a_commit, repo, &a_oid)); - cl_git_pass(git_commit_lookup(&b_commit, repo, &b_oid)); - - cl_git_pass(git_commit_tree(&a_tree, a_commit)); - cl_git_pass(git_commit_tree(&b_tree, b_commit)); - - cl_git_pass(git_diff_tree_to_tree(&diff, repo, a_tree, b_tree, &opts)); - - cl_git_pass(git_apply_to_tree(&index, repo, a_tree, diff, NULL)); - merge_test_index(index, expected, 6); - - git_index_free(index); - git_diff_free(diff); - git_tree_free(a_tree); - git_tree_free(b_tree); - git_commit_free(a_commit); - git_commit_free(b_commit); -} - -void test_apply_tree__adds_file(void) -{ - git_oid a_oid; - git_commit *a_commit; - git_tree *a_tree; - git_diff *diff; - git_index *index = NULL; - - struct merge_index_entry expected[] = { - { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "6370543fcfedb3e6516ec53b06158f3687dc1447", 0, "newfile.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, - }; - - git_oid_fromstr(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707"); - - cl_git_pass(git_commit_lookup(&a_commit, repo, &a_oid)); - - cl_git_pass(git_commit_tree(&a_tree, a_commit)); - - cl_git_pass(git_diff_from_buffer(&diff, - DIFF_ADD_FILE, strlen(DIFF_ADD_FILE))); - - cl_git_pass(git_apply_to_tree(&index, repo, a_tree, diff, NULL)); - merge_test_index(index, expected, 7); - - git_index_free(index); - git_diff_free(diff); - git_tree_free(a_tree); - git_commit_free(a_commit); -} diff --git a/vendor/libgit2/tests/apply/workdir.c b/vendor/libgit2/tests/apply/workdir.c deleted file mode 100644 index d0d9c1ab..00000000 --- a/vendor/libgit2/tests/apply/workdir.c +++ /dev/null @@ -1,358 +0,0 @@ -#include "clar_libgit2.h" -#include "apply_helpers.h" - -static git_repository *repo; - -#define TEST_REPO_PATH "merge-recursive" - -void test_apply_workdir__initialize(void) -{ - git_oid oid; - git_commit *commit; - - repo = cl_git_sandbox_init(TEST_REPO_PATH); - - git_oid_fromstr(&oid, "539bd011c4822c560c1d17cab095006b7a10f707"); - cl_git_pass(git_commit_lookup(&commit, repo, &oid)); - cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL)); - git_commit_free(commit); -} - -void test_apply_workdir__cleanup(void) -{ - cl_git_sandbox_cleanup(); -} - -void test_apply_workdir__generated_diff(void) -{ - git_oid a_oid, b_oid; - git_commit *a_commit, *b_commit; - git_tree *a_tree, *b_tree; - git_diff *diff; - git_diff_options opts = GIT_DIFF_OPTIONS_INIT; - - struct merge_index_entry workdir_expected[] = { - { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, - }; - size_t workdir_expected_cnt = sizeof(workdir_expected) / - sizeof(struct merge_index_entry); - - git_oid_fromstr(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707"); - git_oid_fromstr(&b_oid, "7c7bf85e978f1d18c0566f702d2cb7766b9c8d4f"); cl_git_pass(git_commit_lookup(&a_commit, repo, &a_oid)); - cl_git_pass(git_commit_lookup(&b_commit, repo, &b_oid)); - - cl_git_pass(git_commit_tree(&a_tree, a_commit)); - cl_git_pass(git_commit_tree(&b_tree, b_commit)); - - cl_git_pass(git_diff_tree_to_tree(&diff, repo, a_tree, b_tree, &opts)); - cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); - - validate_index_unchanged(repo); - validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); - - git_diff_free(diff); - git_tree_free(a_tree); - git_tree_free(b_tree); - git_commit_free(a_commit); - git_commit_free(b_commit); -} - -void test_apply_workdir__parsed_diff(void) -{ - git_diff *diff; - - struct merge_index_entry workdir_expected[] = { - { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, - }; - size_t workdir_expected_cnt = sizeof(workdir_expected) / - sizeof(struct merge_index_entry); - - cl_git_pass(git_diff_from_buffer(&diff, - DIFF_MODIFY_TWO_FILES, strlen(DIFF_MODIFY_TWO_FILES))); - cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); - - validate_index_unchanged(repo); - validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); - - git_diff_free(diff); -} - -void test_apply_workdir__removes_file(void) -{ - git_diff *diff; - - struct merge_index_entry workdir_expected[] = { - { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, - }; - size_t workdir_expected_cnt = sizeof(workdir_expected) / - sizeof(struct merge_index_entry); - - cl_git_pass(git_diff_from_buffer(&diff, DIFF_DELETE_FILE, - strlen(DIFF_DELETE_FILE))); - cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); - - validate_index_unchanged(repo); - validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); - - git_diff_free(diff); -} - -void test_apply_workdir__adds_file(void) -{ - git_diff *diff; - - struct merge_index_entry workdir_expected[] = { - { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "6370543fcfedb3e6516ec53b06158f3687dc1447", 0, "newfile.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, - }; - size_t workdir_expected_cnt = sizeof(workdir_expected) / - sizeof(struct merge_index_entry); - - cl_git_pass(git_diff_from_buffer(&diff, - DIFF_ADD_FILE, strlen(DIFF_ADD_FILE))); - cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); - - validate_index_unchanged(repo); - validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); - - git_diff_free(diff); -} - -void test_apply_workdir__modified_index_with_unmodified_workdir_is_ok(void) -{ - git_index *index; - git_index_entry idx_entry = {{0}}; - git_diff *diff; - - const char *diff_file = DIFF_MODIFY_TWO_FILES; - - struct merge_index_entry index_expected[] = { - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "veal.txt" } - }; - size_t index_expected_cnt = sizeof(index_expected) / - sizeof(struct merge_index_entry); - - struct merge_index_entry workdir_expected[] = { - { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, - }; - size_t workdir_expected_cnt = sizeof(workdir_expected) / - sizeof(struct merge_index_entry); - - /* mutate the index and leave the workdir matching HEAD */ - cl_git_pass(git_repository_index(&index, repo)); - - idx_entry.mode = 0100644; - idx_entry.path = "veal.txt"; - cl_git_pass(git_oid_fromstr(&idx_entry.id, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d")); - - cl_git_pass(git_index_add(index, &idx_entry)); - cl_git_pass(git_index_remove(index, "asparagus.txt", 0)); - cl_git_pass(git_index_write(index)); - - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); - cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); - - validate_apply_index(repo, index_expected, index_expected_cnt); - validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); - - git_index_free(index); - git_diff_free(diff); -} - -void test_apply_workdir__application_failure_leaves_workdir_unmodified(void) -{ - git_diff *diff; - - const char *diff_file = DIFF_MODIFY_TWO_FILES; - - struct merge_index_entry workdir_expected[] = { - { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "8684724651336001c5dbce74bed6736d2443958d", 0, "veal.txt" }, - }; - size_t workdir_expected_cnt = sizeof(workdir_expected) / - sizeof(struct merge_index_entry); - - /* mutate the workdir */ - cl_git_rewritefile("merge-recursive/veal.txt", - "This is a modification.\n"); - - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); - cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); - - validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); - - git_diff_free(diff); -} - -void test_apply_workdir__keeps_nonconflicting_changes(void) -{ - git_diff *diff; - - struct merge_index_entry workdir_expected[] = { - { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "f75ba05f340c51065cbea2e1fdbfe5fe13144c97", 0, "gravy.txt" }, - { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, - }; - size_t workdir_expected_cnt = sizeof(workdir_expected) / - sizeof(struct merge_index_entry); - - cl_git_rmfile("merge-recursive/oyster.txt"); - cl_git_rewritefile("merge-recursive/gravy.txt", "Hello, world.\n"); - - cl_git_pass(git_diff_from_buffer(&diff, - DIFF_MODIFY_TWO_FILES, strlen(DIFF_MODIFY_TWO_FILES))); - cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); - - validate_index_unchanged(repo); - validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); - - git_diff_free(diff); -} - -void test_apply_workdir__can_apply_nonconflicting_file_changes(void) -{ - git_diff *diff; - - const char *diff_file = DIFF_MODIFY_TWO_FILES; - - struct merge_index_entry workdir_expected[] = { - { 0100644, "5db1a0fef164cb66cc0c00d35cc5af979ddc1a64", 0, "asparagus.txt" }, - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, - }; - size_t workdir_expected_cnt = sizeof(workdir_expected) / - sizeof(struct merge_index_entry); - - /* - * Replace the workdir file with a version that is different than - * HEAD but such that the patch still applies cleanly. This item - * has a new line appended. - */ - cl_git_append2file("merge-recursive/asparagus.txt", - "This line is added in the workdir.\n"); - - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); - cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); - - validate_index_unchanged(repo); - validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); - - git_diff_free(diff); -} - -void test_apply_workdir__change_mode(void) -{ -#ifndef GIT_WIN32 - git_diff *diff; - - const char *diff_file = DIFF_EXECUTABLE_FILE; - - struct merge_index_entry workdir_expected[] = { - { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, - { 0100755, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, - }; - size_t workdir_expected_cnt = sizeof(workdir_expected) / - sizeof(struct merge_index_entry); - - cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); - cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); - - validate_index_unchanged(repo); - validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); - - git_diff_free(diff); -#endif -} - -void test_apply_workdir__apply_many_changes_one(void) -{ - git_diff *diff; - git_apply_options opts = GIT_APPLY_OPTIONS_INIT; - - struct merge_index_entry workdir_expected[] = { - { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "c9d7d5d58088bc91f6e06f17ca3a205091568d3a", 0, "veal.txt" }, - }; - size_t workdir_expected_cnt = sizeof(workdir_expected) / - sizeof(struct merge_index_entry); - - cl_git_pass(git_diff_from_buffer(&diff, - DIFF_MANY_CHANGES_ONE, strlen(DIFF_MANY_CHANGES_ONE))); - cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, &opts)); - - validate_index_unchanged(repo); - validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); - - git_diff_free(diff); -} - -void test_apply_workdir__apply_many_changes_two(void) -{ - git_diff *diff; - git_apply_options opts = GIT_APPLY_OPTIONS_INIT; - - struct merge_index_entry workdir_expected[] = { - { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, - { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, - { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, - { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, - { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, - { 0100644, "6b943d65af6d8db74d747284fa4ca7d716ad5bbb", 0, "veal.txt" }, - }; - size_t workdir_expected_cnt = sizeof(workdir_expected) / - sizeof(struct merge_index_entry); - - cl_git_pass(git_diff_from_buffer(&diff, - DIFF_MANY_CHANGES_TWO, strlen(DIFF_MANY_CHANGES_TWO))); - cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, &opts)); - - validate_index_unchanged(repo); - validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); - - git_diff_free(diff); -} diff --git a/vendor/libgit2/tests/benchmarks/README.md b/vendor/libgit2/tests/benchmarks/README.md new file mode 100644 index 00000000..f66b27ae --- /dev/null +++ b/vendor/libgit2/tests/benchmarks/README.md @@ -0,0 +1,121 @@ +# libgit2 benchmarks + +This folder contains the individual benchmark tests for libgit2, +meant for understanding the performance characteristics of libgit2, +comparing your development code to the existing libgit2 code, or +comparing libgit2 to the git reference implementation. + +## Running benchmark tests + +Benchmark tests can be run in several different ways: running all +benchmarks, running one (or more) suite of benchmarks, or running a +single individual benchmark. You can target either an individual +version of a CLI, or you can A/B test a baseline CLI against a test +CLI. + +### Specifying the command-line interface to test + +By default, the `git` in your path is benchmarked. Use the +`-c` (or `--cli`) option to specify the command-line interface +to test. + +Example: `libgit2_bench --cli git2_cli` will run the tests against +`git2_cli`. + +### Running tests to compare two different implementations + +You can compare a baseline command-line interface against a test +command-line interface using the `-b (or `--baseline-cli`) option. + +Example: `libgit2_bench --baseline-cli git --cli git2_cli` will +run the tests against both `git` and `git2_cli`. + +### Running individual benchmark tests + +Similar to how a test suite or individual test is specified in +[clar](https://github.com/clar-test/clar), the `-s` (or `--suite`) +option may be used to specify the suite or individual test to run. +Like clar, the suite and test name are separated by `::`, and like +clar, this is a prefix match. + +Examples: +* `libgit2_bench -shash_object` will run the tests in the + `hash_object` suite. +* `libgit2_bench -shash_object::random_1kb` will run the + `hash_object::random_1kb` test. +* `libgit2_bench -shash_object::random` will run all the tests that + begin with `hash_object::random`. + +## Writing benchmark tests + +Benchmark tests are meant to be easy to write. Each individual +benchmark is a shell script that allows it to do set up (eg, creating +or cloning a repository, creating temporary files, etc), then running +benchmarks, then teardown. + +The `benchmark_helpers.sh` script provides many helpful utility +functions to allow for cross-platform benchmarking, as well as a +wrapper for `hyperfine` that is suited to testing libgit2. +Note that the helper script must be included first, at the beginning +of the benchmark test. + +### Benchmark example + +This simplistic example compares the speed of running the `git help` +command in the baseline CLI to the test CLI. + +```bash +#!/bin/bash -e + +# include the benchmark library +. "$(dirname "$0")/benchmark_helpers.sh" + +# run the "help" command; this will benchmark `git2_cli help` +gitbench help +``` + +### Naming + +The filename of the benchmark itself is important. A benchmark's +filename should be the name of the benchmark suite, followed by two +underscores, followed by the name of the benchmark. For example, +`hash-object__random_1kb` is the `random_1kb` test in the `hash-object` +suite. + +### Options + +The `gitbench` function accepts several options. + +* `--sandbox ` + The name of a test resource (in the `tests/resources` directory). + This will be copied as-is to the sandbox location before test + execution. This is copied _before_ the `prepare` script is run. + This option may be specified multiple times. +* `--repository ` + The name of a test resource repository (in the `tests/resources` + directory). This repository will be copied into a sandbox location + before test execution, and your test will run in this directory. + This is copied _before_ the `prepare` script is run. +* `--prepare