diff options
75 files changed, 1407 insertions, 545 deletions
diff --git a/.editorconfig b/.editorconfig index 34c5e9234..2230fd860 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,3 +15,7 @@ indent_size = 2 indent_style = space indent_size = 4 trim_trailing_whitespace = false + +[*.py] +indent_style = space +indent_size = 4 diff --git a/.gitignore b/.gitignore index dec3dca06..b38b7e16e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,37 +1,7 @@ -/tests/clar.suite -/tests/clar.suite.rule -/tests/.clarcache -/apidocs -/trash-*.exe -/libgit2.pc -/config.mak -*.o -*.a -*.exe -*.gcda -*.gcno -*.gcov -.lock-wafbuild -.waf* build/ -build-amiga/ -tests/tmp/ -msvc/Debug/ -msvc/Release/ -*.sln -*.suo -*.vc*proj* -*.sdf -*.opensdf -*.aps -*.cmake -!cmake/Modules/*.cmake .DS_Store *~ .*.swp tags -mkmf.log -*.profdata -*.profraw CMakeSettings.json .vs diff --git a/CMakeLists.txt b/CMakeLists.txt index 8765a97b5..826415893 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ INCLUDE(AddCFlagIfSupported) INCLUDE(FindPkgLibraries) INCLUDE(FindThreads) INCLUDE(FindStatNsec) +INCLUDE(GNUInstallDirs) INCLUDE(IdeSplitSources) INCLUDE(FeatureSummary) INCLUDE(EnableWarnings) @@ -58,7 +59,6 @@ OPTION(USE_SHA1 "Enable SHA1. Can be set to CollisionDetection(ON)/HTTPS/Gene OPTION(USE_GSSAPI "Link with libgssapi for SPNEGO auth" OFF) OPTION(USE_STANDALONE_FUZZERS "Enable standalone fuzzers (compatible with gcc)" OFF) OPTION(USE_LEAK_CHECKER "Run tests with leak checker" OFF) -OPTION(VALGRIND "Configure build for valgrind" OFF) OPTION(DEBUG_POOL "Enable debug pool allocator" OFF) OPTION(ENABLE_WERROR "Enable compilation with -Werror" OFF) OPTION(USE_BUNDLED_ZLIB "Use the bundled version of zlib" OFF) @@ -111,8 +111,8 @@ STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_V STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_VERSION_REV "${GIT2_HEADER}") SET(LIBGIT2_VERSION_STRING "${LIBGIT2_VERSION_MAJOR}.${LIBGIT2_VERSION_MINOR}.${LIBGIT2_VERSION_REV}") -FILE(STRINGS "${libgit2_SOURCE_DIR}/include/git2/version.h" GIT2_HEADER_SOVERSION REGEX "^#define LIBGIT2_SOVERSION [0-9]+$") -STRING(REGEX REPLACE "^.*LIBGIT2_SOVERSION ([0-9]+)$" "\\1" LIBGIT2_SOVERSION "${GIT2_HEADER_SOVERSION}") +FILE(STRINGS "${libgit2_SOURCE_DIR}/include/git2/version.h" GIT2_HEADER_SOVERSION REGEX "^#define LIBGIT2_SOVERSION \"([0-9.]+)\"$") +STRING(REGEX REPLACE "^.*LIBGIT2_SOVERSION \"([0-9.]+)\"$" "\\1" LIBGIT2_SOVERSION "${GIT2_HEADER_SOVERSION}") IF (DEPRECATE_HARD) ADD_DEFINITIONS(-DGIT_DEPRECATE_HARD) @@ -4,9 +4,8 @@ libgit2 - the Git linkable library | Build Status | | | ------------ | - | | **master** branch CI builds | [![Azure Pipelines Build Status](https://dev.azure.com/libgit2/libgit2/_apis/build/status/libgit2?branchName=master)](https://dev.azure.com/libgit2/libgit2/_build/latest?definitionId=7&branchName=master) | +| **v1.0 branch** CI builds | [![Azure Pipelines Build Status](https://dev.azure.com/libgit2/libgit2/_apis/build/status/libgit2?branchName=maint/v1.0)](https://dev.azure.com/libgit2/libgit2/_build/latest?definitionId=7&branchName=maint/v1.0) | | **v0.28 branch** CI builds | [![Azure Pipelines Build Status](https://dev.azure.com/libgit2/libgit2/_apis/build/status/libgit2?branchName=maint/v0.28)](https://dev.azure.com/libgit2/libgit2/_build/latest?definitionId=7&branchName=maint/v0.28) | -| **v0.27 branch** CI builds | [![Azure Pipelines Build Status](https://dev.azure.com/libgit2/libgit2/_apis/build/status/libgit2?branchName=maint/v0.27)](https://dev.azure.com/libgit2/libgit2/_build/latest?definitionId=7&branchName=maint/v0.27) | -| **v0.26 branch** CI builds | [![Azure Pipelines Build Status](https://dev.azure.com/libgit2/libgit2/_apis/build/status/libgit2?branchName=maint/v0.26)](https://dev.azure.com/libgit2/libgit2/_build/latest?definitionId=7&branchName=maint/v0.26) | | **Nightly** builds | [![Azure Pipelines Build Status](https://libgit2.visualstudio.com/libgit2/_apis/build/status/nightly?branchName=master&label=Full+Build)](https://libgit2.visualstudio.com/libgit2/_build/latest?definitionId=9&branchName=master) [![Coverity Build Status](https://dev.azure.com/libgit2/libgit2/_apis/build/status/coverity?branchName=master&label=Coverity+Build)](https://dev.azure.com/libgit2/libgit2/_build/latest?definitionId=21?branchName=master) [![Coverity Scan Build 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 @@ -248,9 +247,9 @@ For more advanced use or questions about CMake please read <https://cmake.org/Wi The following CMake variables are declared: -- `BIN_INSTALL_DIR`: Where to install binaries to. -- `LIB_INSTALL_DIR`: Where to install libraries to. -- `INCLUDE_INSTALL_DIR`: Where to install headers to. +- `CMAKE_INSTALL_BINDIR`: Where to install binaries to. +- `CMAKE_INSTALL_LIBDIR`: Where to install libraries to. +- `CMAKE_INSTALL_INCLUDEDIR`: Where to install headers to. - `BUILD_SHARED_LIBS`: Build libgit2 as a Shared Library (defaults to ON) - `BUILD_CLAR`: Build [Clar](https://github.com/vmg/clar)-based test suite (defaults to ON) - `THREADSAFE`: Build libgit2 with threading support (defaults to ON) @@ -330,6 +329,8 @@ Here are the bindings to libgit2 that are currently available: * hgit2 <https://github.com/jwiegley/gitlib> * Java * Jagged <https://github.com/ethomson/jagged> +* Javascript / WebAssembly ( browser and nodejs ) + * WASM-git <https://github.com/petersalomonsen/wasm-git> * Julia * LibGit2.jl <https://github.com/JuliaLang/julia/tree/master/stdlib/LibGit2> * Lua diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2b593dd2c..20335b33a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,7 +9,7 @@ jobs: - job: linux_amd64_xenial_gcc_openssl displayName: 'Linux (amd64; Xenial; GCC; OpenSSL)' pool: - vmImage: 'Ubuntu 16.04' + vmImage: 'ubuntu-18.04' steps: - template: azure-pipelines/docker.yml parameters: @@ -19,13 +19,13 @@ jobs: environmentVariables: | CC=gcc CMAKE_GENERATOR=Ninja - CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DVALGRIND=on -DUSE_GSSAPI=ON + CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON GITTEST_NEGOTIATE_PASSWORD=${{ variables.GITTEST_NEGOTIATE_PASSWORD }} - job: linux_amd64_xenial_gcc_mbedtls displayName: 'Linux (amd64; Xenial; GCC; mbedTLS)' pool: - vmImage: 'Ubuntu 16.04' + vmImage: 'ubuntu-18.04' steps: - template: azure-pipelines/docker.yml parameters: @@ -35,13 +35,13 @@ jobs: environmentVariables: | CC=gcc CMAKE_GENERATOR=Ninja - CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DVALGRIND=on -DUSE_GSSAPI=ON + CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON GITTEST_NEGOTIATE_PASSWORD=${{ variables.GITTEST_NEGOTIATE_PASSWORD }} - job: linux_amd64_xenial_clang_openssl displayName: 'Linux (amd64; Xenial; Clang; OpenSSL)' pool: - vmImage: 'Ubuntu 16.04' + vmImage: 'ubuntu-18.04' steps: - template: azure-pipelines/docker.yml parameters: @@ -51,13 +51,13 @@ jobs: environmentVariables: | CC=clang CMAKE_GENERATOR=Ninja - CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DVALGRIND=on -DUSE_GSSAPI=ON + CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON GITTEST_NEGOTIATE_PASSWORD=${{ variables.GITTEST_NEGOTIATE_PASSWORD }} - job: linux_amd64_xenial_clang_mbedtls displayName: 'Linux (amd64; Xenial; Clang; mbedTLS)' pool: - vmImage: 'Ubuntu 16.04' + vmImage: 'ubuntu-18.04' steps: - template: azure-pipelines/docker.yml parameters: @@ -67,13 +67,13 @@ jobs: environmentVariables: | CC=clang CMAKE_GENERATOR=Ninja - CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DVALGRIND=on -DUSE_GSSAPI=ON + CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON GITTEST_NEGOTIATE_PASSWORD=${{ variables.GITTEST_NEGOTIATE_PASSWORD }} - job: macos - displayName: 'macOS' + displayName: 'macOS (amd64; 10.15)' pool: - vmImage: 'macOS 10.13' + vmImage: 'macOS-10.15' steps: - bash: . '$(Build.SourcesDirectory)/azure-pipelines/setup-osx.sh' displayName: Setup @@ -89,31 +89,34 @@ jobs: - job: windows_vs_amd64 displayName: 'Windows (amd64; Visual Studio)' - pool: Hosted + pool: + vmImage: 'vs2017-win2016' steps: - template: azure-pipelines/bash.yml parameters: environmentVariables: - CMAKE_GENERATOR: Visual Studio 12 2013 Win64 - CMAKE_OPTIONS: -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON + CMAKE_GENERATOR: Visual Studio 15 2017 + CMAKE_OPTIONS: -A x64 -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - job: windows_vs_x86 displayName: 'Windows (x86; Visual Studio)' - pool: Hosted + pool: + vmImage: 'vs2017-win2016' steps: - template: azure-pipelines/bash.yml parameters: environmentVariables: - CMAKE_GENERATOR: Visual Studio 12 2013 - CMAKE_OPTIONS: -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS + CMAKE_GENERATOR: Visual Studio 15 2017 + CMAKE_OPTIONS: -A Win32 -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true - job: windows_mingw_amd64 displayName: 'Windows (amd64; MinGW)' - pool: Hosted + pool: + vmImage: 'vs2017-win2016' steps: - bash: . '$(Build.SourcesDirectory)\azure-pipelines\setup-mingw.sh' displayName: Setup @@ -131,7 +134,8 @@ jobs: - job: windows_mingw_x86 displayName: 'Windows (x86; MinGW)' - pool: Hosted + pool: + vmImage: 'vs2017-win2016' steps: - bash: . '$(Build.SourcesDirectory)\azure-pipelines\setup-mingw.sh' displayName: Setup @@ -151,7 +155,7 @@ jobs: - job: documentation displayName: 'Generate Documentation' pool: - vmImage: 'Ubuntu 16.04' + vmImage: 'ubuntu-18.04' steps: - script: | cd $(Build.SourcesDirectory)/azure-pipelines/docker diff --git a/azure-pipelines/coverity.sh b/azure-pipelines/coverity.sh index 14faadc49..c68b6f8cc 100755 --- a/azure-pipelines/coverity.sh +++ b/azure-pipelines/coverity.sh @@ -25,7 +25,7 @@ TOOL_DIR=${BUILD_DIR}/coverity-tools if ! test -d "$TOOL_DIR" then mkdir -p "$TOOL_DIR" - curl --silent --location --data "project=libgit2&token=$COVERITY_TOKEN" "$SCAN_TOOL" | + curl --silent --show-error --location --data "project=libgit2&token=$COVERITY_TOKEN" "$SCAN_TOOL" | tar -xzC "$TOOL_DIR" ln -s "$(find "$TOOL_DIR" -type d -name 'cov-analysis*')" "$TOOL_DIR"/cov-analysis fi @@ -44,7 +44,7 @@ COVERITY_UNSUPPORTED=1 \ tar -czf libgit2.tgz cov-int REVISION=$(cd ${SOURCE_DIR} && git rev-parse --short HEAD) HTML="$(curl \ - --silent \ + --silent --show-error \ --write-out "\n%{http_code}" \ --form token="$COVERITY_TOKEN" \ --form email=libgit2@gmail.com \ diff --git a/azure-pipelines/coverity.yml b/azure-pipelines/coverity.yml index 10450af5d..a8747db73 100644 --- a/azure-pipelines/coverity.yml +++ b/azure-pipelines/coverity.yml @@ -5,7 +5,7 @@ jobs: - job: coverity displayName: 'Coverity' pool: - vmImage: 'Ubuntu 16.04' + vmImage: 'ubuntu-18.04' steps: - script: | cd $(Build.SourcesDirectory)/azure-pipelines/docker diff --git a/azure-pipelines/docker.yml b/azure-pipelines/docker.yml index 0e1988c8a..0f0885770 100644 --- a/azure-pipelines/docker.yml +++ b/azure-pipelines/docker.yml @@ -13,9 +13,9 @@ steps: if [ -f /tmp/dockercache/${{parameters.docker.image}}.tar ]; then docker load < /tmp/dockercache/${{parameters.docker.image}}.tar; fi displayName: 'Load Docker cache' - script: | - cd $(Build.SourcesDirectory)/azure-pipelines/docker - docker build -t libgit2/${{parameters.docker.image}} --build-arg BASE=${{parameters.docker.base}} -f ${{parameters.docker.image}} . - if [ ! -d /tmp/dockercache ]; then mkdir /tmp/dockercache; fi + cd $(Build.SourcesDirectory)/azure-pipelines/docker && + docker build -t libgit2/${{parameters.docker.image}} --build-arg BASE=${{parameters.docker.base}} -f ${{parameters.docker.image}} . && + if [ ! -d /tmp/dockercache ]; then mkdir /tmp/dockercache; fi && docker save libgit2/${{parameters.docker.image}} $(docker history -q libgit2/${{parameters.docker.image}} | grep -v '<missing>') > /tmp/dockercache/${{parameters.docker.image}}.tar displayName: 'Build Docker image' - task: docker@0 diff --git a/azure-pipelines/docker/bionic b/azure-pipelines/docker/bionic index 648bda704..65a14063a 100644 --- a/azure-pipelines/docker/bionic +++ b/azure-pipelines/docker/bionic @@ -1,13 +1,12 @@ ARG BASE -FROM $BASE +FROM $BASE AS apt RUN apt-get update && \ - apt-get install -y --no-install-recommends \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ clang \ cmake \ curl \ gcc \ git \ - gosu \ libcurl4-openssl-dev \ libpcre3-dev \ libssh2-1-dev \ @@ -19,13 +18,14 @@ RUN apt-get update && \ openssl \ pkgconf \ python \ + sudo \ valgrind \ && \ rm -rf /var/lib/apt/lists/* -RUN mkdir /var/run/sshd +FROM apt AS mbedtls RUN cd /tmp && \ - curl --location --silent https://tls.mbed.org/download/mbedtls-2.16.2-apache.tgz | \ + curl --location --silent --show-error https://tls.mbed.org/download/mbedtls-2.16.2-apache.tgz | \ tar -xz && \ cd mbedtls-2.16.2 && \ scripts/config.pl set MBEDTLS_MD4_C 1 && \ @@ -34,7 +34,9 @@ RUN cd /tmp && \ cd .. && \ rm -rf mbedtls-2.16.2 +FROM mbedtls AS configure COPY entrypoint.sh /usr/local/bin/entrypoint.sh RUN chmod a+x /usr/local/bin/entrypoint.sh +RUN mkdir /var/run/sshd ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] diff --git a/azure-pipelines/docker/docurium b/azure-pipelines/docker/docurium index 15d10a71e..54a4202b6 100644 --- a/azure-pipelines/docker/docurium +++ b/azure-pipelines/docker/docurium @@ -1,6 +1,3 @@ -FROM debian:jessie-slim -ARG CACHEBUST=1 -RUN apt-get update -RUN apt install -y cmake pkg-config ruby ruby-dev llvm libclang-3.5-dev libssl-dev python-pygments -ARG CACHEBUST=1 +FROM ubuntu:bionic +RUN apt update && apt install -y cmake pkg-config ruby ruby-dev llvm libclang-dev libssl-dev python-pygments RUN gem install docurium diff --git a/azure-pipelines/docker/entrypoint.sh b/azure-pipelines/docker/entrypoint.sh index 38eedf02b..8d96e3acd 100644 --- a/azure-pipelines/docker/entrypoint.sh +++ b/azure-pipelines/docker/entrypoint.sh @@ -1,4 +1,4 @@ #!/bin/bash -e useradd --shell /bin/bash libgit2 -chown -R $(id -u libgit2) /home/libgit2 -exec gosu libgit2 "$@" +chown --recursive libgit2:libgit2 /home/libgit2 +exec sudo --preserve-env --set-home --user=libgit2 "$@" diff --git a/azure-pipelines/docker/xenial b/azure-pipelines/docker/xenial index cb5d4919a..bfb96d9db 100644 --- a/azure-pipelines/docker/xenial +++ b/azure-pipelines/docker/xenial @@ -8,7 +8,6 @@ RUN apt-get update && \ curl \ gcc \ git \ - gosu \ krb5-user \ libcurl4-gnutls-dev \ libgcrypt20-dev \ @@ -23,11 +22,14 @@ RUN apt-get update && \ openssl \ pkgconf \ python \ - valgrind + sudo \ + valgrind \ + && \ + rm -rf /var/lib/apt/lists/* FROM apt AS mbedtls RUN cd /tmp && \ - curl --location --silent https://tls.mbed.org/download/mbedtls-2.16.2-apache.tgz | \ + curl --location --silent --show-error https://tls.mbed.org/download/mbedtls-2.16.2-apache.tgz | \ tar -xz && \ cd mbedtls-2.16.2 && \ scripts/config.pl set MBEDTLS_MD4_C 1 && \ @@ -38,7 +40,7 @@ RUN cd /tmp && \ FROM mbedtls AS libssh2 RUN cd /tmp && \ - curl --location --silent https://www.libssh2.org/download/libssh2-1.8.2.tar.gz | \ + curl --insecure --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 . && \ @@ -48,7 +50,7 @@ RUN cd /tmp && \ FROM libssh2 AS valgrind RUN cd /tmp && \ - curl --location --silent https://sourceware.org/pub/valgrind/valgrind-3.15.0.tar.bz2 | \ + curl --insecure --location --silent --show-error https://sourceware.org/pub/valgrind/valgrind-3.15.0.tar.bz2 | \ tar -xj && \ cd valgrind-3.15.0 && \ ./configure && \ diff --git a/azure-pipelines/nightly.yml b/azure-pipelines/nightly.yml index a193747b5..a75a9cc24 100644 --- a/azure-pipelines/nightly.yml +++ b/azure-pipelines/nightly.yml @@ -5,7 +5,7 @@ jobs: - job: linux_amd64_xenial_gcc_openssl displayName: 'Linux (amd64; Xenial; GCC; OpenSSL)' pool: - vmImage: 'Ubuntu 16.04' + vmImage: 'ubuntu-18.04' steps: - template: docker.yml parameters: @@ -21,7 +21,7 @@ jobs: - job: linux_amd64_xenial_gcc_mbedtls displayName: 'Linux (amd64; Xenial; GCC; mbedTLS)' pool: - vmImage: 'Ubuntu 16.04' + vmImage: 'ubuntu-18.04' steps: - template: docker.yml parameters: @@ -37,7 +37,7 @@ jobs: - job: linux_amd64_xenial_clang_openssl displayName: 'Linux (amd64; Xenial; Clang; OpenSSL)' pool: - vmImage: 'Ubuntu 16.04' + vmImage: 'ubuntu-18.04' steps: - template: docker.yml parameters: @@ -53,7 +53,7 @@ jobs: - job: linux_amd64_xenial_clang_mbedtls displayName: 'Linux (amd64; Xenial; Clang; mbedTLS)' pool: - vmImage: 'Ubuntu 16.04' + vmImage: 'ubuntu-18.04' steps: - template: docker.yml parameters: @@ -67,9 +67,9 @@ jobs: RUN_INVASIVE_TESTS=true - job: macos - displayName: 'macOS' + displayName: 'macOS (amd64; 10.15)' pool: - vmImage: 'macOS 10.13' + vmImage: 'macOS-10.15' steps: - bash: . '$(Build.SourcesDirectory)/azure-pipelines/setup-osx.sh' displayName: Setup @@ -85,31 +85,34 @@ jobs: - job: windows_vs_amd64 displayName: 'Windows (amd64; Visual Studio)' - pool: Hosted + pool: + vmImage: 'vs2017-win2016' steps: - template: bash.yml parameters: environmentVariables: - CMAKE_GENERATOR: Visual Studio 12 2013 Win64 - CMAKE_OPTIONS: -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON + CMAKE_GENERATOR: Visual Studio 15 2017 + CMAKE_OPTIONS: -A x64 -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON RUN_INVASIVE_TESTS: true SKIP_SSH_TESTS: true - job: windows_vs_x86 displayName: 'Windows (x86; Visual Studio)' - pool: Hosted + pool: + vmImage: 'vs2017-win2016' steps: - template: bash.yml parameters: environmentVariables: - CMAKE_GENERATOR: Visual Studio 12 2013 - CMAKE_OPTIONS: -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS + CMAKE_GENERATOR: Visual Studio 15 2017 + CMAKE_OPTIONS: -A Win32 -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS RUN_INVASIVE_TESTS: true SKIP_SSH_TESTS: true - job: windows_mingw_amd64 displayName: 'Windows (amd64; MinGW)' - pool: Hosted + pool: + vmImage: 'vs2017-win2016' steps: - bash: . '$(Build.SourcesDirectory)\azure-pipelines\setup-mingw.sh' displayName: Setup @@ -127,7 +130,8 @@ jobs: - job: windows_mingw_x86 displayName: 'Windows (x86; MinGW)' - pool: Hosted + pool: + vmImage: 'vs2017-win2016' steps: - bash: . '$(Build.SourcesDirectory)\azure-pipelines\setup-mingw.sh' displayName: Setup @@ -147,7 +151,7 @@ jobs: - job: linux_x86_bionic_gcc_openssl displayName: 'Linux (x86; Bionic; GCC; OpenSSL)' pool: - vmImage: 'Ubuntu 16.04' + vmImage: 'ubuntu-18.04' steps: - template: docker.yml parameters: @@ -164,7 +168,7 @@ jobs: - job: linux_x86_bionic_clang_openssl displayName: 'Linux (x86; Bionic; Clang; OpenSSL)' pool: - vmImage: 'Ubuntu 16.04' + vmImage: 'ubuntu-18.04' steps: - template: docker.yml parameters: @@ -181,7 +185,7 @@ jobs: - job: linux_arm32_bionic_gcc_openssl displayName: 'Linux (arm32; Bionic; GCC; OpenSSL)' pool: - vmImage: 'Ubuntu 16.04' + vmImage: 'ubuntu-18.04' steps: - template: docker.yml parameters: @@ -199,7 +203,7 @@ jobs: - job: linux_arm64_bionic_gcc_openssl displayName: 'Linux (arm64; Bionic; GCC; OpenSSL)' pool: - vmImage: 'Ubuntu 16.04' + vmImage: 'ubuntu-18.04' steps: - template: docker.yml parameters: diff --git a/azure-pipelines/setup-linux.sh b/azure-pipelines/setup-linux.sh deleted file mode 100755 index c5ecb550b..000000000 --- a/azure-pipelines/setup-linux.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -set -e -set -x - -TMPDIR=${TMPDIR:-/tmp} - -if [ -z "$SKIP_APT" ]; then - apt-get update - apt-get -y install build-essential pkg-config clang cmake openssl libssl-dev libssh2-1-dev libcurl4-gnutls-dev openssh-server -fi - -mkdir -p /var/run/sshd - -if [ "$MBEDTLS" ]; then - MBEDTLS_DIR=${MBEDTLS_DIR:-$(mktemp -d ${TMPDIR}/mbedtls.XXXXXXXX)} - - git clone --depth 10 --single-branch --branch mbedtls-2.6.1 https://github.com/ARMmbed/mbedtls.git ${MBEDTLS_DIR} - cd ${MBEDTLS_DIR} - - CFLAGS=-fPIC cmake -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=OFF -DUSE_STATIC_MBEDTLS_LIBRARY=ON . - cmake --build . - - if [ -z "$SKIP_MBEDTLS_INSTALL" ]; then - make install - fi -fi diff --git a/azure-pipelines/test.sh b/azure-pipelines/test.sh index 96832d64c..2b43ba198 100755 --- a/azure-pipelines/test.sh +++ b/azure-pipelines/test.sh @@ -85,7 +85,7 @@ if [ -z "$SKIP_GITDAEMON_TESTS" ]; then fi if [ -z "$SKIP_PROXY_TESTS" ]; then - curl --location --silent https://github.com/ethomson/poxyproxy/releases/download/v0.7.0/poxyproxy-0.7.0.jar >poxyproxy.jar + 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)..." @@ -97,7 +97,7 @@ if [ -z "$SKIP_PROXY_TESTS" ]; then fi if [ -z "$SKIP_NTLM_TESTS" ]; then - curl --location --silent https://github.com/ethomson/poxygit/releases/download/v0.4.0/poxygit-0.4.0.jar >poxygit.jar + curl --location --silent --show-error https://github.com/ethomson/poxygit/releases/download/v0.4.0/poxygit-0.4.0.jar >poxygit.jar echo "" echo "Starting HTTP server..." diff --git a/cmake/Modules/PkgBuildConfig.cmake b/cmake/Modules/PkgBuildConfig.cmake index 1c0079eb0..54c5e294c 100644 --- a/cmake/Modules/PkgBuildConfig.cmake +++ b/cmake/Modules/PkgBuildConfig.cmake @@ -1,10 +1,5 @@ # pkg-config file generation # -# Uses the following globals: -# - PKG_BUILD_PREFIX: the build location (aka prefix). Defaults to CMAKE_INSTALL_PREFIX -# - PKG_BUILD_LIBDIR: the libdir location. Defaults to ${prefix}/lib. -# - PKG_BUILD_INCLUDEDIR: the includedir location. Defaults to ${prefix}/include. -# function(pkg_build_config) set(options) @@ -29,37 +24,11 @@ function(pkg_build_config) message(FATAL_ERROR "Missing VERSION argument") endif() - if (DEFINED PKG_BUILD_PREFIX) - set(PKGCONFIG_PREFIX "${PKG_BUILD_PREFIX}") - else() - set(PKGCONFIG_PREFIX "${CMAKE_INSTALL_PREFIX}") - endif() - - if(DEFINED PKG_BUILD_LIBDIR) - if (IS_ABSOLUTE ${PKG_BUILD_LIBDIR}) - set(PKGCONFIG_LIBDIR ${PKG_BUILD_LIBDIR}) - else() - set(PKGCONFIG_LIBDIR "\${prefix}/${PKG_BUILD_LIBDIR}") - endif() - else() - set(PKGCONFIG_LIBDIR "\${prefix}/lib") - endif() - - if(DEFINED PKG_BUILD_INCLUDEDIR) - if (IS_ABSOLUTE ${PKG_BUILD_INCLUDEDIR}) - set(PKGCONFIG_INCLUDEDIR ${PKG_BUILD_INCLUDEDIR}) - else() - set(PKGCONFIG_INCLUDEDIR "\${prefix}/${PKG_BUILD_INCLUDEDIR}") - endif() - else() - set(PKGCONFIG_INCLUDEDIR "\${prefix}/include") - endif() - # Write .pc "header" file(WRITE "${PKGCONFIG_FILE}" - "prefix=\"${PKGCONFIG_PREFIX}\"\n" - "libdir=\"${PKGCONFIG_LIBDIR}\"\n" - "includedir=\"${PKGCONFIG_INCLUDEDIR}\"\n" + "prefix=\"${CMAKE_INSTALL_PREFIX}\"\n" + "libdir=\"${CMAKE_INSTALL_FULL_LIBDIR}\"\n" + "includedir=\"${CMAKE_INSTALL_FULL_INCLUDEDIR}\"\n" "\n" "Name: ${PKGCONFIG_NAME}\n" "Description: ${PKGCONFIG_DESCRIPTION}\n" @@ -104,7 +73,5 @@ function(pkg_build_config) file(APPEND "${PKGCONFIG_FILE}" "Cflags: -I\${includedir} ${PKGCONFIG_CFLAGS}\n") # Install .pc file - install(FILES "${PKGCONFIG_FILE}" - DESTINATION "${PKGCONFIG_PREFIX}/${PKGCONFIG_LIBDIR}/pkgconfig" - ) + install(FILES "${PKGCONFIG_FILE}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") endfunction() diff --git a/cmake/Modules/SanitizeBool.cmake b/cmake/Modules/SanitizeBool.cmake new file mode 100644 index 000000000..b5b99a690 --- /dev/null +++ b/cmake/Modules/SanitizeBool.cmake @@ -0,0 +1,20 @@ +FUNCTION(SanitizeBool VAR) + STRING(TOLOWER "${${VAR}}" VALUE) + IF(VALUE STREQUAL "on") + SET(${VAR} "ON" PARENT_SCOPE) + ELSEIF(VALUE STREQUAL "yes") + SET(${VAR} "ON" PARENT_SCOPE) + ELSEIF(VALUE STREQUAL "true") + SET(${VAR} "ON" PARENT_SCOPE) + ELSEIF(VALUE STREQUAL "1") + SET(${VAR} "ON" PARENT_SCOPE) + ELSEIF(VALUE STREQUAL "off") + SET(${VAR} "OFF" PARENT_SCOPE) + ELSEIF(VALUE STREQUAL "no") + SET(${VAR} "OFF" PARENT_SCOPE) + ELSEIF(VALUE STREQUAL "false") + SET(${VAR} "OFF" PARENT_SCOPE) + ELSEIF(VALUE STREQUAL "0") + SET(${VAR} "OFF" PARENT_SCOPE) + ENDIF() +ENDFUNCTION() diff --git a/cmake/Modules/SelectGSSAPI.cmake b/cmake/Modules/SelectGSSAPI.cmake index 857c449e7..0a42eeefd 100644 --- a/cmake/Modules/SelectGSSAPI.cmake +++ b/cmake/Modules/SelectGSSAPI.cmake @@ -1,32 +1,27 @@ -# Select the backend to use +INCLUDE(SanitizeBool) # We try to find any packages our backends might use - FIND_PACKAGE(GSSAPI) IF (CMAKE_SYSTEM_NAME MATCHES "Darwin") INCLUDE(FindGSSFramework) ENDIF() -# Auto-select GSS backend -IF (USE_GSSAPI STREQUAL ON) - IF (GSSFRAMEWORK_FOUND) - SET(GSS_BACKEND "GSS.framework") - ELSEIF(GSSAPI_FOUND) - SET(GSS_BACKEND "gssapi") - ELSE() - MESSAGE(FATAL_ERROR "Unable to autodetect a usable GSS backend." - "Please pass the backend name explicitly (-DUSE_GSS=backend)") +IF(USE_GSSAPI) + # Auto-select GSS backend + SanitizeBool(USE_GSSAPI) + IF (USE_GSSAPI STREQUAL ON) + IF (GSSFRAMEWORK_FOUND) + SET(USE_GSSAPI "GSS.framework") + ELSEIF(GSSAPI_FOUND) + SET(USE_GSSAPI "gssapi") + ELSE() + MESSAGE(FATAL_ERROR "Unable to autodetect a usable GSS backend." + "Please pass the backend name explicitly (-DUSE_GSS=backend)") + ENDIF() ENDIF() -ELSEIF(USE_GSSAPI) - # Backend was explicitly set - SET(GSS_BACKEND ${USE_GSSAPI}) -ELSE() - SET(GSS_BACKEND NO) -ENDIF() -IF(GSS_BACKEND) # Check that we can find what's required for the selected backend - IF (GSS_BACKEND STREQUAL "GSS.framework") + IF (USE_GSSAPI STREQUAL "GSS.framework") IF (NOT GSSFRAMEWORK_FOUND) MESSAGE(FATAL_ERROR "Asked for GSS.framework backend, but it wasn't found") ENDIF() @@ -34,8 +29,8 @@ IF(GSS_BACKEND) LIST(APPEND LIBGIT2_LIBS ${GSSFRAMEWORK_LIBRARIES}) SET(GIT_GSSFRAMEWORK 1) - ADD_FEATURE_INFO(SPNEGO GIT_GSSFRAMEWORK "SPNEGO authentication support (${GSS_BACKEND})") - ELSEIF (GSS_BACKEND STREQUAL "gssapi") + ADD_FEATURE_INFO(SPNEGO GIT_GSSFRAMEWORK "SPNEGO authentication support (${USE_GSSAPI})") + ELSEIF (USE_GSSAPI STREQUAL "gssapi") IF (NOT GSSAPI_FOUND) MESSAGE(FATAL_ERROR "Asked for gssapi GSS backend, but it wasn't found") ENDIF() @@ -43,9 +38,9 @@ IF(GSS_BACKEND) LIST(APPEND LIBGIT2_LIBS ${GSSAPI_LIBRARIES}) SET(GIT_GSSAPI 1) - ADD_FEATURE_INFO(SPNEGO GIT_GSSAPI "SPNEGO authentication support (${GSS_BACKEND})") + ADD_FEATURE_INFO(SPNEGO GIT_GSSAPI "SPNEGO authentication support (${USE_GSSAPI})") ELSE() - MESSAGE(FATAL_ERROR "Asked for backend ${GSS_BACKEND} but it wasn't found") + MESSAGE(FATAL_ERROR "Asked for backend ${USE_GSSAPI} but it wasn't found") ENDIF() ELSE() SET(GIT_GSSAPI 0) diff --git a/cmake/Modules/SelectHTTPSBackend.cmake b/cmake/Modules/SelectHTTPSBackend.cmake index c7f6b8f1d..afbeac424 100644 --- a/cmake/Modules/SelectHTTPSBackend.cmake +++ b/cmake/Modules/SelectHTTPSBackend.cmake @@ -1,4 +1,4 @@ -# Select the backend to use +INCLUDE(SanitizeBool) # We try to find any packages our backends might use FIND_PACKAGE(OpenSSL) @@ -8,35 +8,31 @@ IF (CMAKE_SYSTEM_NAME MATCHES "Darwin") FIND_PACKAGE(CoreFoundation) ENDIF() -# Auto-select TLS backend -IF (USE_HTTPS STREQUAL ON) - IF (SECURITY_FOUND) - IF (SECURITY_HAS_SSLCREATECONTEXT) - SET(HTTPS_BACKEND "SecureTransport") +IF(USE_HTTPS) + # Auto-select TLS backend + SanitizeBool(USE_HTTPS) + IF (USE_HTTPS STREQUAL ON) + IF (SECURITY_FOUND) + IF (SECURITY_HAS_SSLCREATECONTEXT) + SET(USE_HTTPS "SecureTransport") + ELSE() + MESSAGE(STATUS "Security framework is too old, falling back to OpenSSL") + SET(USE_HTTPS "OpenSSL") + ENDIF() + ELSEIF (WINHTTP) + SET(USE_HTTPS "WinHTTP") + ELSEIF(OPENSSL_FOUND) + SET(USE_HTTPS "OpenSSL") + ELSEIF(MBEDTLS_FOUND) + SET(USE_HTTPS "mbedTLS") ELSE() - MESSAGE(STATUS "Security framework is too old, falling back to OpenSSL") - SET(HTTPS_BACKEND "OpenSSL") + MESSAGE(FATAL_ERROR "Unable to autodetect a usable HTTPS backend." + "Please pass the backend name explicitly (-DUSE_HTTPS=backend)") ENDIF() - ELSEIF (WINHTTP) - SET(HTTPS_BACKEND "WinHTTP") - ELSEIF(OPENSSL_FOUND) - SET(HTTPS_BACKEND "OpenSSL") - ELSEIF(MBEDTLS_FOUND) - SET(HTTPS_BACKEND "mbedTLS") - ELSE() - MESSAGE(FATAL_ERROR "Unable to autodetect a usable HTTPS backend." - "Please pass the backend name explicitly (-DUSE_HTTPS=backend)") ENDIF() -ELSEIF(USE_HTTPS) - # HTTPS backend was explicitly set - SET(HTTPS_BACKEND ${USE_HTTPS}) -ELSE() - SET(HTTPS_BACKEND NO) -ENDIF() -IF(HTTPS_BACKEND) # Check that we can find what's required for the selected backend - IF (HTTPS_BACKEND STREQUAL "SecureTransport") + IF (USE_HTTPS STREQUAL "SecureTransport") IF (NOT COREFOUNDATION_FOUND) MESSAGE(FATAL_ERROR "Cannot use SecureTransport backend, CoreFoundation.framework not found") ENDIF() @@ -51,7 +47,7 @@ IF(HTTPS_BACKEND) LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${SECURITY_INCLUDE_DIR}) LIST(APPEND LIBGIT2_LIBS ${COREFOUNDATION_LDFLAGS} ${SECURITY_LDFLAGS}) LIST(APPEND LIBGIT2_PC_LIBS ${COREFOUNDATION_LDFLAGS} ${SECURITY_LDFLAGS}) - ELSEIF (HTTPS_BACKEND STREQUAL "OpenSSL") + ELSEIF (USE_HTTPS STREQUAL "OpenSSL") IF (NOT OPENSSL_FOUND) MESSAGE(FATAL_ERROR "Asked for OpenSSL TLS backend, but it wasn't found") ENDIF() @@ -61,7 +57,7 @@ IF(HTTPS_BACKEND) LIST(APPEND LIBGIT2_LIBS ${OPENSSL_LIBRARIES}) LIST(APPEND LIBGIT2_PC_LIBS ${OPENSSL_LDFLAGS}) LIST(APPEND LIBGIT2_PC_REQUIRES "openssl") - ELSEIF(HTTPS_BACKEND STREQUAL "mbedTLS") + ELSEIF(USE_HTTPS STREQUAL "mbedTLS") IF (NOT MBEDTLS_FOUND) MESSAGE(FATAL_ERROR "Asked for mbedTLS backend, but it wasn't found") ENDIF() @@ -110,14 +106,14 @@ IF(HTTPS_BACKEND) # https://github.com/ARMmbed/mbedtls/issues/228 # For now, pass its link flags as our own LIST(APPEND LIBGIT2_PC_LIBS ${MBEDTLS_LIBRARIES}) - ELSEIF (HTTPS_BACKEND STREQUAL "WinHTTP") + ELSEIF (USE_HTTPS STREQUAL "WinHTTP") # WinHTTP setup was handled in the WinHTTP-specific block above ELSE() - MESSAGE(FATAL_ERROR "Asked for backend ${HTTPS_BACKEND} but it wasn't found") + MESSAGE(FATAL_ERROR "Asked for backend ${USE_HTTPS} but it wasn't found") ENDIF() SET(GIT_HTTPS 1) - ADD_FEATURE_INFO(HTTPS GIT_HTTPS "using ${HTTPS_BACKEND}") + ADD_FEATURE_INFO(HTTPS GIT_HTTPS "using ${USE_HTTPS}") ELSE() SET(GIT_HTTPS 0) ADD_FEATURE_INFO(HTTPS NO "") diff --git a/cmake/Modules/SelectHashes.cmake b/cmake/Modules/SelectHashes.cmake index ce28ac23c..27059db6f 100644 --- a/cmake/Modules/SelectHashes.cmake +++ b/cmake/Modules/SelectHashes.cmake @@ -1,38 +1,32 @@ # Select a hash backend +INCLUDE(SanitizeBool) + # USE_SHA1=CollisionDetection(ON)/HTTPS/Generic/OFF -IF(USE_SHA1 STREQUAL ON OR USE_SHA1 STREQUAL "CollisionDetection") - SET(SHA1_BACKEND "CollisionDetection") +SanitizeBool(USE_SHA1) +IF(USE_SHA1 STREQUAL ON) + SET(USE_SHA1 "CollisionDetection") ELSEIF(USE_SHA1 STREQUAL "HTTPS") - message(STATUS "Checking HTTPS backend… ${HTTPS_BACKEND}") - IF(HTTPS_BACKEND STREQUAL "SecureTransport") - SET(SHA1_BACKEND "CommonCrypto") - ELSEIF(HTTPS_BACKEND STREQUAL "WinHTTP") - SET(SHA1_BACKEND "Win32") - ELSEIF(HTTPS_BACKEND) - SET(SHA1_BACKEND ${HTTPS_BACKEND}) + IF(USE_HTTPS STREQUAL "SecureTransport") + SET(USE_SHA1 "CommonCrypto") + ELSEIF(USE_HTTPS STREQUAL "WinHTTP") + SET(USE_SHA1 "Win32") + ELSEIF(USE_HTTPS) + SET(USE_SHA1 ${USE_HTTPS}) ELSE() + SET(USE_SHA1 "CollisionDetection") ENDIF() - IF(NOT HTTPS_BACKEND) - SET(SHA1_BACKEND "CollisionDetection") - ENDIF() - message(STATUS "Using SHA1 backend ${SHA1_BACKEND}") -ELSEIF(USE_SHA1 STREQUAL "Generic") - SET(SHA1_BACKEND "Generic") -# ELSEIF(NOT USE_SHA1) -ELSE() - MESSAGE(FATAL_ERROR "Invalid value for USE_SHA1: ${USE_SHA1}") ENDIF() -IF(SHA1_BACKEND STREQUAL "CollisionDetection") +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\") FILE(GLOB SRC_SHA1 hash/sha1/collisiondetect.* hash/sha1/sha1dc/*) -ELSEIF(SHA1_BACKEND STREQUAL "OpenSSL") - # OPENSSL_FOUND should already be set, we're checking HTTPS_BACKEND +ELSEIF(USE_SHA1 STREQUAL "OpenSSL") + # OPENSSL_FOUND should already be set, we're checking USE_HTTPS SET(GIT_SHA1_OPENSSL 1) IF(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") @@ -41,10 +35,10 @@ ELSEIF(SHA1_BACKEND STREQUAL "OpenSSL") LIST(APPEND LIBGIT2_PC_REQUIRES "openssl") ENDIF() FILE(GLOB SRC_SHA1 hash/sha1/openssl.*) -ELSEIF(SHA1_BACKEND STREQUAL "CommonCrypto") +ELSEIF(USE_SHA1 STREQUAL "CommonCrypto") SET(GIT_SHA1_COMMON_CRYPTO 1) FILE(GLOB SRC_SHA1 hash/sha1/common_crypto.*) -ELSEIF(SHA1_BACKEND STREQUAL "mbedTLS") +ELSEIF(USE_SHA1 STREQUAL "mbedTLS") SET(GIT_SHA1_MBEDTLS 1) FILE(GLOB SRC_SHA1 hash/sha1/mbedtls.*) LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${MBEDTLS_INCLUDE_DIR}) @@ -53,14 +47,13 @@ ELSEIF(SHA1_BACKEND STREQUAL "mbedTLS") # https://github.com/ARMmbed/mbedtls/issues/228 # For now, pass its link flags as our own LIST(APPEND LIBGIT2_PC_LIBS ${MBEDTLS_LIBRARIES}) -ELSEIF(SHA1_BACKEND STREQUAL "Win32") +ELSEIF(USE_SHA1 STREQUAL "Win32") SET(GIT_SHA1_WIN32 1) FILE(GLOB SRC_SHA1 hash/sha1/win32.*) -ELSEIF(SHA1_BACKEND STREQUAL "Generic") +ELSEIF(USE_SHA1 STREQUAL "Generic") FILE(GLOB SRC_SHA1 hash/sha1/generic.*) -# ELSEIF(NOT USE_SHA1) ELSE() - MESSAGE(FATAL_ERROR "Asked for unknown SHA1 backend: ${SHA1_BACKEND}") + MESSAGE(FATAL_ERROR "Asked for unknown SHA1 backend: ${USE_SHA1}") ENDIF() -ADD_FEATURE_INFO(SHA ON "using ${SHA1_BACKEND}") +ADD_FEATURE_INFO(SHA ON "using ${USE_SHA1}") diff --git a/deps/ntlmclient/CMakeLists.txt b/deps/ntlmclient/CMakeLists.txt index 66e96d6f6..43d32185a 100644 --- a/deps/ntlmclient/CMakeLists.txt +++ b/deps/ntlmclient/CMakeLists.txt @@ -4,18 +4,20 @@ ADD_DEFINITIONS(-DNTLM_STATIC=1) DISABLE_WARNINGS(implicit-fallthrough) -IF (HTTPS_BACKEND STREQUAL "SecureTransport") +IF(USE_HTTPS STREQUAL "SecureTransport") ADD_DEFINITIONS(-DCRYPT_COMMONCRYPTO) SET(SRC_NTLMCLIENT_CRYPTO "crypt_commoncrypto.c") -ELSEIF (HTTPS_BACKEND STREQUAL "OpenSSL") + # CC_MD4 has been deprecated in macOS 10.15. + SET_SOURCE_FILES_PROPERTIES("crypt_commoncrypto.c" COMPILE_FLAGS "-Wno-deprecated") +ELSEIF(USE_HTTPS STREQUAL "OpenSSL") ADD_DEFINITIONS(-DCRYPT_OPENSSL) INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) SET(SRC_NTLMCLIENT_CRYPTO "crypt_openssl.c") -ELSEIF (HTTPS_BACKEND STREQUAL "mbedTLS") +ELSEIF(USE_HTTPS STREQUAL "mbedTLS") ADD_DEFINITIONS(-DCRYPT_MBEDTLS) SET(SRC_NTLMCLIENT_CRYPTO "crypt_mbedtls.c") -ELSE () - MESSAGE(FATAL_ERROR "Unable to use libgit2's HTTPS backend (${HTTPS_BACKEND}) for NTLM crypto") +ELSE() + MESSAGE(FATAL_ERROR "Unable to use libgit2's HTTPS backend (${USE_HTTPS}) for NTLM crypto") ENDIF() ADD_LIBRARY(ntlmclient OBJECT ${SRC_NTLMCLIENT} ${SRC_NTLMCLIENT_CRYPTO}) diff --git a/deps/ntlmclient/compat.h b/deps/ntlmclient/compat.h index efdf34514..555fa3fe4 100644 --- a/deps/ntlmclient/compat.h +++ b/deps/ntlmclient/compat.h @@ -22,8 +22,30 @@ #endif #ifdef __linux__ +/* See man page endian(3) */ # include <endian.h> # define htonll htobe64 +#elif defined(__OpenBSD__) +/* See man page htobe64(3) */ +# include <endian.h> +# define htonll htobe64 +#elif defined(__FreeBSD__) +/* See man page bwaps64(9) */ +# include <sys/endian.h> +# define htonll htobe64 +#elif defined(sun) || defined(__sun) +/* See man page byteorder(3SOCKET) */ +# include <sys/types.h> +# include <netinet/in.h> +# include <inttypes.h> + +# if !defined(htonll) +# if defined(_BIG_ENDIAN) +# define htonll(x) (x) +# else +# define htonll(x) ((((uint64_t)htonl(x)) << 32) + htonl((uint64_t)(x) >> 32)) +# endif +# endif #endif #ifndef MIN diff --git a/docs/changelog.md b/docs/changelog.md index c75164901..97cf94c6b 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,5 +1,340 @@ -v0.28 + 1 ---------- +v1.0 +---- + +This is release v1.0 "Luftschloss", which is the first stabe release of +libgit2. The API will stay compatible across all releases of the same major +version. This release includes bugfixes only and supersedes v0.99, which will +stop being maintained. Both v0.27 and v0.28 stay supported in accordance with +our release policy. + +### Changes or improvements + +- CMake was converted to make use of the GNUInstallDirs module for both our + pkgconfig and install targets in favor of our custom build options + `BIN_INSTALL_DIR`, `LIB_INSTALL_DIR` and `INCLUDE_INSTALL_DIR`. Instead, you + can now use CMakes standard variables `CMAKE_INSTALL_BINDIR`, + `CMAKE_INSTALL_LIBDIR` and `CMAKE_INSTALL_INCLUDEDIR`. + +- Some CMake build options accepted either a specific value or a boolean value + to disable the option altogether or use automatic detection. We only accepted + "ON" or "OFF", but none of the other values CMake recognizes as boolean. This + was aligned with CMake's understanding of booleans. + +- The installed pkgconfig file contained incorrect values for both `libdir` and + `includedir` variables. + +- If using pcre2 for regular expressions, then we incorrectly added "pcre2" + instead of "pcre2-8" to our pkgconfig dependencies, which was corrected. + +- Fixed building the bundled ntlmclient dependency on FreeBSD, OpenBSD and + SunOS. + +- When writing symlinks on Windows, we incorrectly handled relative symlink + targets, which was corrected. + +- When using the HTTP protocol via macOS' SecureTransport implementation, reads + could stall at the end of the session and only continue after a timeout of 60 + seconds was reached. + +- The filesystem-based reference callback didn't corectly initialize the backend + version. + +- A segmentation fault was fixed when calling `git_blame_buffer()` for files + that were modified and added to the index. + +- A backwards-incompatible change was introduced when we moved some structures + from "git2/credentials.h" into "git2/sys/credentials.h". This was fixed in the + case where you do not use hard deprecation. + +- Improved error handling in various places. + + +v0.99 +----- + +This is v0.99 "Torschlusspanik". This will be the last minor release +before libgit2 v1.0. We expect to only respond to bugs in this release, +to stabilize it for next major release. + +It contains significant refactorings, but is expected to be API-compatible +with v0.28.0. + +### Changes or improvements + +* When fetching from an anonymous remote using a URL with authentication + information provided in the URL (eg `https://foo:bar@example.com/repo`), + we would erroneously include the literal URL in the FETCH_HEAD file. + We now remove that to match git's behavior. + +* Some credential structures, enums and values have been renamed: + `git_cred` is now `git_credential`. `git_credtype_t` is now + `git_credential_t`. Functions and types beginning with + `git_cred_` now begin with `git_credential`, and constants beginning + with `GIT_CREDTYPE` now begin with `GIT_CREDENTIAL`. The former names + are deprecated. + +* Several function signatures have been changed to return an `int` to + indicate error conditions. We encourage you to check them for errors + in the standard way. + + * `git_attr_cache_flush` + * `git_error_set_str` + * `git_index_name_clear` + * `git_index_reuc_clear` + * `git_libgit2_version` + * `git_mempack_reset` + * `git_oid_cpy` + * `git_oid_fmt` + * `git_oid_fromraw` + * `git_oid_nfmt` + * `git_oid_pathfmt` + * `git_remote_stop` + * `git_remote_disconnect` + * `git_repository__cleanup` + * `git_repository_set_config` + * `git_repository_set_index` + * `git_repository_set_odb` + * `git_repository_set_refdb` + * `git_revwalk_reset` + * `git_revwalk_simplify_first_parent` + * `git_revwalk_sorting` + * `git_treebuilder_clear` + * `git_treebuilder_filter` + +* The NTLM and Negotiate authentication mechanisms are now supported when + talking to git implementations hosted on Apache or nginx servers. + +* The `HEAD` symbolic reference can no longer be deleted. + +* `git_merge_driver_source_repo` no longer returns a `const git_repository *`, + it now returns a non-`const` `git_repository *`. + +* Relative symbolic links are now supported on Windows when `core.symlinks` + is enabled. + +* Servers that provide query parameters with a redirect are now supported. + +* `git_submodule_sync` will now resolve relative URLs. + +* When creating git endpoint URLs, double-slashes are no longer used when + the given git URL has a trailing slash. + +* On Windows, a `DllMain` function is no longer included and thread-local + storage has moved to fiber-local storage in order to prevent race + conditions during shutdown. + +* The tracing mechanism (`GIT_TRACE`) is now enabled by default and does + not need to be explicitly enabled in CMake. + +* The size of Git objects is now represented by `git_object_size_t` + instead of `off_t`. + +* Binary patches without data can now be parsed. + +* A configuration snapshot can now be created from another configuration + snapshot, not just a "true" configuration object. + +* The `git_commit_with_signature` API will now ensure that referenced + objects exist in the object database. + +* Stash messages containing newlines will now be replaced with spaces; + they will no longer be (erroneously) written to the repository. + +* `git_commit_create_with_signature` now verifies the commit information + to ensure that it points to a valid tree and valid parents. + +* `git_apply` has an option `GIT_APPLY_CHECK` that will only do a dry-run. + The index and working directory will remain unmodified, and application + will report if it would have worked. + +* Patches produced by Mercurial (those that lack some git extended headers) + can now be parsed and applied. + +* Reference locks are obeyed correctly on POSIX platforms, instead of + being removed. + +* Patches with empty new files can now be read and applied. + +* `git_apply_to_tree` can now correctly apply patches that add new files. + +* The program data configuration on Windows (`C:\ProgramData\Git\config`) + must be owned by an administrator, a system account or the current user + to be read. + +* `git_blob_filtered_content` is now deprecated in favor of `git_blob_filter`. + +* Configuration files can now be included conditionally using the + `onbranch` conditional. + +* Checkout can now properly create and remove symbolic links to directories + on Windows. + +* Stash no longer recomputes trees when committing a worktree, for + improved performance. + +* Repository templates can now include a `HEAD` file to default the + initial default branch. + +* Some configuration structures, enums and values have been renamed: + `git_cvar_map` is now `git_configmap`, `git_cvar_t` is now + `git_configmap_t`, `GIT_CVAR_FALSE` is now `GIT_CONFIGMAP_FALSE`, + `GIT_CVAR_TRUE` is now `GIT_CONFIGMAP_TRUE`, `GIT_CVAR_INT32` is now + `GIT_CONFIGMAP_INT32`, and `GIT_CVAR_STRING` is now `GIT_CONFIGMAP_STRING`. + The former names are deprecated. + +* Repositories can now be created at the root of a Windows drive. + +* Configuration lookups are now more efficiently cached. + +* `git_commit_create_with_signature` now supports a `NULL` signature, + which will create a commit without adding a signature. + +* When a repository lacks an `info` "common directory", we will no + longer erroneously return `GIT_ENOTFOUND` for all attribute lookups. + +* Several attribute macros have been renamed: `GIT_ATTR_TRUE` is now + `GIT_ATTR_IS_TRUE`, `GIT_ATTR_FALSE` is now `GIT_ATTR_IS_FALSE`, + `GIT_ATTR_UNSPECIFIED` is now `GIT_ATTR_IS_UNSPECIFIED`. The + attribute enum `git_attr_t` is now `git_attr_value_t` and its + values have been renamed: `GIT_ATTR_UNSPECIFIED_T` is now + `GIT_ATTR_VALUE_UNSPECIFIED`, `GIT_ATTR_TRUE_T` is now + `GIT_ATTR_VALUE_TRUE`, `GIT_ATTR_FALSE_T` is now `GIT_ATTR_VALUE_FALSE`, + and `GIT_ATTR_VALUE_T` is now `GIT_ATTR_VALUE_STRING`. The + former names are deprecated. + +* `git_object__size` is now `git_object_size`. The former name is + deprecated. + +* `git_tag_create_frombuffer` is now `git_tag_create_from_buffer`. The + former name is deprecated. + +* Several blob creation functions have been renamed: + `git_blob_create_frombuffer` is now named `git_blob_create_from_buffer`, + `git_blob_create_fromdisk` is now named `git_blob_create_from_disk`, + `git_blob_create_fromworkdir` is now named `git_blob_create_from_workdir`, + `git_blob_create_fromstream` is now named `git_blob_create_from_stream`, + and `git_blob_create_fromstream_commit` is now named + `git_blob_create_from_stream_commit`. The former names are deprecated. + +* The function `git_oid_iszero` is now named `git_oid_is_zero`. The + former name is deprecated. + +* Pattern matching is now done using `wildmatch` instead of `fnmatch` + for compatibility with git. + +* The option initialization functions suffixed by `init_options` are now + suffixed with `options_init`. (For example, `git_checkout_init_options` + is now `git_checkout_options_init`.) The former names are deprecated. + +* NTLM2 authentication is now supported on non-Windows platforms. + +* The `git_cred_sign_callback` callback is now named `git_cred_sign_cb`. + The `git_cred_ssh_interactive_callback` callback is now named + `git_cred_ssh_interactive_cb`. + +* Ignore files now: + + * honor escaped trailing whitespace. + * do not incorrectly negate sibling paths of a negated pattern. + * honor rules that stop ignoring files after a wildcard + +* Attribute files now: + + * honor leading and trailing whitespace. + * treat paths beginning with `\` as absolute only on Windows. + * properly handle escaped characters. + * stop reading macros defined in subdirectories + +* The C locale is now correctly used when parsing regular expressions. + +* The system PCRE2 or PCRE regular expression libraries are now used + when `regcomp_l` is not available on the system. If none of these + are available on the system, an included version of PCRE is used. + +* Wildcards in reference specifications are now supported beyond simply + a bare wildcard (`*`) for compatibility with git. + +* When `git_ignore_path_is_ignored` is provided a path with a trailing + slash (eg, `dir/`), it will now treat it as a directory for the + purposes of ignore matching. + +* Patches that add or remove a file with a space in the path can now + be correctly parsed. + +* The `git_remote_completion_type` type is now `git_remote_completion_t`. + The former name is deprecated. + +* The `git_odb_backend_malloc` is now `git_odb_backend_data_alloc`. The + former name is deprecated. + +* The `git_transfer_progress_cb` callback is now `git_indexer_progress_cb` + and the `git_transfer_progress` structure is now `git_indexer_progress`. + The former names are deprecated. + +* The example projects are now contained in a single `lg2` executable + for ease of use. + +* libgit2 now correctly handles more URLs, such as + `http://example.com:/repo.git` (colon but no port), + `http://example.com` (no path), + and `http://example.com:8080/` (path is /, nonstandard port). + +* A carefully constructed commit object with a very large number + of parents may lead to potential out-of-bounds writes or + potential denial of service. + +* The ProgramData configuration file is always read for compatibility + with Git for Windows and Portable Git installations. The ProgramData + location is not necessarily writable only by administrators, so we + now ensure that the configuration file is owned by the administrator + or the current user. + +### API additions + +* The SSH host key now supports SHA-256 when `GIT_CERT_SSH_SHA256` is set. + +* The diff format option `GIT_DIFF_FORMAT_PATCH_ID` can now be used to + emit an output like `git patch-id`. + +* The `git_apply_options_init` function will initialize a + `git_apply_options` structure. + +* The remote callbacks structure adds a `git_url_resolve_cb` callback + that is invoked when connecting to a server, so that applications + may edit or replace the URL before connection. + +* The information about the original `HEAD` in a rebase operation is + available with `git_rebase_orig_head_name`. Its ID is available with + `git_rebase_orig_head_id`. The `onto` reference name is available with + `git_rebase_onto_name` and its ID is available with `git_rebase_onto_id`. + +* ODB backends can now free backend data when an error occurs during its + backend data creation using `git_odb_backend_data_free`. + +* Options may be specified to `git_repository_foreach_head` to control + its behavior: `GIT_REPOSITORY_FOREACH_HEAD_SKIP_REPO` will not skip + the main repository's HEAD reference, while + `GIT_REPOSITORY_FOREACH_HEAD_SKIP_WORKTREES` will now skip the + worktree HEAD references. + +* The `GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS` option can be specified to + `git_libgit2_opts()` to avoid looking for `.keep` files that correspond + to packfiles. This setting can improve performance when packfiles are + stored on high-latency filesystems like network filesystems. + +* Blobs can now be filtered with `git_blob_filter`, which allows for + options to be set with `git_blob_filter_options`, including + `GIT_FILTER_NO_SYSTEM_ATTRIBUTES` to disable filtering with system-level + attributes in `/etc/gitattributes` and `GIT_ATTR_CHECK_INCLUDE_HEAD` to + enable filtering with `.gitattributes` files in the HEAD revision. + +### API removals + +* The unused `git_headlist_cb` function declaration was removed. + +* The unused `git_time_monotonic` API is removed. + +* The erroneously exported `inttypes.h` header was removed. # Security Fixes @@ -82,22 +417,62 @@ v0.28 + 1 "CollisionDetection". If you were using `SHA1_BACKEND` previously, you'll need to check the value you've used, or switch to the autodetection. -### Changes or improvements - -* libgit2 now correctly handles more URLs, such as - `http://example.com:/repo.git` (colon but no port), - `http://example.com` (no path), - and `http://example.com:8080/` (path is /, nonstandard port). - -* A carefully constructed commit object with a very large number - of parents may lead to potential out-of-bounds writes or - potential denial of service. - -* The ProgramData configuration file is always read for compatibility - with Git for Windows and Portable Git installations. The ProgramData - location is not necessarily writable only by administrators, so we - now ensure that the configuration file is owned by the administrator - or the current user. +### Authors + +The following individuals provided changes that were included in this +release: + +* Aaron Patterson +* Alberto Fanjul +* Anders Borum +* Augie Fackler +* Augustin Fabre +* Ayush Shridhar +* brian m. carlson +* buddyspike +* Carlos Martín Nieto +* cheese1 +* Dan Skorupski +* Daniel Cohen Gindi +* Dave Lee +* David Brooks +* David Turner +* Denis Laxalde +* Dhruva Krishnamurthy +* Dominik Ritter +* Drew DeVault +* Edward Thomson +* Eric Huss +* Erik Aigner +* Etienne Samson +* Gregory Herrero +* Heiko Voigt +* Ian Hattendorf +* Jacques Germishuys +* Janardhan Pulivarthi +* Jason Haslam +* Johannes Schindelin +* Jordan Wallet +* Josh Bleecher Snyder +* kas +* kdj0c +* Laurence McGlashan +* lhchavez +* Lukas Berk +* Max Kostyukevich +* Patrick Steinhardt +* pcpthm +* Remy Suen +* Robert Coup +* romkatv +* Scott Furry +* Sebastian Henke +* Stefan Widgren +* Steve King Jr +* Sven Strickroth +* Tobias Nießen +* Tyler Ang-Wanek +* Tyler Wanek v0.28 ----- diff --git a/docs/fuzzing.md b/docs/fuzzing.md index cd825766b..25b32cb04 100644 --- a/docs/fuzzing.md +++ b/docs/fuzzing.md @@ -3,7 +3,7 @@ libgit2 is currently using [libFuzzer](https://libfuzzer.info) to perform automated fuzz testing. libFuzzer only works with clang. -## Prerequisites** for building fuzz targets: +## Prerequisites for building fuzz targets: 1. All the prerequisites for [building libgit2](https://github.com/libgit2/libgit2). 2. A recent version of clang. 6.0 is preferred. [pre-build Debian/Ubuntu @@ -27,14 +27,15 @@ automated fuzz testing. libFuzzer only works with clang. ## Run the fuzz targets -1. `ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolize-6.0 +1. `ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolize LSAN_OPTIONS=allocator_may_return_null=1 - ASAN_OPTIONS=allocator_may_return_null=1 ./build/fuzz/fuzz_packfile_raw - fuzz/corpora/fuzz_packfile_raw/` + ASAN_OPTIONS=allocator_may_return_null=1 ./build/fuzzers/packfile_fuzzer + fuzzers/corpora/packfile/` The `LSAN_OPTIONS` and `ASAN_OPTIONS` are there to allow `malloc(3)` to return -`NULL`. The `LLVM_PROFILE_FILE` is there to override the path where libFuzzer -will write the coverage report. +`NULL`, which is expected if a huge chunk of memory is allocated. The +`LLVM_PROFILE_FILE` environment string can also be added to override the path +where libFuzzer will write the coverage report. ## Get coverage diff --git a/include/git2/deprecated.h b/include/git2/deprecated.h index 61d0115fd..e5e56edae 100644 --- a/include/git2/deprecated.h +++ b/include/git2/deprecated.h @@ -41,6 +41,13 @@ */ #ifndef GIT_DEPRECATE_HARD +/* + * The credential structures are now opaque by default, and their + * definition has moved into the `sys/credential.h` header; include + * them here for backward compatibility. + */ +#include "sys/credential.h" + /** * @file git2/deprecated.h * @brief libgit2 deprecated functions and values diff --git a/include/git2/repository.h b/include/git2/repository.h index 45d7962b2..9ddcd3404 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -481,10 +481,11 @@ GIT_EXTERN(const char *) git_repository_path(const git_repository *repo); 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 is not a worktree, the git directory - * path is returned. + * 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. * * @param repo A repository object * @return the path to the common dir diff --git a/include/git2/sys/refdb_backend.h b/include/git2/sys/refdb_backend.h index 8e22c4f02..c31e26d95 100644 --- a/include/git2/sys/refdb_backend.h +++ b/include/git2/sys/refdb_backend.h @@ -64,6 +64,12 @@ struct git_refdb_backend { * Queries the refdb backend for the existence of a reference. * * A refdb implementation must provide this function. + * + * @arg exists The implementation shall set this to `0` if a ref does + * not exist, otherwise to `1`. + * @arg ref_name The reference's name that should be checked for + * existence. + * @return `0` on success, a negative error value code. */ int GIT_CALLBACK(exists)( int *exists, @@ -74,6 +80,13 @@ struct git_refdb_backend { * Queries the refdb backend for a given reference. * * A refdb implementation must provide this function. + * + * @arg out The implementation shall set this to the allocated + * reference, if it could be found, otherwise to `NULL`. + * @arg ref_name The reference's name that should be checked for + * existence. + * @return `0` on success, `GIT_ENOTFOUND` if the reference does + * exist, otherwise a negative error code. */ int GIT_CALLBACK(lookup)( git_reference **out, @@ -84,6 +97,16 @@ struct git_refdb_backend { * Allocate an iterator object for the backend. * * A refdb implementation must provide this function. + * + * @arg out The implementation shall set this to the allocated + * reference iterator. A custom structure may be used with an + * embedded `git_reference_iterator` structure. Both `next` + * and `next_name` functions of `git_reference_iterator` need + * to be populated. + * @arg glob A pattern to filter references by. If given, the iterator + * shall only return references that match the glob when + * passed to `wildmatch`. + * @return `0` on success, otherwise a negative error code. */ int GIT_CALLBACK(iterator)( git_reference_iterator **iter, @@ -94,6 +117,27 @@ struct git_refdb_backend { * Writes the given reference to the refdb. * * A refdb implementation must provide this function. + * + * @arg ref The reference to persist. May either be a symbolic or + * direct reference. + * @arg force Whether to write the reference if a reference with the + * same name already exists. + * @arg who The person updating the reference. Shall be used to create + * a reflog entry. + * @arg message The message detailing what kind of reference update is + * performed. Shall be used to create a reflog entry. + * @arg old If not `NULL` and `force` is not set, then the + * implementation needs to ensure that the reference is currently at + * the given OID before writing the new value. If both `old` + * and `old_target` are `NULL`, then the reference should not + * exist at the point of writing. + * @arg old_target If not `NULL` and `force` is not set, then the + * implementation needs to ensure that the symbolic + * reference is currently at the given target before + * writing the new value. If both `old` and + * `old_target` are `NULL`, then the reference should + * not exist at the point of writing. + * @return `0` on success, otherwise a negative error code. */ int GIT_CALLBACK(write)(git_refdb_backend *backend, const git_reference *ref, int force, @@ -104,6 +148,18 @@ struct git_refdb_backend { * Rename a reference in the refdb. * * A refdb implementation must provide this function. + * + * @arg out The implementation shall set this to the newly created + * reference or `NULL` on error. + * @arg old_name The current name of the reference that is to be renamed. + * @arg new_name The new name that the old reference shall be renamed to. + * @arg force Whether to write the reference if a reference with the + * target name already exists. + * @arg who The person updating the reference. Shall be used to create + * a reflog entry. + * @arg message The message detailing what kind of reference update is + * performed. Shall be used to create a reflog entry. + * @return `0` on success, otherwise a negative error code. */ int GIT_CALLBACK(rename)( git_reference **out, git_refdb_backend *backend, @@ -116,6 +172,16 @@ struct git_refdb_backend { * If it exists, its reflog should be deleted as well. * * A refdb implementation must provide this function. + * + * @arg ref_name The name of the reference name that shall be deleted. + * @arg old_id If not `NULL` and `force` is not set, then the + * implementation needs to ensure that the reference is currently at + * the given OID before writing the new value. + * @arg old_target If not `NULL` and `force` is not set, then the + * implementation needs to ensure that the symbolic + * reference is currently at the given target before + * writing the new value. + * @return `0` on success, otherwise a negative error code. */ int GIT_CALLBACK(del)(git_refdb_backend *backend, const char *ref_name, const git_oid *old_id, const char *old_target); @@ -127,13 +193,21 @@ struct git_refdb_backend { * * A refdb implementation may provide this function; if it is not * provided, nothing will be done. + * + * @return `0` on success a negative error code otherwise */ int GIT_CALLBACK(compress)(git_refdb_backend *backend); /** * Query whether a particular reference has a log (may be empty) * + * Shall return 1 if it has a reflog, 0 it it doesn't and negative in + * case an error occurred. + * * A refdb implementation must provide this function. + * + * @return `0` on success, `1` if the reflog for the given reference + * exists, a negative error code otherwise */ int GIT_CALLBACK(has_log)(git_refdb_backend *backend, const char *refname); @@ -142,6 +216,8 @@ struct git_refdb_backend { * will be appended to on writes. * * A refdb implementation must provide this function. + * + * @return `0` on success, a negative error code otherwise */ int GIT_CALLBACK(ensure_log)(git_refdb_backend *backend, const char *refname); @@ -157,6 +233,8 @@ struct git_refdb_backend { * Read the reflog for the given reference name. * * A refdb implementation must provide this function. + * + * @return `0` on success, a negative error code otherwise */ int GIT_CALLBACK(reflog_read)(git_reflog **out, git_refdb_backend *backend, const char *name); @@ -164,6 +242,11 @@ struct git_refdb_backend { * Write a reflog to disk. * * A refdb implementation must provide this function. + * + * @arg reflog The complete reference log for a given reference. Note + * that this may contain entries that have already been + * written to disk. + * @return `0` on success, a negative error code otherwise */ int GIT_CALLBACK(reflog_write)(git_refdb_backend *backend, git_reflog *reflog); @@ -171,6 +254,10 @@ struct git_refdb_backend { * Rename a reflog. * * A refdb implementation must provide this function. + * + * @arg old_name The name of old reference whose reflog shall be renamed from. + * @arg new_name The name of new reference whose reflog shall be renamed to. + * @return `0` on success, a negative error code otherwise */ int GIT_CALLBACK(reflog_rename)(git_refdb_backend *_backend, const char *old_name, const char *new_name); @@ -178,16 +265,22 @@ struct git_refdb_backend { * Remove a reflog. * * A refdb implementation must provide this function. + * + * @arg name The name of the reference whose reflog shall be deleted. + * @return `0` on success, a negative error code otherwise */ int GIT_CALLBACK(reflog_delete)(git_refdb_backend *backend, const char *name); /** * Lock a reference. * - * The opaque parameter will be passed to the unlock function. - * * A refdb implementation may provide this function; if it is not * provided, the transaction API will fail to work. + * + * @arg payload_out Opaque parameter that will be passed verbosely to + * `unlock`. + * @arg refname Reference that shall be locked. + * @return `0` on success, a negative error code otherwise */ int GIT_CALLBACK(lock)(void **payload_out, git_refdb_backend *backend, const char *refname); @@ -200,6 +293,20 @@ struct git_refdb_backend { * * A refdb implementation must provide this function if a `lock` * implementation is provided. + * + * @arg payload The payload returned by `lock`. + * @arg success `1` if a reference should be updated, `2` if + * a reference should be deleted, `0` if the lock must be + * discarded. + * @arg update_reflog `1` in case the reflog should be updated, `0` + * otherwise. + * @arg ref The reference which should be unlocked. + * @arg who The person updating the reference. Shall be used to create + * a reflog entry in case `update_reflog` is set. + * @arg message The message detailing what kind of reference update is + * performed. Shall be used to create a reflog entry in + * case `update_reflog` is set. + * @return `0` on success, a negative error code otherwise */ int GIT_CALLBACK(unlock)(git_refdb_backend *backend, void *payload, int success, int update_reflog, const git_reference *ref, const git_signature *sig, const char *message); diff --git a/include/git2/version.h b/include/git2/version.h index 148808ca0..b078e1ea2 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -7,12 +7,12 @@ #ifndef INCLUDE_git_version_h__ #define INCLUDE_git_version_h__ -#define LIBGIT2_VERSION "0.28.0" -#define LIBGIT2_VER_MAJOR 0 -#define LIBGIT2_VER_MINOR 28 +#define LIBGIT2_VERSION "1.0.0" +#define LIBGIT2_VER_MAJOR 1 +#define LIBGIT2_VER_MINOR 0 #define LIBGIT2_VER_REVISION 0 #define LIBGIT2_VER_PATCH 0 -#define LIBGIT2_SOVERSION 28 +#define LIBGIT2_SOVERSION "1.0" #endif diff --git a/script/release.py b/script/release.py new file mode 100755 index 000000000..e0f29538e --- /dev/null +++ b/script/release.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python + +from collections import namedtuple + +import argparse +import base64 +import copy +import json +import subprocess +import sys +import urllib.parse +import urllib.request +import urllib.error + +class Error(Exception): + pass + +class Version(object): + def __init__(self, version): + versions = version.split(sep='.') + if len(versions) < 2 or len(versions) > 3: + raise Error("Invalid version string '{}'".format(version)) + self.major = int(versions[0]) + self.minor = int(versions[1]) + self.revision = int(versions[2]) if len(versions) == 3 else 0 + + def __str__(self): + return '{}.{}.{}'.format(self.major, self.minor, self.revision) + + def __eq__(self, other): + return self.major == other.major and self.minor == other.minor and self.revision == other.revision + +def verify_version(version): + expected = { + 'VERSION': [ '"{}"'.format(version), None ], + 'VER_MAJOR': [ str(version.major), None ], + 'VER_MINOR': [ str(version.minor), None ], + 'VER_REVISION': [ str(version.revision), None ], + 'VER_PATCH': [ '0', None ], + 'SOVERSION': [ '"{}.{}"'.format(version.major, version.minor), None ], + } + + with open('include/git2/version.h') as f: + lines = f.readlines() + + for key in expected.keys(): + define = '#define LIBGIT2_{} '.format(key) + for line in lines: + if line.startswith(define): + expected[key][1] = line[len(define):].strip() + break + else: + raise Error("version.h: missing define for '{}'".format(key)) + + for k, v in expected.items(): + if v[0] != v[1]: + raise Error("version.h: define '{}' does not match (got '{}', expected '{}')".format(k, v[0], v[1])) + +def generate_relnotes(tree, version): + with open('docs/changelog.md') as f: + lines = f.readlines() + + if not lines[0].startswith('v'): + raise Error("changelog.md: missing section for v{}".format(version)) + try: + v = Version(lines[0][1:].strip()) + except: + raise Error("changelog.md: invalid version string {}".format(lines[0].strip())) + if v != version: + raise Error("changelog.md: changelog version doesn't match (got {}, expected {})".format(v, version)) + if not lines[1].startswith('----'): + raise Error("changelog.md: missing version header") + if lines[2] != '\n': + raise Error("changelog.md: missing newline after version header") + + for i, line in enumerate(lines[3:]): + if not line.startswith('v'): + continue + try: + Version(line[1:].strip()) + break + except: + continue + else: + raise Error("changelog.md: cannot find section header of preceding release") + + return ''.join(lines[3:i + 3]).strip() + +def git(*args): + process = subprocess.run([ 'git', *args ], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + if process.returncode != 0: + raise Error('Failed executing git {}: {}'.format(' '.join(args), process.stderr.decode())) + return process.stdout + +def post(url, data, contenttype, user, password): + request = urllib.request.Request(url, data=data) + request.add_header('Accept', 'application/json') + request.add_header('Content-Type', contenttype) + request.add_header('Content-Length', len(data)) + request.add_header('Authorization', 'Basic ' + base64.b64encode('{}:{}'.format(user, password).encode()).decode()) + + try: + response = urllib.request.urlopen(request) + if response.getcode() != 201: + raise Error("POST to '{}' failed: {}".format(url, response.reason)) + except urllib.error.URLError as e: + raise Error("POST to '{}' failed: {}".format(url, e)) + data = json.load(response) + + return data + +def generate_asset(version, tree, archive_format): + Asset = namedtuple('Asset', ['name', 'label', 'mimetype', 'data']) + mimetype = 'application/{}'.format('gzip' if archive_format == 'tar.gz' else 'zip') + return Asset( + "libgit2-{}.{}".format(version, archive_format), "Release sources: libgit2-{}.{}".format(version, archive_format), mimetype, + git('archive', '--format', archive_format, '--prefix', 'libgit2-{}/'.format(version), tree) + ) + +def release(args): + params = { + "tag_name": 'v' + str(args.version), + "name": 'libgit2 v' + str(args.version), + "target_commitish": git('rev-parse', args.tree).decode().strip(), + "body": generate_relnotes(args.tree, args.version), + } + assets = [ + generate_asset(args.version, args.tree, 'tar.gz'), + generate_asset(args.version, args.tree, 'zip'), + ] + + if args.dryrun: + for k, v in params.items(): + print('{}: {}'.format(k, v)) + for asset in assets: + print('asset: name={}, label={}, mimetype={}, bytes={}'.format(asset.name, asset.label, asset.mimetype, len(asset.data))) + return + + try: + url = 'https://api.github.com/repos/{}/releases'.format(args.repository) + response = post(url, json.dumps(params).encode(), 'application/json', args.user, args.password) + except Error as e: + raise Error('Could not create release: ' + str(e)) + + for asset in assets: + try: + url = list(urllib.parse.urlparse(response['upload_url'].split('{?')[0])) + url[4] = urllib.parse.urlencode({ 'name': asset.name, 'label': asset.label }) + post(urllib.parse.urlunparse(url), asset.data, asset.mimetype, args.user, args.password) + except Error as e: + raise Error('Could not upload asset: ' + str(e)) + +def main(): + parser = argparse.ArgumentParser(description='Create a libgit2 release') + parser.add_argument('--tree', default='HEAD', help='tree to create release for (default: HEAD)') + parser.add_argument('--dryrun', action='store_true', help='generate release, but do not post it') + parser.add_argument('--repository', default='libgit2/libgit2', help='GitHub repository to create repository in') + parser.add_argument('--user', help='user to authenitcate as') + parser.add_argument('--password', help='password to authenticate with') + parser.add_argument('version', type=Version, help='version of the new release') + args = parser.parse_args() + + verify_version(args.version) + release(args) + +if __name__ == '__main__': + try: + main() + except Error as e: + print(e) + sys.exit(1) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9e4a41a61..dff1d94e8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,14 +21,8 @@ SET(LIBGIT2_INCLUDES SET(LIBGIT2_SYSTEM_INCLUDES "") SET(LIBGIT2_LIBS "") -# Installation paths -# -SET(BIN_INSTALL_DIR bin CACHE PATH "Where to install binaries to.") -SET(LIB_INSTALL_DIR lib CACHE PATH "Where to install libraries to.") -SET(INCLUDE_INSTALL_DIR include CACHE PATH "Where to install headers to.") - # Enable tracing -IF (ENABLE_TRACE STREQUAL "ON") +IF(ENABLE_TRACE) SET(GIT_TRACE 1) ENDIF() ADD_FEATURE_INFO(tracing GIT_TRACE "tracing support") @@ -140,7 +134,7 @@ ELSEIF(REGEX_BACKEND STREQUAL "pcre2") LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${PCRE2_INCLUDE_DIRS}) LIST(APPEND LIBGIT2_LIBS ${PCRE2_LIBRARIES}) - LIST(APPEND LIBGIT2_PC_REQUIRES "libpcre2") + LIST(APPEND LIBGIT2_PC_REQUIRES "libpcre2-8") ELSEIF(REGEX_BACKEND STREQUAL "pcre") ADD_FEATURE_INFO(regex ON "using system PCRE") SET(GIT_REGEX_PCRE 1) @@ -288,19 +282,22 @@ IF (WIN32 AND NOT CYGWIN) ELSEIF (AMIGA) ADD_DEFINITIONS(-DNO_ADDRINFO -DNO_READDIR_R -DNO_MMAP) ELSE() - ADD_FEATURE_INFO(valgrind VALGRIND "valgrind hints") - IF (VALGRIND) - ADD_DEFINITIONS(-DVALGRIND) - ENDIF() - FILE(GLOB SRC_OS unix/*.c unix/*.h) ENDIF() +IF (USE_LEAK_CHECKER STREQUAL "valgrind") + ADD_DEFINITIONS(-DVALGRIND) +ENDIF() + FILE(GLOB SRC_GIT2 *.c *.h allocators/*.c allocators/*.h streams/*.c streams/*.h transports/*.c transports/*.h xdiff/*.c xdiff/*.h) +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() # the xdiff dependency is not (yet) warning-free, disable warnings as # errors for the xdiff sources until we've sorted them out @@ -388,9 +385,9 @@ ENDIF () # Install INSTALL(TARGETS git2 - RUNTIME DESTINATION ${BIN_INSTALL_DIR} - LIBRARY DESTINATION ${LIB_INSTALL_DIR} - ARCHIVE DESTINATION ${LIB_INSTALL_DIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) -INSTALL(DIRECTORY ${libgit2_SOURCE_DIR}/include/git2 DESTINATION ${INCLUDE_INSTALL_DIR} ) -INSTALL(FILES ${libgit2_SOURCE_DIR}/include/git2.h DESTINATION ${INCLUDE_INSTALL_DIR} ) +INSTALL(DIRECTORY ${libgit2_SOURCE_DIR}/include/git2 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +INSTALL(FILES ${libgit2_SOURCE_DIR}/include/git2.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/src/blame.c b/src/blame.c index 404f1f643..23c21027a 100644 --- a/src/blame.c +++ b/src/blame.c @@ -415,7 +415,7 @@ on_error: static bool hunk_is_bufferblame(git_blame_hunk *hunk) { - return git_oid_is_zero(&hunk->final_commit_id); + return hunk && git_oid_is_zero(&hunk->final_commit_id); } static int buffer_hunk_cb( diff --git a/src/cache.c b/src/cache.c index 32ba993b0..af42b3959 100644 --- a/src/cache.c +++ b/src/cache.c @@ -208,10 +208,14 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry) entry = stored_entry; } else if (stored_entry->flags == GIT_CACHE_STORE_RAW && entry->flags == GIT_CACHE_STORE_PARSED) { - git_cached_obj_decref(stored_entry); - git_cached_obj_incref(entry); - - git_oidmap_set(cache->map, &entry->oid, entry); + if (git_oidmap_set(cache->map, &entry->oid, entry) == 0) { + git_cached_obj_decref(stored_entry); + git_cached_obj_incref(entry); + } else { + git_cached_obj_decref(entry); + git_cached_obj_incref(stored_entry); + entry = stored_entry; + } } else { /* NO OP */ } diff --git a/src/diff_print.c b/src/diff_print.c index 369e5c1e6..a78953c32 100644 --- a/src/diff_print.c +++ b/src/diff_print.c @@ -359,9 +359,9 @@ int diff_delta_format_similarity_header( abort(); if ((error = git_buf_puts(&old_path, delta->old_file.path)) < 0 || - (error = git_buf_puts(&new_path, delta->new_file.path)) < 0 || - (error = git_buf_quote(&old_path)) < 0 || - (error = git_buf_quote(&new_path)) < 0) + (error = git_buf_puts(&new_path, delta->new_file.path)) < 0 || + (error = git_buf_quote(&old_path)) < 0 || + (error = git_buf_quote(&new_path)) < 0) goto done; git_buf_printf(out, @@ -428,8 +428,11 @@ int git_diff_delta__format_file_header( git_buf_printf(out, "diff --git %s %s\n", old_path.ptr, new_path.ptr); + if (unchanged && delta->old_file.mode != delta->new_file.mode) + diff_print_modes(out, delta); + if (delta->status == GIT_DELTA_RENAMED || - (delta->status == GIT_DELTA_COPIED && unchanged)) { + (delta->status == GIT_DELTA_COPIED && unchanged)) { if ((error = diff_delta_format_similarity_header(out, delta)) < 0) goto done; } @@ -444,9 +447,6 @@ int git_diff_delta__format_file_header( "--- %s\n+++ %s\n", old_path.ptr, new_path.ptr); } - if (unchanged && delta->old_file.mode != delta->new_file.mode) - diff_print_modes(out, delta); - if (git_buf_oom(out)) error = -1; diff --git a/src/indexer.c b/src/indexer.c index 717549fa2..68fdd85c5 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -150,11 +150,11 @@ int git_indexer_new( idx->progress_cb = opts.progress_cb; idx->progress_payload = opts.progress_cb_payload; idx->mode = mode ? mode : GIT_PACK_FILE_MODE; - git_hash_ctx_init(&idx->hash_ctx); - git_hash_ctx_init(&idx->trailer); git_buf_init(&idx->entry_data, 0); - if ((error = git_oidmap_new(&idx->expected_oids)) < 0) + if ((error = git_hash_ctx_init(&idx->hash_ctx)) < 0 || + (error = git_hash_ctx_init(&idx->trailer)) < 0 || + (error = git_oidmap_new(&idx->expected_oids)) < 0) goto cleanup; idx->do_verify = opts.verify; diff --git a/src/notes.c b/src/notes.c index 4633a16ea..68d2ae9ec 100644 --- a/src/notes.c +++ b/src/notes.c @@ -808,8 +808,11 @@ int git_note_next( git_oid_cpy(note_id, &item->id); - if (!(error = process_entry_path(item->path, annotated_id))) - git_iterator_advance(NULL, it); + if ((error = process_entry_path(item->path, annotated_id)) < 0) + return error; - return error; + if ((error = git_iterator_advance(NULL, it)) < 0 && error != GIT_ITEROVER) + return error; + + return 0; } diff --git a/src/odb_pack.c b/src/odb_pack.c index c93d07c46..86c858df1 100644 --- a/src/odb_pack.c +++ b/src/odb_pack.c @@ -15,7 +15,6 @@ #include "hash.h" #include "odb.h" #include "delta.h" -#include "sha1_lookup.h" #include "mwindow.h" #include "pack.h" diff --git a/src/pack-objects.c b/src/pack-objects.c index bdd5171a8..49b4e4772 100644 --- a/src/pack-objects.c +++ b/src/pack-objects.c @@ -374,7 +374,9 @@ static int write_object( GIT_ERROR_CHECK_ALLOC(zbuf); git_zstream_reset(&pb->zstream); - git_zstream_set_input(&pb->zstream, data, data_len); + + if ((error = git_zstream_set_input(&pb->zstream, data, data_len)) < 0) + goto done; while (!git_zstream_done(&pb->zstream)) { if ((error = git_zstream_get_output(zbuf, &zbuf_len, &pb->zstream)) < 0 || diff --git a/src/pack.c b/src/pack.c index 7c6fc2cdb..fcf64f57d 100644 --- a/src/pack.c +++ b/src/pack.c @@ -12,7 +12,6 @@ #include "mwindow.h" #include "odb.h" #include "oid.h" -#include "sha1_lookup.h" /* Option to bypass checking existence of '.keep' files */ bool git_disable_pack_keep_file_checks = false; @@ -1239,6 +1238,27 @@ int git_pack_foreach_entry( return error; } +static int sha1_position(const void *table, size_t stride, unsigned lo, + unsigned hi, const unsigned char *key) +{ + const unsigned char *base = table; + + while (lo < hi) { + unsigned mi = (lo + hi) / 2; + int cmp = git_oid__hashcmp(base + mi * stride, key); + + if (!cmp) + return mi; + + if (cmp > 0) + hi = mi; + else + lo = mi+1; + } + + return -((int)lo)-1; +} + static int pack_entry_find_offset( off64_t *offset_out, git_oid *found_oid, diff --git a/src/patch_parse.c b/src/patch_parse.c index 9d089ad83..0e251cb88 100644 --- a/src/patch_parse.c +++ b/src/patch_parse.c @@ -411,6 +411,7 @@ static const parse_header_transition transitions[] = { { "GIT binary patch" , STATE_INDEX, STATE_END, NULL }, { "Binary files " , STATE_INDEX, STATE_END, NULL }, + { "similarity index " , STATE_END, STATE_SIMILARITY, parse_header_similarity }, { "similarity index " , STATE_DIFF, STATE_SIMILARITY, parse_header_similarity }, { "dissimilarity index ", STATE_DIFF, STATE_SIMILARITY, parse_header_dissimilarity }, { "rename from " , STATE_SIMILARITY, STATE_RENAME, parse_header_renamefrom }, diff --git a/src/push.c b/src/push.c index 67ebcfb3e..34867c2e4 100644 --- a/src/push.c +++ b/src/push.c @@ -349,8 +349,9 @@ static int queue_objects(git_push *push) if (git_oid_is_zero(&head->oid)) continue; - /* TODO */ - git_revwalk_hide(rw, &head->oid); + 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); diff --git a/src/refdb_fs.c b/src/refdb_fs.c index a721f9841..653cc1b97 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -5,8 +5,6 @@ * a Linking Exception. For full terms see the included COPYING file. */ -#include "refdb_fs.h" - #include "refs.h" #include "hash.h" #include "repository.h" @@ -2129,6 +2127,9 @@ int git_refdb_backend_fs( backend = git__calloc(1, sizeof(refdb_fs_backend)); GIT_ERROR_CHECK_ALLOC(backend); + if (git_refdb_init_backend(&backend->parent, GIT_REFDB_BACKEND_VERSION) < 0) + goto fail; + backend->repo = repository; if (repository->gitdir) { diff --git a/src/refdb_fs.h b/src/refdb_fs.h deleted file mode 100644 index 0c84814df..000000000 --- a/src/refdb_fs.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_refdb_fs_h__ -#define INCLUDE_refdb_fs_h__ - -#include "common.h" - -#include "strmap.h" - -typedef struct { - git_strmap *packfile; - time_t packfile_time; -} git_refcache; - -#endif diff --git a/src/repository.c b/src/repository.c index 721ce5e90..da92b274c 100644 --- a/src/repository.c +++ b/src/repository.c @@ -191,19 +191,25 @@ void git_repository_free(git_repository *repo) * * Open a repository object from its path */ -static bool valid_repository_path(git_buf *repository_path, git_buf *common_path) +static int is_valid_repository_path(bool *out, git_buf *repository_path, git_buf *common_path) { + int error; + + *out = false; + /* Check if we have a separate commondir (e.g. we have a * worktree) */ if (git_path_contains_file(repository_path, GIT_COMMONDIR_FILE)) { git_buf common_link = GIT_BUF_INIT; - git_buf_joinpath(&common_link, repository_path->ptr, GIT_COMMONDIR_FILE); - git_futils_readbuffer(&common_link, common_link.ptr); - git_buf_rtrim(&common_link); + if ((error = git_buf_joinpath(&common_link, repository_path->ptr, GIT_COMMONDIR_FILE)) < 0 || + (error = git_futils_readbuffer(&common_link, common_link.ptr)) < 0) + return error; + git_buf_rtrim(&common_link); if (git_path_is_relative(common_link.ptr)) { - git_buf_joinpath(common_path, repository_path->ptr, common_link.ptr); + if ((error = git_buf_joinpath(common_path, repository_path->ptr, common_link.ptr)) < 0) + return error; } else { git_buf_swap(common_path, &common_link); } @@ -211,24 +217,26 @@ static bool valid_repository_path(git_buf *repository_path, git_buf *common_path git_buf_dispose(&common_link); } else { - git_buf_set(common_path, repository_path->ptr, repository_path->size); + if ((error = git_buf_set(common_path, repository_path->ptr, repository_path->size)) < 0) + return error; } /* Make sure the commondir path always has a trailing * slash */ if (git_buf_rfind(common_path, '/') != (ssize_t)common_path->size - 1) - git_buf_putc(common_path, '/'); + if ((error = git_buf_putc(common_path, '/')) < 0) + return error; /* Ensure HEAD file exists */ if (git_path_contains_file(repository_path, GIT_HEAD_FILE) == false) - return false; - + return 0; /* Check files in common dir */ if (git_path_contains_dir(common_path, GIT_OBJECTS_DIR) == false) - return false; + return 0; if (git_path_contains_dir(common_path, GIT_REFS_DIR) == false) - return false; + return 0; - return true; + *out = true; + return 0; } static git_repository *repository_alloc(void) @@ -443,15 +451,15 @@ static int find_repo( uint32_t flags, const char *ceiling_dirs) { - int error; git_buf path = GIT_BUF_INIT; git_buf repo_link = GIT_BUF_INIT; git_buf common_link = GIT_BUF_INIT; struct stat st; dev_t initial_device = 0; int min_iterations; - bool in_dot_git; + bool in_dot_git, is_valid; size_t ceiling_offset = 0; + int error; git_buf_clear(gitdir_path); @@ -477,9 +485,8 @@ static int find_repo( for (;;) { if (!(flags & GIT_REPOSITORY_OPEN_NO_DOTGIT)) { if (!in_dot_git) { - error = git_buf_joinpath(&path, path.ptr, DOT_GIT); - if (error < 0) - break; + if ((error = git_buf_joinpath(&path, path.ptr, DOT_GIT)) < 0) + goto out; } in_dot_git = !in_dot_git; } @@ -493,28 +500,33 @@ static int find_repo( break; if (S_ISDIR(st.st_mode)) { - if (valid_repository_path(&path, &common_link)) { - git_path_to_dir(&path); - git_buf_set(gitdir_path, path.ptr, path.size); + if ((error = is_valid_repository_path(&is_valid, &path, &common_link)) < 0) + goto out; + + if (is_valid) { + if ((error = git_path_to_dir(&path)) < 0 || + (error = git_buf_set(gitdir_path, path.ptr, path.size)) < 0) + goto out; if (gitlink_path) - git_buf_attach(gitlink_path, - git_worktree__read_link(path.ptr, GIT_GITDIR_FILE), 0); + if ((error = git_buf_attach(gitlink_path, git_worktree__read_link(path.ptr, GIT_GITDIR_FILE), 0)) < 0) + goto out; if (commondir_path) git_buf_swap(&common_link, commondir_path); break; } - } - else if (S_ISREG(st.st_mode) && git__suffixcmp(path.ptr, "/" DOT_GIT) == 0) { - error = read_gitfile(&repo_link, path.ptr); - if (error < 0) - break; - if (valid_repository_path(&repo_link, &common_link)) { + } 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_buf_swap(gitdir_path, &repo_link); if (gitlink_path) - error = git_buf_put(gitlink_path, path.ptr, path.size); + if ((error = git_buf_put(gitlink_path, path.ptr, path.size)) < 0) + goto out; if (commondir_path) git_buf_swap(&common_link, commondir_path); } @@ -525,10 +537,8 @@ static int find_repo( /* 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 (git_path_dirname_r(&path, path.ptr) < 0) { - error = -1; - break; - } + if ((error = git_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. */ @@ -536,31 +546,28 @@ static int find_repo( 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))) + if (min_iterations == 0 && + (path.ptr[ceiling_offset] == 0 || (flags & GIT_REPOSITORY_OPEN_NO_SEARCH))) break; } - if (!error && workdir_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) { + if (workdir_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) { if (!git_buf_len(gitdir_path)) git_buf_clear(workdir_path); - else { - git_path_dirname_r(workdir_path, path.ptr); - git_path_to_dir(workdir_path); - } - if (git_buf_oom(workdir_path)) - return -1; + else if ((error = git_path_dirname_r(workdir_path, path.ptr)) < 0 || + (error = git_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_buf_len(gitdir_path) && !error) { - git_error_set(GIT_ERROR_REPOSITORY, - "could not find repository from '%s'", start_path); + if (!git_buf_len(gitdir_path)) { + git_error_set(GIT_ERROR_REPOSITORY, "could not find repository from '%s'", start_path); error = GIT_ENOTFOUND; + goto out; } +out: git_buf_dispose(&path); git_buf_dispose(&repo_link); git_buf_dispose(&common_link); @@ -571,14 +578,16 @@ int git_repository_open_bare( git_repository **repo_ptr, const char *bare_path) { - int error; git_buf path = GIT_BUF_INIT, common_path = GIT_BUF_INIT; git_repository *repo = NULL; + bool is_valid; + int error; - if ((error = git_path_prettify_dir(&path, bare_path, NULL)) < 0) + if ((error = git_path_prettify_dir(&path, bare_path, NULL)) < 0 || + (error = is_valid_repository_path(&is_valid, &path, &common_path)) < 0) return error; - if (!valid_repository_path(&path, &common_path)) { + if (!is_valid) { git_buf_dispose(&path); git_buf_dispose(&common_path); git_error_set(GIT_ERROR_REPOSITORY, "path is not a repository: %s", bare_path); @@ -2084,6 +2093,7 @@ int git_repository_init_ext( git_buf repo_path = GIT_BUF_INIT, wd_path = GIT_BUF_INIT, common_path = GIT_BUF_INIT, head_path = GIT_BUF_INIT; const char *wd; + bool is_valid; int error; assert(out && given_repo && opts); @@ -2095,7 +2105,10 @@ int git_repository_init_ext( wd = (opts->flags & GIT_REPOSITORY_INIT_BARE) ? NULL : git_buf_cstr(&wd_path); - if (valid_repository_path(&repo_path, &common_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); diff --git a/src/revwalk.c b/src/revwalk.c index 4587b5acc..abbd65ac2 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -58,7 +58,7 @@ int git_revwalk__push_commit(git_revwalk *walk, const git_oid *oid, const git_re return 0; git_error_set(GIT_ERROR_INVALID, "object is not a committish"); - return -1; + return error; } if (error < 0) return error; diff --git a/src/sha1_lookup.c b/src/sha1_lookup.c deleted file mode 100644 index 14fcb40e5..000000000 --- a/src/sha1_lookup.c +++ /dev/null @@ -1,35 +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 "sha1_lookup.h" - -#include <stdio.h> - -#include "oid.h" - -int sha1_position(const void *table, - size_t stride, - unsigned lo, unsigned hi, - const unsigned char *key) -{ - const unsigned char *base = table; - - while (lo < hi) { - unsigned mi = (lo + hi) / 2; - int cmp = git_oid__hashcmp(base + mi * stride, key); - - if (!cmp) - return mi; - - if (cmp > 0) - hi = mi; - else - lo = mi+1; - } - - return -((int)lo)-1; -} diff --git a/src/sha1_lookup.h b/src/sha1_lookup.h deleted file mode 100644 index 841ea5b22..000000000 --- a/src/sha1_lookup.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_sha1_lookup_h__ -#define INCLUDE_sha1_lookup_h__ - -#include "common.h" - -#include <stdlib.h> - -int sha1_position(const void *table, - size_t stride, - unsigned lo, unsigned hi, - const unsigned char *key); - -#endif diff --git a/src/streams/openssl.c b/src/streams/openssl.c index 98a3635af..5b66352ca 100644 --- a/src/streams/openssl.c +++ b/src/streams/openssl.c @@ -30,10 +30,6 @@ #include <openssl/x509v3.h> #include <openssl/bio.h> -#ifdef VALGRIND -# include <valgrind/memcheck.h> -#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" @@ -160,7 +156,7 @@ static void openssl_locking_function( lock = mode & CRYPTO_LOCK; if (lock) { - git_mutex_lock(&openssl_locks[n]); + (void)git_mutex_lock(&openssl_locks[n]); } else { git_mutex_unlock(&openssl_locks[n]); } @@ -200,16 +196,69 @@ static void shutdown_ssl(void) } } +#ifdef VALGRIND +#ifdef OPENSSL_LEGACY_API +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) +{ + return git__free(mem); +} +#else +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); + return git__free(mem); +} +#endif +#endif + int git_openssl_stream_global_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 */ + if (!allocators_initialized && + CRYPTO_set_mem_functions(git_openssl_malloc, + git_openssl_realloc, + git_openssl_free) != 1) + goto error; + allocators_initialized = true; +#endif + OPENSSL_init_ssl(0, NULL); /* @@ -314,11 +363,6 @@ static int bio_read(BIO *b, char *buf, int len) static int bio_write(BIO *b, const char *buf, int len) { git_stream *io = (git_stream *) BIO_get_data(b); - -#ifdef VALGRIND - VALGRIND_MAKE_MEM_DEFINED(buf, len); -#endif - return (int) git_stream_write(io, buf, len, 0); } @@ -595,10 +639,6 @@ static int openssl_connect(git_stream *stream) BIO_set_data(bio, st->io); SSL_set_bio(st->ssl, bio, bio); -#ifdef VALGRIND - VALGRIND_MAKE_MEM_DEFINED(st->ssl, sizeof(SSL)); -#endif - /* specify the host in case SNI is needed */ #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME SSL_set_tlsext_host_name(st->ssl, st->host); @@ -609,10 +649,6 @@ static int openssl_connect(git_stream *stream) st->connected = true; -#ifdef VALGRIND - VALGRIND_MAKE_MEM_DEFINED(st->ssl, sizeof(SSL)); -#endif - return verify_server_cert(st->ssl, st->host); } @@ -679,10 +715,6 @@ static ssize_t openssl_read(git_stream *stream, void *data, size_t len) if ((ret = SSL_read(st->ssl, data, len)) <= 0) return ssl_set_error(st->ssl, ret); -#ifdef VALGRIND - VALGRIND_MAKE_MEM_DEFINED(data, ret); -#endif - return ret; } diff --git a/src/transports/auth_ntlm.c b/src/transports/auth_ntlm.c index 02a861f07..d134a3db6 100644 --- a/src/transports/auth_ntlm.c +++ b/src/transports/auth_ntlm.c @@ -50,10 +50,10 @@ static int ntlm_set_credentials(http_auth_ntlm_context *ctx, git_credential *_cr cred = (git_credential_userpass_plaintext *)_cred; if ((sep = strchr(cred->username, '\\')) != NULL) { - domain = strndup(cred->username, (sep - cred->username)); + domain = git__strndup(cred->username, (sep - cred->username)); GIT_ERROR_CHECK_ALLOC(domain); - domainuser = strdup(sep + 1); + domainuser = git__strdup(sep + 1); GIT_ERROR_CHECK_ALLOC(domainuser); username = domainuser; diff --git a/src/transports/httpclient.c b/src/transports/httpclient.c index f5c2ce58d..bde67ca9f 100644 --- a/src/transports/httpclient.c +++ b/src/transports/httpclient.c @@ -29,7 +29,18 @@ static git_http_auth_scheme auth_schemes[] = { { GIT_HTTP_AUTH_BASIC, "Basic", GIT_CREDENTIAL_USERPASS_PLAINTEXT, git_http_auth_basic }, }; -#define GIT_READ_BUFFER_SIZE 8192 +/* + * Use a 16kb read buffer to match the maximum size of a TLS packet. This + * is critical for compatibility with SecureTransport, which will always do + * a network read on every call, even if it has data buffered to return to + * you. That buffered data may be the _end_ of a keep-alive response, so + * if SecureTransport performs another network read, it will wait until the + * server ultimately times out before it returns that buffered data to you. + * Since SecureTransport only reads a single TLS packet at a time, by + * calling it with a read buffer that is the maximum size of a TLS packet, + * we ensure that it will never buffer. + */ +#define GIT_READ_BUFFER_SIZE (16 * 1024) typedef struct { git_net_url url; @@ -585,7 +596,7 @@ static int apply_credentials( if (auth->connection_affinity) free_auth_context(server); } else if (!token.size) { - git_error_set(GIT_ERROR_HTTP, "failed to respond to authentication challange"); + git_error_set(GIT_ERROR_HTTP, "failed to respond to authentication challenge"); error = -1; goto done; } diff --git a/src/unix/posix.h b/src/unix/posix.h index d1f902489..4fa725013 100644 --- a/src/unix/posix.h +++ b/src/unix/posix.h @@ -33,7 +33,7 @@ typedef int GIT_SOCKET; # 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_NEC) +#elif !defined(GIT_USE_STAT_MTIME_NSEC) && defined(GIT_USE_NSEC) # error GIT_USE_NSEC defined but unknown struct stat nanosecond type #endif diff --git a/src/win32/path_w32.c b/src/win32/path_w32.c index eda85abf4..18b43e728 100644 --- a/src/win32/path_w32.c +++ b/src/win32/path_w32.c @@ -25,6 +25,9 @@ #define path__is_unc(p) \ (((p)[0] == '\\' && (p)[1] == '\\') || ((p)[0] == '/' && (p)[1] == '/')) +#define path__startswith_slash(p) \ + ((p)[0] == '\\' || (p)[0] == '/') + GIT_INLINE(int) path__cwd(wchar_t *path, int size) { int len; @@ -221,7 +224,7 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src) goto on_error; } /* Absolute paths omitting the drive letter */ - else if (src[0] == '\\' || src[0] == '/') { + else if (path__startswith_slash(src)) { if (path__cwd(dest, MAX_PATH) < 0) goto on_error; @@ -257,6 +260,30 @@ on_error: return -1; } +int git_win32_path_relative_from_utf8(git_win32_path out, const char *src) +{ + wchar_t *dest = out, *p; + int len; + + /* Handle absolute paths */ + if (git_path_is_absolute(src) || + path__is_nt_namespace(src) || + path__is_unc(src) || + path__startswith_slash(src)) { + return git_win32_path_from_utf8(out, src); + } + + if ((len = git__utf8_to_16(dest, MAX_PATH, src)) < 0) + return -1; + + for (p = dest; p < (dest + len); p++) { + if (*p == L'/') + *p = L'\\'; + } + + return len; +} + int git_win32_path_to_utf8(git_win32_utf8_path dest, const wchar_t *src) { char *out = dest; diff --git a/src/win32/path_w32.h b/src/win32/path_w32.h index afd0aa155..dab8b96fa 100644 --- a/src/win32/path_w32.h +++ b/src/win32/path_w32.h @@ -11,7 +11,9 @@ #include "vector.h" /** - * Create a Win32 path (in UCS-2 format) from a UTF-8 string. + * Create a Win32 path (in UCS-2 format) from a UTF-8 string. If the given + * path is relative, then it will be turned into an absolute path by having + * the current working directory prepended. * * @param dest The buffer to receive the wide string. * @param src The UTF-8 string to convert. @@ -20,12 +22,25 @@ extern int git_win32_path_from_utf8(git_win32_path dest, const char *src); /** + * Create a Win32 path (in UCS-2 format) from a UTF-8 string. If the given + * path is relative, then it will not be turned into an absolute path. + * + * @param dest The buffer to receive 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 + */ +extern int git_win32_path_relative_from_utf8(git_win32_path dest, const char *src); + +/** * Canonicalize a Win32 UCS-2 path so that it is suitable for delivery to the * Win32 APIs: remove multiple directory separators, squashing to a single one, * strip trailing directory separators, ensure directory separators are all * canonical (always backslashes, never forward slashes) and process any * directory entries of '.' or '..'. * + * Note that this is intended to be used on absolute Windows paths, those + * that start with `C:\`, `\\server\share`, `\\?\`, etc. + * * This processes the buffer in place. * * @param path The buffer to process diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c index 29641bdaf..cacf986e8 100644 --- a/src/win32/posix_w32.c +++ b/src/win32/posix_w32.c @@ -447,8 +447,7 @@ int p_symlink(const char *target, const char *path) * relative symlinks, this is not someting we want. */ if (git_win32_path_from_utf8(path_w, path) < 0 || - git__utf8_to_16(target_w, MAX_PATH, target) < 0 || - git_win32_path_canonicalize(target_w) < 0) + git_win32_path_relative_from_utf8(target_w, target) < 0) return -1; dwFlags = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; diff --git a/src/worktree.c b/src/worktree.c index ef4ebfda8..e171afbb2 100644 --- a/src/worktree.c +++ b/src/worktree.c @@ -136,11 +136,11 @@ static int open_worktree_dir(git_worktree **out, const char *parent, const char 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_path_dirname(wt->gitlink_path)) == NULL) { + 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_path_dirname(wt->gitlink_path)) == NULL) { error = -1; goto out; } @@ -149,7 +149,10 @@ static int open_worktree_dir(git_worktree **out, const char *parent, const char goto out; wt->gitdir_path = git_buf_detach(&gitdir); - wt->locked = !!git_worktree_is_locked(NULL, wt); + if ((error = git_worktree_is_locked(NULL, wt)) < 0) + goto out; + wt->locked = !!error; + error = 0; *out = wt; @@ -403,20 +406,24 @@ out: int git_worktree_lock(git_worktree *wt, const char *reason) { git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT; - int err; + int error; assert(wt); - if ((err = git_worktree_is_locked(NULL, wt)) < 0) + if ((error = git_worktree_is_locked(NULL, wt)) < 0) + goto out; + if (error) { + error = GIT_ELOCKED; goto out; + } - if ((err = git_buf_joinpath(&path, wt->gitdir_path, "locked")) < 0) + if ((error = git_buf_joinpath(&path, wt->gitdir_path, "locked")) < 0) goto out; if (reason) git_buf_attach_notowned(&buf, reason, strlen(reason)); - if ((err = git_futils_writebuffer(&buf, path.ptr, O_CREAT|O_EXCL|O_WRONLY, 0644)) < 0) + if ((error = git_futils_writebuffer(&buf, path.ptr, O_CREAT|O_EXCL|O_WRONLY, 0644)) < 0) goto out; wt->locked = 1; @@ -424,16 +431,19 @@ int git_worktree_lock(git_worktree *wt, const char *reason) out: git_buf_dispose(&path); - return err; + return error; } int git_worktree_unlock(git_worktree *wt) { git_buf path = GIT_BUF_INIT; + int error; assert(wt); - if (!git_worktree_is_locked(NULL, wt)) + if ((error = git_worktree_is_locked(NULL, wt)) < 0) + return error; + if (!error) return 1; if (git_buf_joinpath(&path, wt->gitdir_path, "locked") < 0) @@ -454,22 +464,25 @@ int git_worktree_unlock(git_worktree *wt) int git_worktree_is_locked(git_buf *reason, const git_worktree *wt) { git_buf path = GIT_BUF_INIT; - int ret; + int error, locked; assert(wt); if (reason) git_buf_clear(reason); - if ((ret = git_buf_joinpath(&path, wt->gitdir_path, "locked")) < 0) + if ((error = git_buf_joinpath(&path, wt->gitdir_path, "locked")) < 0) + goto out; + locked = git_path_exists(path.ptr); + if (locked && reason && + (error = git_futils_readbuffer(reason, path.ptr)) < 0) goto out; - if ((ret = git_path_exists(path.ptr)) && reason) - git_futils_readbuffer(reason, path.ptr); + error = locked; out: git_buf_dispose(&path); - return ret; + return error; } const char *git_worktree_name(const git_worktree *wt) @@ -502,7 +515,6 @@ int git_worktree_pruneinit_options(git_worktree_prune_options *opts, int git_worktree_is_prunable(git_worktree *wt, git_worktree_prune_options *opts) { - git_buf reason = GIT_BUF_INIT; git_worktree_prune_options popts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; GIT_ERROR_CHECK_VERSION( @@ -512,20 +524,24 @@ int git_worktree_is_prunable(git_worktree *wt, if (opts) memcpy(&popts, opts, sizeof(popts)); - if ((popts.flags & GIT_WORKTREE_PRUNE_LOCKED) == 0 && - git_worktree_is_locked(&reason, wt)) - { - if (!reason.size) - git_buf_attach_notowned(&reason, "no reason given", 15); - git_error_set(GIT_ERROR_WORKTREE, "not pruning locked working tree: '%s'", reason.ptr); - git_buf_dispose(&reason); + if ((popts.flags & GIT_WORKTREE_PRUNE_LOCKED) == 0) { + git_buf reason = GIT_BUF_INIT; + int error; - return 0; + if ((error = git_worktree_is_locked(&reason, wt)) < 0) + return error; + + if (error) { + if (!reason.size) + git_buf_attach_notowned(&reason, "no reason given", 15); + git_error_set(GIT_ERROR_WORKTREE, "not pruning locked working tree: '%s'", reason.ptr); + git_buf_dispose(&reason); + return 0; + } } if ((popts.flags & GIT_WORKTREE_PRUNE_VALID) == 0 && - git_worktree_validate(wt) == 0) - { + git_worktree_validate(wt) == 0) { git_error_set(GIT_ERROR_WORKTREE, "not pruning valid working tree"); return 0; } diff --git a/tests/blame/blame_helpers.c b/tests/blame/blame_helpers.c index 61e87350c..6b3ce677d 100644 --- a/tests/blame/blame_helpers.c +++ b/tests/blame/blame_helpers.c @@ -31,13 +31,13 @@ void check_blame_hunk_index(git_repository *repo, git_blame *blame, int idx, } if (hunk->final_start_line_number != start_line) { - hunk_message(idx, hunk, "mismatched start line number: expected %d, got %d", + hunk_message(idx, hunk, "mismatched start line number: expected %"PRIuZ", got %"PRIuZ, start_line, hunk->final_start_line_number); } cl_assert_equal_i(hunk->final_start_line_number, start_line); if (hunk->lines_in_hunk != len) { - hunk_message(idx, hunk, "mismatched line count: expected %d, got %d", + hunk_message(idx, hunk, "mismatched line count: expected %"PRIuZ", got %"PRIuZ, len, hunk->lines_in_hunk); } cl_assert_equal_i(hunk->lines_in_hunk, len); diff --git a/tests/blame/blame_helpers.h b/tests/blame/blame_helpers.h index fd5a35d2c..5b34b4aef 100644 --- a/tests/blame/blame_helpers.h +++ b/tests/blame/blame_helpers.h @@ -1,7 +1,7 @@ #include "clar_libgit2.h" #include "blame.h" -void hunk_message(size_t idx, const git_blame_hunk *hunk, const char *fmt, ...); +void hunk_message(size_t idx, const git_blame_hunk *hunk, const char *fmt, ...) GIT_FORMAT_PRINTF(3, 4); void check_blame_hunk_index( git_repository *repo, diff --git a/tests/blame/buffer.c b/tests/blame/buffer.c index 340b1dced..06d5042dd 100644 --- a/tests/blame/buffer.c +++ b/tests/blame/buffer.c @@ -17,6 +17,32 @@ void test_blame_buffer__cleanup(void) git_repository_free(g_repo); } +void test_blame_buffer__index(void) +{ + const git_blame_hunk *hunk; + const char *buffer = "Hello\nWorld!"; + + /* + * We need to open a different file from the ones used in other tests. Close + * the one opened in test_blame_buffer__initialize() to avoid a leak. + */ + git_blame_free(g_fileblame); + g_fileblame = NULL; + cl_git_pass(git_blame_file(&g_fileblame, g_repo, "file.txt", NULL)); + + cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer))); + cl_assert_equal_i(2, git_blame_get_hunk_count(g_bufferblame)); + + check_blame_hunk_index(g_repo, g_bufferblame, 0, 1, 1, 0, "836bc00b", "file.txt"); + hunk = git_blame_get_hunk_byline(g_bufferblame, 1); + cl_assert(hunk); + cl_assert_equal_s("lhchavez", hunk->final_signature->name); + check_blame_hunk_index(g_repo, g_bufferblame, 1, 2, 1, 0, "00000000", "file.txt"); + hunk = git_blame_get_hunk_byline(g_bufferblame, 2); + cl_assert(hunk); + cl_assert(hunk->final_signature == NULL); +} + void test_blame_buffer__added_line(void) { const git_blame_hunk *hunk; diff --git a/tests/config/global.c b/tests/config/global.c index b64b71677..ed47d0251 100644 --- a/tests/config/global.c +++ b/tests/config/global.c @@ -81,7 +81,7 @@ void test_config_global__lock_missing_global_config(void) git_config_entry *entry; git_transaction *transaction; - p_unlink("home/.gitconfig"); /* No global config */ + (void)p_unlink("home/.gitconfig"); /* No global config */ cl_git_pass(git_config_open_default(&cfg)); cl_git_pass(git_config_lock(&transaction, cfg)); diff --git a/tests/config/new.c b/tests/config/new.c index 2f5d83d52..22c330f6f 100644 --- a/tests/config/new.c +++ b/tests/config/new.c @@ -30,5 +30,5 @@ void test_config_new__write_new_config(void) git_buf_dispose(&buf); git_config_free(config); - p_unlink(TEST_CONFIG); + cl_must_pass(p_unlink(TEST_CONFIG)); } diff --git a/tests/core/posix.c b/tests/core/posix.c index 764ca1942..1bb1e9c6b 100644 --- a/tests/core/posix.c +++ b/tests/core/posix.c @@ -190,6 +190,26 @@ void test_core_posix__symlink_resolves_to_correct_type(void) git_buf_dispose(&contents); } +void test_core_posix__relative_symlink(void) +{ + git_buf contents = GIT_BUF_INIT; + + if (!git_path_supports_symlinks(clar_sandbox_path())) + clar__skip(); + + cl_must_pass(git_futils_mkdir("dir", 0777, 0)); + cl_git_mkfile("file", "contents"); + cl_git_pass(p_symlink("../file", "dir/link")); + cl_git_pass(git_futils_readbuffer(&contents, "dir/link")); + cl_assert_equal_s(contents.ptr, "contents"); + + cl_must_pass(p_unlink("file")); + cl_must_pass(p_unlink("dir/link")); + cl_must_pass(p_rmdir("dir")); + + git_buf_dispose(&contents); +} + void test_core_posix__symlink_to_file_across_dirs(void) { git_buf contents = GIT_BUF_INIT; diff --git a/tests/diff/tree.c b/tests/diff/tree.c index 2359a834b..dfe4d254c 100644 --- a/tests/diff/tree.c +++ b/tests/diff/tree.c @@ -524,3 +524,52 @@ void test_diff_tree__diff_configs(void) cl_assert_equal_i(7, expect.line_adds); cl_assert_equal_i(15, expect.line_dels); } + +void test_diff_tree__diff_tree_with_empty_dir_entry_succeeds(void) +{ + const char *content = "This is a blob\n"; + const git_diff_delta *delta; + git_oid empty_tree, invalid_tree, blob; + git_buf patch = GIT_BUF_INIT; + git_treebuilder *builder; + + g_repo = cl_git_sandbox_init("empty_standard_repo"); + + cl_git_pass(git_blob_create_from_buffer(&blob, g_repo, content, strlen(content))); + cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL)); + cl_git_pass(git_treebuilder_write(&empty_tree, builder)); + cl_git_pass(git_treebuilder_insert(NULL, builder, "empty_tree", &empty_tree, GIT_FILEMODE_TREE)); + cl_git_pass(git_treebuilder_insert(NULL, builder, "blob", &blob, GIT_FILEMODE_BLOB)); + cl_git_pass(git_treebuilder_write(&invalid_tree, builder)); + + cl_git_pass(git_tree_lookup(&a, g_repo, &empty_tree)); + cl_git_pass(git_tree_lookup(&b, g_repo, &invalid_tree)); + cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL)); + + cl_git_pass(git_diff_foreach(diff, + diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expect)); + cl_assert_equal_i(1, expect.files); + cl_assert_equal_i(0, expect.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(1, expect.hunks); + cl_assert_equal_i(1, expect.lines); + cl_assert_equal_i(0, expect.line_ctxt); + cl_assert_equal_i(1, expect.line_adds); + cl_assert_equal_i(0, expect.line_dels); + + cl_git_pass(git_diff_to_buf(&patch, diff, GIT_DIFF_FORMAT_PATCH)); + cl_assert_equal_s(patch.ptr, + "diff --git a/blob b/blob\n" + "new file mode 100644\n" + "index 0000000..bbf2e80\n" + "--- /dev/null\n" + "+++ b/blob\n" + "@@ -0,0 +1 @@\n" + "+This is a blob\n"); + + cl_assert_equal_i(git_diff_num_deltas(diff), 1); + delta = git_diff_get_delta(diff, 0); + cl_assert_equal_s(delta->new_file.path, "blob"); + + git_treebuilder_free(builder); + git_buf_dispose(&patch); +} diff --git a/tests/diff/workdir.c b/tests/diff/workdir.c index 8b0445214..71b2e91a7 100644 --- a/tests/diff/workdir.c +++ b/tests/diff/workdir.c @@ -2160,3 +2160,46 @@ void test_diff_workdir__symlink_changed_on_non_symlink_platform(void) git_tree_free(tree); git_vector_free(&pathlist); } + +void test_diff_workdir__order(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_buf patch = GIT_BUF_INIT; + git_oid tree_oid, blob_oid; + git_treebuilder *builder; + git_tree *tree; + git_diff *diff; + + g_repo = cl_git_sandbox_init("empty_standard_repo"); + + /* Build tree with a single file "abc.txt" */ + cl_git_pass(git_blob_create_from_buffer(&blob_oid, g_repo, "foo\n", 4)); + cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL)); + cl_git_pass(git_treebuilder_insert(NULL, builder, "abc.txt", &blob_oid, GIT_FILEMODE_BLOB)); + cl_git_pass(git_treebuilder_write(&tree_oid, builder)); + cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_oid)); + + /* Create a directory that sorts before and one that sorts after "abc.txt" */ + cl_git_mkfile("empty_standard_repo/abc.txt", "bar\n"); + cl_must_pass(p_mkdir("empty_standard_repo/abb", 0777)); + cl_must_pass(p_mkdir("empty_standard_repo/abd", 0777)); + + opts.flags = GIT_DIFF_INCLUDE_UNTRACKED; + cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &opts)); + + cl_assert_equal_i(1, git_diff_num_deltas(diff)); + cl_git_pass(git_diff_to_buf(&patch, diff, GIT_DIFF_FORMAT_PATCH)); + cl_assert_equal_s(patch.ptr, + "diff --git a/abc.txt b/abc.txt\n" + "index 257cc56..5716ca5 100644\n" + "--- a/abc.txt\n" + "+++ b/abc.txt\n" + "@@ -1 +1 @@\n" + "-foo\n" + "+bar\n"); + + git_treebuilder_free(builder); + git_buf_dispose(&patch); + git_diff_free(diff); + git_tree_free(tree); +} diff --git a/tests/ignore/path.c b/tests/ignore/path.c index 864fba41b..e23ac7712 100644 --- a/tests/ignore/path.c +++ b/tests/ignore/path.c @@ -255,7 +255,7 @@ void test_ignore_path__globs_without_star(void) void test_ignore_path__skip_gitignore_directory(void) { cl_git_rewritefile("attr/.git/info/exclude", "/NewFolder\n/NewFolder/NewFolder"); - p_unlink("attr/.gitignore"); + cl_must_pass(p_unlink("attr/.gitignore")); cl_assert(!git_path_exists("attr/.gitignore")); p_mkdir("attr/.gitignore", 0777); cl_git_mkfile("attr/.gitignore/garbage.txt", "new_file\n"); @@ -268,12 +268,11 @@ void test_ignore_path__skip_gitignore_directory(void) void test_ignore_path__subdirectory_gitignore(void) { - p_unlink("attr/.gitignore"); + cl_must_pass(p_unlink("attr/.gitignore")); cl_assert(!git_path_exists("attr/.gitignore")); cl_git_mkfile( "attr/.gitignore", "file1\n"); - p_mkdir("attr/dir", 0777); cl_git_mkfile( "attr/dir/.gitignore", "file2/\n"); diff --git a/tests/index/nsec.c b/tests/index/nsec.c index dee1509e1..6edcf030a 100644 --- a/tests/index/nsec.c +++ b/tests/index/nsec.c @@ -54,7 +54,7 @@ static bool should_expect_nsecs(void) expect = try_create_file_with_nsec_timestamp(nsec_path.ptr); - p_unlink(nsec_path.ptr); + cl_must_pass(p_unlink(nsec_path.ptr)); git_buf_dispose(&nsec_path); diff --git a/tests/index/tests.c b/tests/index/tests.c index 4c9deaaba..d9d8371dd 100644 --- a/tests/index/tests.c +++ b/tests/index/tests.c @@ -566,8 +566,7 @@ void test_index_tests__cannot_add_invalid_filename(void) { git_repository *repo; - p_mkdir("invalid", 0700); - + cl_must_pass(p_mkdir("invalid", 0700)); cl_git_pass(git_repository_init(&repo, "./invalid", 0)); cl_must_pass(p_mkdir("./invalid/subdir", 0777)); diff --git a/tests/network/refspecs.c b/tests/network/refspecs.c index 734759060..5c8eb1502 100644 --- a/tests/network/refspecs.c +++ b/tests/network/refspecs.c @@ -153,7 +153,7 @@ static void assert_invalid_rtransform(const char *refspec, const char *name) git_refspec spec; git_buf buf = GIT_BUF_INIT; - git_refspec__parse(&spec, refspec, true); + cl_git_pass(git_refspec__parse(&spec, refspec, true)); cl_git_fail(git_refspec_rtransform(&buf, &spec, name)); git_buf_dispose(&buf); diff --git a/tests/notes/notes.c b/tests/notes/notes.c index f2457665c..af9686790 100644 --- a/tests/notes/notes.c +++ b/tests/notes/notes.c @@ -400,15 +400,11 @@ void test_notes_notes__can_read_a_note_from_a_commit(void) git_note *note; cl_git_pass(git_oid_fromstr(&oid, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045")); - cl_git_pass(git_note_commit_create(¬es_commit_oid, NULL, _repo, NULL, _sig, _sig, &oid, "I decorate 4a20\n", 1)); - - git_commit_lookup(¬es_commit, _repo, ¬es_commit_oid); - + cl_git_pass(git_commit_lookup(¬es_commit, _repo, ¬es_commit_oid)); cl_assert(notes_commit); cl_git_pass(git_note_commit_read(¬e, _repo, notes_commit, &oid)); - cl_assert_equal_s(git_note_message(note), "I decorate 4a20\n"); git_commit_free(notes_commit); @@ -457,7 +453,7 @@ void test_notes_notes__can_insert_a_note_in_an_existing_fanout(void) git_note *_note; cl_git_pass(git_oid_fromstr(&target_oid, "08b041783f40edfe12bb406c9c9a8a040177c125")); - + for (i = 0; i < MESSAGES_COUNT; i++) { cl_git_pass(git_note_create(¬e_oid, _repo, "refs/notes/fanout", _sig, _sig, &target_oid, messages[i], 0)); cl_git_pass(git_note_read(&_note, _repo, "refs/notes/fanout", &target_oid)); @@ -511,7 +507,7 @@ void test_notes_notes__can_remove_a_note_from_commit(void) cl_git_pass(git_note_commit_create(¬es_commit_oid, NULL, _repo, NULL, _sig, _sig, &oid, "I decorate 4a20\n", 0)); - git_commit_lookup(&existing_notes_commit, _repo, ¬es_commit_oid); + cl_git_pass(git_commit_lookup(&existing_notes_commit, _repo, ¬es_commit_oid)); cl_assert(existing_notes_commit); @@ -547,7 +543,7 @@ void test_notes_notes__removing_a_note_which_doesnt_exists_returns_ENOTFOUND(voi cl_git_pass(git_oid_fromstr(&target_oid, "8496071c1b46c854b31185ea97743be6a8774479")); cl_git_pass(git_note_remove(_repo, "refs/notes/fanout", _sig, _sig, &target_oid)); - + error = git_note_remove(_repo, "refs/notes/fanout", _sig, _sig, &target_oid); cl_git_fail(error); cl_assert_equal_i(GIT_ENOTFOUND, error); diff --git a/tests/object/cache.c b/tests/object/cache.c index 3ccc325e4..08bf03648 100644 --- a/tests/object/cache.c +++ b/tests/object/cache.c @@ -244,15 +244,15 @@ static void *cache_quick(void *arg) void test_object_cache__fast_thread_rush(void) { - int try, th, data[THREADCOUNT*2]; + int try, th, data[THREADCOUNT]; #ifdef GIT_THREADS - git_thread t[THREADCOUNT*2]; + git_thread t[THREADCOUNT]; #endif for (try = 0; try < REPEAT; ++try) { cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); - for (th = 0; th < THREADCOUNT*2; ++th) { + for (th = 0; th < THREADCOUNT; ++th) { data[th] = th; #ifdef GIT_THREADS cl_git_pass( @@ -263,7 +263,7 @@ void test_object_cache__fast_thread_rush(void) } #ifdef GIT_THREADS - for (th = 0; th < THREADCOUNT*2; ++th) { + for (th = 0; th < THREADCOUNT; ++th) { void *rval; cl_git_pass(git_thread_join(&t[th], &rval)); cl_assert_equal_i(th, *((int *)rval)); diff --git a/tests/patch/patch_common.h b/tests/patch/patch_common.h index 731524767..1e03889fc 100644 --- a/tests/patch/patch_common.h +++ b/tests/patch/patch_common.h @@ -579,6 +579,14 @@ "rename from file.txt\n" \ "rename to newfile.txt\n" +#define PATCH_RENAME_EXACT_WITH_MODE \ + "diff --git a/RENAMED.md b/README.md\n" \ + "old mode 100644\n" \ + "new mode 100755\n" \ + "similarity index 100%\n" \ + "rename from RENAMED.md\n" \ + "rename to README.md\n" + #define PATCH_RENAME_SIMILAR \ "diff --git a/file.txt b/newfile.txt\n" \ "similarity index 77%\n" \ diff --git a/tests/patch/print.c b/tests/patch/print.c index c4ff479e9..b0a933943 100644 --- a/tests/patch/print.c +++ b/tests/patch/print.c @@ -107,6 +107,12 @@ void test_patch_print__rename_exact(void) strlen(PATCH_RENAME_EXACT)); } +void test_patch_print__rename_exact_with_mode(void) +{ + patch_print_from_patchfile(PATCH_RENAME_EXACT_WITH_MODE, + strlen(PATCH_RENAME_EXACT_WITH_MODE)); +} + void test_patch_print__rename_similar(void) { patch_print_from_patchfile(PATCH_RENAME_SIMILAR, diff --git a/tests/path/win32.c b/tests/path/win32.c index 3ed7d7a6a..b416e9e60 100644 --- a/tests/path/win32.c +++ b/tests/path/win32.c @@ -21,6 +21,21 @@ void test_utf8_to_utf16(const char *utf8_in, const wchar_t *utf16_expected) #endif } +void test_utf8_to_utf16_relative(const char* utf8_in, const wchar_t* utf16_expected) +{ +#ifdef GIT_WIN32 + git_win32_path path_utf16; + int path_utf16len; + + cl_assert((path_utf16len = git_win32_path_relative_from_utf8(path_utf16, utf8_in)) >= 0); + cl_assert_equal_wcs(utf16_expected, path_utf16); + cl_assert_equal_i(wcslen(utf16_expected), path_utf16len); +#else + GIT_UNUSED(utf8_in); + GIT_UNUSED(utf16_expected); +#endif +} + void test_path_win32__utf8_to_utf16(void) { #ifdef GIT_WIN32 @@ -129,6 +144,31 @@ void test_path_win32__absolute_from_relative(void) #endif } +void test_path_win32__keeps_relative(void) +{ +#ifdef GIT_WIN32 + /* Relative paths stay relative */ + test_utf8_to_utf16_relative("Foo", L"Foo"); + test_utf8_to_utf16_relative("..\\..\\Foo", L"..\\..\\Foo"); + test_utf8_to_utf16_relative("Foo\\..", L"Foo\\.."); + test_utf8_to_utf16_relative("Foo\\..\\..", L"Foo\\..\\.."); + test_utf8_to_utf16_relative("Foo\\Bar", L"Foo\\Bar"); + test_utf8_to_utf16_relative("Foo\\..\\Bar", L"Foo\\..\\Bar"); + test_utf8_to_utf16_relative("../../Foo", L"..\\..\\Foo"); + test_utf8_to_utf16_relative("Foo/..", L"Foo\\.."); + test_utf8_to_utf16_relative("Foo/../..", L"Foo\\..\\.."); + test_utf8_to_utf16_relative("Foo/Bar", L"Foo\\Bar"); + test_utf8_to_utf16_relative("Foo/../Bar", L"Foo\\..\\Bar"); + test_utf8_to_utf16_relative("Foo/../Bar/", L"Foo\\..\\Bar\\"); + test_utf8_to_utf16_relative("", L""); + + /* Absolute paths are canonicalized */ + test_utf8_to_utf16_relative("\\Foo", L"\\\\?\\C:\\Foo"); + test_utf8_to_utf16_relative("/Foo/Bar/", L"\\\\?\\C:\\Foo\\Bar"); + test_utf8_to_utf16_relative("\\\\server\\c$\\unc\\path", L"\\\\?\\UNC\\server\\c$\\unc\\path"); +#endif +} + #ifdef GIT_WIN32 static void test_canonicalize(const wchar_t *in, const wchar_t *expected) { @@ -203,16 +243,6 @@ void test_path_win32__canonicalize(void) test_canonicalize(L"C:/Foo/Bar", L"C:\\Foo\\Bar"); test_canonicalize(L"C:/", L"C:\\"); - test_canonicalize(L"Foo\\\\Bar\\\\Asdf\\\\", L"Foo\\Bar\\Asdf"); - test_canonicalize(L"Foo\\\\Bar\\\\..\\\\Asdf\\", L"Foo\\Asdf"); - test_canonicalize(L"Foo\\\\Bar\\\\.\\\\Asdf\\", L"Foo\\Bar\\Asdf"); - test_canonicalize(L"Foo\\\\..\\Bar\\\\.\\\\Asdf\\", L"Bar\\Asdf"); - test_canonicalize(L"\\", L""); - test_canonicalize(L"", L""); - test_canonicalize(L"Foo\\..\\..\\..\\..", L""); - test_canonicalize(L"..\\..\\..\\..", L""); - test_canonicalize(L"\\..\\..\\..\\..", L""); - test_canonicalize(L"\\\\?\\C:\\Foo\\Bar", L"\\\\?\\C:\\Foo\\Bar"); test_canonicalize(L"\\\\?\\C:\\Foo\\Bar\\", L"\\\\?\\C:\\Foo\\Bar"); test_canonicalize(L"\\\\?\\C:\\\\Foo\\.\\Bar\\\\..\\", L"\\\\?\\C:\\Foo"); diff --git a/tests/resources/blametest.git/objects/83/6bc00b06cb60eb0f629e237ad2b58adb2cfc7e b/tests/resources/blametest.git/objects/83/6bc00b06cb60eb0f629e237ad2b58adb2cfc7e new file mode 100644 index 000000000..71f9c980e --- /dev/null +++ b/tests/resources/blametest.git/objects/83/6bc00b06cb60eb0f629e237ad2b58adb2cfc7e @@ -0,0 +1,3 @@ +xK +1D]B$OD{{:OգAyu"RA41f/]UϲȣX +MȖ,sFc8S[}⩼壏78pO.%fZua\uJF
\ No newline at end of file diff --git a/tests/resources/blametest.git/objects/a8/ba8436b5d8ccbdfd5be597c194e7bb8e0a092f b/tests/resources/blametest.git/objects/a8/ba8436b5d8ccbdfd5be597c194e7bb8e0a092f new file mode 100644 index 000000000..0bab0ef53 --- /dev/null +++ b/tests/resources/blametest.git/objects/a8/ba8436b5d8ccbdfd5be597c194e7bb8e0a092f @@ -0,0 +1 @@ +x+)JMU04`040031QH+(aٵJ5Ѕ'3P%0 }_ՉΓE{4٩r -3'槚^uU'ݘanP55?p9_$*\9
\ No newline at end of file diff --git a/tests/resources/blametest.git/objects/f9/264f7fbd31ae7a18b7931ed8946fb0aebb0af3 b/tests/resources/blametest.git/objects/f9/264f7fbd31ae7a18b7931ed8946fb0aebb0af3 Binary files differnew file mode 100644 index 000000000..942a7eedc --- /dev/null +++ b/tests/resources/blametest.git/objects/f9/264f7fbd31ae7a18b7931ed8946fb0aebb0af3 diff --git a/tests/resources/blametest.git/refs/heads/master b/tests/resources/blametest.git/refs/heads/master index d1bc4ca6b..994877a20 100644 --- a/tests/resources/blametest.git/refs/heads/master +++ b/tests/resources/blametest.git/refs/heads/master @@ -1 +1 @@ -6653ff42313eb5c82806f145391b18a9699800c7 +836bc00b06cb60eb0f629e237ad2b58adb2cfc7e |