mirror of
https://github.com/git-for-windows/git.git
synced 2026-06-27 22:28:38 -05:00
Merge branch 'ready-for-upstream'
This is the branch thicket of patches in Git for Windows that are considered ready for upstream. To keep them in a ready-to-submit shape, they are kept as close to the beginning of the branch thicket as possible.
This commit is contained in:
committed by
Git for Windows Build Agent
commit
127ed08af6
2
.github/workflows/check-style.yml
vendored
2
.github/workflows/check-style.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
jobname: ClangFormat
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
2
.github/workflows/check-whitespace.yml
vendored
2
.github/workflows/check-whitespace.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
check-whitespace:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
3
.github/workflows/coverity.yml
vendored
3
.github/workflows/coverity.yml
vendored
@@ -37,8 +37,9 @@ jobs:
|
||||
COVERITY_PROJECT: ${{ vars.COVERITY_PROJECT || 'git' }}
|
||||
COVERITY_LANGUAGE: cxx
|
||||
COVERITY_PLATFORM: overridden-below
|
||||
NO_RUST: Yup
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- name: install minimal Git for Windows SDK
|
||||
if: contains(matrix.os, 'windows')
|
||||
uses: git-for-windows/setup-git-for-windows-sdk@v2
|
||||
|
||||
43
.github/workflows/main.yml
vendored
43
.github/workflows/main.yml
vendored
@@ -112,7 +112,7 @@ jobs:
|
||||
group: windows-build-${{ github.ref }}
|
||||
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- uses: git-for-windows/setup-git-for-windows-sdk@v2
|
||||
- name: build
|
||||
shell: bash
|
||||
@@ -169,14 +169,17 @@ jobs:
|
||||
NO_PERL: 1
|
||||
GIT_CONFIG_PARAMETERS: "'user.name=CI' 'user.email=ci@git'"
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x64, arm64]
|
||||
concurrency:
|
||||
group: vs-build-${{ github.ref }}
|
||||
group: vs-build-${{ github.ref }}-${{ matrix.arch }}
|
||||
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- uses: git-for-windows/setup-git-for-windows-sdk@v2
|
||||
- name: initialize vcpkg
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
repository: 'microsoft/vcpkg'
|
||||
path: 'compat/vcbuild/vcpkg'
|
||||
@@ -189,14 +192,16 @@ jobs:
|
||||
uses: microsoft/setup-msbuild@v3
|
||||
- name: copy dlls to root
|
||||
shell: cmd
|
||||
run: compat\vcbuild\vcpkg_copy_dlls.bat release
|
||||
run: compat\vcbuild\vcpkg_copy_dlls.bat release ${{ matrix.arch }}-windows
|
||||
- name: generate Visual Studio solution
|
||||
shell: bash
|
||||
run: |
|
||||
cmake `pwd`/contrib/buildsystems/ -DCMAKE_PREFIX_PATH=`pwd`/compat/vcbuild/vcpkg/installed/x64-windows \
|
||||
-DNO_GETTEXT=YesPlease -DPERL_TESTS=OFF -DPYTHON_TESTS=OFF -DCURL_NO_CURL_CMAKE=ON
|
||||
cmake `pwd`/contrib/buildsystems/ -DCMAKE_PREFIX_PATH=`pwd`/compat/vcbuild/vcpkg/installed/${{ matrix.arch }}-windows \
|
||||
-DNO_GETTEXT=YesPlease -DPERL_TESTS=OFF -DPYTHON_TESTS=OFF -DCURL_NO_CURL_CMAKE=ON -DCMAKE_GENERATOR_PLATFORM=${{ matrix.arch }} -DVCPKG_ARCH=${{ matrix.arch }}-windows -DHOST_CPU=${{ matrix.arch }}
|
||||
- name: MSBuild
|
||||
run: msbuild git.sln -property:Configuration=Release -property:Platform=x64 -maxCpuCount:4 -property:PlatformToolset=v142
|
||||
run: |
|
||||
$sln = if (Test-Path git.slnx) { 'git.slnx' } else { 'git.sln' }
|
||||
msbuild $sln -property:Configuration=Release -property:Platform=${{ matrix.arch }} -maxCpuCount:4
|
||||
- name: bundle artifact tar
|
||||
shell: bash
|
||||
env:
|
||||
@@ -210,7 +215,7 @@ jobs:
|
||||
- name: upload tracked files and build artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: vs-artifacts
|
||||
name: vs-artifacts-${{ matrix.arch }}
|
||||
path: artifacts
|
||||
vs-test:
|
||||
name: win+VS test
|
||||
@@ -228,7 +233,7 @@ jobs:
|
||||
- name: download tracked files and build artifacts
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: vs-artifacts
|
||||
name: vs-artifacts-x64
|
||||
path: ${{github.workspace}}
|
||||
- name: extract tracked files and build artifacts
|
||||
shell: bash
|
||||
@@ -258,7 +263,7 @@ jobs:
|
||||
group: windows-meson-build-${{ github.ref }}
|
||||
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-python@v6
|
||||
- name: Set up dependencies
|
||||
shell: pwsh
|
||||
@@ -286,7 +291,7 @@ jobs:
|
||||
group: windows-meson-test-${{ matrix.nr }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-python@v6
|
||||
- name: Set up dependencies
|
||||
shell: pwsh
|
||||
@@ -341,7 +346,7 @@ jobs:
|
||||
TEST_OUTPUT_DIRECTORY: ${{github.workspace}}/t
|
||||
runs-on: ${{matrix.vector.pool}}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- run: ci/install-dependencies.sh
|
||||
- run: ci/run-build-and-tests.sh
|
||||
- name: print test failures
|
||||
@@ -362,7 +367,7 @@ jobs:
|
||||
CI_JOB_IMAGE: ubuntu-latest
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- run: ci/install-dependencies.sh
|
||||
- run: ci/run-build-and-minimal-fuzzers.sh
|
||||
dockerized:
|
||||
@@ -441,7 +446,7 @@ jobs:
|
||||
else
|
||||
apt-get -q update && apt-get -q -y install git
|
||||
fi
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- run: ci/install-dependencies.sh
|
||||
- run: useradd builder --create-home
|
||||
- run: chown -R builder .
|
||||
@@ -466,7 +471,7 @@ jobs:
|
||||
group: static-analysis-${{ github.ref }}
|
||||
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- run: ci/install-dependencies.sh
|
||||
- run: ci/run-static-analysis.sh
|
||||
- run: ci/check-directional-formatting.bash
|
||||
@@ -482,7 +487,7 @@ jobs:
|
||||
group: rust-analysis-${{ github.ref }}
|
||||
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- run: ci/install-dependencies.sh
|
||||
- run: ci/run-rust-checks.sh
|
||||
sparse:
|
||||
@@ -496,7 +501,7 @@ jobs:
|
||||
group: sparse-${{ github.ref }}
|
||||
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- name: Install other dependencies
|
||||
run: ci/install-dependencies.sh
|
||||
- run: make sparse
|
||||
@@ -512,6 +517,6 @@ jobs:
|
||||
CI_JOB_IMAGE: ubuntu-latest
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- run: ci/install-dependencies.sh
|
||||
- run: ci/test-documentation.sh
|
||||
|
||||
76
.github/workflows/nano-server.yml
vendored
Normal file
76
.github/workflows/nano-server.yml
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
name: Windows Nano Server tests
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
DEVELOPER: 1
|
||||
|
||||
jobs:
|
||||
test-nano-server:
|
||||
runs-on: windows-2022
|
||||
env:
|
||||
WINDBG_DIR: "C:/Program Files (x86)/Windows Kits/10/Debuggers/x64"
|
||||
IMAGE: mcr.microsoft.com/powershell:nanoserver-ltsc2022
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: git-for-windows/setup-git-for-windows-sdk@v2
|
||||
- name: build Git
|
||||
shell: bash
|
||||
run: make -j15
|
||||
- name: pull nanoserver image
|
||||
shell: bash
|
||||
run: docker pull $IMAGE
|
||||
- name: run nano-server test
|
||||
shell: bash
|
||||
run: |
|
||||
docker run \
|
||||
--user "ContainerAdministrator" \
|
||||
-v "$WINDBG_DIR:C:/dbg" \
|
||||
-v "$(cygpath -aw /mingw64/bin):C:/mingw64-bin" \
|
||||
-v "$(cygpath -aw .):C:/test" \
|
||||
$IMAGE pwsh.exe -Command '
|
||||
# Extend the PATH to include the `.dll` files in /mingw64/bin/
|
||||
$env:PATH += ";C:\mingw64-bin"
|
||||
|
||||
# For each executable to test pick some no-operation set of
|
||||
# flags/subcommands or something that should quickly result in an
|
||||
# error with known exit code that is not a negative 32-bit
|
||||
# number, and set the expected return code appropriately.
|
||||
#
|
||||
# Only test executables that could be expected to run in a UI
|
||||
# less environment.
|
||||
#
|
||||
# ( Executable path, arguments, expected return code )
|
||||
# also note space is required before close parenthesis (a
|
||||
# powershell quirk when defining nested arrays like this)
|
||||
|
||||
$executables_to_test = @(
|
||||
("C:\test\git.exe", "", 1 ),
|
||||
("C:\test\scalar.exe", "version", 0 )
|
||||
)
|
||||
|
||||
foreach ($executable in $executables_to_test)
|
||||
{
|
||||
Write-Output "Now testing $($executable[0])"
|
||||
&$executable[0] $executable[1]
|
||||
if ($LASTEXITCODE -ne $executable[2]) {
|
||||
# if we failed, run the debugger to find out what function
|
||||
# or DLL could not be found and then exit the script with
|
||||
# failure The missing DLL or EXE will be referenced near
|
||||
# the end of the output
|
||||
|
||||
# Set a flag to have the debugger show loader stub
|
||||
# diagnostics. This requires running as administrator,
|
||||
# otherwise the flag will be ignored.
|
||||
C:\dbg\gflags -i $executable[0] +SLS
|
||||
|
||||
C:\dbg\cdb.exe -c "g" -c "q" $executable[0] $executable[1]
|
||||
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
exit 0
|
||||
'
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -172,6 +172,7 @@
|
||||
/git-submodule
|
||||
/git-submodule--helper
|
||||
/git-subtree
|
||||
/git-survey
|
||||
/git-svn
|
||||
/git-switch
|
||||
/git-symbolic-ref
|
||||
@@ -259,5 +260,6 @@ Release/
|
||||
/git.VC.db
|
||||
*.dSYM
|
||||
/contrib/buildsystems/out
|
||||
CMakeSettings.json
|
||||
/contrib/libgit-rs/target
|
||||
/contrib/libgit-sys/target
|
||||
|
||||
@@ -523,6 +523,8 @@ include::config/safe.adoc[]
|
||||
|
||||
include::config/sendemail.adoc[]
|
||||
|
||||
include::config/sendpack.adoc[]
|
||||
|
||||
include::config/sequencer.adoc[]
|
||||
|
||||
include::config/showbranch.adoc[]
|
||||
@@ -541,6 +543,8 @@ include::config/status.adoc[]
|
||||
|
||||
include::config/submodule.adoc[]
|
||||
|
||||
include::config/survey.adoc[]
|
||||
|
||||
include::config/tag.adoc[]
|
||||
|
||||
include::config/tar.adoc[]
|
||||
@@ -563,4 +567,6 @@ include::config/versionsort.adoc[]
|
||||
|
||||
include::config/web.adoc[]
|
||||
|
||||
include::config/windows.adoc[]
|
||||
|
||||
include::config/worktree.adoc[]
|
||||
|
||||
@@ -788,3 +788,9 @@ core.maxTreeDepth::
|
||||
to allow Git to abort cleanly, and should not generally need to
|
||||
be adjusted. When Git is compiled with MSVC, the default is 512.
|
||||
Otherwise, the default is 2048.
|
||||
|
||||
core.WSLCompat::
|
||||
Tells Git whether to enable wsl compatibility mode.
|
||||
The default value is false. When set to true, Git will set the mode
|
||||
bits of the file in the way of wsl, so that the executable flag of
|
||||
files can be set or read correctly.
|
||||
|
||||
@@ -242,13 +242,20 @@ http.sslKeyType::
|
||||
See also libcurl `CURLOPT_SSLKEYTYPE`. Can be overridden by the
|
||||
`GIT_SSL_KEY_TYPE` environment variable.
|
||||
|
||||
http.allowNTLMAuth::
|
||||
Whether or not to allow NTLM authentication. While very convenient to set
|
||||
up, and therefore still used in many on-prem scenarios, NTLM is a weak
|
||||
authentication method and therefore deprecated. Defaults to "false".
|
||||
|
||||
http.schannelCheckRevoke::
|
||||
Used to enforce or disable certificate revocation checks in cURL
|
||||
when http.sslBackend is set to "schannel". Defaults to `true` if
|
||||
unset. Only necessary to disable this if Git consistently errors
|
||||
and the message is about checking the revocation status of a
|
||||
certificate. This option is ignored if cURL lacks support for
|
||||
setting the relevant SSL option at runtime.
|
||||
when http.sslBackend is set to "schannel" via "true" and "false",
|
||||
respectively. Another accepted value is "best-effort" (the default)
|
||||
in which case revocation checks are performed, but errors due to
|
||||
revocation list distribution points that are offline are silently
|
||||
ignored, as well as errors due to certificates missing revocation
|
||||
list distribution points. This option is ignored if cURL lacks
|
||||
support for setting the relevant SSL option at runtime.
|
||||
|
||||
http.schannelUseSSLCAInfo::
|
||||
As of cURL v7.60.0, the Secure Channel backend can use the
|
||||
@@ -258,6 +265,11 @@ http.schannelUseSSLCAInfo::
|
||||
when the `schannel` backend was configured via `http.sslBackend`,
|
||||
unless `http.schannelUseSSLCAInfo` overrides this behavior.
|
||||
|
||||
http.sslAutoClientCert::
|
||||
As of cURL v7.77.0, the Secure Channel backend won't automatically
|
||||
send client certificates from the Windows Certificate Store anymore.
|
||||
To opt in to the old behavior, http.sslAutoClientCert can be set.
|
||||
|
||||
http.pinnedPubkey::
|
||||
Public key of the https service. It may either be the filename of
|
||||
a PEM or DER encoded public key file or a string starting with
|
||||
|
||||
5
Documentation/config/sendpack.adoc
Normal file
5
Documentation/config/sendpack.adoc
Normal file
@@ -0,0 +1,5 @@
|
||||
sendpack.sideband::
|
||||
Allows to disable the side-band-64k capability for send-pack even
|
||||
when it is advertised by the server. Makes it possible to work
|
||||
around a limitation in the git for windows implementation together
|
||||
with the dump git protocol. Defaults to true.
|
||||
14
Documentation/config/survey.adoc
Normal file
14
Documentation/config/survey.adoc
Normal file
@@ -0,0 +1,14 @@
|
||||
survey.*::
|
||||
These variables adjust the default behavior of the `git survey`
|
||||
command. The intention is that this command could be run in the
|
||||
background with these options.
|
||||
+
|
||||
--
|
||||
verbose::
|
||||
This boolean value implies the `--[no-]verbose` option.
|
||||
progress::
|
||||
This boolean value implies the `--[no-]progress` option.
|
||||
top::
|
||||
This integer value implies `--top=<N>`, specifying the
|
||||
number of entries in the detail tables.
|
||||
--
|
||||
4
Documentation/config/windows.adoc
Normal file
4
Documentation/config/windows.adoc
Normal file
@@ -0,0 +1,4 @@
|
||||
windows.appendAtomically::
|
||||
By default, append atomic API is used on windows. But it works only with
|
||||
local disk files, if you're working on a network file system, you should
|
||||
set it false to turn it off.
|
||||
83
Documentation/git-survey.adoc
Normal file
83
Documentation/git-survey.adoc
Normal file
@@ -0,0 +1,83 @@
|
||||
git-survey(1)
|
||||
=============
|
||||
|
||||
NAME
|
||||
----
|
||||
git-survey - EXPERIMENTAL: Measure various repository dimensions of scale
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
(EXPERIMENTAL!) 'git survey' <options>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
Survey the repository and measure various dimensions of scale.
|
||||
|
||||
As repositories grow to "monorepo" size, certain data shapes can cause
|
||||
performance problems. `git-survey` attempts to measure and report on
|
||||
known problem areas.
|
||||
|
||||
Ref Selection and Reachable Objects
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In this first analysis phase, `git survey` will iterate over the set of
|
||||
requested branches, tags, and other refs and treewalk over all of the
|
||||
reachable commits, trees, and blobs and generate various statistics.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
--progress::
|
||||
Show progress. This is automatically enabled when interactive.
|
||||
|
||||
Ref Selection
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
The following options control the set of refs that `git survey` will examine.
|
||||
By default, `git survey` will look at tags, local branches, and remote refs.
|
||||
If any of the following options are given, the default set is cleared and
|
||||
only refs for the given options are added.
|
||||
|
||||
--all-refs::
|
||||
Use all refs. This includes local branches, tags, remote refs,
|
||||
notes, and stashes. This option overrides all of the following.
|
||||
|
||||
--branches::
|
||||
Add local branches (`refs/heads/`) to the set.
|
||||
|
||||
--tags::
|
||||
Add tags (`refs/tags/`) to the set.
|
||||
|
||||
--remotes::
|
||||
Add remote branches (`refs/remote/`) to the set.
|
||||
|
||||
--detached::
|
||||
Add HEAD to the set.
|
||||
|
||||
--other::
|
||||
Add notes (`refs/notes/`) and stashes (`refs/stash/`) to the set.
|
||||
|
||||
OUTPUT
|
||||
------
|
||||
|
||||
By default, `git survey` will print information about the repository in a
|
||||
human-readable format that includes overviews and tables.
|
||||
|
||||
References Summary
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The references summary includes a count of each kind of reference,
|
||||
including branches, remote refs, and tags (split by "all" and
|
||||
"annotated").
|
||||
|
||||
Reachable Object Summary
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The reachable object summary shows the total number of each kind of Git
|
||||
object, including tags, commits, trees, and blobs.
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the linkgit:git[1] suite
|
||||
@@ -403,6 +403,36 @@ sign `$` upon checkout. Any byte sequence that begins with
|
||||
with `$Id$` upon check-in.
|
||||
|
||||
|
||||
`symlink`
|
||||
^^^^^^^^^
|
||||
|
||||
On Windows, symbolic links have a type: a "file symlink" must point at
|
||||
a file, and a "directory symlink" must point at a directory. If the
|
||||
type of symlink does not match its target, it doesn't work.
|
||||
|
||||
Git does not record the type of symlink in the index or in a tree. On
|
||||
checkout it'll guess the type, which only works if the target exists
|
||||
at the time the symlink is created. This may often not be the case,
|
||||
for example when the link points at a directory inside a submodule.
|
||||
|
||||
The `symlink` attribute allows you to explicitly set the type of symlink
|
||||
to `file` or `dir`, so Git doesn't have to guess. If you have a set of
|
||||
symlinks that point at other files, you can do:
|
||||
|
||||
------------------------
|
||||
*.gif symlink=file
|
||||
------------------------
|
||||
|
||||
To tell Git that a symlink points at a directory, use:
|
||||
|
||||
------------------------
|
||||
tools_folder symlink=dir
|
||||
------------------------
|
||||
|
||||
The `symlink` attribute is ignored on platforms other than Windows,
|
||||
since they don't distinguish between different types of symlinks.
|
||||
|
||||
|
||||
`filter`
|
||||
^^^^^^^^
|
||||
|
||||
|
||||
@@ -145,6 +145,7 @@ manpages = {
|
||||
'git-status.adoc' : 1,
|
||||
'git-stripspace.adoc' : 1,
|
||||
'git-submodule.adoc' : 1,
|
||||
'git-survey.adoc' : 1,
|
||||
'git-svn.adoc' : 1,
|
||||
'git-switch.adoc' : 1,
|
||||
'git-symbolic-ref.adoc' : 1,
|
||||
|
||||
37
Makefile
37
Makefile
@@ -479,6 +479,11 @@ include shared.mak
|
||||
#
|
||||
# CURL_LDFLAGS=-lcurl
|
||||
#
|
||||
# Define LAZYLOAD_LIBCURL to dynamically load the libcurl; This can be useful
|
||||
# if Multiple libcurl versions exist (with different file names) that link to
|
||||
# various SSL/TLS backends, to support the `http.sslBackend` runtime switch in
|
||||
# such a scenario.
|
||||
#
|
||||
# === Optional library: libpcre2 ===
|
||||
#
|
||||
# Define USE_LIBPCRE if you have and want to use libpcre. Various
|
||||
@@ -1489,6 +1494,7 @@ BUILTIN_OBJS += builtin/sparse-checkout.o
|
||||
BUILTIN_OBJS += builtin/stash.o
|
||||
BUILTIN_OBJS += builtin/stripspace.o
|
||||
BUILTIN_OBJS += builtin/submodule--helper.o
|
||||
BUILTIN_OBJS += builtin/survey.o
|
||||
BUILTIN_OBJS += builtin/symbolic-ref.o
|
||||
BUILTIN_OBJS += builtin/tag.o
|
||||
BUILTIN_OBJS += builtin/unpack-file.o
|
||||
@@ -1528,6 +1534,7 @@ CLAR_TEST_SUITES += u-hash
|
||||
CLAR_TEST_SUITES += u-hashmap
|
||||
CLAR_TEST_SUITES += u-list-objects-filter-options
|
||||
CLAR_TEST_SUITES += u-mem-pool
|
||||
CLAR_TEST_SUITES += u-mingw
|
||||
CLAR_TEST_SUITES += u-odb-inmemory
|
||||
CLAR_TEST_SUITES += u-oid-array
|
||||
CLAR_TEST_SUITES += u-oidmap
|
||||
@@ -1790,10 +1797,23 @@ else
|
||||
CURL_LIBCURL =
|
||||
endif
|
||||
|
||||
ifndef CURL_LDFLAGS
|
||||
CURL_LDFLAGS = $(eval CURL_LDFLAGS := $$(shell $$(CURL_CONFIG) --libs))$(CURL_LDFLAGS)
|
||||
ifdef LAZYLOAD_LIBCURL
|
||||
LAZYLOAD_LIBCURL_OBJ = compat/lazyload-curl.o
|
||||
OBJECTS += $(LAZYLOAD_LIBCURL_OBJ)
|
||||
# The `CURL_STATICLIB` constant must be defined to avoid seeing the functions
|
||||
# declared as DLL imports
|
||||
CURL_CFLAGS = -DCURL_STATICLIB
|
||||
ifneq ($(uname_S),MINGW)
|
||||
ifneq ($(uname_S),Windows)
|
||||
CURL_LIBCURL = -ldl
|
||||
endif
|
||||
endif
|
||||
else
|
||||
ifndef CURL_LDFLAGS
|
||||
CURL_LDFLAGS = $(eval CURL_LDFLAGS := $$(shell $$(CURL_CONFIG) --libs))$(CURL_LDFLAGS)
|
||||
endif
|
||||
CURL_LIBCURL += $(CURL_LDFLAGS)
|
||||
endif
|
||||
CURL_LIBCURL += $(CURL_LDFLAGS)
|
||||
|
||||
ifndef CURL_CFLAGS
|
||||
CURL_CFLAGS = $(eval CURL_CFLAGS := $$(shell $$(CURL_CONFIG) --cflags))$(CURL_CFLAGS)
|
||||
@@ -1814,7 +1834,7 @@ else
|
||||
endif
|
||||
ifdef USE_CURL_FOR_IMAP_SEND
|
||||
BASIC_CFLAGS += -DUSE_CURL_FOR_IMAP_SEND
|
||||
IMAP_SEND_BUILDDEPS = http.o
|
||||
IMAP_SEND_BUILDDEPS = http.o $(LAZYLOAD_LIBCURL_OBJ)
|
||||
IMAP_SEND_LDFLAGS += $(CURL_LIBCURL)
|
||||
endif
|
||||
ifndef NO_EXPAT
|
||||
@@ -2993,10 +3013,10 @@ git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)
|
||||
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
|
||||
$(IMAP_SEND_LDFLAGS) $(LIBS)
|
||||
|
||||
git-http-fetch$X: http.o http-walker.o http-fetch.o GIT-LDFLAGS $(GITLIBS)
|
||||
git-http-fetch$X: http.o http-walker.o http-fetch.o $(LAZYLOAD_LIBCURL_OBJ) GIT-LDFLAGS $(GITLIBS)
|
||||
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
|
||||
$(CURL_LIBCURL) $(LIBS)
|
||||
git-http-push$X: http.o http-push.o GIT-LDFLAGS $(GITLIBS)
|
||||
git-http-push$X: http.o http-push.o $(LAZYLOAD_LIBCURL_OBJ) GIT-LDFLAGS $(GITLIBS)
|
||||
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
|
||||
$(CURL_LIBCURL) $(EXPAT_LIBEXPAT) $(LIBS)
|
||||
|
||||
@@ -3006,7 +3026,7 @@ $(REMOTE_CURL_ALIASES): $(REMOTE_CURL_PRIMARY)
|
||||
ln -s $< $@ 2>/dev/null || \
|
||||
cp $< $@
|
||||
|
||||
$(REMOTE_CURL_PRIMARY): remote-curl.o http.o http-walker.o GIT-LDFLAGS $(GITLIBS)
|
||||
$(REMOTE_CURL_PRIMARY): remote-curl.o http.o http-walker.o $(LAZYLOAD_LIBCURL_OBJ) GIT-LDFLAGS $(GITLIBS)
|
||||
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
|
||||
$(CURL_LIBCURL) $(EXPAT_LIBEXPAT) $(LIBS)
|
||||
|
||||
@@ -3901,12 +3921,15 @@ ifdef MSVC
|
||||
$(RM) $(patsubst %.o,%.o.pdb,$(OBJECTS))
|
||||
$(RM) headless-git.o.pdb
|
||||
$(RM) $(patsubst %.exe,%.pdb,$(OTHER_PROGRAMS))
|
||||
$(RM) $(patsubst %.exe,%.ilk,$(OTHER_PROGRAMS))
|
||||
$(RM) $(patsubst %.exe,%.iobj,$(OTHER_PROGRAMS))
|
||||
$(RM) $(patsubst %.exe,%.ipdb,$(OTHER_PROGRAMS))
|
||||
$(RM) $(patsubst %.exe,%.pdb,$(PROGRAMS))
|
||||
$(RM) $(patsubst %.exe,%.ilk,$(PROGRAMS))
|
||||
$(RM) $(patsubst %.exe,%.iobj,$(PROGRAMS))
|
||||
$(RM) $(patsubst %.exe,%.ipdb,$(PROGRAMS))
|
||||
$(RM) $(patsubst %.exe,%.pdb,$(TEST_PROGRAMS))
|
||||
$(RM) $(patsubst %.exe,%.ilk,$(TEST_PROGRAMS))
|
||||
$(RM) $(patsubst %.exe,%.iobj,$(TEST_PROGRAMS))
|
||||
$(RM) $(patsubst %.exe,%.ipdb,$(TEST_PROGRAMS))
|
||||
$(RM) compat/vcbuild/MSVC-DEFS-GEN
|
||||
|
||||
@@ -93,6 +93,9 @@ static char *strbuf_realpath_1(struct strbuf *resolved, const char *path,
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
if (platform_strbuf_realpath(resolved, path))
|
||||
return resolved->buf;
|
||||
|
||||
strbuf_addstr(&remaining, path);
|
||||
get_root_part(resolved, &remaining);
|
||||
|
||||
|
||||
2
apply.c
2
apply.c
@@ -4515,7 +4515,7 @@ static int try_create_file(struct apply_state *state, const char *path,
|
||||
/* Although buf:size is counted string, it also is NUL
|
||||
* terminated.
|
||||
*/
|
||||
return !!symlink(buf, path);
|
||||
return !!create_symlink(state && state->repo ? state->repo->index : NULL, buf, path);
|
||||
|
||||
fd = open(path, O_CREAT | O_EXCL | O_WRONLY, (mode & 0100) ? 0777 : 0666);
|
||||
if (fd < 0)
|
||||
|
||||
@@ -206,7 +206,7 @@ static void *zlib_deflate_raw(void *data, unsigned long size,
|
||||
unsigned long *compressed_size)
|
||||
{
|
||||
git_zstream stream;
|
||||
unsigned long maxsize;
|
||||
size_t maxsize;
|
||||
void *buffer;
|
||||
int result;
|
||||
|
||||
|
||||
2
attr.c
2
attr.c
@@ -793,7 +793,7 @@ static struct attr_stack *read_attr_from_index(struct index_state *istate,
|
||||
{
|
||||
struct attr_stack *stack = NULL;
|
||||
char *buf;
|
||||
unsigned long size;
|
||||
size_t size;
|
||||
int sparse_dir_pos = -1;
|
||||
|
||||
if (!istate)
|
||||
|
||||
21
blame.c
21
blame.c
@@ -238,7 +238,7 @@ static struct commit *fake_working_tree_commit(struct repository *r,
|
||||
struct stat st;
|
||||
const char *read_from;
|
||||
char *buf_ptr;
|
||||
unsigned long buf_len;
|
||||
size_t buf_len;
|
||||
|
||||
if (contents_from) {
|
||||
if (stat(contents_from, &st) < 0)
|
||||
@@ -335,7 +335,7 @@ static const char *get_next_line(const char *start, const char *end)
|
||||
}
|
||||
|
||||
static int find_line_starts(int **line_starts, const char *buf,
|
||||
unsigned long len)
|
||||
size_t len)
|
||||
{
|
||||
const char *end = buf + len;
|
||||
const char *p;
|
||||
@@ -1034,20 +1034,17 @@ static void fill_origin_blob(struct diff_options *opt,
|
||||
{
|
||||
if (!o->file.ptr) {
|
||||
enum object_type type;
|
||||
unsigned long file_size;
|
||||
size_t file_size;
|
||||
|
||||
(*num_read_blob)++;
|
||||
if (opt->flags.allow_textconv &&
|
||||
textconv_object(opt->repo, o->path, o->mode,
|
||||
&o->blob_oid, 1, &file->ptr, &file_size))
|
||||
;
|
||||
else {
|
||||
size_t file_size_st = 0;
|
||||
else
|
||||
file->ptr = odb_read_object(the_repository->objects,
|
||||
&o->blob_oid, &type,
|
||||
&file_size_st);
|
||||
file_size = cast_size_t_to_ulong(file_size_st);
|
||||
}
|
||||
&file_size);
|
||||
file->size = file_size;
|
||||
|
||||
if (!file->ptr)
|
||||
@@ -2872,14 +2869,10 @@ void setup_scoreboard(struct blame_scoreboard *sb,
|
||||
textconv_object(sb->repo, sb->path, o->mode, &o->blob_oid, 1, (char **) &sb->final_buf,
|
||||
&sb->final_buf_size))
|
||||
;
|
||||
else {
|
||||
size_t final_buf_size_st = 0;
|
||||
else
|
||||
sb->final_buf = odb_read_object(the_repository->objects,
|
||||
&o->blob_oid, &type,
|
||||
&final_buf_size_st);
|
||||
sb->final_buf_size =
|
||||
cast_size_t_to_ulong(final_buf_size_st);
|
||||
}
|
||||
&sb->final_buf_size);
|
||||
|
||||
if (!sb->final_buf)
|
||||
die(_("cannot read blob %s for path %s"),
|
||||
|
||||
2
blame.h
2
blame.h
@@ -117,7 +117,7 @@ struct blame_scoreboard {
|
||||
* indexed with scoreboard.lineno[blame_entry.lno].
|
||||
*/
|
||||
char *final_buf;
|
||||
unsigned long final_buf_size;
|
||||
size_t final_buf_size;
|
||||
|
||||
/* linked list of blames */
|
||||
struct blame_entry *ent;
|
||||
|
||||
@@ -260,6 +260,7 @@ int cmd_sparse_checkout(int argc, const char **argv, const char *prefix, struct
|
||||
int cmd_status(int argc, const char **argv, const char *prefix, struct repository *repo);
|
||||
int cmd_stash(int argc, const char **argv, const char *prefix, struct repository *repo);
|
||||
int cmd_stripspace(int argc, const char **argv, const char *prefix, struct repository *repo);
|
||||
int cmd_survey(int argc, const char **argv, const char *prefix, struct repository *repo);
|
||||
int cmd_submodule__helper(int argc, const char **argv, const char *prefix, struct repository *repo);
|
||||
int cmd_switch(int argc, const char **argv, const char *prefix, struct repository *repo);
|
||||
int cmd_symbolic_ref(int argc, const char **argv, const char *prefix, struct repository *repo);
|
||||
|
||||
@@ -186,11 +186,9 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
|
||||
|
||||
case 'c':
|
||||
{
|
||||
unsigned long size_ul = 0;
|
||||
int textconv_ret = textconv_object(the_repository, path,
|
||||
obj_context.mode, &oid, 1,
|
||||
&buf, &size_ul);
|
||||
size = size_ul;
|
||||
&buf, &size);
|
||||
if (textconv_ret)
|
||||
break;
|
||||
}
|
||||
@@ -413,12 +411,9 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
|
||||
oid_to_hex(oid), data->rest);
|
||||
} else if (opt->transform_mode == 'c') {
|
||||
enum object_type type;
|
||||
unsigned long size_ul = 0;
|
||||
if (textconv_object(the_repository,
|
||||
data->rest, 0100644, oid,
|
||||
1, &contents, &size_ul))
|
||||
size = size_ul;
|
||||
else
|
||||
if (!textconv_object(the_repository,
|
||||
data->rest, 0100644, oid,
|
||||
1, &contents, &size))
|
||||
contents = odb_read_object(the_repository->objects,
|
||||
oid, &type, &size);
|
||||
if (!contents)
|
||||
|
||||
@@ -41,6 +41,10 @@ static const char *msg_remove = N_("Removing %s\n");
|
||||
static const char *msg_would_remove = N_("Would remove %s\n");
|
||||
static const char *msg_skip_git_dir = N_("Skipping repository %s\n");
|
||||
static const char *msg_would_skip_git_dir = N_("Would skip repository %s\n");
|
||||
#ifndef CAN_UNLINK_MOUNT_POINTS
|
||||
static const char *msg_skip_mount_point = N_("Skipping mount point %s\n");
|
||||
static const char *msg_would_skip_mount_point = N_("Would skip mount point %s\n");
|
||||
#endif
|
||||
static const char *msg_warn_remove_failed = N_("failed to remove %s");
|
||||
static const char *msg_warn_lstat_failed = N_("could not lstat %s\n");
|
||||
static const char *msg_skip_cwd = N_("Refusing to remove current working directory\n");
|
||||
@@ -185,6 +189,29 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (is_mount_point(path)) {
|
||||
#ifndef CAN_UNLINK_MOUNT_POINTS
|
||||
if (!quiet) {
|
||||
quote_path(path->buf, prefix, "ed, 0);
|
||||
printf(dry_run ?
|
||||
_(msg_would_skip_mount_point) :
|
||||
_(msg_skip_mount_point), quoted.buf);
|
||||
}
|
||||
*dir_gone = 0;
|
||||
#else
|
||||
if (!dry_run && unlink(path->buf)) {
|
||||
int saved_errno = errno;
|
||||
quote_path(path->buf, prefix, "ed, 0);
|
||||
errno = saved_errno;
|
||||
warning_errno(_(msg_warn_remove_failed), quoted.buf);
|
||||
*dir_gone = 0;
|
||||
ret = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
dir = opendir(path->buf);
|
||||
if (!dir) {
|
||||
/* an empty dir could be removed even if it is unreadble */
|
||||
|
||||
@@ -23,7 +23,7 @@ static int connection_closed(int error)
|
||||
|
||||
static int connection_fatally_broken(int error)
|
||||
{
|
||||
return (error != ENOENT) && (error != ENETDOWN);
|
||||
return (error != ENOENT) && (error != ENETDOWN) && (error != ECONNREFUSED);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
@@ -544,7 +544,7 @@ static int run_dir_diff(struct repository *repo,
|
||||
}
|
||||
add_path(&wtdir, wtdir_len, dst_path);
|
||||
if (dt_options->symlinks) {
|
||||
if (symlink(wtdir.buf, rdir.buf)) {
|
||||
if (create_symlink(lstate.istate, wtdir.buf, rdir.buf)) {
|
||||
ret = error_errno("could not symlink '%s' to '%s'", wtdir.buf, rdir.buf);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ static void show_progress(void)
|
||||
* There's no need to cache this result with anonymize_mem, since
|
||||
* we already handle blob content caching with marks.
|
||||
*/
|
||||
static char *anonymize_blob(unsigned long *size)
|
||||
static char *anonymize_blob(size_t *size)
|
||||
{
|
||||
static int counter;
|
||||
struct strbuf out = STRBUF_INIT;
|
||||
@@ -296,7 +296,7 @@ static char *anonymize_blob(unsigned long *size)
|
||||
|
||||
static void export_blob(const struct object_id *oid)
|
||||
{
|
||||
unsigned long size;
|
||||
size_t size;
|
||||
enum object_type type;
|
||||
char *buf;
|
||||
struct object *object;
|
||||
@@ -317,10 +317,8 @@ static void export_blob(const struct object_id *oid)
|
||||
object = (struct object *)lookup_blob(the_repository, oid);
|
||||
eaten = 0;
|
||||
} else {
|
||||
size_t size_st = 0;
|
||||
buf = odb_read_object(the_repository->objects, oid, &type,
|
||||
&size_st);
|
||||
size = cast_size_t_to_ulong(size_st);
|
||||
&size);
|
||||
if (!buf)
|
||||
die(_("could not read blob %s"), oid_to_hex(oid));
|
||||
if (check_object_signature(the_repository, oid, buf, size,
|
||||
|
||||
@@ -962,7 +962,7 @@ static int store_object(
|
||||
struct object_entry *e;
|
||||
unsigned char hdr[96];
|
||||
struct object_id oid;
|
||||
unsigned long hdrlen, deltalen;
|
||||
size_t hdrlen, deltalen;
|
||||
struct git_hash_ctx c;
|
||||
git_zstream s;
|
||||
struct repo_config_values *cfg = repo_config_values(the_repository);
|
||||
@@ -998,7 +998,6 @@ static int store_object(
|
||||
|
||||
if (last && last->data.len && last->data.buf && last->depth < max_depth
|
||||
&& dat->len > the_hash_algo->rawsz) {
|
||||
|
||||
delta_count_attempts_by_type[type]++;
|
||||
delta = diff_delta(last->data.buf, last->data.len,
|
||||
dat->buf, dat->len,
|
||||
@@ -1238,10 +1237,9 @@ out:
|
||||
*/
|
||||
static void *gfi_unpack_entry(
|
||||
struct object_entry *oe,
|
||||
unsigned long *sizep)
|
||||
size_t *sizep)
|
||||
{
|
||||
enum object_type type;
|
||||
size_t size_st = 0;
|
||||
void *data;
|
||||
struct packed_git *p = all_packs[oe->pack_id];
|
||||
if (p == pack_data && p->pack_size < (pack_size + the_hash_algo->rawsz)) {
|
||||
@@ -1264,9 +1262,7 @@ static void *gfi_unpack_entry(
|
||||
*/
|
||||
p->pack_size = pack_size + the_hash_algo->rawsz;
|
||||
}
|
||||
data = unpack_entry(the_repository, p, oe->idx.offset, &type, &size_st);
|
||||
if (sizep)
|
||||
*sizep = cast_size_t_to_ulong(size_st);
|
||||
data = unpack_entry(the_repository, p, oe->idx.offset, &type, sizep);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -1275,7 +1271,7 @@ static void load_tree(struct tree_entry *root)
|
||||
struct object_id *oid = &root->versions[1].oid;
|
||||
struct object_entry *myoe;
|
||||
struct tree_content *t;
|
||||
unsigned long size;
|
||||
size_t size;
|
||||
char *buf;
|
||||
const char *c;
|
||||
|
||||
@@ -1293,10 +1289,8 @@ static void load_tree(struct tree_entry *root)
|
||||
die(_("can't load tree %s"), oid_to_hex(oid));
|
||||
} else {
|
||||
enum object_type type;
|
||||
size_t size_st = 0;
|
||||
buf = odb_read_object(the_repository->objects, oid, &type,
|
||||
&size_st);
|
||||
size = cast_size_t_to_ulong(size_st);
|
||||
&size);
|
||||
if (!buf || type != OBJ_TREE)
|
||||
die(_("can't load tree %s"), oid_to_hex(oid));
|
||||
}
|
||||
@@ -2614,7 +2608,7 @@ static void file_change_deleteall(struct branch *b)
|
||||
b->num_notes = 0;
|
||||
}
|
||||
|
||||
static void parse_from_commit(struct branch *b, char *buf, unsigned long size)
|
||||
static void parse_from_commit(struct branch *b, char *buf, size_t size)
|
||||
{
|
||||
if (!buf || size < the_hash_algo->hexsz + 6)
|
||||
die(_("not a valid commit: %s"), oid_to_hex(&b->oid));
|
||||
@@ -2631,13 +2625,11 @@ static void parse_from_existing(struct branch *b)
|
||||
oidclr(&b->branch_tree.versions[0].oid, the_repository->hash_algo);
|
||||
oidclr(&b->branch_tree.versions[1].oid, the_repository->hash_algo);
|
||||
} else {
|
||||
unsigned long size;
|
||||
size_t size_st = 0;
|
||||
size_t size;
|
||||
char *buf;
|
||||
|
||||
buf = odb_read_object_peeled(the_repository->objects, &b->oid,
|
||||
OBJ_COMMIT, &size_st, &b->oid);
|
||||
size = cast_size_t_to_ulong(size_st);
|
||||
OBJ_COMMIT, &size, &b->oid);
|
||||
parse_from_commit(b, buf, size);
|
||||
free(buf);
|
||||
}
|
||||
@@ -2666,7 +2658,7 @@ static int parse_objectish(struct branch *b, const char *objectish)
|
||||
if (!oideq(&b->oid, &oe->idx.oid)) {
|
||||
oidcpy(&b->oid, &oe->idx.oid);
|
||||
if (oe->pack_id != MAX_PACK_ID) {
|
||||
unsigned long size;
|
||||
size_t size;
|
||||
char *buf = gfi_unpack_entry(oe, &size);
|
||||
parse_from_commit(b, buf, size);
|
||||
free(buf);
|
||||
@@ -3332,15 +3324,13 @@ static void cat_blob_write(const char *buf, unsigned long size)
|
||||
static void cat_blob(struct object_entry *oe, struct object_id *oid)
|
||||
{
|
||||
struct strbuf line = STRBUF_INIT;
|
||||
unsigned long size;
|
||||
size_t size;
|
||||
enum object_type type = 0;
|
||||
char *buf;
|
||||
|
||||
if (!oe || oe->pack_id == MAX_PACK_ID) {
|
||||
size_t size_st = 0;
|
||||
buf = odb_read_object(the_repository->objects, oid, &type,
|
||||
&size_st);
|
||||
size = cast_size_t_to_ulong(size_st);
|
||||
&size);
|
||||
} else {
|
||||
type = oe->type;
|
||||
buf = gfi_unpack_entry(oe, &size);
|
||||
@@ -3419,7 +3409,7 @@ static void parse_cat_blob(const char *p)
|
||||
static struct object_entry *dereference(struct object_entry *oe,
|
||||
struct object_id *oid)
|
||||
{
|
||||
unsigned long size;
|
||||
size_t size;
|
||||
char *buf = NULL;
|
||||
const unsigned hexsz = the_hash_algo->hexsz;
|
||||
|
||||
@@ -3448,10 +3438,8 @@ static struct object_entry *dereference(struct object_entry *oe,
|
||||
buf = gfi_unpack_entry(oe, &size);
|
||||
} else {
|
||||
enum object_type unused;
|
||||
size_t size_st = 0;
|
||||
buf = odb_read_object(the_repository->objects, oid,
|
||||
&unused, &size_st);
|
||||
size = cast_size_t_to_ulong(size_st);
|
||||
&unused, &size);
|
||||
}
|
||||
if (!buf)
|
||||
die(_("can't load object %s"), oid_to_hex(oid));
|
||||
|
||||
@@ -584,7 +584,7 @@ static int show_blob_object(const struct object_id *oid, struct rev_info *rev, c
|
||||
struct object_id oidc;
|
||||
struct object_context obj_context = {0};
|
||||
char *buf;
|
||||
unsigned long size;
|
||||
size_t size;
|
||||
|
||||
fflush(rev->diffopt.file);
|
||||
if (!rev->diffopt.flags.textconv_set_via_cmdline ||
|
||||
|
||||
@@ -260,8 +260,8 @@ static int exclude_promisor_objects_best_effort;
|
||||
|
||||
static int use_delta_islands;
|
||||
|
||||
static unsigned long delta_cache_size = 0;
|
||||
static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
|
||||
static size_t delta_cache_size = 0;
|
||||
static size_t max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
|
||||
static unsigned long cache_max_small_delta_size = 1000;
|
||||
|
||||
static unsigned long window_memory_limit = 0;
|
||||
@@ -353,20 +353,17 @@ static void index_commit_for_bitmap(struct commit *commit)
|
||||
|
||||
static void *get_delta(struct object_entry *entry)
|
||||
{
|
||||
unsigned long size, base_size, delta_size;
|
||||
size_t size, base_size, delta_size;
|
||||
void *buf, *base_buf, *delta_buf;
|
||||
enum object_type type;
|
||||
size_t size_st = 0, base_size_st = 0;
|
||||
|
||||
buf = odb_read_object(the_repository->objects, &entry->idx.oid,
|
||||
&type, &size_st);
|
||||
size = cast_size_t_to_ulong(size_st);
|
||||
&type, &size);
|
||||
if (!buf)
|
||||
die(_("unable to read %s"), oid_to_hex(&entry->idx.oid));
|
||||
base_buf = odb_read_object(the_repository->objects,
|
||||
&DELTA(entry)->idx.oid, &type,
|
||||
&base_size_st);
|
||||
base_size = cast_size_t_to_ulong(base_size_st);
|
||||
&base_size);
|
||||
if (!base_buf)
|
||||
die("unable to read %s",
|
||||
oid_to_hex(&DELTA(entry)->idx.oid));
|
||||
@@ -384,11 +381,11 @@ static void *get_delta(struct object_entry *entry)
|
||||
return delta_buf;
|
||||
}
|
||||
|
||||
static unsigned long do_compress(void **pptr, unsigned long size)
|
||||
static size_t do_compress(void **pptr, size_t size)
|
||||
{
|
||||
git_zstream stream;
|
||||
void *in, *out;
|
||||
unsigned long maxsize;
|
||||
size_t maxsize;
|
||||
struct repo_config_values *cfg = repo_config_values(the_repository);
|
||||
|
||||
git_deflate_init(&stream, cfg->pack_compression_level);
|
||||
@@ -487,7 +484,7 @@ static void copy_pack_data(struct hashfile *f,
|
||||
off_t len)
|
||||
{
|
||||
unsigned char *in;
|
||||
unsigned long avail;
|
||||
size_t avail;
|
||||
|
||||
while (len) {
|
||||
in = use_pack(p, w_curs, offset, &avail);
|
||||
@@ -514,7 +511,7 @@ static inline int oe_size_greater_than(struct packing_data *pack,
|
||||
static unsigned long write_no_reuse_object(struct hashfile *f, struct object_entry *entry,
|
||||
unsigned long limit, int usable_delta)
|
||||
{
|
||||
unsigned long size, datalen;
|
||||
size_t size, datalen;
|
||||
unsigned char header[MAX_PACK_OBJECT_HEADER],
|
||||
dheader[MAX_PACK_OBJECT_HEADER];
|
||||
unsigned hdrlen;
|
||||
@@ -533,11 +530,9 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent
|
||||
type = st->type;
|
||||
size = st->size;
|
||||
} else {
|
||||
size_t size_st = 0;
|
||||
buf = odb_read_object(the_repository->objects,
|
||||
&entry->idx.oid, &type,
|
||||
&size_st);
|
||||
size = cast_size_t_to_ulong(size_st);
|
||||
&size);
|
||||
if (!buf)
|
||||
die(_("unable to read %s"),
|
||||
oid_to_hex(&entry->idx.oid));
|
||||
@@ -1916,7 +1911,7 @@ struct pbase_tree_cache {
|
||||
int ref;
|
||||
int temporary;
|
||||
void *tree_data;
|
||||
unsigned long tree_size;
|
||||
size_t tree_size;
|
||||
};
|
||||
|
||||
static struct pbase_tree_cache *(pbase_tree_cache[256]);
|
||||
@@ -1943,8 +1938,7 @@ static struct pbase_tree_cache *pbase_tree_get(const struct object_id *oid)
|
||||
{
|
||||
struct pbase_tree_cache *ent, *nent;
|
||||
void *data;
|
||||
unsigned long size;
|
||||
size_t size_st = 0;
|
||||
size_t size;
|
||||
enum object_type type;
|
||||
int neigh;
|
||||
int my_ix = pbase_tree_cache_ix(oid);
|
||||
@@ -1972,8 +1966,7 @@ static struct pbase_tree_cache *pbase_tree_get(const struct object_id *oid)
|
||||
/* Did not find one. Either we got a bogus request or
|
||||
* we need to read and perhaps cache.
|
||||
*/
|
||||
data = odb_read_object(the_repository->objects, oid, &type, &size_st);
|
||||
size = cast_size_t_to_ulong(size_st);
|
||||
data = odb_read_object(the_repository->objects, oid, &type, &size);
|
||||
if (!data)
|
||||
return NULL;
|
||||
if (type != OBJ_TREE) {
|
||||
@@ -2127,16 +2120,14 @@ static void add_preferred_base(struct object_id *oid)
|
||||
{
|
||||
struct pbase_tree *it;
|
||||
void *data;
|
||||
unsigned long size;
|
||||
size_t size_st = 0;
|
||||
size_t size;
|
||||
struct object_id tree_oid;
|
||||
|
||||
if (window <= num_preferred_base++)
|
||||
return;
|
||||
|
||||
data = odb_read_object_peeled(the_repository->objects, oid,
|
||||
OBJ_TREE, &size_st, &tree_oid);
|
||||
size = cast_size_t_to_ulong(size_st);
|
||||
OBJ_TREE, &size, &tree_oid);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
@@ -2259,7 +2250,7 @@ static void check_object(struct object_entry *entry, uint32_t object_index)
|
||||
struct object_id base_ref;
|
||||
struct object_entry *base_entry;
|
||||
unsigned long used, used_0;
|
||||
unsigned long avail;
|
||||
size_t avail;
|
||||
off_t ofs;
|
||||
unsigned char *buf, c;
|
||||
enum object_type type;
|
||||
@@ -2687,8 +2678,8 @@ struct unpacked {
|
||||
unsigned depth;
|
||||
};
|
||||
|
||||
static int delta_cacheable(unsigned long src_size, unsigned long trg_size,
|
||||
unsigned long delta_size)
|
||||
static int delta_cacheable(size_t src_size, size_t trg_size,
|
||||
size_t delta_size)
|
||||
{
|
||||
if (max_delta_cache_size && delta_cache_size + delta_size > max_delta_cache_size)
|
||||
return 0;
|
||||
@@ -2755,8 +2746,8 @@ size_t oe_get_size_slow(struct packing_data *pack,
|
||||
struct pack_window *w_curs;
|
||||
unsigned char *buf;
|
||||
enum object_type type;
|
||||
unsigned long used, avail;
|
||||
size_t size;
|
||||
unsigned long used;
|
||||
size_t avail, size;
|
||||
|
||||
if (e->type_ != OBJ_OFS_DELTA && e->type_ != OBJ_REF_DELTA) {
|
||||
size_t sz;
|
||||
@@ -2787,11 +2778,11 @@ size_t oe_get_size_slow(struct packing_data *pack,
|
||||
}
|
||||
|
||||
static int try_delta(struct unpacked *trg, struct unpacked *src,
|
||||
unsigned max_depth, unsigned long *mem_usage)
|
||||
unsigned max_depth, size_t *mem_usage)
|
||||
{
|
||||
struct object_entry *trg_entry = trg->entry;
|
||||
struct object_entry *src_entry = src->entry;
|
||||
unsigned long trg_size, src_size, delta_size, sizediff, max_size, sz;
|
||||
size_t trg_size, src_size, delta_size, sizediff, max_size, sz;
|
||||
unsigned ref_depth;
|
||||
enum object_type type;
|
||||
void *delta_buf;
|
||||
@@ -2844,12 +2835,10 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
|
||||
|
||||
/* Load data if not already done */
|
||||
if (!trg->data) {
|
||||
size_t sz_st = 0;
|
||||
packing_data_lock(&to_pack);
|
||||
trg->data = odb_read_object(the_repository->objects,
|
||||
&trg_entry->idx.oid, &type,
|
||||
&sz_st);
|
||||
sz = cast_size_t_to_ulong(sz_st);
|
||||
&sz);
|
||||
packing_data_unlock(&to_pack);
|
||||
if (!trg->data)
|
||||
die(_("object %s cannot be read"),
|
||||
@@ -2861,12 +2850,10 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
|
||||
*mem_usage += sz;
|
||||
}
|
||||
if (!src->data) {
|
||||
size_t sz_st = 0;
|
||||
packing_data_lock(&to_pack);
|
||||
src->data = odb_read_object(the_repository->objects,
|
||||
&src_entry->idx.oid, &type,
|
||||
&sz_st);
|
||||
sz = cast_size_t_to_ulong(sz_st);
|
||||
&sz);
|
||||
packing_data_unlock(&to_pack);
|
||||
if (!src->data) {
|
||||
if (src_entry->preferred_base) {
|
||||
@@ -2955,9 +2942,9 @@ static unsigned int check_delta_limit(struct object_entry *me, unsigned int n)
|
||||
return m;
|
||||
}
|
||||
|
||||
static unsigned long free_unpacked(struct unpacked *n)
|
||||
static size_t free_unpacked(struct unpacked *n)
|
||||
{
|
||||
unsigned long freed_mem = sizeof_delta_index(n->index);
|
||||
size_t freed_mem = sizeof_delta_index(n->index);
|
||||
free_delta_index(n->index);
|
||||
n->index = NULL;
|
||||
if (n->data) {
|
||||
@@ -2974,7 +2961,7 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
|
||||
{
|
||||
uint32_t i, idx = 0, count = 0;
|
||||
struct unpacked *array;
|
||||
unsigned long mem_usage = 0;
|
||||
size_t mem_usage = 0;
|
||||
|
||||
CALLOC_ARRAY(array, window);
|
||||
|
||||
|
||||
@@ -459,7 +459,7 @@ static int create_graft(int argc, const char **argv, int force, int gentle)
|
||||
struct commit *commit;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
const char *buffer;
|
||||
unsigned long size;
|
||||
size_t size;
|
||||
|
||||
if (repo_get_oid(the_repository, old_ref, &old_oid) < 0)
|
||||
return error(_("not a valid object name: '%s'"), old_ref);
|
||||
|
||||
@@ -783,15 +783,14 @@ static int count_objects(const char *path UNUSED, struct oid_array *oids,
|
||||
|
||||
for (size_t i = 0; i < oids->nr; i++) {
|
||||
struct object_info oi = OBJECT_INFO_INIT;
|
||||
unsigned long inflated;
|
||||
size_t inflated_st = 0;
|
||||
size_t inflated;
|
||||
struct commit *commit;
|
||||
struct object *obj;
|
||||
void *content;
|
||||
off_t disk;
|
||||
int eaten;
|
||||
|
||||
oi.sizep = &inflated_st;
|
||||
oi.sizep = &inflated;
|
||||
oi.disk_sizep = &disk;
|
||||
oi.contentp = &content;
|
||||
|
||||
@@ -799,7 +798,6 @@ static int count_objects(const char *path UNUSED, struct oid_array *oids,
|
||||
OBJECT_INFO_SKIP_FETCH_OBJECT |
|
||||
OBJECT_INFO_QUICK) < 0)
|
||||
continue;
|
||||
inflated = cast_size_t_to_ulong(inflated_st);
|
||||
|
||||
obj = parse_object_buffer(the_repository, &oids->oid[i], type,
|
||||
inflated, content, &eaten);
|
||||
|
||||
@@ -2083,7 +2083,7 @@ static int write_commit_with_parents(struct repository *r,
|
||||
const char *orig_author, *orig_committer;
|
||||
char *author = NULL, *committer = NULL;
|
||||
const char *buffer;
|
||||
unsigned long bufsize;
|
||||
size_t bufsize;
|
||||
const char *p;
|
||||
struct strbuf msg = STRBUF_INIT;
|
||||
int ret = 0;
|
||||
@@ -2135,7 +2135,7 @@ static int do_import_stash(struct repository *r, const char *rev)
|
||||
struct object_id chain;
|
||||
int res = 0;
|
||||
const char *buffer = NULL;
|
||||
unsigned long bufsize;
|
||||
size_t bufsize;
|
||||
struct commit *this = NULL;
|
||||
struct commit_list *items = NULL, *cur;
|
||||
char *msg = NULL;
|
||||
|
||||
934
builtin/survey.c
Normal file
934
builtin/survey.c
Normal file
@@ -0,0 +1,934 @@
|
||||
#define USE_THE_REPOSITORY_VARIABLE
|
||||
|
||||
#include "builtin.h"
|
||||
#include "config.h"
|
||||
#include "environment.h"
|
||||
#include "hex.h"
|
||||
#include "object.h"
|
||||
#include "odb.h"
|
||||
#include "object-name.h"
|
||||
#include "parse-options.h"
|
||||
#include "path-walk.h"
|
||||
#include "progress.h"
|
||||
#include "ref-filter.h"
|
||||
#include "refs.h"
|
||||
#include "revision.h"
|
||||
#include "strbuf.h"
|
||||
#include "strvec.h"
|
||||
#include "tag.h"
|
||||
#include "trace2.h"
|
||||
#include "color.h"
|
||||
|
||||
static const char * const survey_usage[] = {
|
||||
N_("(EXPERIMENTAL!) git survey <options>"),
|
||||
NULL,
|
||||
};
|
||||
|
||||
struct survey_refs_wanted {
|
||||
int want_all_refs; /* special override */
|
||||
|
||||
int want_branches;
|
||||
int want_tags;
|
||||
int want_remotes;
|
||||
int want_detached;
|
||||
int want_other; /* see FILTER_REFS_OTHERS -- refs/notes/, refs/stash/ */
|
||||
};
|
||||
|
||||
static struct survey_refs_wanted default_ref_options = {
|
||||
.want_all_refs = 1,
|
||||
};
|
||||
|
||||
struct survey_opts {
|
||||
int verbose;
|
||||
int show_progress;
|
||||
int top_nr;
|
||||
struct survey_refs_wanted refs;
|
||||
};
|
||||
|
||||
struct survey_report_ref_summary {
|
||||
size_t refs_nr;
|
||||
size_t branches_nr;
|
||||
size_t remote_refs_nr;
|
||||
size_t tags_nr;
|
||||
size_t tags_annotated_nr;
|
||||
size_t others_nr;
|
||||
size_t unknown_nr;
|
||||
};
|
||||
|
||||
struct survey_report_object_summary {
|
||||
size_t commits_nr;
|
||||
size_t tags_nr;
|
||||
size_t trees_nr;
|
||||
size_t blobs_nr;
|
||||
};
|
||||
|
||||
/**
|
||||
* For some category given by 'label', count the number of objects
|
||||
* that match that label along with the on-disk size and the size
|
||||
* after decompressing (both with delta bases and zlib).
|
||||
*/
|
||||
struct survey_report_object_size_summary {
|
||||
char *label;
|
||||
size_t nr;
|
||||
size_t disk_size;
|
||||
size_t inflated_size;
|
||||
size_t num_missing;
|
||||
};
|
||||
|
||||
typedef int (*survey_top_cmp)(void *v1, void *v2);
|
||||
|
||||
static int cmp_by_nr(void *v1, void *v2)
|
||||
{
|
||||
struct survey_report_object_size_summary *s1 = v1;
|
||||
struct survey_report_object_size_summary *s2 = v2;
|
||||
|
||||
if (s1->nr < s2->nr)
|
||||
return -1;
|
||||
if (s1->nr > s2->nr)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmp_by_disk_size(void *v1, void *v2)
|
||||
{
|
||||
struct survey_report_object_size_summary *s1 = v1;
|
||||
struct survey_report_object_size_summary *s2 = v2;
|
||||
|
||||
if (s1->disk_size < s2->disk_size)
|
||||
return -1;
|
||||
if (s1->disk_size > s2->disk_size)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmp_by_inflated_size(void *v1, void *v2)
|
||||
{
|
||||
struct survey_report_object_size_summary *s1 = v1;
|
||||
struct survey_report_object_size_summary *s2 = v2;
|
||||
|
||||
if (s1->inflated_size < s2->inflated_size)
|
||||
return -1;
|
||||
if (s1->inflated_size > s2->inflated_size)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a list of "top" categories by some sorting function. When
|
||||
* inserting a new category, reorder the list and free the one that
|
||||
* got ejected (if any).
|
||||
*/
|
||||
struct survey_report_top_table {
|
||||
const char *name;
|
||||
survey_top_cmp cmp_fn;
|
||||
size_t nr;
|
||||
size_t alloc;
|
||||
|
||||
/**
|
||||
* 'data' stores an array of structs and must be cast into
|
||||
* the proper array type before evaluating an index.
|
||||
*/
|
||||
void *data;
|
||||
};
|
||||
|
||||
static void init_top_sizes(struct survey_report_top_table *top,
|
||||
size_t limit, const char *name,
|
||||
survey_top_cmp cmp)
|
||||
{
|
||||
struct survey_report_object_size_summary *sz_array;
|
||||
|
||||
top->name = name;
|
||||
top->cmp_fn = cmp;
|
||||
top->alloc = limit;
|
||||
top->nr = 0;
|
||||
|
||||
CALLOC_ARRAY(sz_array, limit);
|
||||
top->data = sz_array;
|
||||
}
|
||||
|
||||
MAYBE_UNUSED
|
||||
static void clear_top_sizes(struct survey_report_top_table *top)
|
||||
{
|
||||
struct survey_report_object_size_summary *sz_array = top->data;
|
||||
|
||||
for (size_t i = 0; i < top->nr; i++)
|
||||
free(sz_array[i].label);
|
||||
free(sz_array);
|
||||
}
|
||||
|
||||
static void maybe_insert_into_top_size(struct survey_report_top_table *top,
|
||||
struct survey_report_object_size_summary *summary)
|
||||
{
|
||||
struct survey_report_object_size_summary *sz_array = top->data;
|
||||
size_t pos = top->nr;
|
||||
|
||||
/* Compare against list from the bottom. */
|
||||
while (pos > 0 && top->cmp_fn(&sz_array[pos - 1], summary) < 0)
|
||||
pos--;
|
||||
|
||||
/* Not big enough! */
|
||||
if (pos >= top->alloc)
|
||||
return;
|
||||
|
||||
/* We need to shift the data. */
|
||||
if (top->nr == top->alloc)
|
||||
free(sz_array[top->nr - 1].label);
|
||||
else
|
||||
top->nr++;
|
||||
|
||||
for (size_t i = top->nr - 1; i > pos; i--)
|
||||
memcpy(&sz_array[i], &sz_array[i - 1], sizeof(*sz_array));
|
||||
|
||||
memcpy(&sz_array[pos], summary, sizeof(*summary));
|
||||
sz_array[pos].label = xstrdup(summary->label);
|
||||
}
|
||||
|
||||
/**
|
||||
* This struct contains all of the information that needs to be printed
|
||||
* at the end of the exploration of the repository and its references.
|
||||
*/
|
||||
struct survey_report {
|
||||
struct survey_report_ref_summary refs;
|
||||
struct survey_report_object_summary reachable_objects;
|
||||
|
||||
struct survey_report_object_size_summary *by_type;
|
||||
|
||||
struct survey_report_top_table *top_paths_by_count;
|
||||
struct survey_report_top_table *top_paths_by_disk;
|
||||
struct survey_report_top_table *top_paths_by_inflate;
|
||||
};
|
||||
|
||||
#define REPORT_TYPE_COMMIT 0
|
||||
#define REPORT_TYPE_TREE 1
|
||||
#define REPORT_TYPE_BLOB 2
|
||||
#define REPORT_TYPE_TAG 3
|
||||
#define REPORT_TYPE_COUNT 4
|
||||
|
||||
struct survey_context {
|
||||
struct repository *repo;
|
||||
|
||||
/* Options that control what is done. */
|
||||
struct survey_opts opts;
|
||||
|
||||
/* Info for output only. */
|
||||
struct survey_report report;
|
||||
|
||||
/*
|
||||
* The rest of the members are about enabling the activity
|
||||
* of the 'git survey' command, including ref listings, object
|
||||
* pointers, and progress.
|
||||
*/
|
||||
|
||||
struct progress *progress;
|
||||
size_t progress_nr;
|
||||
size_t progress_total;
|
||||
|
||||
struct strvec refs;
|
||||
struct ref_array ref_array;
|
||||
};
|
||||
|
||||
static void clear_survey_context(struct survey_context *ctx)
|
||||
{
|
||||
ref_array_clear(&ctx->ref_array);
|
||||
strvec_clear(&ctx->refs);
|
||||
}
|
||||
|
||||
struct survey_table {
|
||||
const char *table_name;
|
||||
struct strvec header;
|
||||
struct strvec *rows;
|
||||
size_t rows_nr;
|
||||
size_t rows_alloc;
|
||||
};
|
||||
|
||||
#define SURVEY_TABLE_INIT { \
|
||||
.header = STRVEC_INIT, \
|
||||
}
|
||||
|
||||
static void clear_table(struct survey_table *table)
|
||||
{
|
||||
strvec_clear(&table->header);
|
||||
for (size_t i = 0; i < table->rows_nr; i++)
|
||||
strvec_clear(&table->rows[i]);
|
||||
free(table->rows);
|
||||
}
|
||||
|
||||
static void insert_table_rowv(struct survey_table *table, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *arg;
|
||||
ALLOC_GROW(table->rows, table->rows_nr + 1, table->rows_alloc);
|
||||
|
||||
memset(&table->rows[table->rows_nr], 0, sizeof(struct strvec));
|
||||
|
||||
va_start(ap, table);
|
||||
while ((arg = va_arg(ap, char *)))
|
||||
strvec_push(&table->rows[table->rows_nr], arg);
|
||||
va_end(ap);
|
||||
|
||||
table->rows_nr++;
|
||||
}
|
||||
|
||||
#define SECTION_SEGMENT "========================================"
|
||||
#define SECTION_SEGMENT_LEN 40
|
||||
static const char *section_line = SECTION_SEGMENT
|
||||
SECTION_SEGMENT
|
||||
SECTION_SEGMENT
|
||||
SECTION_SEGMENT;
|
||||
static const size_t section_len = 4 * SECTION_SEGMENT_LEN;
|
||||
|
||||
static void print_table_title(const char *name, size_t *widths, size_t nr)
|
||||
{
|
||||
size_t width = 3 * (nr - 1);
|
||||
size_t min_width = strlen(name);
|
||||
|
||||
for (size_t i = 0; i < nr; i++)
|
||||
width += widths[i];
|
||||
|
||||
if (width < min_width)
|
||||
width = min_width;
|
||||
|
||||
if (width > section_len)
|
||||
width = section_len;
|
||||
|
||||
printf("\n%s\n%.*s\n", name, (int)width, section_line);
|
||||
}
|
||||
|
||||
static void print_row_plaintext(struct strvec *row, size_t *widths)
|
||||
{
|
||||
static struct strbuf line = STRBUF_INIT;
|
||||
strbuf_setlen(&line, 0);
|
||||
|
||||
for (size_t i = 0; i < row->nr; i++) {
|
||||
const char *str = row->v[i];
|
||||
size_t len = strlen(str);
|
||||
if (i)
|
||||
strbuf_add(&line, " | ", 3);
|
||||
strbuf_addchars(&line, ' ', widths[i] - len);
|
||||
strbuf_add(&line, str, len);
|
||||
}
|
||||
printf("%s\n", line.buf);
|
||||
}
|
||||
|
||||
static void print_divider_plaintext(size_t *widths, size_t nr)
|
||||
{
|
||||
static struct strbuf line = STRBUF_INIT;
|
||||
strbuf_setlen(&line, 0);
|
||||
|
||||
for (size_t i = 0; i < nr; i++) {
|
||||
if (i)
|
||||
strbuf_add(&line, "-+-", 3);
|
||||
strbuf_addchars(&line, '-', widths[i]);
|
||||
}
|
||||
printf("%s\n", line.buf);
|
||||
}
|
||||
|
||||
static void print_table_plaintext(struct survey_table *table)
|
||||
{
|
||||
size_t *column_widths;
|
||||
size_t columns_nr = table->header.nr;
|
||||
CALLOC_ARRAY(column_widths, columns_nr);
|
||||
|
||||
for (size_t i = 0; i < columns_nr; i++) {
|
||||
column_widths[i] = strlen(table->header.v[i]);
|
||||
|
||||
for (size_t j = 0; j < table->rows_nr; j++) {
|
||||
size_t rowlen = strlen(table->rows[j].v[i]);
|
||||
if (column_widths[i] < rowlen)
|
||||
column_widths[i] = rowlen;
|
||||
}
|
||||
}
|
||||
|
||||
print_table_title(table->table_name, column_widths, columns_nr);
|
||||
print_row_plaintext(&table->header, column_widths);
|
||||
print_divider_plaintext(column_widths, columns_nr);
|
||||
|
||||
for (size_t j = 0; j < table->rows_nr; j++)
|
||||
print_row_plaintext(&table->rows[j], column_widths);
|
||||
|
||||
free(column_widths);
|
||||
}
|
||||
|
||||
static void survey_report_plaintext_refs(struct survey_context *ctx)
|
||||
{
|
||||
struct survey_report_ref_summary *refs = &ctx->report.refs;
|
||||
struct survey_table table = SURVEY_TABLE_INIT;
|
||||
|
||||
table.table_name = _("REFERENCES SUMMARY");
|
||||
|
||||
strvec_push(&table.header, _("Ref Type"));
|
||||
strvec_push(&table.header, _("Count"));
|
||||
|
||||
if (ctx->opts.refs.want_all_refs || ctx->opts.refs.want_branches) {
|
||||
char *fmt = xstrfmt("%"PRIuMAX"", (uintmax_t)refs->branches_nr);
|
||||
insert_table_rowv(&table, _("Branches"), fmt, NULL);
|
||||
free(fmt);
|
||||
}
|
||||
|
||||
if (ctx->opts.refs.want_all_refs || ctx->opts.refs.want_remotes) {
|
||||
char *fmt = xstrfmt("%"PRIuMAX"", (uintmax_t)refs->remote_refs_nr);
|
||||
insert_table_rowv(&table, _("Remote refs"), fmt, NULL);
|
||||
free(fmt);
|
||||
}
|
||||
|
||||
if (ctx->opts.refs.want_all_refs || ctx->opts.refs.want_tags) {
|
||||
char *fmt = xstrfmt("%"PRIuMAX"", (uintmax_t)refs->tags_nr);
|
||||
insert_table_rowv(&table, _("Tags (all)"), fmt, NULL);
|
||||
free(fmt);
|
||||
fmt = xstrfmt("%"PRIuMAX"", (uintmax_t)refs->tags_annotated_nr);
|
||||
insert_table_rowv(&table, _("Tags (annotated)"), fmt, NULL);
|
||||
free(fmt);
|
||||
}
|
||||
|
||||
print_table_plaintext(&table);
|
||||
clear_table(&table);
|
||||
}
|
||||
|
||||
static void survey_report_plaintext_reachable_object_summary(struct survey_context *ctx)
|
||||
{
|
||||
struct survey_report_object_summary *objs = &ctx->report.reachable_objects;
|
||||
struct survey_table table = SURVEY_TABLE_INIT;
|
||||
char *fmt;
|
||||
|
||||
table.table_name = _("REACHABLE OBJECT SUMMARY");
|
||||
|
||||
strvec_push(&table.header, _("Object Type"));
|
||||
strvec_push(&table.header, _("Count"));
|
||||
|
||||
fmt = xstrfmt("%"PRIuMAX"", (uintmax_t)objs->tags_nr);
|
||||
insert_table_rowv(&table, _("Tags"), fmt, NULL);
|
||||
free(fmt);
|
||||
|
||||
fmt = xstrfmt("%"PRIuMAX"", (uintmax_t)objs->commits_nr);
|
||||
insert_table_rowv(&table, _("Commits"), fmt, NULL);
|
||||
free(fmt);
|
||||
|
||||
fmt = xstrfmt("%"PRIuMAX"", (uintmax_t)objs->trees_nr);
|
||||
insert_table_rowv(&table, _("Trees"), fmt, NULL);
|
||||
free(fmt);
|
||||
|
||||
fmt = xstrfmt("%"PRIuMAX"", (uintmax_t)objs->blobs_nr);
|
||||
insert_table_rowv(&table, _("Blobs"), fmt, NULL);
|
||||
free(fmt);
|
||||
|
||||
print_table_plaintext(&table);
|
||||
clear_table(&table);
|
||||
}
|
||||
|
||||
static void survey_report_object_sizes(const char *title,
|
||||
const char *categories,
|
||||
struct survey_report_object_size_summary *summary,
|
||||
size_t summary_nr)
|
||||
{
|
||||
struct survey_table table = SURVEY_TABLE_INIT;
|
||||
table.table_name = title;
|
||||
|
||||
strvec_push(&table.header, categories);
|
||||
strvec_push(&table.header, _("Count"));
|
||||
strvec_push(&table.header, _("Disk Size"));
|
||||
strvec_push(&table.header, _("Inflated Size"));
|
||||
|
||||
for (size_t i = 0; i < summary_nr; i++) {
|
||||
char *label_str = xstrdup(summary[i].label);
|
||||
char *nr_str = xstrfmt("%"PRIuMAX, (uintmax_t)summary[i].nr);
|
||||
char *disk_str = xstrfmt("%"PRIuMAX, (uintmax_t)summary[i].disk_size);
|
||||
char *inflate_str = xstrfmt("%"PRIuMAX, (uintmax_t)summary[i].inflated_size);
|
||||
|
||||
insert_table_rowv(&table, label_str, nr_str,
|
||||
disk_str, inflate_str, NULL);
|
||||
|
||||
free(label_str);
|
||||
free(nr_str);
|
||||
free(disk_str);
|
||||
free(inflate_str);
|
||||
}
|
||||
|
||||
print_table_plaintext(&table);
|
||||
clear_table(&table);
|
||||
}
|
||||
|
||||
static void survey_report_plaintext_sorted_size(
|
||||
struct survey_report_top_table *top)
|
||||
{
|
||||
survey_report_object_sizes(top->name, _("Path"),
|
||||
top->data, top->nr);
|
||||
}
|
||||
|
||||
static void survey_report_plaintext(struct survey_context *ctx)
|
||||
{
|
||||
printf("GIT SURVEY for \"%s\"\n", ctx->repo->worktree);
|
||||
printf("-----------------------------------------------------\n");
|
||||
survey_report_plaintext_refs(ctx);
|
||||
survey_report_plaintext_reachable_object_summary(ctx);
|
||||
survey_report_object_sizes(_("TOTAL OBJECT SIZES BY TYPE"),
|
||||
_("Object Type"),
|
||||
ctx->report.by_type,
|
||||
REPORT_TYPE_COUNT);
|
||||
|
||||
survey_report_plaintext_sorted_size(
|
||||
&ctx->report.top_paths_by_count[REPORT_TYPE_TREE]);
|
||||
survey_report_plaintext_sorted_size(
|
||||
&ctx->report.top_paths_by_count[REPORT_TYPE_BLOB]);
|
||||
|
||||
survey_report_plaintext_sorted_size(
|
||||
&ctx->report.top_paths_by_disk[REPORT_TYPE_TREE]);
|
||||
survey_report_plaintext_sorted_size(
|
||||
&ctx->report.top_paths_by_disk[REPORT_TYPE_BLOB]);
|
||||
|
||||
survey_report_plaintext_sorted_size(
|
||||
&ctx->report.top_paths_by_inflate[REPORT_TYPE_TREE]);
|
||||
survey_report_plaintext_sorted_size(
|
||||
&ctx->report.top_paths_by_inflate[REPORT_TYPE_BLOB]);
|
||||
}
|
||||
|
||||
/*
|
||||
* After parsing the command line arguments, figure out which refs we
|
||||
* should scan.
|
||||
*
|
||||
* If ANY were given in positive sense, then we ONLY include them and
|
||||
* do not use the builtin values.
|
||||
*/
|
||||
static void fixup_refs_wanted(struct survey_context *ctx)
|
||||
{
|
||||
struct survey_refs_wanted *rw = &ctx->opts.refs;
|
||||
|
||||
/*
|
||||
* `--all-refs` overrides and enables everything.
|
||||
*/
|
||||
if (rw->want_all_refs == 1) {
|
||||
rw->want_branches = 1;
|
||||
rw->want_tags = 1;
|
||||
rw->want_remotes = 1;
|
||||
rw->want_detached = 1;
|
||||
rw->want_other = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If none of the `--<ref-type>` were given, we assume all
|
||||
* of the builtin unspecified values.
|
||||
*/
|
||||
if (rw->want_branches == -1 &&
|
||||
rw->want_tags == -1 &&
|
||||
rw->want_remotes == -1 &&
|
||||
rw->want_detached == -1 &&
|
||||
rw->want_other == -1) {
|
||||
*rw = default_ref_options;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since we only allow positive boolean values on the command
|
||||
* line, we will only have true values where they specified
|
||||
* a `--<ref-type>`.
|
||||
*
|
||||
* So anything that still has an unspecified value should be
|
||||
* set to false.
|
||||
*/
|
||||
if (rw->want_branches == -1)
|
||||
rw->want_branches = 0;
|
||||
if (rw->want_tags == -1)
|
||||
rw->want_tags = 0;
|
||||
if (rw->want_remotes == -1)
|
||||
rw->want_remotes = 0;
|
||||
if (rw->want_detached == -1)
|
||||
rw->want_detached = 0;
|
||||
if (rw->want_other == -1)
|
||||
rw->want_other = 0;
|
||||
}
|
||||
|
||||
static int survey_load_config_cb(const char *var, const char *value,
|
||||
const struct config_context *cctx, void *pvoid)
|
||||
{
|
||||
struct survey_context *ctx = pvoid;
|
||||
|
||||
if (!strcmp(var, "survey.verbose")) {
|
||||
ctx->opts.verbose = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "survey.progress")) {
|
||||
ctx->opts.show_progress = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "survey.top")) {
|
||||
ctx->opts.top_nr = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return git_default_config(var, value, cctx, pvoid);
|
||||
}
|
||||
|
||||
static void survey_load_config(struct survey_context *ctx)
|
||||
{
|
||||
repo_config(the_repository, survey_load_config_cb, ctx);
|
||||
}
|
||||
|
||||
static void do_load_refs(struct survey_context *ctx,
|
||||
struct ref_array *ref_array)
|
||||
{
|
||||
struct ref_filter filter = REF_FILTER_INIT;
|
||||
struct ref_sorting *sorting;
|
||||
struct string_list sorting_options = STRING_LIST_INIT_DUP;
|
||||
|
||||
string_list_append(&sorting_options, "objectname");
|
||||
sorting = ref_sorting_options(&sorting_options);
|
||||
|
||||
if (ctx->opts.refs.want_detached)
|
||||
strvec_push(&ctx->refs, "HEAD");
|
||||
|
||||
if (ctx->opts.refs.want_all_refs) {
|
||||
strvec_push(&ctx->refs, "refs/");
|
||||
} else {
|
||||
if (ctx->opts.refs.want_branches)
|
||||
strvec_push(&ctx->refs, "refs/heads/");
|
||||
if (ctx->opts.refs.want_tags)
|
||||
strvec_push(&ctx->refs, "refs/tags/");
|
||||
if (ctx->opts.refs.want_remotes)
|
||||
strvec_push(&ctx->refs, "refs/remotes/");
|
||||
if (ctx->opts.refs.want_other) {
|
||||
strvec_push(&ctx->refs, "refs/notes/");
|
||||
strvec_push(&ctx->refs, "refs/stash/");
|
||||
}
|
||||
}
|
||||
|
||||
filter.name_patterns = ctx->refs.v;
|
||||
filter.ignore_case = 0;
|
||||
filter.match_as_path = 1;
|
||||
|
||||
if (ctx->opts.show_progress) {
|
||||
ctx->progress_total = 0;
|
||||
ctx->progress = start_progress(ctx->repo,
|
||||
_("Scanning refs..."), 0);
|
||||
}
|
||||
|
||||
filter_refs(ref_array, &filter, FILTER_REFS_KIND_MASK);
|
||||
|
||||
if (ctx->opts.show_progress) {
|
||||
ctx->progress_total = ref_array->nr;
|
||||
display_progress(ctx->progress, ctx->progress_total);
|
||||
}
|
||||
|
||||
ref_array_sort(sorting, ref_array);
|
||||
|
||||
stop_progress(&ctx->progress);
|
||||
ref_filter_clear(&filter);
|
||||
ref_sorting_release(sorting);
|
||||
}
|
||||
|
||||
/*
|
||||
* The REFS phase:
|
||||
*
|
||||
* Load the set of requested refs and assess them for scalablity problems.
|
||||
* Use that set to start a treewalk to all reachable objects and assess
|
||||
* them.
|
||||
*
|
||||
* This data will give us insights into the repository itself (the number
|
||||
* of refs, the size and shape of the DAG, the number and size of the
|
||||
* objects).
|
||||
*
|
||||
* Theoretically, this data is independent of the on-disk representation
|
||||
* (e.g. independent of packing concerns).
|
||||
*/
|
||||
static void survey_phase_refs(struct survey_context *ctx)
|
||||
{
|
||||
trace2_region_enter("survey", "phase/refs", ctx->repo);
|
||||
do_load_refs(ctx, &ctx->ref_array);
|
||||
|
||||
ctx->report.refs.refs_nr = ctx->ref_array.nr;
|
||||
for (int i = 0; i < ctx->ref_array.nr; i++) {
|
||||
size_t size;
|
||||
struct ref_array_item *item = ctx->ref_array.items[i];
|
||||
|
||||
switch (item->kind) {
|
||||
case FILTER_REFS_TAGS:
|
||||
ctx->report.refs.tags_nr++;
|
||||
if (odb_read_object_info(ctx->repo->objects,
|
||||
&item->objectname,
|
||||
&size) == OBJ_TAG)
|
||||
ctx->report.refs.tags_annotated_nr++;
|
||||
break;
|
||||
|
||||
case FILTER_REFS_BRANCHES:
|
||||
ctx->report.refs.branches_nr++;
|
||||
break;
|
||||
|
||||
case FILTER_REFS_REMOTES:
|
||||
ctx->report.refs.remote_refs_nr++;
|
||||
break;
|
||||
|
||||
case FILTER_REFS_OTHERS:
|
||||
ctx->report.refs.others_nr++;
|
||||
break;
|
||||
|
||||
default:
|
||||
ctx->report.refs.unknown_nr++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
trace2_region_leave("survey", "phase/refs", ctx->repo);
|
||||
}
|
||||
|
||||
static void increment_object_counts(
|
||||
struct survey_report_object_summary *summary,
|
||||
enum object_type type,
|
||||
size_t nr)
|
||||
{
|
||||
switch (type) {
|
||||
case OBJ_COMMIT:
|
||||
summary->commits_nr += nr;
|
||||
break;
|
||||
|
||||
case OBJ_TREE:
|
||||
summary->trees_nr += nr;
|
||||
break;
|
||||
|
||||
case OBJ_BLOB:
|
||||
summary->blobs_nr += nr;
|
||||
break;
|
||||
|
||||
case OBJ_TAG:
|
||||
summary->tags_nr += nr;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void increment_totals(struct survey_context *ctx,
|
||||
struct oid_array *oids,
|
||||
struct survey_report_object_size_summary *summary)
|
||||
{
|
||||
for (size_t i = 0; i < oids->nr; i++) {
|
||||
struct object_info oi = OBJECT_INFO_INIT;
|
||||
unsigned oi_flags = OBJECT_INFO_FOR_PREFETCH;
|
||||
size_t object_length = 0;
|
||||
off_t disk_sizep = 0;
|
||||
enum object_type type;
|
||||
|
||||
oi.typep = &type;
|
||||
oi.sizep = &object_length;
|
||||
oi.disk_sizep = &disk_sizep;
|
||||
|
||||
if (odb_read_object_info_extended(ctx->repo->objects,
|
||||
&oids->oid[i],
|
||||
&oi, oi_flags) < 0) {
|
||||
summary->num_missing++;
|
||||
} else {
|
||||
summary->nr++;
|
||||
summary->disk_size += disk_sizep;
|
||||
summary->inflated_size += object_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void increment_object_totals(struct survey_context *ctx,
|
||||
struct oid_array *oids,
|
||||
enum object_type type,
|
||||
const char *path)
|
||||
{
|
||||
struct survey_report_object_size_summary *total;
|
||||
struct survey_report_object_size_summary summary = { 0 };
|
||||
|
||||
increment_totals(ctx, oids, &summary);
|
||||
|
||||
switch (type) {
|
||||
case OBJ_COMMIT:
|
||||
total = &ctx->report.by_type[REPORT_TYPE_COMMIT];
|
||||
break;
|
||||
|
||||
case OBJ_TREE:
|
||||
total = &ctx->report.by_type[REPORT_TYPE_TREE];
|
||||
break;
|
||||
|
||||
case OBJ_BLOB:
|
||||
total = &ctx->report.by_type[REPORT_TYPE_BLOB];
|
||||
break;
|
||||
|
||||
case OBJ_TAG:
|
||||
total = &ctx->report.by_type[REPORT_TYPE_TAG];
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG("No other type allowed");
|
||||
}
|
||||
|
||||
total->nr += summary.nr;
|
||||
total->disk_size += summary.disk_size;
|
||||
total->inflated_size += summary.inflated_size;
|
||||
total->num_missing += summary.num_missing;
|
||||
|
||||
if (type == OBJ_TREE || type == OBJ_BLOB) {
|
||||
int index = type == OBJ_TREE ?
|
||||
REPORT_TYPE_TREE : REPORT_TYPE_BLOB;
|
||||
struct survey_report_top_table *top;
|
||||
|
||||
/*
|
||||
* Temporarily store (const char *) here, but it will
|
||||
* be duped if inserted and will not be freed.
|
||||
*/
|
||||
summary.label = (char *)path;
|
||||
|
||||
top = ctx->report.top_paths_by_count;
|
||||
maybe_insert_into_top_size(&top[index], &summary);
|
||||
|
||||
top = ctx->report.top_paths_by_disk;
|
||||
maybe_insert_into_top_size(&top[index], &summary);
|
||||
|
||||
top = ctx->report.top_paths_by_inflate;
|
||||
maybe_insert_into_top_size(&top[index], &summary);
|
||||
}
|
||||
}
|
||||
|
||||
static int survey_objects_path_walk_fn(const char *path,
|
||||
struct oid_array *oids,
|
||||
enum object_type type,
|
||||
void *data)
|
||||
{
|
||||
struct survey_context *ctx = data;
|
||||
|
||||
increment_object_counts(&ctx->report.reachable_objects,
|
||||
type, oids->nr);
|
||||
increment_object_totals(ctx, oids, type, path);
|
||||
|
||||
ctx->progress_nr += oids->nr;
|
||||
display_progress(ctx->progress, ctx->progress_nr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void initialize_report(struct survey_context *ctx)
|
||||
{
|
||||
CALLOC_ARRAY(ctx->report.by_type, REPORT_TYPE_COUNT);
|
||||
ctx->report.by_type[REPORT_TYPE_COMMIT].label = xstrdup(_("Commits"));
|
||||
ctx->report.by_type[REPORT_TYPE_TREE].label = xstrdup(_("Trees"));
|
||||
ctx->report.by_type[REPORT_TYPE_BLOB].label = xstrdup(_("Blobs"));
|
||||
ctx->report.by_type[REPORT_TYPE_TAG].label = xstrdup(_("Tags"));
|
||||
|
||||
CALLOC_ARRAY(ctx->report.top_paths_by_count, REPORT_TYPE_COUNT);
|
||||
init_top_sizes(&ctx->report.top_paths_by_count[REPORT_TYPE_TREE],
|
||||
ctx->opts.top_nr, _("TOP DIRECTORIES BY COUNT"), cmp_by_nr);
|
||||
init_top_sizes(&ctx->report.top_paths_by_count[REPORT_TYPE_BLOB],
|
||||
ctx->opts.top_nr, _("TOP FILES BY COUNT"), cmp_by_nr);
|
||||
|
||||
CALLOC_ARRAY(ctx->report.top_paths_by_disk, REPORT_TYPE_COUNT);
|
||||
init_top_sizes(&ctx->report.top_paths_by_disk[REPORT_TYPE_TREE],
|
||||
ctx->opts.top_nr, _("TOP DIRECTORIES BY DISK SIZE"), cmp_by_disk_size);
|
||||
init_top_sizes(&ctx->report.top_paths_by_disk[REPORT_TYPE_BLOB],
|
||||
ctx->opts.top_nr, _("TOP FILES BY DISK SIZE"), cmp_by_disk_size);
|
||||
|
||||
CALLOC_ARRAY(ctx->report.top_paths_by_inflate, REPORT_TYPE_COUNT);
|
||||
init_top_sizes(&ctx->report.top_paths_by_inflate[REPORT_TYPE_TREE],
|
||||
ctx->opts.top_nr, _("TOP DIRECTORIES BY INFLATED SIZE"), cmp_by_inflated_size);
|
||||
init_top_sizes(&ctx->report.top_paths_by_inflate[REPORT_TYPE_BLOB],
|
||||
ctx->opts.top_nr, _("TOP FILES BY INFLATED SIZE"), cmp_by_inflated_size);
|
||||
}
|
||||
|
||||
static void survey_phase_objects(struct survey_context *ctx)
|
||||
{
|
||||
struct rev_info revs = REV_INFO_INIT;
|
||||
struct path_walk_info info = PATH_WALK_INFO_INIT;
|
||||
unsigned int add_flags = 0;
|
||||
|
||||
trace2_region_enter("survey", "phase/objects", ctx->repo);
|
||||
|
||||
info.revs = &revs;
|
||||
info.path_fn = survey_objects_path_walk_fn;
|
||||
info.path_fn_data = ctx;
|
||||
|
||||
initialize_report(ctx);
|
||||
|
||||
repo_init_revisions(ctx->repo, &revs, "");
|
||||
revs.tag_objects = 1;
|
||||
|
||||
ctx->progress_nr = 0;
|
||||
ctx->progress_total = ctx->ref_array.nr;
|
||||
if (ctx->opts.show_progress)
|
||||
ctx->progress = start_progress(ctx->repo,
|
||||
_("Preparing object walk"),
|
||||
ctx->progress_total);
|
||||
for (int i = 0; i < ctx->ref_array.nr; i++) {
|
||||
struct ref_array_item *item = ctx->ref_array.items[i];
|
||||
add_pending_oid(&revs, NULL, &item->objectname, add_flags);
|
||||
display_progress(ctx->progress, ++(ctx->progress_nr));
|
||||
}
|
||||
stop_progress(&ctx->progress);
|
||||
|
||||
ctx->progress_nr = 0;
|
||||
ctx->progress_total = 0;
|
||||
if (ctx->opts.show_progress)
|
||||
ctx->progress = start_progress(ctx->repo,
|
||||
_("Walking objects"), 0);
|
||||
walk_objects_by_path(&info);
|
||||
stop_progress(&ctx->progress);
|
||||
|
||||
release_revisions(&revs);
|
||||
trace2_region_leave("survey", "phase/objects", ctx->repo);
|
||||
}
|
||||
|
||||
int cmd_survey(int argc, const char **argv, const char *prefix, struct repository *repo)
|
||||
{
|
||||
static struct survey_context ctx = {
|
||||
.opts = {
|
||||
.verbose = 0,
|
||||
.show_progress = -1, /* defaults to isatty(2) */
|
||||
.top_nr = 10,
|
||||
|
||||
.refs.want_all_refs = -1,
|
||||
|
||||
.refs.want_branches = -1, /* default these to undefined */
|
||||
.refs.want_tags = -1,
|
||||
.refs.want_remotes = -1,
|
||||
.refs.want_detached = -1,
|
||||
.refs.want_other = -1,
|
||||
},
|
||||
.refs = STRVEC_INIT,
|
||||
};
|
||||
|
||||
static struct option survey_options[] = {
|
||||
OPT__VERBOSE(&ctx.opts.verbose, N_("verbose output")),
|
||||
OPT_BOOL(0, "progress", &ctx.opts.show_progress, N_("show progress")),
|
||||
OPT_INTEGER('n', "top", &ctx.opts.top_nr,
|
||||
N_("number of entries to include in detail tables")),
|
||||
|
||||
OPT_BOOL_F(0, "all-refs", &ctx.opts.refs.want_all_refs, N_("include all refs"), PARSE_OPT_NONEG),
|
||||
|
||||
OPT_BOOL_F(0, "branches", &ctx.opts.refs.want_branches, N_("include branches"), PARSE_OPT_NONEG),
|
||||
OPT_BOOL_F(0, "tags", &ctx.opts.refs.want_tags, N_("include tags"), PARSE_OPT_NONEG),
|
||||
OPT_BOOL_F(0, "remotes", &ctx.opts.refs.want_remotes, N_("include all remotes refs"), PARSE_OPT_NONEG),
|
||||
OPT_BOOL_F(0, "detached", &ctx.opts.refs.want_detached, N_("include detached HEAD"), PARSE_OPT_NONEG),
|
||||
OPT_BOOL_F(0, "other", &ctx.opts.refs.want_other, N_("include notes and stashes"), PARSE_OPT_NONEG),
|
||||
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
show_usage_with_options_if_asked(argc, argv,
|
||||
survey_usage, survey_options);
|
||||
|
||||
if (isatty(2))
|
||||
color_fprintf_ln(stderr,
|
||||
want_color_fd(2, GIT_COLOR_AUTO) ? GIT_COLOR_YELLOW : "",
|
||||
"(THIS IS EXPERIMENTAL, EXPECT THE OUTPUT FORMAT TO CHANGE!)");
|
||||
|
||||
ctx.repo = repo;
|
||||
|
||||
prepare_repo_settings(ctx.repo);
|
||||
survey_load_config(&ctx);
|
||||
|
||||
argc = parse_options(argc, argv, prefix, survey_options, survey_usage, 0);
|
||||
|
||||
if (ctx.opts.show_progress < 0)
|
||||
ctx.opts.show_progress = isatty(2);
|
||||
|
||||
fixup_refs_wanted(&ctx);
|
||||
|
||||
survey_phase_refs(&ctx);
|
||||
|
||||
survey_phase_objects(&ctx);
|
||||
|
||||
survey_report_plaintext(&ctx);
|
||||
|
||||
clear_survey_context(&ctx);
|
||||
return 0;
|
||||
}
|
||||
@@ -40,7 +40,7 @@ static struct progress *progress;
|
||||
*/
|
||||
struct obj_buffer {
|
||||
char *buffer;
|
||||
unsigned long size;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static struct decoration obj_decorate;
|
||||
@@ -50,7 +50,7 @@ static struct obj_buffer *lookup_object_buffer(struct object *base)
|
||||
return lookup_decoration(&obj_decorate, base);
|
||||
}
|
||||
|
||||
static void add_object_buffer(struct object *object, char *buffer, unsigned long size)
|
||||
static void add_object_buffer(struct object *object, char *buffer, size_t size)
|
||||
{
|
||||
struct obj_buffer *obj;
|
||||
CALLOC_ARRAY(obj, 1);
|
||||
@@ -114,10 +114,10 @@ static void use(int bytes)
|
||||
* allocated buffer which is reused to hold temporary zstream output
|
||||
* and return NULL instead of returning garbage data.
|
||||
*/
|
||||
static void *get_data(unsigned long size)
|
||||
static void *get_data(size_t size)
|
||||
{
|
||||
git_zstream stream;
|
||||
unsigned long bufsize = dry_run && size > 8192 ? 8192 : size;
|
||||
size_t bufsize = dry_run && size > 8192 ? 8192 : size;
|
||||
void *buf = xmallocz(bufsize);
|
||||
|
||||
memset(&stream, 0, sizeof(stream));
|
||||
@@ -161,7 +161,7 @@ struct delta_info {
|
||||
struct object_id base_oid;
|
||||
unsigned nr;
|
||||
off_t base_offset;
|
||||
unsigned long size;
|
||||
size_t size;
|
||||
void *delta;
|
||||
struct delta_info *next;
|
||||
};
|
||||
@@ -170,7 +170,7 @@ static struct delta_info *delta_list;
|
||||
|
||||
static void add_delta_to_list(unsigned nr, const struct object_id *base_oid,
|
||||
off_t base_offset,
|
||||
void *delta, unsigned long size)
|
||||
void *delta, size_t size)
|
||||
{
|
||||
struct delta_info *info = xmalloc(sizeof(*info));
|
||||
|
||||
@@ -261,7 +261,7 @@ static void write_rest(void)
|
||||
}
|
||||
|
||||
static void added_object(unsigned nr, enum object_type type,
|
||||
void *data, unsigned long size);
|
||||
void *data, size_t size);
|
||||
|
||||
/*
|
||||
* Write out nr-th object from the list, now we know the contents
|
||||
@@ -269,7 +269,7 @@ static void added_object(unsigned nr, enum object_type type,
|
||||
* to be checked at the end.
|
||||
*/
|
||||
static void write_object(unsigned nr, enum object_type type,
|
||||
void *buf, unsigned long size)
|
||||
void *buf, size_t size)
|
||||
{
|
||||
if (!strict) {
|
||||
if (odb_write_object(the_repository->objects, buf, size, type,
|
||||
@@ -310,8 +310,8 @@ static void write_object(unsigned nr, enum object_type type,
|
||||
}
|
||||
|
||||
static void resolve_delta(unsigned nr, enum object_type type,
|
||||
void *base, unsigned long base_size,
|
||||
void *delta, unsigned long delta_size)
|
||||
void *base, size_t base_size,
|
||||
void *delta, size_t delta_size)
|
||||
{
|
||||
void *result;
|
||||
size_t result_size;
|
||||
@@ -330,7 +330,7 @@ static void resolve_delta(unsigned nr, enum object_type type,
|
||||
* resolve all the deltified objects that are based on it.
|
||||
*/
|
||||
static void added_object(unsigned nr, enum object_type type,
|
||||
void *data, unsigned long size)
|
||||
void *data, size_t size)
|
||||
{
|
||||
struct delta_info **p = &delta_list;
|
||||
struct delta_info *info;
|
||||
@@ -349,7 +349,7 @@ static void added_object(unsigned nr, enum object_type type,
|
||||
}
|
||||
}
|
||||
|
||||
static void unpack_non_delta_entry(enum object_type type, unsigned long size,
|
||||
static void unpack_non_delta_entry(enum object_type type, size_t size,
|
||||
unsigned nr)
|
||||
{
|
||||
void *buf = get_data(size);
|
||||
@@ -385,7 +385,7 @@ static ssize_t feed_input_zstream(struct odb_write_stream *in_stream,
|
||||
return buf_len - zstream->avail_out;
|
||||
}
|
||||
|
||||
static void stream_blob(unsigned long size, unsigned nr)
|
||||
static void stream_blob(size_t size, unsigned nr)
|
||||
{
|
||||
git_zstream zstream = { 0 };
|
||||
struct input_zstream_data data = { 0 };
|
||||
@@ -416,7 +416,7 @@ static void stream_blob(unsigned long size, unsigned nr)
|
||||
}
|
||||
|
||||
static int resolve_against_held(unsigned nr, const struct object_id *base,
|
||||
void *delta_data, unsigned long delta_size)
|
||||
void *delta_data, size_t delta_size)
|
||||
{
|
||||
struct object *obj;
|
||||
struct obj_buffer *obj_buffer;
|
||||
@@ -431,12 +431,11 @@ static int resolve_against_held(unsigned nr, const struct object_id *base,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
||||
static void unpack_delta_entry(enum object_type type, size_t delta_size,
|
||||
unsigned nr)
|
||||
{
|
||||
void *delta_data, *base;
|
||||
unsigned long base_size;
|
||||
size_t base_size_st = 0;
|
||||
size_t base_size;
|
||||
struct object_id base_oid;
|
||||
|
||||
if (type == OBJ_REF_DELTA) {
|
||||
@@ -513,8 +512,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
||||
return;
|
||||
|
||||
base = odb_read_object(the_repository->objects, &base_oid,
|
||||
&type, &base_size_st);
|
||||
base_size = cast_size_t_to_ulong(base_size_st);
|
||||
&type, &base_size);
|
||||
if (!base) {
|
||||
error("failed to read delta-pack base object %s",
|
||||
oid_to_hex(&base_oid));
|
||||
|
||||
@@ -19,6 +19,7 @@ problems=()
|
||||
commit=
|
||||
commitText=
|
||||
commitTextmd=
|
||||
committerEmail=
|
||||
goodParent=
|
||||
|
||||
if ! git rev-parse --quiet --verify "${baseCommit}"
|
||||
@@ -27,7 +28,7 @@ then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while read dash sha etc
|
||||
while read dash email sha etc
|
||||
do
|
||||
case "${dash}" in
|
||||
"---") # Line contains commit information.
|
||||
@@ -40,10 +41,14 @@ do
|
||||
commit="${sha}"
|
||||
commitText="${sha} ${etc}"
|
||||
commitTextmd="[${sha}](${url}/commit/${sha}) ${etc}"
|
||||
committerEmail="${email}"
|
||||
;;
|
||||
"")
|
||||
;;
|
||||
*) # Line contains whitespace error information for current commit.
|
||||
# Quod licet Iovi non licet bovi
|
||||
test gitster@pobox.com != "$committerEmail" || break
|
||||
|
||||
if test -n "${goodParent}"
|
||||
then
|
||||
problems+=("1) --- ${commitTextmd}")
|
||||
@@ -64,7 +69,7 @@ do
|
||||
echo "${dash} ${sha} ${etc}"
|
||||
;;
|
||||
esac
|
||||
done <<< "$(git log --check --pretty=format:"---% h% s" "${baseCommit}"..)"
|
||||
done <<< "$(git log --check --pretty=format:"---% ce% h% s" "${baseCommit}"..)"
|
||||
|
||||
if test ${#problems[*]} -gt 0
|
||||
then
|
||||
|
||||
@@ -119,11 +119,12 @@ macos-*)
|
||||
# brew install gnu-time
|
||||
brew link --force gettext
|
||||
|
||||
mkdir -p "$CUSTOM_PATH"
|
||||
wget -q "$P4WHENCE/bin.macosx12arm64/helix-core-server.tgz" &&
|
||||
tar -xf helix-core-server.tgz -C "$CUSTOM_PATH" p4 p4d &&
|
||||
sudo xattr -d com.apple.quarantine "$CUSTOM_PATH/p4" "$CUSTOM_PATH/p4d" 2>/dev/null || true
|
||||
rm helix-core-server.tgz
|
||||
# Uncomment this block if you want to run `git p4` tests:
|
||||
# mkdir -p "$CUSTOM_PATH"
|
||||
# wget -q "$P4WHENCE/bin.macosx12arm64/helix-core-server.tgz" &&
|
||||
# tar -xf helix-core-server.tgz -C "$CUSTOM_PATH" p4 p4d &&
|
||||
# sudo xattr -d com.apple.quarantine "$CUSTOM_PATH/p4" "$CUSTOM_PATH/p4d" 2>/dev/null || true
|
||||
# rm helix-core-server.tgz
|
||||
|
||||
case "$jobname" in
|
||||
osx-meson)
|
||||
|
||||
@@ -72,5 +72,9 @@ case "$jobname" in
|
||||
;;
|
||||
esac
|
||||
|
||||
case " $MAKE_TARGETS " in
|
||||
*" all "*) make -C contrib/subtree test;;
|
||||
esac
|
||||
|
||||
check_unignored_build_artifacts
|
||||
save_good_tree
|
||||
|
||||
@@ -15,4 +15,7 @@ if [ "$1" == "0" ] ; then
|
||||
group "Run unit tests" make --quiet -C t unit-tests-test-tool
|
||||
fi
|
||||
|
||||
# Run the git subtree tests only if main tests succeeded
|
||||
test 0 != "$1" || make -C contrib/subtree test
|
||||
|
||||
check_unignored_build_artifacts
|
||||
|
||||
@@ -304,7 +304,7 @@ static struct lline *coalesce_lines(struct lline *base, int *lenbase,
|
||||
|
||||
static char *grab_blob(struct repository *r,
|
||||
const struct object_id *oid, unsigned int mode,
|
||||
unsigned long *size, struct userdiff_driver *textconv,
|
||||
size_t *size, struct userdiff_driver *textconv,
|
||||
const char *path)
|
||||
{
|
||||
char *blob;
|
||||
@@ -325,9 +325,7 @@ static char *grab_blob(struct repository *r,
|
||||
*size = fill_textconv(r, textconv, df, &blob);
|
||||
free_filespec(df);
|
||||
} else {
|
||||
size_t size_st = 0;
|
||||
blob = odb_read_object(r->objects, oid, &type, &size_st);
|
||||
*size = cast_size_t_to_ulong(size_st);
|
||||
blob = odb_read_object(r->objects, oid, &type, size);
|
||||
if (!blob)
|
||||
die(_("unable to read %s"), oid_to_hex(oid));
|
||||
if (type != OBJ_BLOB)
|
||||
@@ -431,7 +429,7 @@ static void combine_diff(struct repository *r,
|
||||
xdemitconf_t xecfg;
|
||||
mmfile_t parent_file;
|
||||
struct combine_diff_state state;
|
||||
unsigned long sz;
|
||||
size_t sz;
|
||||
|
||||
if (result_deleted)
|
||||
return; /* result deleted */
|
||||
@@ -1015,7 +1013,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
|
||||
struct rev_info *rev)
|
||||
{
|
||||
struct diff_options *opt = &rev->diffopt;
|
||||
unsigned long result_size, cnt, lno;
|
||||
size_t result_size, cnt, lno;
|
||||
int result_deleted = 0;
|
||||
char *result, *cp;
|
||||
struct sline *sline; /* survived lines */
|
||||
@@ -1134,7 +1132,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
|
||||
is_binary = buffer_is_binary(result, result_size);
|
||||
for (i = 0; !is_binary && i < num_parent; i++) {
|
||||
char *buf;
|
||||
unsigned long size;
|
||||
size_t size;
|
||||
buf = grab_blob(opt->repo,
|
||||
&elem->parent[i].oid,
|
||||
elem->parent[i].mode,
|
||||
|
||||
@@ -192,6 +192,7 @@ git-stash mainporcelain
|
||||
git-status mainporcelain info
|
||||
git-stripspace purehelpers
|
||||
git-submodule mainporcelain
|
||||
git-survey mainporcelain
|
||||
git-svn foreignscminterface
|
||||
git-switch mainporcelain history
|
||||
git-symbolic-ref plumbingmanipulators
|
||||
|
||||
19
commit.c
19
commit.c
@@ -349,7 +349,7 @@ int for_each_commit_graft(each_commit_graft_fn fn, void *cb_data)
|
||||
|
||||
struct commit_buffer {
|
||||
void *buffer;
|
||||
unsigned long size;
|
||||
size_t size;
|
||||
};
|
||||
define_commit_slab(buffer_slab, struct commit_buffer);
|
||||
|
||||
@@ -366,7 +366,8 @@ void free_commit_buffer_slab(struct buffer_slab *bs)
|
||||
free(bs);
|
||||
}
|
||||
|
||||
void set_commit_buffer(struct repository *r, struct commit *commit, void *buffer, unsigned long size)
|
||||
void set_commit_buffer(struct repository *r, struct commit *commit,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
struct commit_buffer *v = buffer_slab_at(
|
||||
r->parsed_objects->buffer_slab, commit);
|
||||
@@ -374,7 +375,9 @@ void set_commit_buffer(struct repository *r, struct commit *commit, void *buffer
|
||||
v->size = size;
|
||||
}
|
||||
|
||||
const void *get_cached_commit_buffer(struct repository *r, const struct commit *commit, unsigned long *sizep)
|
||||
const void *get_cached_commit_buffer(struct repository *r,
|
||||
const struct commit *commit,
|
||||
size_t *sizep)
|
||||
{
|
||||
struct commit_buffer *v = buffer_slab_peek(
|
||||
r->parsed_objects->buffer_slab, commit);
|
||||
@@ -390,7 +393,7 @@ const void *get_cached_commit_buffer(struct repository *r, const struct commit *
|
||||
|
||||
const void *repo_get_commit_buffer(struct repository *r,
|
||||
const struct commit *commit,
|
||||
unsigned long *sizep)
|
||||
size_t *sizep)
|
||||
{
|
||||
const void *ret = get_cached_commit_buffer(r, commit, sizep);
|
||||
if (!ret) {
|
||||
@@ -404,7 +407,7 @@ const void *repo_get_commit_buffer(struct repository *r,
|
||||
die("expected commit for %s, got %s",
|
||||
oid_to_hex(&commit->object.oid), type_name(type));
|
||||
if (sizep)
|
||||
*sizep = cast_size_t_to_ulong(size);
|
||||
*sizep = size;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -1192,7 +1195,7 @@ int parse_signed_commit(const struct commit *commit,
|
||||
struct strbuf *payload, struct strbuf *signature,
|
||||
const struct git_hash_algo *algop)
|
||||
{
|
||||
unsigned long size;
|
||||
size_t size;
|
||||
const char *buffer = repo_get_commit_buffer(the_repository, commit,
|
||||
&size);
|
||||
int ret = parse_buffer_signed_by_header(buffer, size, payload, signature, algop);
|
||||
@@ -1365,7 +1368,7 @@ int verify_commit_buffer(const char *buffer, size_t size,
|
||||
|
||||
int check_commit_signature(const struct commit *commit, struct signature_check *sigc)
|
||||
{
|
||||
unsigned long size;
|
||||
size_t size;
|
||||
const char *buffer = repo_get_commit_buffer(the_repository, commit, &size);
|
||||
int ret = verify_commit_buffer(buffer, size, sigc);
|
||||
|
||||
@@ -1462,7 +1465,7 @@ struct commit_extra_header *read_commit_extra_headers(struct commit *commit,
|
||||
const char **exclude)
|
||||
{
|
||||
struct commit_extra_header *extra = NULL;
|
||||
unsigned long size;
|
||||
size_t size;
|
||||
const char *buffer = repo_get_commit_buffer(the_repository, commit,
|
||||
&size);
|
||||
extra = read_commit_extra_header_lines(buffer, size, exclude);
|
||||
|
||||
8
commit.h
8
commit.h
@@ -131,13 +131,15 @@ void free_commit_buffer_slab(struct buffer_slab *bs);
|
||||
* Associate an object buffer with the commit. The ownership of the
|
||||
* memory is handed over to the commit, and must be free()-able.
|
||||
*/
|
||||
void set_commit_buffer(struct repository *r, struct commit *, void *buffer, unsigned long size);
|
||||
void set_commit_buffer(struct repository *r, struct commit *,
|
||||
void *buffer, size_t size);
|
||||
|
||||
/*
|
||||
* Get any cached object buffer associated with the commit. Returns NULL
|
||||
* if none. The resulting memory should not be freed.
|
||||
*/
|
||||
const void *get_cached_commit_buffer(struct repository *, const struct commit *, unsigned long *size);
|
||||
const void *get_cached_commit_buffer(struct repository *,
|
||||
const struct commit *, size_t *size);
|
||||
|
||||
/*
|
||||
* Get the commit's object contents, either from cache or by reading the object
|
||||
@@ -146,7 +148,7 @@ const void *get_cached_commit_buffer(struct repository *, const struct commit *,
|
||||
*/
|
||||
const void *repo_get_commit_buffer(struct repository *r,
|
||||
const struct commit *,
|
||||
unsigned long *size);
|
||||
size_t *size);
|
||||
|
||||
/*
|
||||
* Tell the commit subsystem that we are done with a particular commit buffer.
|
||||
|
||||
@@ -11,6 +11,13 @@ static void check_bug_if_BUG(void)
|
||||
/* We wrap exit() to call common_exit() in git-compat-util.h */
|
||||
int common_exit(const char *file, int line, int code)
|
||||
{
|
||||
/*
|
||||
* Windows Filtering Platform driver provided by the security software
|
||||
* may change buffer type of stdout from _IONBF to _IOFBF.
|
||||
* It will no output without fflush manually.
|
||||
*/
|
||||
fflush(stdout);
|
||||
|
||||
/*
|
||||
* For non-POSIX systems: Take the lowest 8 bits of the "code"
|
||||
* to e.g. turn -1 into 255. On a POSIX system this is
|
||||
|
||||
428
compat/lazyload-curl.c
Normal file
428
compat/lazyload-curl.c
Normal file
@@ -0,0 +1,428 @@
|
||||
#include "../git-compat-util.h"
|
||||
#include "../git-curl-compat.h"
|
||||
#ifndef WIN32
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The ABI version of libcurl is encoded in its shared libraries' file names.
|
||||
* This ABI version has not changed since October 2006 and is unlikely to be
|
||||
* changed in the future. See https://curl.se/libcurl/abi.html for details.
|
||||
*/
|
||||
#define LIBCURL_ABI_VERSION "4"
|
||||
|
||||
typedef void (*func_t)(void);
|
||||
|
||||
#ifndef WIN32
|
||||
#ifdef __APPLE__
|
||||
#define LIBCURL_FILE_NAME(base) base "." LIBCURL_ABI_VERSION ".dylib"
|
||||
#else
|
||||
#define LIBCURL_FILE_NAME(base) base ".so." LIBCURL_ABI_VERSION
|
||||
#endif
|
||||
|
||||
static void *load_library(const char *name)
|
||||
{
|
||||
return dlopen(name, RTLD_LAZY);
|
||||
}
|
||||
|
||||
static func_t load_function(void *handle, const char *name)
|
||||
{
|
||||
/*
|
||||
* Casting the return value of `dlsym()` to a function pointer is
|
||||
* explicitly allowed in recent POSIX standards, but GCC complains
|
||||
* about this in pedantic mode nevertheless. For more about this issue,
|
||||
* see https://stackoverflow.com/q/31526876/1860823 and
|
||||
* http://stackoverflow.com/a/36385690/1905491.
|
||||
*/
|
||||
func_t f;
|
||||
*(void **)&f = dlsym(handle, name);
|
||||
return f;
|
||||
}
|
||||
#else
|
||||
#define LIBCURL_FILE_NAME(base) base "-" LIBCURL_ABI_VERSION ".dll"
|
||||
|
||||
static void *load_library(const char *name)
|
||||
{
|
||||
size_t name_size = strlen(name) + 1;
|
||||
const char *path = getenv("PATH");
|
||||
char dll_path[MAX_PATH];
|
||||
|
||||
while (path && *path) {
|
||||
const char *sep = strchrnul(path, ';');
|
||||
size_t len = sep - path;
|
||||
|
||||
if (len && len + name_size < sizeof(dll_path)) {
|
||||
memcpy(dll_path, path, len);
|
||||
dll_path[len] = '/';
|
||||
memcpy(dll_path + len + 1, name, name_size);
|
||||
|
||||
if (!access(dll_path, R_OK)) {
|
||||
wchar_t wpath[MAX_PATH];
|
||||
int wlen = MultiByteToWideChar(CP_UTF8, 0, dll_path, -1, wpath, ARRAY_SIZE(wpath));
|
||||
void *res = wlen ? (void *)LoadLibraryExW(wpath, NULL, 0) : NULL;
|
||||
if (!res) {
|
||||
DWORD err = GetLastError();
|
||||
char buf[1024];
|
||||
|
||||
if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_ARGUMENT_ARRAY |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, err, LANG_NEUTRAL,
|
||||
buf, sizeof(buf) - 1, NULL))
|
||||
xsnprintf(buf, sizeof(buf), "last error: %ld", err);
|
||||
error("LoadLibraryExW() failed with: %s", buf);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
path = *sep ? sep + 1 : NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static func_t load_function(void *handle, const char *name)
|
||||
{
|
||||
return (func_t)GetProcAddress((HANDLE)handle, name);
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef struct curl_version_info_data *(*curl_version_info_type)(CURLversion version);
|
||||
static curl_version_info_type curl_version_info_func;
|
||||
|
||||
typedef char *(*curl_easy_escape_type)(CURL *handle, const char *string, int length);
|
||||
static curl_easy_escape_type curl_easy_escape_func;
|
||||
|
||||
typedef void (*curl_free_type)(void *p);
|
||||
static curl_free_type curl_free_func;
|
||||
|
||||
typedef CURLcode (*curl_global_init_type)(long flags);
|
||||
static curl_global_init_type curl_global_init_func;
|
||||
|
||||
typedef CURLsslset (*curl_global_sslset_type)(curl_sslbackend id, const char *name, const curl_ssl_backend ***avail);
|
||||
static curl_global_sslset_type curl_global_sslset_func;
|
||||
|
||||
typedef void (*curl_global_cleanup_type)(void);
|
||||
static curl_global_cleanup_type curl_global_cleanup_func;
|
||||
|
||||
typedef CURLcode (*curl_global_trace_type)(const char *config);
|
||||
static curl_global_trace_type curl_global_trace_func;
|
||||
|
||||
typedef struct curl_slist *(*curl_slist_append_type)(struct curl_slist *list, const char *data);
|
||||
static curl_slist_append_type curl_slist_append_func;
|
||||
|
||||
typedef void (*curl_slist_free_all_type)(struct curl_slist *list);
|
||||
static curl_slist_free_all_type curl_slist_free_all_func;
|
||||
|
||||
typedef const char *(*curl_easy_strerror_type)(CURLcode error);
|
||||
static curl_easy_strerror_type curl_easy_strerror_func;
|
||||
|
||||
typedef CURLM *(*curl_multi_init_type)(void);
|
||||
static curl_multi_init_type curl_multi_init_func;
|
||||
|
||||
typedef CURLMcode (*curl_multi_add_handle_type)(CURLM *multi_handle, CURL *curl_handle);
|
||||
static curl_multi_add_handle_type curl_multi_add_handle_func;
|
||||
|
||||
typedef CURLMcode (*curl_multi_remove_handle_type)(CURLM *multi_handle, CURL *curl_handle);
|
||||
static curl_multi_remove_handle_type curl_multi_remove_handle_func;
|
||||
|
||||
typedef CURLMcode (*curl_multi_fdset_type)(CURLM *multi_handle, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *exc_fd_set, int *max_fd);
|
||||
static curl_multi_fdset_type curl_multi_fdset_func;
|
||||
|
||||
typedef CURLMcode (*curl_multi_perform_type)(CURLM *multi_handle, int *running_handles);
|
||||
static curl_multi_perform_type curl_multi_perform_func;
|
||||
|
||||
typedef CURLMcode (*curl_multi_cleanup_type)(CURLM *multi_handle);
|
||||
static curl_multi_cleanup_type curl_multi_cleanup_func;
|
||||
|
||||
typedef CURLMsg *(*curl_multi_info_read_type)(CURLM *multi_handle, int *msgs_in_queue);
|
||||
static curl_multi_info_read_type curl_multi_info_read_func;
|
||||
|
||||
typedef const char *(*curl_multi_strerror_type)(CURLMcode error);
|
||||
static curl_multi_strerror_type curl_multi_strerror_func;
|
||||
|
||||
typedef CURLMcode (*curl_multi_timeout_type)(CURLM *multi_handle, long *milliseconds);
|
||||
static curl_multi_timeout_type curl_multi_timeout_func;
|
||||
|
||||
typedef CURL *(*curl_easy_init_type)(void);
|
||||
static curl_easy_init_type curl_easy_init_func;
|
||||
|
||||
typedef CURLcode (*curl_easy_perform_type)(CURL *curl);
|
||||
static curl_easy_perform_type curl_easy_perform_func;
|
||||
|
||||
typedef void (*curl_easy_cleanup_type)(CURL *curl);
|
||||
static curl_easy_cleanup_type curl_easy_cleanup_func;
|
||||
|
||||
typedef CURL *(*curl_easy_duphandle_type)(CURL *curl);
|
||||
static curl_easy_duphandle_type curl_easy_duphandle_func;
|
||||
|
||||
typedef CURLcode (*curl_easy_getinfo_long_type)(CURL *curl, CURLINFO info, long *value);
|
||||
static curl_easy_getinfo_long_type curl_easy_getinfo_long_func;
|
||||
|
||||
typedef CURLcode (*curl_easy_getinfo_pointer_type)(CURL *curl, CURLINFO info, void **value);
|
||||
static curl_easy_getinfo_pointer_type curl_easy_getinfo_pointer_func;
|
||||
|
||||
typedef CURLcode (*curl_easy_getinfo_off_t_type)(CURL *curl, CURLINFO info, curl_off_t *value);
|
||||
static curl_easy_getinfo_off_t_type curl_easy_getinfo_off_t_func;
|
||||
|
||||
typedef CURLcode (*curl_easy_setopt_long_type)(CURL *curl, CURLoption opt, long value);
|
||||
static curl_easy_setopt_long_type curl_easy_setopt_long_func;
|
||||
|
||||
typedef CURLcode (*curl_easy_setopt_pointer_type)(CURL *curl, CURLoption opt, void *value);
|
||||
static curl_easy_setopt_pointer_type curl_easy_setopt_pointer_func;
|
||||
|
||||
typedef CURLcode (*curl_easy_setopt_off_t_type)(CURL *curl, CURLoption opt, curl_off_t value);
|
||||
static curl_easy_setopt_off_t_type curl_easy_setopt_off_t_func;
|
||||
|
||||
static char ssl_backend[64];
|
||||
|
||||
static void lazy_load_curl(void)
|
||||
{
|
||||
static int initialized;
|
||||
void *libcurl = NULL;
|
||||
func_t curl_easy_getinfo_func, curl_easy_setopt_func;
|
||||
|
||||
if (initialized)
|
||||
return;
|
||||
|
||||
initialized = 1;
|
||||
if (ssl_backend[0]) {
|
||||
char dll_name[64 + 16];
|
||||
snprintf(dll_name, sizeof(dll_name) - 1,
|
||||
LIBCURL_FILE_NAME("libcurl-%s"), ssl_backend);
|
||||
libcurl = load_library(dll_name);
|
||||
}
|
||||
if (!libcurl)
|
||||
libcurl = load_library(LIBCURL_FILE_NAME("libcurl"));
|
||||
if (!libcurl)
|
||||
die("failed to load library '%s'", LIBCURL_FILE_NAME("libcurl"));
|
||||
|
||||
curl_version_info_func = (curl_version_info_type)load_function(libcurl, "curl_version_info");
|
||||
curl_easy_escape_func = (curl_easy_escape_type)load_function(libcurl, "curl_easy_escape");
|
||||
curl_free_func = (curl_free_type)load_function(libcurl, "curl_free");
|
||||
curl_global_init_func = (curl_global_init_type)load_function(libcurl, "curl_global_init");
|
||||
curl_global_sslset_func = (curl_global_sslset_type)load_function(libcurl, "curl_global_sslset");
|
||||
curl_global_cleanup_func = (curl_global_cleanup_type)load_function(libcurl, "curl_global_cleanup");
|
||||
curl_global_trace_func = (curl_global_trace_type)load_function(libcurl, "curl_global_trace");
|
||||
curl_slist_append_func = (curl_slist_append_type)load_function(libcurl, "curl_slist_append");
|
||||
curl_slist_free_all_func = (curl_slist_free_all_type)load_function(libcurl, "curl_slist_free_all");
|
||||
curl_easy_strerror_func = (curl_easy_strerror_type)load_function(libcurl, "curl_easy_strerror");
|
||||
curl_multi_init_func = (curl_multi_init_type)load_function(libcurl, "curl_multi_init");
|
||||
curl_multi_add_handle_func = (curl_multi_add_handle_type)load_function(libcurl, "curl_multi_add_handle");
|
||||
curl_multi_remove_handle_func = (curl_multi_remove_handle_type)load_function(libcurl, "curl_multi_remove_handle");
|
||||
curl_multi_fdset_func = (curl_multi_fdset_type)load_function(libcurl, "curl_multi_fdset");
|
||||
curl_multi_perform_func = (curl_multi_perform_type)load_function(libcurl, "curl_multi_perform");
|
||||
curl_multi_cleanup_func = (curl_multi_cleanup_type)load_function(libcurl, "curl_multi_cleanup");
|
||||
curl_multi_info_read_func = (curl_multi_info_read_type)load_function(libcurl, "curl_multi_info_read");
|
||||
curl_multi_strerror_func = (curl_multi_strerror_type)load_function(libcurl, "curl_multi_strerror");
|
||||
curl_multi_timeout_func = (curl_multi_timeout_type)load_function(libcurl, "curl_multi_timeout");
|
||||
curl_easy_init_func = (curl_easy_init_type)load_function(libcurl, "curl_easy_init");
|
||||
curl_easy_perform_func = (curl_easy_perform_type)load_function(libcurl, "curl_easy_perform");
|
||||
curl_easy_cleanup_func = (curl_easy_cleanup_type)load_function(libcurl, "curl_easy_cleanup");
|
||||
curl_easy_duphandle_func = (curl_easy_duphandle_type)load_function(libcurl, "curl_easy_duphandle");
|
||||
|
||||
curl_easy_getinfo_func = load_function(libcurl, "curl_easy_getinfo");
|
||||
curl_easy_getinfo_long_func = (curl_easy_getinfo_long_type)curl_easy_getinfo_func;
|
||||
curl_easy_getinfo_pointer_func = (curl_easy_getinfo_pointer_type)curl_easy_getinfo_func;
|
||||
curl_easy_getinfo_off_t_func = (curl_easy_getinfo_off_t_type)curl_easy_getinfo_func;
|
||||
|
||||
curl_easy_setopt_func = load_function(libcurl, "curl_easy_setopt");
|
||||
curl_easy_setopt_long_func = (curl_easy_setopt_long_type)curl_easy_setopt_func;
|
||||
curl_easy_setopt_pointer_func = (curl_easy_setopt_pointer_type)curl_easy_setopt_func;
|
||||
curl_easy_setopt_off_t_func = (curl_easy_setopt_off_t_type)curl_easy_setopt_func;
|
||||
}
|
||||
|
||||
struct curl_version_info_data *curl_version_info(CURLversion version)
|
||||
{
|
||||
lazy_load_curl();
|
||||
return curl_version_info_func(version);
|
||||
}
|
||||
|
||||
char *curl_easy_escape(CURL *handle, const char *string, int length)
|
||||
{
|
||||
lazy_load_curl();
|
||||
return curl_easy_escape_func(handle, string, length);
|
||||
}
|
||||
|
||||
void curl_free(void *p)
|
||||
{
|
||||
lazy_load_curl();
|
||||
curl_free_func(p);
|
||||
}
|
||||
|
||||
CURLcode curl_global_init(long flags)
|
||||
{
|
||||
lazy_load_curl();
|
||||
return curl_global_init_func(flags);
|
||||
}
|
||||
|
||||
CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, const curl_ssl_backend ***avail)
|
||||
{
|
||||
if (name && strlen(name) < sizeof(ssl_backend))
|
||||
strlcpy(ssl_backend, name, sizeof(ssl_backend));
|
||||
|
||||
lazy_load_curl();
|
||||
return curl_global_sslset_func(id, name, avail);
|
||||
}
|
||||
|
||||
void curl_global_cleanup(void)
|
||||
{
|
||||
lazy_load_curl();
|
||||
curl_global_cleanup_func();
|
||||
}
|
||||
|
||||
CURLcode curl_global_trace(const char *config)
|
||||
{
|
||||
lazy_load_curl();
|
||||
return curl_global_trace_func(config);
|
||||
}
|
||||
|
||||
struct curl_slist *curl_slist_append(struct curl_slist *list, const char *data)
|
||||
{
|
||||
lazy_load_curl();
|
||||
return curl_slist_append_func(list, data);
|
||||
}
|
||||
|
||||
void curl_slist_free_all(struct curl_slist *list)
|
||||
{
|
||||
lazy_load_curl();
|
||||
curl_slist_free_all_func(list);
|
||||
}
|
||||
|
||||
const char *curl_easy_strerror(CURLcode error)
|
||||
{
|
||||
lazy_load_curl();
|
||||
return curl_easy_strerror_func(error);
|
||||
}
|
||||
|
||||
CURLM *curl_multi_init(void)
|
||||
{
|
||||
lazy_load_curl();
|
||||
return curl_multi_init_func();
|
||||
}
|
||||
|
||||
CURLMcode curl_multi_add_handle(CURLM *multi_handle, CURL *curl_handle)
|
||||
{
|
||||
lazy_load_curl();
|
||||
return curl_multi_add_handle_func(multi_handle, curl_handle);
|
||||
}
|
||||
|
||||
CURLMcode curl_multi_remove_handle(CURLM *multi_handle, CURL *curl_handle)
|
||||
{
|
||||
lazy_load_curl();
|
||||
return curl_multi_remove_handle_func(multi_handle, curl_handle);
|
||||
}
|
||||
|
||||
CURLMcode curl_multi_fdset(CURLM *multi_handle, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *exc_fd_set, int *max_fd)
|
||||
{
|
||||
lazy_load_curl();
|
||||
return curl_multi_fdset_func(multi_handle, read_fd_set, write_fd_set, exc_fd_set, max_fd);
|
||||
}
|
||||
|
||||
CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
||||
{
|
||||
lazy_load_curl();
|
||||
return curl_multi_perform_func(multi_handle, running_handles);
|
||||
}
|
||||
|
||||
CURLMcode curl_multi_cleanup(CURLM *multi_handle)
|
||||
{
|
||||
lazy_load_curl();
|
||||
return curl_multi_cleanup_func(multi_handle);
|
||||
}
|
||||
|
||||
CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue)
|
||||
{
|
||||
lazy_load_curl();
|
||||
return curl_multi_info_read_func(multi_handle, msgs_in_queue);
|
||||
}
|
||||
|
||||
const char *curl_multi_strerror(CURLMcode error)
|
||||
{
|
||||
lazy_load_curl();
|
||||
return curl_multi_strerror_func(error);
|
||||
}
|
||||
|
||||
CURLMcode curl_multi_timeout(CURLM *multi_handle, long *milliseconds)
|
||||
{
|
||||
lazy_load_curl();
|
||||
return curl_multi_timeout_func(multi_handle, milliseconds);
|
||||
}
|
||||
|
||||
CURL *curl_easy_init(void)
|
||||
{
|
||||
lazy_load_curl();
|
||||
return curl_easy_init_func();
|
||||
}
|
||||
|
||||
CURLcode curl_easy_perform(CURL *curl)
|
||||
{
|
||||
lazy_load_curl();
|
||||
return curl_easy_perform_func(curl);
|
||||
}
|
||||
|
||||
void curl_easy_cleanup(CURL *curl)
|
||||
{
|
||||
lazy_load_curl();
|
||||
curl_easy_cleanup_func(curl);
|
||||
}
|
||||
|
||||
CURL *curl_easy_duphandle(CURL *curl)
|
||||
{
|
||||
lazy_load_curl();
|
||||
return curl_easy_duphandle_func(curl);
|
||||
}
|
||||
|
||||
#ifndef CURL_IGNORE_DEPRECATION
|
||||
#define CURL_IGNORE_DEPRECATION(x) x
|
||||
#endif
|
||||
|
||||
#ifndef CURLOPTTYPE_BLOB
|
||||
#define CURLOPTTYPE_BLOB 40000
|
||||
#endif
|
||||
|
||||
#undef curl_easy_getinfo
|
||||
CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...)
|
||||
{
|
||||
va_list ap;
|
||||
CURLcode res;
|
||||
|
||||
va_start(ap, info);
|
||||
lazy_load_curl();
|
||||
CURL_IGNORE_DEPRECATION(
|
||||
if (info >= CURLINFO_LONG && info < CURLINFO_DOUBLE)
|
||||
res = curl_easy_getinfo_long_func(curl, info, va_arg(ap, long *));
|
||||
else if ((info >= CURLINFO_STRING && info < CURLINFO_LONG) ||
|
||||
(info >= CURLINFO_SLIST && info < CURLINFO_SOCKET))
|
||||
res = curl_easy_getinfo_pointer_func(curl, info, va_arg(ap, void **));
|
||||
else if (info >= CURLINFO_OFF_T)
|
||||
res = curl_easy_getinfo_off_t_func(curl, info, va_arg(ap, curl_off_t *));
|
||||
else
|
||||
die("%s:%d: TODO (info: %d)!", __FILE__, __LINE__, info);
|
||||
)
|
||||
va_end(ap);
|
||||
return res;
|
||||
}
|
||||
|
||||
#undef curl_easy_setopt
|
||||
CURLcode curl_easy_setopt(CURL *curl, CURLoption opt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
CURLcode res;
|
||||
|
||||
va_start(ap, opt);
|
||||
lazy_load_curl();
|
||||
CURL_IGNORE_DEPRECATION(
|
||||
if (opt >= CURLOPTTYPE_LONG && opt < CURLOPTTYPE_OBJECTPOINT)
|
||||
res = curl_easy_setopt_long_func(curl, opt, va_arg(ap, long));
|
||||
else if (opt >= CURLOPTTYPE_OBJECTPOINT && opt < CURLOPTTYPE_OFF_T)
|
||||
res = curl_easy_setopt_pointer_func(curl, opt, va_arg(ap, void *));
|
||||
else if (opt >= CURLOPTTYPE_OFF_T && opt < CURLOPTTYPE_BLOB)
|
||||
res = curl_easy_setopt_off_t_func(curl, opt, va_arg(ap, curl_off_t));
|
||||
else
|
||||
die("%s:%d: TODO (opt: %d)!", __FILE__, __LINE__, opt);
|
||||
)
|
||||
va_end(ap);
|
||||
return res;
|
||||
}
|
||||
@@ -193,8 +193,10 @@ int setitimer(int type, struct itimerval *in, struct itimerval *out);
|
||||
int sigaction(int sig, struct sigaction *in, struct sigaction *out);
|
||||
int link(const char *oldpath, const char *newpath);
|
||||
int uname(struct utsname *buf);
|
||||
int symlink(const char *target, const char *link);
|
||||
int readlink(const char *path, char *buf, size_t bufsiz);
|
||||
struct index_state;
|
||||
int mingw_create_symlink(struct index_state *index, const char *target, const char *link);
|
||||
#define create_symlink mingw_create_symlink
|
||||
|
||||
/*
|
||||
* replacements of existing functions
|
||||
@@ -288,6 +290,11 @@ int mingw_socket(int domain, int type, int protocol);
|
||||
int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz);
|
||||
#define connect mingw_connect
|
||||
|
||||
char *mingw_strerror(int errnum);
|
||||
#ifndef _UCRT
|
||||
#define strerror mingw_strerror
|
||||
#endif
|
||||
|
||||
int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz);
|
||||
#define bind mingw_bind
|
||||
|
||||
|
||||
778
compat/mingw.c
778
compat/mingw.c
File diff suppressed because it is too large
Load Diff
@@ -36,9 +36,16 @@ static inline void convert_slashes(char *path)
|
||||
if (*path == '\\')
|
||||
*path = '/';
|
||||
}
|
||||
struct strbuf;
|
||||
int mingw_is_mount_point(struct strbuf *path);
|
||||
#define is_mount_point mingw_is_mount_point
|
||||
#define CAN_UNLINK_MOUNT_POINTS 1
|
||||
#define PATH_SEP ';'
|
||||
char *mingw_query_user_email(void);
|
||||
#define query_user_email mingw_query_user_email
|
||||
struct strbuf;
|
||||
char *mingw_strbuf_realpath(struct strbuf *resolved, const char *path);
|
||||
#define platform_strbuf_realpath mingw_strbuf_realpath
|
||||
|
||||
/**
|
||||
* Verifies that the specified path is owned by the user running the
|
||||
@@ -46,6 +53,7 @@ char *mingw_query_user_email(void);
|
||||
*/
|
||||
int is_path_owned_by_current_sid(const char *path, struct strbuf *report);
|
||||
#define is_path_owned_by_current_user is_path_owned_by_current_sid
|
||||
int is_valid_windows_path_element(wchar_t ch);
|
||||
|
||||
/**
|
||||
* Verifies that the given path is a valid one on Windows.
|
||||
@@ -213,3 +221,8 @@ int mingw_have_unix_sockets(void);
|
||||
#undef have_unix_sockets
|
||||
#define have_unix_sockets mingw_have_unix_sockets
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check current process is inside Windows Container.
|
||||
*/
|
||||
int is_inside_windows_container(void);
|
||||
|
||||
@@ -418,6 +418,55 @@ static int getchar_with_timeout(int timeout)
|
||||
return getchar();
|
||||
}
|
||||
|
||||
static char *shell_prompt(const char *prompt, int echo)
|
||||
{
|
||||
const char *read_input[] = {
|
||||
/* Note: call 'bash' explicitly, as 'read -s' is bash-specific */
|
||||
"bash", "-c", echo ?
|
||||
"cat >/dev/tty && read -r line </dev/tty && echo \"$line\"" :
|
||||
"cat >/dev/tty && read -r -s line </dev/tty && echo \"$line\" && echo >/dev/tty",
|
||||
NULL
|
||||
};
|
||||
struct child_process child = CHILD_PROCESS_INIT;
|
||||
static struct strbuf buffer = STRBUF_INIT;
|
||||
int prompt_len = strlen(prompt), len = -1, code;
|
||||
|
||||
strvec_pushv(&child.args, read_input);
|
||||
child.in = -1;
|
||||
child.out = -1;
|
||||
child.silent_exec_failure = 1;
|
||||
|
||||
if (start_command(&child))
|
||||
return NULL;
|
||||
|
||||
if (write_in_full(child.in, prompt, prompt_len) != prompt_len) {
|
||||
error("could not write to prompt script");
|
||||
close(child.in);
|
||||
goto ret;
|
||||
}
|
||||
close(child.in);
|
||||
|
||||
strbuf_reset(&buffer);
|
||||
len = strbuf_read(&buffer, child.out, 1024);
|
||||
if (len < 0) {
|
||||
error("could not read from prompt script");
|
||||
goto ret;
|
||||
}
|
||||
|
||||
strbuf_strip_suffix(&buffer, "\n");
|
||||
strbuf_strip_suffix(&buffer, "\r");
|
||||
|
||||
ret:
|
||||
close(child.out);
|
||||
code = finish_command(&child);
|
||||
if (code) {
|
||||
error("failed to execute prompt script (exit code %d)", code);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return len < 0 ? NULL : buffer.buf;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef FORCE_TEXT
|
||||
@@ -430,6 +479,15 @@ char *git_terminal_prompt(const char *prompt, int echo)
|
||||
int r;
|
||||
FILE *input_fh, *output_fh;
|
||||
|
||||
#ifdef GIT_WINDOWS_NATIVE
|
||||
|
||||
/* try shell_prompt first, fall back to CONIN/OUT if bash is missing */
|
||||
char *result = shell_prompt(prompt, echo);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
#endif
|
||||
|
||||
input_fh = fopen(INPUT_PATH, "r" FORCE_TEXT);
|
||||
if (!input_fh)
|
||||
return NULL;
|
||||
|
||||
@@ -6,7 +6,11 @@ The Steps to Build Git with VS2015 or VS2017 from the command line.
|
||||
Prompt or from an SDK bash window:
|
||||
|
||||
$ cd <repo_root>
|
||||
$ ./compat/vcbuild/vcpkg_install.bat
|
||||
$ ./compat/vcbuild/vcpkg_install.bat x64-windows
|
||||
|
||||
or
|
||||
|
||||
$ ./compat/vcbuild/vcpkg_install.bat arm64-windows
|
||||
|
||||
The vcpkg tools and all of the third-party sources will be installed
|
||||
in this folder:
|
||||
@@ -37,27 +41,17 @@ The Steps to Build Git with VS2015 or VS2017 from the command line.
|
||||
|
||||
================================================================
|
||||
|
||||
Alternatively, run `make vcxproj` and then load the generated `git.sln` in
|
||||
Visual Studio. The initial build will install the vcpkg system and build the
|
||||
Alternatively, just open Git's top-level directory in Visual Studio, via
|
||||
`File>Open>Folder...`. This will use CMake internally to generate the
|
||||
project definitions. It will also install the vcpkg system and build the
|
||||
dependencies automatically. This will take a while.
|
||||
|
||||
Instead of generating the `git.sln` file yourself (which requires a full Git
|
||||
for Windows SDK), you may want to consider fetching the `vs/master` branch of
|
||||
https://github.com/git-for-windows/git instead (which is updated automatically
|
||||
via CI running `make vcxproj`). The `vs/master` branch does not require a Git
|
||||
for Windows to build, but you can run the test scripts in a regular Git Bash.
|
||||
You can also generate the Visual Studio solution manually by downloading
|
||||
and running CMake explicitly rather than letting Visual Studio doing
|
||||
that implicitly.
|
||||
|
||||
Note that `make vcxproj` will automatically add and commit the generated `.sln`
|
||||
and `.vcxproj` files to the repo. This is necessary to allow building a
|
||||
fully-testable Git in Visual Studio, where a regular Git Bash can be used to
|
||||
run the test scripts (as opposed to a full Git for Windows SDK): a number of
|
||||
build targets, such as Git commands implemented as Unix shell scripts (where
|
||||
`@@SHELL_PATH@@` and other placeholders are interpolated) require a full-blown
|
||||
Git for Windows SDK (which is about 10x the size of a regular Git for Windows
|
||||
installation).
|
||||
|
||||
If your plan is to open a Pull Request with Git for Windows, it is a good idea
|
||||
to drop this commit before submitting.
|
||||
Another, deprecated option is to run `make vcxproj`. This option is
|
||||
superseded by the CMake-based build, and will be removed at some point.
|
||||
|
||||
================================================================
|
||||
The Steps of Build Git with VS2008
|
||||
|
||||
@@ -99,6 +99,7 @@ REM ================================================================
|
||||
|
||||
SET sdk_dir=%WindowsSdkDir%
|
||||
SET sdk_ver=%WindowsSDKVersion%
|
||||
SET sdk_ver_bin_dir=%WindowsSdkVerBinPath%%tgt%
|
||||
SET si=%sdk_dir%Include\%sdk_ver%
|
||||
SET sdk_includes=-I"%si%ucrt" -I"%si%um" -I"%si%shared"
|
||||
SET sl=%sdk_dir%lib\%sdk_ver%
|
||||
@@ -130,6 +131,7 @@ REM ================================================================
|
||||
|
||||
SET sdk_dir=%WindowsSdkDir%
|
||||
SET sdk_ver=%WindowsSDKVersion%
|
||||
SET sdk_ver_bin_dir=%WindowsSdkVerBinPath%bin\amd64
|
||||
SET si=%sdk_dir%Include\%sdk_ver%
|
||||
SET sdk_includes=-I"%si%ucrt" -I"%si%um" -I"%si%shared" -I"%si%winrt"
|
||||
SET sl=%sdk_dir%lib\%sdk_ver%
|
||||
@@ -160,6 +162,11 @@ REM ================================================================
|
||||
echo msvc_includes=%msvc_includes%
|
||||
echo msvc_libs=%msvc_libs%
|
||||
|
||||
echo sdk_ver_bin_dir=%sdk_ver_bin_dir%
|
||||
SET X1=%sdk_ver_bin_dir:C:=/C%
|
||||
SET X2=%X1:\=/%
|
||||
echo sdk_ver_bin_dir_msys=%X2%
|
||||
|
||||
echo sdk_includes=%sdk_includes%
|
||||
echo sdk_libs=%sdk_libs%
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ my @cflags = ();
|
||||
my @lflags = ();
|
||||
my $is_linking = 0;
|
||||
my $is_debug = 0;
|
||||
my $is_gui = 0;
|
||||
while (@ARGV) {
|
||||
my $arg = shift @ARGV;
|
||||
if ("$arg" eq "-DDEBUG") {
|
||||
@@ -56,7 +57,8 @@ while (@ARGV) {
|
||||
# need to use that instead?
|
||||
foreach my $flag (@lflags) {
|
||||
if ($flag =~ /^-LIBPATH:(.*)/) {
|
||||
foreach my $l ("libcurl_imp.lib", "libcurl.lib") {
|
||||
my $libcurl = $is_debug ? "libcurl-d.lib" : "libcurl.lib";
|
||||
foreach my $l ("libcurl_imp.lib", $libcurl) {
|
||||
if (-f "$1/$l") {
|
||||
$lib = $l;
|
||||
last;
|
||||
@@ -66,7 +68,11 @@ while (@ARGV) {
|
||||
}
|
||||
push(@args, $lib);
|
||||
} elsif ("$arg" eq "-lexpat") {
|
||||
if ($is_debug) {
|
||||
push(@args, "libexpatd.lib");
|
||||
} else {
|
||||
push(@args, "libexpat.lib");
|
||||
}
|
||||
} elsif ("$arg" =~ /^-L/ && "$arg" ne "-LTCG") {
|
||||
$arg =~ s/^-L/-LIBPATH:/;
|
||||
push(@lflags, $arg);
|
||||
@@ -118,11 +124,23 @@ while (@ARGV) {
|
||||
push(@cflags, "-wd4996");
|
||||
} elsif ("$arg" =~ /^-W[a-z]/) {
|
||||
# let's ignore those
|
||||
} elsif ("$arg" eq "-fno-stack-protector") {
|
||||
# eat this
|
||||
} elsif ("$arg" eq "-mwindows") {
|
||||
$is_gui = 1;
|
||||
} else {
|
||||
push(@args, $arg);
|
||||
}
|
||||
}
|
||||
if ($is_linking) {
|
||||
if ($is_gui) {
|
||||
push(@args, "-ENTRY:wWinMainCRTStartup");
|
||||
push(@args, "-SUBSYSTEM:WINDOWS");
|
||||
} else {
|
||||
push(@args, "-ENTRY:wmainCRTStartup");
|
||||
push(@args, "-SUBSYSTEM:CONSOLE");
|
||||
}
|
||||
|
||||
push(@args, @lflags);
|
||||
unshift(@args, "link.exe");
|
||||
} else {
|
||||
|
||||
46
compat/vcbuild/scripts/rc.pl
Normal file
46
compat/vcbuild/scripts/rc.pl
Normal file
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/perl -w
|
||||
######################################################################
|
||||
# Compile Resources on Windows
|
||||
#
|
||||
# This is a wrapper to facilitate the compilation of Git with MSVC
|
||||
# using GNU Make as the build system. So, instead of manipulating the
|
||||
# Makefile into something nasty, just to support non-space arguments
|
||||
# etc, we use this wrapper to fix the command line options
|
||||
#
|
||||
######################################################################
|
||||
use strict;
|
||||
my @args = ();
|
||||
my @input = ();
|
||||
|
||||
while (@ARGV) {
|
||||
my $arg = shift @ARGV;
|
||||
if ("$arg" =~ /^-[dD]/) {
|
||||
# GIT_VERSION gets passed with too many
|
||||
# layers of dquote escaping.
|
||||
$arg =~ s/\\"/"/g;
|
||||
|
||||
push(@args, $arg);
|
||||
|
||||
} elsif ("$arg" eq "-i") {
|
||||
my $arg = shift @ARGV;
|
||||
# TODO complain if NULL or is dashed ??
|
||||
push(@input, $arg);
|
||||
|
||||
} elsif ("$arg" eq "-o") {
|
||||
my $arg = shift @ARGV;
|
||||
# TODO complain if NULL or is dashed ??
|
||||
push(@args, "-fo$arg");
|
||||
|
||||
} else {
|
||||
push(@args, $arg);
|
||||
}
|
||||
}
|
||||
|
||||
push(@args, "-nologo");
|
||||
push(@args, "-v");
|
||||
push(@args, @input);
|
||||
|
||||
unshift(@args, "rc.exe");
|
||||
printf("**** @args\n");
|
||||
|
||||
exit (system(@args) != 0);
|
||||
@@ -15,7 +15,12 @@ REM ================================================================
|
||||
@FOR /F "delims=" %%D IN ("%~dp0") DO @SET cwd=%%~fD
|
||||
cd %cwd%
|
||||
|
||||
SET arch=x64-windows
|
||||
SET arch=%2
|
||||
IF NOT DEFINED arch (
|
||||
echo defaulting to 'x64-windows`. Invoke %0 with 'x86-windows', 'x64-windows', or 'arm64-windows'
|
||||
set arch=x64-windows
|
||||
)
|
||||
|
||||
SET inst=%cwd%vcpkg\installed\%arch%
|
||||
|
||||
IF [%1]==[release] (
|
||||
|
||||
@@ -31,11 +31,24 @@ REM ================================================================
|
||||
|
||||
SETLOCAL EnableDelayedExpansion
|
||||
|
||||
SET arch=%1
|
||||
IF NOT DEFINED arch (
|
||||
echo defaulting to 'x64-windows`. Invoke %0 with 'x86-windows', 'x64-windows', or 'arm64-windows'
|
||||
set arch=x64-windows
|
||||
)
|
||||
|
||||
@FOR /F "delims=" %%D IN ("%~dp0") DO @SET cwd=%%~fD
|
||||
cd %cwd%
|
||||
|
||||
dir vcpkg\vcpkg.exe >nul 2>nul && GOTO :install_libraries
|
||||
|
||||
git.exe version 2>nul
|
||||
IF ERRORLEVEL 1 (
|
||||
echo "***"
|
||||
echo "Git not found. Please adjust your CMD path or Git install option."
|
||||
echo "***"
|
||||
EXIT /B 1 )
|
||||
|
||||
echo Fetching vcpkg in %cwd%vcpkg
|
||||
git.exe clone https://github.com/Microsoft/vcpkg vcpkg
|
||||
IF ERRORLEVEL 1 ( EXIT /B 1 )
|
||||
@@ -48,9 +61,8 @@ REM ================================================================
|
||||
echo Successfully installed %cwd%vcpkg\vcpkg.exe
|
||||
|
||||
:install_libraries
|
||||
SET arch=x64-windows
|
||||
|
||||
echo Installing third-party libraries...
|
||||
echo Installing third-party libraries(%arch%)...
|
||||
FOR %%i IN (zlib expat libiconv openssl libssh2 curl) DO (
|
||||
cd %cwd%vcpkg
|
||||
IF NOT EXIST "packages\%%i_%arch%" CALL :sub__install_one %%i
|
||||
@@ -73,8 +85,47 @@ REM ================================================================
|
||||
:sub__install_one
|
||||
echo Installing package %1...
|
||||
|
||||
.\vcpkg.exe install %1:%arch%
|
||||
call :%1_features
|
||||
|
||||
REM vcpkg may not be reliable on slow, intermittent or proxy
|
||||
REM connections, see e.g.
|
||||
REM https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/4a8f7be5-5e15-4213-a7bb-ddf424a954e6/winhttpsendrequest-ends-with-12002-errorhttptimeout-after-21-seconds-no-matter-what-timeout?forum=windowssdk
|
||||
REM which explains the hidden 21 second timeout
|
||||
REM (last post by Dave : Microsoft - Windows Networking team)
|
||||
|
||||
.\vcpkg.exe install %1%features%:%arch%
|
||||
IF ERRORLEVEL 1 ( EXIT /B 1 )
|
||||
|
||||
echo Finished %1
|
||||
goto :EOF
|
||||
|
||||
::
|
||||
:: features for each vcpkg to install
|
||||
:: there should be an entry here for each package to install
|
||||
:: 'set features=' means use the default otherwise
|
||||
:: 'set features=[comma-delimited-feature-set]' is the syntax
|
||||
::
|
||||
|
||||
:zlib_features
|
||||
set features=
|
||||
goto :EOF
|
||||
|
||||
:expat_features
|
||||
set features=
|
||||
goto :EOF
|
||||
|
||||
:libiconv_features
|
||||
set features=
|
||||
goto :EOF
|
||||
|
||||
:openssl_features
|
||||
set features=
|
||||
goto :EOF
|
||||
|
||||
:libssh2_features
|
||||
set features=
|
||||
goto :EOF
|
||||
|
||||
:curl_features
|
||||
set features=[core,openssl,schannel]
|
||||
goto :EOF
|
||||
|
||||
@@ -6,19 +6,7 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
static inline int file_attr_to_st_mode (DWORD attr, DWORD tag)
|
||||
{
|
||||
int fMode = S_IREAD;
|
||||
if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) && tag == IO_REPARSE_TAG_SYMLINK)
|
||||
fMode |= S_IFLNK;
|
||||
else if (attr & FILE_ATTRIBUTE_DIRECTORY)
|
||||
fMode |= S_IFDIR;
|
||||
else
|
||||
fMode |= S_IFREG;
|
||||
if (!(attr & FILE_ATTRIBUTE_READONLY))
|
||||
fMode |= S_IWRITE;
|
||||
return fMode;
|
||||
}
|
||||
extern int file_attr_to_st_mode (DWORD attr, DWORD tag, const char *path);
|
||||
|
||||
static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fdata)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
#include "../../git-compat-util.h"
|
||||
#include "../../environment.h"
|
||||
#include "../../wrapper.h"
|
||||
#include "../../strbuf.h"
|
||||
#include "../../versioncmp.h"
|
||||
|
||||
int win32_has_dos_drive_prefix(const char *path)
|
||||
{
|
||||
@@ -89,3 +92,199 @@ int win32_fspathcmp(const char *a, const char *b)
|
||||
{
|
||||
return win32_fspathncmp(a, b, (size_t)-1);
|
||||
}
|
||||
|
||||
static int read_at(int fd, char *buffer, size_t offset, size_t size)
|
||||
{
|
||||
if (lseek(fd, offset, SEEK_SET) < 0) {
|
||||
fprintf(stderr, "could not seek to 0x%x\n", (unsigned int)offset);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return read_in_full(fd, buffer, size);
|
||||
}
|
||||
|
||||
static size_t le16(const char *buffer)
|
||||
{
|
||||
unsigned char *u = (unsigned char *)buffer;
|
||||
return u[0] | (u[1] << 8);
|
||||
}
|
||||
|
||||
static size_t le32(const char *buffer)
|
||||
{
|
||||
return le16(buffer) | (le16(buffer + 2) << 16);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the Go version of a given executable, if it was built with Go.
|
||||
*
|
||||
* This recapitulates the logic from
|
||||
* https://github.com/golang/go/blob/master/src/cmd/go/internal/version/version.go
|
||||
* (without requiring the user to install `go.exe` to find out).
|
||||
*/
|
||||
static ssize_t get_go_version(const char *path, char *go_version, size_t go_version_size)
|
||||
{
|
||||
int fd = open(path, O_RDONLY);
|
||||
char buffer[1024];
|
||||
off_t offset;
|
||||
size_t num_sections, opt_header_size, i;
|
||||
char *p = NULL, *q;
|
||||
ssize_t res = -1;
|
||||
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
if (read_in_full(fd, buffer, 2) < 0)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* Parse the PE file format, for more details, see
|
||||
* https://en.wikipedia.org/wiki/Portable_Executable#Layout and
|
||||
* https://learn.microsoft.com/en-us/windows/win32/debug/pe-format
|
||||
*/
|
||||
if (buffer[0] != 'M' || buffer[1] != 'Z')
|
||||
goto fail;
|
||||
|
||||
if (read_at(fd, buffer, 0x3c, 4) < 0)
|
||||
goto fail;
|
||||
|
||||
/* Read the `PE\0\0` signature and the COFF file header */
|
||||
offset = le32(buffer);
|
||||
if (read_at(fd, buffer, offset, 24) < 0)
|
||||
goto fail;
|
||||
|
||||
if (buffer[0] != 'P' || buffer[1] != 'E' || buffer[2] != '\0' || buffer[3] != '\0')
|
||||
goto fail;
|
||||
|
||||
num_sections = le16(buffer + 6);
|
||||
opt_header_size = le16(buffer + 20);
|
||||
offset += 24; /* skip file header */
|
||||
|
||||
/*
|
||||
* Validate magic number 0x10b or 0x20b, for full details see
|
||||
* https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#optional-header-standard-fields-image-only
|
||||
*/
|
||||
if (read_at(fd, buffer, offset, 2) < 0 ||
|
||||
((i = le16(buffer)) != 0x10b && i != 0x20b))
|
||||
goto fail;
|
||||
|
||||
offset += opt_header_size;
|
||||
|
||||
for (i = 0; i < num_sections; i++) {
|
||||
if (read_at(fd, buffer, offset + i * 40, 40) < 0)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* For full details about the section headers, see
|
||||
* https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#section-table-section-headers
|
||||
*/
|
||||
if ((le32(buffer + 36) /* characteristics */ & ~0x600000) /* IMAGE_SCN_ALIGN_32BYTES */ ==
|
||||
(/* IMAGE_SCN_CNT_INITIALIZED_DATA */ 0x00000040 |
|
||||
/* IMAGE_SCN_MEM_READ */ 0x40000000 |
|
||||
/* IMAGE_SCN_MEM_WRITE */ 0x80000000)) {
|
||||
size_t size = le32(buffer + 16); /* "SizeOfRawData " */
|
||||
size_t pointer = le32(buffer + 20); /* "PointerToRawData " */
|
||||
|
||||
/*
|
||||
* Skip the section if either size or pointer is 0, see
|
||||
* https://github.com/golang/go/blob/go1.21.0/src/debug/buildinfo/buildinfo.go#L333
|
||||
* for full details.
|
||||
*
|
||||
* Merely seeing a non-zero size will not actually do,
|
||||
* though: he size must be at least `buildInfoSize`,
|
||||
* i.e. 32, and we expect a UVarint (at least another
|
||||
* byte) _and_ the bytes representing the string,
|
||||
* which we expect to start with the letters "go" and
|
||||
* continue with the Go version number.
|
||||
*/
|
||||
if (size < 32 + 1 + 2 + 1 || !pointer)
|
||||
continue;
|
||||
|
||||
p = malloc(size);
|
||||
|
||||
if (!p || read_at(fd, p, pointer, size) < 0)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* Look for the build information embedded by Go, see
|
||||
* https://github.com/golang/go/blob/go1.21.0/src/debug/buildinfo/buildinfo.go#L165-L175
|
||||
* for full details.
|
||||
*
|
||||
* Note: Go contains code to enforce alignment along a
|
||||
* 16-byte boundary. In practice, no `.exe` has been
|
||||
* observed that required any adjustment, therefore
|
||||
* this here code skips that logic for simplicity.
|
||||
*/
|
||||
q = memmem(p, size - 18, "\xff Go buildinf:", 14);
|
||||
if (!q)
|
||||
goto fail;
|
||||
/*
|
||||
* Decode the build blob. For full details, see
|
||||
* https://github.com/golang/go/blob/go1.21.0/src/debug/buildinfo/buildinfo.go#L177-L191
|
||||
*
|
||||
* Note: The `endianness` values observed in practice
|
||||
* were always 2, therefore the complex logic to handle
|
||||
* any other value is skipped for simplicty.
|
||||
*/
|
||||
if ((q[14] == 8 || q[14] == 4) && q[15] == 2) {
|
||||
/*
|
||||
* Only handle a Go version string with fewer
|
||||
* than 128 characters, so the Go UVarint at
|
||||
* q[32] that indicates the string's length must
|
||||
* be only one byte (without the high bit set).
|
||||
*/
|
||||
if ((q[32] & 0x80) ||
|
||||
!q[32] ||
|
||||
(q + 33 + q[32] - p) > (ssize_t)size ||
|
||||
q[32] + 1 > (ssize_t)go_version_size)
|
||||
goto fail;
|
||||
res = q[32];
|
||||
memcpy(go_version, q + 33, res);
|
||||
go_version[res] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
free(p);
|
||||
close(fd);
|
||||
return res;
|
||||
}
|
||||
|
||||
void win32_warn_about_git_lfs_on_windows7(int exit_code, const char *argv0)
|
||||
{
|
||||
char buffer[128], *git_lfs = NULL;
|
||||
const char *p;
|
||||
|
||||
/*
|
||||
* Git LFS v3.5.1 fails with an Access Violation on Windows 7; That
|
||||
* would usually show up as an exit code 0xc0000005. For some reason
|
||||
* (probably because at this point, we no longer have the _original_
|
||||
* HANDLE that was returned by `CreateProcess()`) we observe other
|
||||
* values like 0xb00 and 0x2 instead. Since the exact exit code
|
||||
* seems to be inconsistent, we check for a non-zero exit status.
|
||||
*/
|
||||
if (exit_code == 0)
|
||||
return;
|
||||
if (GetVersion() >> 16 > 7601)
|
||||
return; /* Warn only on Windows 7 or older */
|
||||
if (!istarts_with(argv0, "git-lfs ") &&
|
||||
strcasecmp(argv0, "git-lfs"))
|
||||
return;
|
||||
if (!(git_lfs = locate_in_PATH("git-lfs")))
|
||||
return;
|
||||
if (get_go_version(git_lfs, buffer, sizeof(buffer)) > 0 &&
|
||||
skip_prefix(buffer, "go", &p) &&
|
||||
versioncmp("1.21.0", p) <= 0)
|
||||
warning("This program was built with Go v%s\n"
|
||||
"i.e. without support for this Windows version:\n"
|
||||
"\n\t%s\n"
|
||||
"\n"
|
||||
"To work around this, you can download and install a "
|
||||
"working version from\n"
|
||||
"\n"
|
||||
"\thttps://github.com/git-lfs/git-lfs/releases/tag/"
|
||||
"v3.4.1\n",
|
||||
p, git_lfs);
|
||||
free(git_lfs);
|
||||
}
|
||||
|
||||
@@ -34,4 +34,7 @@ int win32_fspathcmp(const char *a, const char *b);
|
||||
int win32_fspathncmp(const char *a, const char *b, size_t count);
|
||||
#define fspathncmp win32_fspathncmp
|
||||
|
||||
void win32_warn_about_git_lfs_on_windows7(int exit_code, const char *argv0);
|
||||
#define warn_about_git_lfs_on_windows7 win32_warn_about_git_lfs_on_windows7
|
||||
|
||||
#endif
|
||||
|
||||
142
compat/win32/wsl.c
Normal file
142
compat/win32/wsl.c
Normal file
@@ -0,0 +1,142 @@
|
||||
#define USE_THE_REPOSITORY_VARIABLE
|
||||
#include "../../git-compat-util.h"
|
||||
#include "../win32.h"
|
||||
#include "../../repository.h"
|
||||
#include "config.h"
|
||||
#include "ntifs.h"
|
||||
#include "wsl.h"
|
||||
|
||||
int are_wsl_compatible_mode_bits_enabled(void)
|
||||
{
|
||||
/* default to `false` during initialization */
|
||||
static const int fallback = 0;
|
||||
static int enabled = -1;
|
||||
|
||||
if (enabled < 0) {
|
||||
/* avoid infinite recursion */
|
||||
if (!the_repository)
|
||||
return fallback;
|
||||
|
||||
if (the_repository->config &&
|
||||
the_repository->config->hash_initialized &&
|
||||
repo_config_get_bool(the_repository, "core.wslcompat", &enabled) < 0)
|
||||
enabled = 0;
|
||||
}
|
||||
|
||||
return enabled < 0 ? fallback : enabled;
|
||||
}
|
||||
|
||||
int copy_wsl_mode_bits_from_disk(const wchar_t *wpath, ssize_t wpathlen,
|
||||
_mode_t *mode)
|
||||
{
|
||||
int ret = -1;
|
||||
HANDLE h;
|
||||
if (wpathlen >= 0) {
|
||||
/*
|
||||
* It's caller's duty to make sure wpathlen is reasonable so
|
||||
* it does not overflow.
|
||||
*/
|
||||
wchar_t *fn2 = (wchar_t*)alloca((wpathlen + 1) * sizeof(wchar_t));
|
||||
memcpy(fn2, wpath, wpathlen * sizeof(wchar_t));
|
||||
fn2[wpathlen] = 0;
|
||||
wpath = fn2;
|
||||
}
|
||||
h = CreateFileW(wpath, FILE_READ_EA | SYNCHRONIZE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL, OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS |
|
||||
FILE_FLAG_OPEN_REPARSE_POINT,
|
||||
NULL);
|
||||
if (h != INVALID_HANDLE_VALUE) {
|
||||
ret = get_wsl_mode_bits_by_handle(h, mode);
|
||||
CloseHandle(h);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef LX_FILE_METADATA_HAS_UID
|
||||
#define LX_FILE_METADATA_HAS_UID 0x1
|
||||
#define LX_FILE_METADATA_HAS_GID 0x2
|
||||
#define LX_FILE_METADATA_HAS_MODE 0x4
|
||||
#define LX_FILE_METADATA_HAS_DEVICE_ID 0x8
|
||||
#define LX_FILE_CASE_SENSITIVE_DIR 0x10
|
||||
typedef struct _FILE_STAT_LX_INFORMATION {
|
||||
LARGE_INTEGER FileId;
|
||||
LARGE_INTEGER CreationTime;
|
||||
LARGE_INTEGER LastAccessTime;
|
||||
LARGE_INTEGER LastWriteTime;
|
||||
LARGE_INTEGER ChangeTime;
|
||||
LARGE_INTEGER AllocationSize;
|
||||
LARGE_INTEGER EndOfFile;
|
||||
uint32_t FileAttributes;
|
||||
uint32_t ReparseTag;
|
||||
uint32_t NumberOfLinks;
|
||||
ACCESS_MASK EffectiveAccess;
|
||||
uint32_t LxFlags;
|
||||
uint32_t LxUid;
|
||||
uint32_t LxGid;
|
||||
uint32_t LxMode;
|
||||
uint32_t LxDeviceIdMajor;
|
||||
uint32_t LxDeviceIdMinor;
|
||||
} FILE_STAT_LX_INFORMATION, *PFILE_STAT_LX_INFORMATION;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This struct is extended from the original FILE_FULL_EA_INFORMATION of
|
||||
* Microsoft Windows.
|
||||
*/
|
||||
struct wsl_full_ea_info_t {
|
||||
uint32_t NextEntryOffset;
|
||||
uint8_t Flags;
|
||||
uint8_t EaNameLength;
|
||||
uint16_t EaValueLength;
|
||||
char EaName[7];
|
||||
char EaValue[4];
|
||||
char Padding[1];
|
||||
};
|
||||
|
||||
enum {
|
||||
FileStatLxInformation = 70,
|
||||
};
|
||||
__declspec(dllimport) NTSTATUS WINAPI
|
||||
NtQueryInformationFile(HANDLE FileHandle,
|
||||
PIO_STATUS_BLOCK IoStatusBlock,
|
||||
PVOID FileInformation, ULONG Length,
|
||||
uint32_t FileInformationClass);
|
||||
__declspec(dllimport) NTSTATUS WINAPI
|
||||
NtSetInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock,
|
||||
PVOID FileInformation, ULONG Length,
|
||||
uint32_t FileInformationClass);
|
||||
__declspec(dllimport) NTSTATUS WINAPI
|
||||
NtSetEaFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock,
|
||||
PVOID EaBuffer, ULONG EaBufferSize);
|
||||
|
||||
int set_wsl_mode_bits_by_handle(HANDLE h, _mode_t mode)
|
||||
{
|
||||
uint32_t value = mode;
|
||||
struct wsl_full_ea_info_t ea_info;
|
||||
IO_STATUS_BLOCK iob;
|
||||
/* mode should be valid to make WSL happy */
|
||||
assert(S_ISREG(mode) || S_ISDIR(mode));
|
||||
ea_info.NextEntryOffset = 0;
|
||||
ea_info.Flags = 0;
|
||||
ea_info.EaNameLength = 6;
|
||||
ea_info.EaValueLength = sizeof(value); /* 4 */
|
||||
strlcpy(ea_info.EaName, "$LXMOD", sizeof(ea_info.EaName));
|
||||
memcpy(ea_info.EaValue, &value, sizeof(value));
|
||||
ea_info.Padding[0] = 0;
|
||||
return NtSetEaFile(h, &iob, &ea_info, sizeof(ea_info));
|
||||
}
|
||||
|
||||
int get_wsl_mode_bits_by_handle(HANDLE h, _mode_t *mode)
|
||||
{
|
||||
FILE_STAT_LX_INFORMATION fxi;
|
||||
IO_STATUS_BLOCK iob;
|
||||
if (NtQueryInformationFile(h, &iob, &fxi, sizeof(fxi),
|
||||
FileStatLxInformation) == 0) {
|
||||
if (fxi.LxFlags & LX_FILE_METADATA_HAS_MODE)
|
||||
*mode = (_mode_t)fxi.LxMode;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
12
compat/win32/wsl.h
Normal file
12
compat/win32/wsl.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef COMPAT_WIN32_WSL_H
|
||||
#define COMPAT_WIN32_WSL_H
|
||||
|
||||
int are_wsl_compatible_mode_bits_enabled(void);
|
||||
|
||||
int copy_wsl_mode_bits_from_disk(const wchar_t *wpath, ssize_t wpathlen,
|
||||
_mode_t *mode);
|
||||
|
||||
int get_wsl_mode_bits_by_handle(HANDLE h, _mode_t *mode);
|
||||
int set_wsl_mode_bits_by_handle(HANDLE h, _mode_t mode);
|
||||
|
||||
#endif
|
||||
@@ -546,6 +546,9 @@ static void detect_msys_tty(int fd)
|
||||
if (!NT_SUCCESS(NtQueryObject(h, ObjectNameInformation,
|
||||
buffer, sizeof(buffer) - 2, &result)))
|
||||
return;
|
||||
if (result < sizeof(*nameinfo) || !nameinfo->Name.Buffer ||
|
||||
!nameinfo->Name.Length)
|
||||
return;
|
||||
name = nameinfo->Name.Buffer;
|
||||
name[nameinfo->Name.Length / sizeof(*name)] = 0;
|
||||
|
||||
@@ -564,6 +567,49 @@ static void detect_msys_tty(int fd)
|
||||
|
||||
#endif
|
||||
|
||||
static HANDLE std_console_handle;
|
||||
static DWORD std_console_mode = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
static UINT std_console_code_page = CP_UTF8;
|
||||
|
||||
static void reset_std_console(void)
|
||||
{
|
||||
if (std_console_mode != ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
||||
SetConsoleMode(std_console_handle, std_console_mode);
|
||||
if (std_console_code_page != CP_UTF8)
|
||||
SetConsoleOutputCP(std_console_code_page);
|
||||
}
|
||||
|
||||
static int enable_virtual_processing(void)
|
||||
{
|
||||
std_console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (std_console_handle == INVALID_HANDLE_VALUE ||
|
||||
!GetConsoleMode(std_console_handle, &std_console_mode)) {
|
||||
std_console_handle = GetStdHandle(STD_ERROR_HANDLE);
|
||||
if (std_console_handle == INVALID_HANDLE_VALUE ||
|
||||
!GetConsoleMode(std_console_handle, &std_console_mode))
|
||||
return 0;
|
||||
}
|
||||
|
||||
std_console_code_page = GetConsoleOutputCP();
|
||||
if (std_console_code_page != CP_UTF8)
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
if (!std_console_code_page)
|
||||
std_console_code_page = CP_UTF8;
|
||||
|
||||
atexit(reset_std_console);
|
||||
|
||||
if (std_console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
||||
return 1;
|
||||
|
||||
if (!SetConsoleMode(std_console_handle,
|
||||
std_console_mode |
|
||||
ENABLE_PROCESSED_OUTPUT |
|
||||
ENABLE_VIRTUAL_TERMINAL_PROCESSING))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper for isatty(). Most calls in the main git code
|
||||
* call isatty(1 or 2) to see if the instance is interactive
|
||||
@@ -602,6 +648,9 @@ void winansi_init(void)
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable_virtual_processing())
|
||||
return;
|
||||
|
||||
/* create a named pipe to communicate with the console thread */
|
||||
if (swprintf(name, ARRAY_SIZE(name) - 1, L"\\\\.\\pipe\\winansi%lu",
|
||||
GetCurrentProcessId()) < 0)
|
||||
|
||||
@@ -465,14 +465,8 @@ ifeq ($(uname_S),Windows)
|
||||
GIT_VERSION := $(GIT_VERSION).MSVC
|
||||
pathsep = ;
|
||||
# Assume that this is built in Git for Windows' SDK
|
||||
ifeq (MINGW32,$(MSYSTEM))
|
||||
prefix = /mingw32
|
||||
else
|
||||
ifeq (CLANGARM64,$(MSYSTEM))
|
||||
prefix = /clangarm64
|
||||
else
|
||||
prefix = /mingw64
|
||||
endif
|
||||
ifneq (,$(MSYSTEM))
|
||||
prefix = $(MINGW_PREFIX)
|
||||
endif
|
||||
# Prepend MSVC 64-bit tool-chain to PATH.
|
||||
#
|
||||
@@ -480,7 +474,7 @@ ifeq ($(uname_S),Windows)
|
||||
# link.exe next to, and required by, cl.exe, we have to prepend this
|
||||
# onto the existing $PATH.
|
||||
#
|
||||
SANE_TOOL_PATH ?= $(msvc_bin_dir_msys)
|
||||
SANE_TOOL_PATH ?= $(msvc_bin_dir_msys):$(sdk_ver_bin_dir_msys)
|
||||
HAVE_ALLOCA_H = YesPlease
|
||||
NO_PREAD = YesPlease
|
||||
NEEDS_CRYPTO_WITH_SSL = YesPlease
|
||||
@@ -524,7 +518,8 @@ ifeq ($(uname_S),Windows)
|
||||
NO_POSIX_GOODIES = UnfortunatelyYes
|
||||
NATIVE_CRLF = YesPlease
|
||||
DEFAULT_HELP_FORMAT = html
|
||||
ifeq (/mingw64,$(subst 32,64,$(subst clangarm,mingw,$(prefix))))
|
||||
SKIP_DASHED_BUILT_INS = YabbaDabbaDoo
|
||||
ifneq (,$(MINGW_PREFIX))
|
||||
# Move system config into top-level /etc/
|
||||
ETC_GITCONFIG = ../etc/gitconfig
|
||||
ETC_GITATTRIBUTES = ../etc/gitattributes
|
||||
@@ -539,14 +534,18 @@ endif
|
||||
compat/win32/path-utils.o \
|
||||
compat/win32/pthread.o compat/win32/syslog.o \
|
||||
compat/win32/trace2_win32_process_info.o \
|
||||
compat/win32/dirent.o
|
||||
COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DDETECT_MSYS_TTY -DNOGDI -DHAVE_STRING_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
|
||||
BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -ENTRY:wmainCRTStartup -SUBSYSTEM:CONSOLE
|
||||
compat/win32/dirent.o compat/win32/wsl.o
|
||||
COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DDETECT_MSYS_TTY \
|
||||
-DENSURE_MSYSTEM_IS_SET="\"$(MSYSTEM)\"" -DMINGW_PREFIX="\"$(patsubst /%,%,$(MINGW_PREFIX))\"" \
|
||||
-DNOGDI -DHAVE_STRING_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
|
||||
BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO
|
||||
# invalidcontinue.obj allows Git's source code to close the same file
|
||||
# handle twice, or to access the osfhandle of an already-closed stdout
|
||||
# See https://msdn.microsoft.com/en-us/library/ms235330.aspx
|
||||
EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib invalidcontinue.obj kernel32.lib ntdll.lib
|
||||
GITLIBS += git.res
|
||||
PTHREAD_LIBS =
|
||||
RC = compat/vcbuild/scripts/rc.pl
|
||||
lib =
|
||||
BASIC_CFLAGS += $(vcpkg_inc) $(sdk_includes) $(msvc_includes)
|
||||
ifndef DEBUG
|
||||
@@ -716,6 +715,7 @@ ifeq ($(uname_S),MINGW)
|
||||
FSMONITOR_DAEMON_BACKEND = win32
|
||||
FSMONITOR_OS_SETTINGS = win32
|
||||
|
||||
SKIP_DASHED_BUILT_INS = YabbaDabbaDoo
|
||||
RUNTIME_PREFIX = YesPlease
|
||||
HAVE_WPGMPTR = YesWeDo
|
||||
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
|
||||
@@ -730,7 +730,8 @@ ifeq ($(uname_S),MINGW)
|
||||
DEFAULT_HELP_FORMAT = html
|
||||
HAVE_PLATFORM_PROCINFO = YesPlease
|
||||
CSPRNG_METHOD = rtlgenrandom
|
||||
BASIC_LDFLAGS += -municode
|
||||
BASIC_LDFLAGS += -municode -Wl,--tsaware
|
||||
LAZYLOAD_LIBCURL = YesDoThatPlease
|
||||
COMPAT_CFLAGS += -DNOGDI -Icompat -Icompat/win32
|
||||
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
|
||||
COMPAT_OBJS += compat/mingw.o compat/winansi.o \
|
||||
@@ -738,7 +739,7 @@ ifeq ($(uname_S),MINGW)
|
||||
compat/win32/flush.o \
|
||||
compat/win32/path-utils.o \
|
||||
compat/win32/pthread.o compat/win32/syslog.o \
|
||||
compat/win32/dirent.o
|
||||
compat/win32/dirent.o compat/win32/wsl.o
|
||||
BASIC_CFLAGS += -DWIN32
|
||||
EXTLIBS += -lws2_32
|
||||
GITLIBS += git.res
|
||||
@@ -754,26 +755,25 @@ ifeq ($(uname_S),MINGW)
|
||||
ifneq (,$(findstring -O,$(filter-out -O0 -Og,$(CFLAGS))))
|
||||
BASIC_LDFLAGS += -Wl,--dynamicbase
|
||||
endif
|
||||
ifeq (MINGW32,$(MSYSTEM))
|
||||
prefix = /mingw32
|
||||
HOST_CPU = i686
|
||||
BASIC_LDFLAGS += -Wl,--pic-executable,-e,_mainCRTStartup
|
||||
ifneq (,$(MSYSTEM))
|
||||
ifeq ($(MINGW_PREFIX),$(filter-out /%,$(MINGW_PREFIX)))
|
||||
# Override if empty or does not start with a slash
|
||||
MINGW_PREFIX := /$(shell echo '$(MSYSTEM)' | tr A-Z a-z)
|
||||
endif
|
||||
prefix = $(MINGW_PREFIX)
|
||||
HOST_CPU = $(patsubst %-w64-mingw32,%,$(MINGW_CHOST))
|
||||
BASIC_LDFLAGS += -Wl,--pic-executable
|
||||
COMPAT_CFLAGS += -DDETECT_MSYS_TTY \
|
||||
-DENSURE_MSYSTEM_IS_SET="\"$(MSYSTEM)\"" \
|
||||
-DMINGW_PREFIX="\"$(patsubst /%,%,$(MINGW_PREFIX))\""
|
||||
ifeq (MINGW32,$(MSYSTEM))
|
||||
BASIC_LDFLAGS += -Wl,--large-address-aware
|
||||
endif
|
||||
# Move system config into top-level /etc/
|
||||
ETC_GITCONFIG = ../etc/gitconfig
|
||||
ETC_GITATTRIBUTES = ../etc/gitattributes
|
||||
endif
|
||||
ifeq (MINGW64,$(MSYSTEM))
|
||||
prefix = /mingw64
|
||||
HOST_CPU = x86_64
|
||||
BASIC_LDFLAGS += -Wl,--pic-executable,-e,mainCRTStartup
|
||||
else ifeq (CLANGARM64,$(MSYSTEM))
|
||||
prefix = /clangarm64
|
||||
HOST_CPU = aarch64
|
||||
BASIC_LDFLAGS += -Wl,--pic-executable,-e,mainCRTStartup
|
||||
else
|
||||
COMPAT_CFLAGS += -D_USE_32BIT_TIME_T
|
||||
BASIC_LDFLAGS += -Wl,--large-address-aware
|
||||
endif
|
||||
CC = gcc
|
||||
COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 -DDETECT_MSYS_TTY \
|
||||
-fstack-protector-strong
|
||||
COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 -fstack-protector-strong
|
||||
EXTLIBS += -lntdll
|
||||
EXTRA_PROGRAMS += headless-git$X
|
||||
INSTALL = /bin/install
|
||||
@@ -781,11 +781,7 @@ ifeq ($(uname_S),MINGW)
|
||||
HAVE_LIBCHARSET_H = YesPlease
|
||||
USE_GETTEXT_SCHEME = fallthrough
|
||||
USE_LIBPCRE = YesPlease
|
||||
ifeq (/mingw64,$(subst 32,64,$(subst clangarm,mingw,$(prefix))))
|
||||
# Move system config into top-level /etc/
|
||||
ETC_GITCONFIG = ../etc/gitconfig
|
||||
ETC_GITATTRIBUTES = ../etc/gitattributes
|
||||
endif
|
||||
NO_PYTHON =
|
||||
endif
|
||||
ifeq ($(uname_S),QNX)
|
||||
COMPAT_CFLAGS += -DSA_RESTART=0
|
||||
|
||||
@@ -14,6 +14,11 @@ Note: Visual Studio also has the option of opening `CMakeLists.txt`
|
||||
directly; Using this option, Visual Studio will not find the source code,
|
||||
though, therefore the `File>Open>Folder...` option is preferred.
|
||||
|
||||
Visual Studio does not produce a .sln solution file nor the .vcxproj files
|
||||
that may be required by VS extension tools.
|
||||
|
||||
To generate the .sln/.vcxproj files run CMake manually, as described below.
|
||||
|
||||
Instructions to run CMake manually:
|
||||
|
||||
mkdir -p contrib/buildsystems/out
|
||||
@@ -22,7 +27,7 @@ Instructions to run CMake manually:
|
||||
|
||||
This will build the git binaries in contrib/buildsystems/out
|
||||
directory (our top-level .gitignore file knows to ignore contents of
|
||||
this directory).
|
||||
this directory). The project .sln and .vcxproj files are also generated.
|
||||
|
||||
Possible build configurations(-DCMAKE_BUILD_TYPE) with corresponding
|
||||
compiler flags
|
||||
@@ -35,17 +40,16 @@ empty(default) :
|
||||
NOTE: -DCMAKE_BUILD_TYPE is optional. For multi-config generators like Visual Studio
|
||||
this option is ignored
|
||||
|
||||
This process generates a Makefile(Linux/*BSD/MacOS) , Visual Studio solution(Windows) by default.
|
||||
This process generates a Makefile(Linux/*BSD/MacOS), Visual Studio solution(Windows) by default.
|
||||
Run `make` to build Git on Linux/*BSD/MacOS.
|
||||
Open git.sln on Windows and build Git.
|
||||
|
||||
NOTE: By default CMake uses Makefile as the build tool on Linux and Visual Studio in Windows,
|
||||
to use another tool say `ninja` add this to the command line when configuring.
|
||||
`-G Ninja`
|
||||
|
||||
NOTE: By default CMake will install vcpkg locally to your source tree on configuration,
|
||||
to avoid this, add `-DNO_VCPKG=TRUE` to the command line when configuring.
|
||||
|
||||
The Visual Studio default generator changed in v16.6 from its Visual Studio
|
||||
implemenation to `Ninja` This required changes to many CMake scripts.
|
||||
|
||||
]]
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
@@ -59,15 +63,29 @@ endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_EXPORT_COMPILE_COMMANDS)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
|
||||
message("settting CMAKE_EXPORT_COMPILE_COMMANDS: ${CMAKE_EXPORT_COMPILE_COMMANDS}")
|
||||
endif()
|
||||
|
||||
if(USE_VCPKG)
|
||||
set(VCPKG_DIR "${CMAKE_SOURCE_DIR}/compat/vcbuild/vcpkg")
|
||||
message("WIN32: ${WIN32}") # show its underlying text values
|
||||
message("VCPKG_DIR: ${VCPKG_DIR}")
|
||||
message("VCPKG_ARCH: ${VCPKG_ARCH}") # maybe unset
|
||||
message("MSVC: ${MSVC}")
|
||||
message("CMAKE_GENERATOR: ${CMAKE_GENERATOR}")
|
||||
message("CMAKE_CXX_COMPILER_ID: ${CMAKE_CXX_COMPILER_ID}")
|
||||
message("CMAKE_GENERATOR_PLATFORM: ${CMAKE_GENERATOR_PLATFORM}")
|
||||
message("CMAKE_EXPORT_COMPILE_COMMANDS: ${CMAKE_EXPORT_COMPILE_COMMANDS}")
|
||||
message("ENV(CMAKE_EXPORT_COMPILE_COMMANDS): $ENV{CMAKE_EXPORT_COMPILE_COMMANDS}")
|
||||
if(NOT EXISTS ${VCPKG_DIR})
|
||||
message("Initializing vcpkg and building the Git's dependencies (this will take a while...)")
|
||||
execute_process(COMMAND ${CMAKE_SOURCE_DIR}/compat/vcbuild/vcpkg_install.bat)
|
||||
execute_process(COMMAND ${CMAKE_SOURCE_DIR}/compat/vcbuild/vcpkg_install.bat ${VCPKG_ARCH})
|
||||
endif()
|
||||
list(APPEND CMAKE_PREFIX_PATH "${VCPKG_DIR}/installed/x64-windows")
|
||||
if(NOT EXISTS ${VCPKG_ARCH})
|
||||
message("VCPKG_ARCH: unset, using 'x64-windows'")
|
||||
set(VCPKG_ARCH "x64-windows") # default from vcpkg_install.bat
|
||||
endif()
|
||||
list(APPEND CMAKE_PREFIX_PATH "${VCPKG_DIR}/installed/${VCPKG_ARCH}")
|
||||
|
||||
# In the vcpkg edition, we need this to be able to link to libcurl
|
||||
set(CURL_NO_CURL_CMAKE ON)
|
||||
@@ -208,11 +226,19 @@ if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR})
|
||||
add_compile_options(/MP /std:c11)
|
||||
add_link_options(/MANIFEST:NO)
|
||||
endif()
|
||||
|
||||
#default behaviour
|
||||
include_directories(${CMAKE_SOURCE_DIR})
|
||||
add_compile_definitions(GIT_HOST_CPU="${CMAKE_SYSTEM_PROCESSOR}")
|
||||
|
||||
# When cross-compiling, define HOST_CPU as the canonical name of the CPU on
|
||||
# which the built Git will run (for instance "x86_64").
|
||||
if(NOT HOST_CPU)
|
||||
add_compile_definitions(GIT_HOST_CPU="${CMAKE_SYSTEM_PROCESSOR}")
|
||||
else()
|
||||
add_compile_definitions(GIT_HOST_CPU="${HOST_CPU}")
|
||||
endif()
|
||||
add_compile_definitions(SHA256_BLK INTERNAL_QSORT RUNTIME_PREFIX)
|
||||
add_compile_definitions(NO_OPENSSL SHA1_DC SHA1DC_NO_STANDARD_INCLUDES
|
||||
SHA1DC_INIT_SAFE_HASH_DEFAULT=0
|
||||
@@ -256,7 +282,14 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
_CONSOLE DETECT_MSYS_TTY STRIP_EXTENSION=".exe" NO_SYMLINK_HEAD UNRELIABLE_FSTAT
|
||||
NOGDI OBJECT_CREATION_MODE=1 __USE_MINGW_ANSI_STDIO=0
|
||||
OVERRIDE_STRDUP MMAP_PREVENTS_DELETE USE_WIN32_MMAP
|
||||
HAVE_WPGMPTR ENSURE_MSYSTEM_IS_SET HAVE_RTLGENRANDOM)
|
||||
HAVE_WPGMPTR HAVE_RTLGENRANDOM)
|
||||
if(CMAKE_GENERATOR_PLATFORM STREQUAL "x64")
|
||||
add_compile_definitions(ENSURE_MSYSTEM_IS_SET="MINGW64" MINGW_PREFIX="mingw64")
|
||||
elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "arm64")
|
||||
add_compile_definitions(ENSURE_MSYSTEM_IS_SET="CLANGARM64" MINGW_PREFIX="clangarm64")
|
||||
elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "x86")
|
||||
add_compile_definitions(ENSURE_MSYSTEM_IS_SET="MINGW32" MINGW_PREFIX="mingw32")
|
||||
endif()
|
||||
list(APPEND compat_SOURCES
|
||||
compat/mingw.c
|
||||
compat/winansi.c
|
||||
@@ -267,6 +300,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
compat/win32/syslog.c
|
||||
compat/win32/trace2_win32_process_info.c
|
||||
compat/win32/dirent.c
|
||||
compat/win32/wsl.c
|
||||
compat/strdup.c)
|
||||
set(NO_UNIX_SOCKETS 1)
|
||||
|
||||
@@ -733,6 +767,7 @@ if(WIN32)
|
||||
endif()
|
||||
|
||||
add_executable(headless-git ${CMAKE_SOURCE_DIR}/compat/win32/headless.c)
|
||||
list(APPEND PROGRAMS_BUILT headless-git)
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
target_link_options(headless-git PUBLIC -municode -Wl,-subsystem,windows)
|
||||
elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
|
||||
@@ -933,7 +968,7 @@ list(TRANSFORM git_perl_scripts PREPEND "${CMAKE_BINARY_DIR}/")
|
||||
|
||||
#install
|
||||
foreach(program ${PROGRAMS_BUILT})
|
||||
if(program MATCHES "^(git|git-shell|scalar)$")
|
||||
if(program MATCHES "^(git|git-shell|headless-git|scalar)$")
|
||||
install(TARGETS ${program}
|
||||
RUNTIME DESTINATION bin)
|
||||
else()
|
||||
@@ -1201,7 +1236,7 @@ string(REPLACE "@USE_LIBPCRE2@" "" git_build_options "${git_build_options}")
|
||||
string(REPLACE "@WITH_BREAKING_CHANGES@" "" git_build_options "${git_build_options}")
|
||||
string(REPLACE "@X@" "${EXE_EXTENSION}" git_build_options "${git_build_options}")
|
||||
if(USE_VCPKG)
|
||||
string(APPEND git_build_options "PATH=\"$PATH:$TEST_DIRECTORY/../compat/vcbuild/vcpkg/installed/x64-windows/bin\"\n")
|
||||
string(APPEND git_build_options "PATH=\"$PATH:$TEST_DIRECTORY/../compat/vcbuild/vcpkg/installed/${VCPKG_ARCH}/bin\"\n")
|
||||
endif()
|
||||
file(WRITE ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS ${git_build_options})
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ $(GIT_SUBTREE_TEST): $(GIT_SUBTREE)
|
||||
cp $< $@
|
||||
|
||||
test: $(GIT_SUBTREE_TEST)
|
||||
$(MAKE) -C t/ test
|
||||
$(MAKE) -C t/ all
|
||||
|
||||
clean:
|
||||
$(RM) $(GIT_SUBTREE)
|
||||
|
||||
@@ -102,7 +102,7 @@ static int convert_is_binary(const struct text_stat *stats)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int gather_convert_stats(const char *data, unsigned long size)
|
||||
static unsigned int gather_convert_stats(const char *data, size_t size)
|
||||
{
|
||||
struct text_stat stats;
|
||||
int ret = 0;
|
||||
@@ -119,7 +119,7 @@ static unsigned int gather_convert_stats(const char *data, unsigned long size)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *gather_convert_stats_ascii(const char *data, unsigned long size)
|
||||
static const char *gather_convert_stats_ascii(const char *data, size_t size)
|
||||
{
|
||||
unsigned int convert_stats = gather_convert_stats(data, size);
|
||||
|
||||
@@ -141,7 +141,7 @@ const char *get_cached_convert_stats_ascii(struct index_state *istate,
|
||||
const char *path)
|
||||
{
|
||||
const char *ret;
|
||||
unsigned long sz;
|
||||
size_t sz;
|
||||
void *data = read_blob_data_from_index(istate, path, &sz);
|
||||
ret = gather_convert_stats_ascii(data, sz);
|
||||
free(data);
|
||||
@@ -223,7 +223,7 @@ static void check_global_conv_flags_eol(const char *path,
|
||||
|
||||
static int has_crlf_in_index(struct index_state *istate, const char *path)
|
||||
{
|
||||
unsigned long sz;
|
||||
size_t sz;
|
||||
void *data;
|
||||
const char *crp;
|
||||
int has_crlf = 0;
|
||||
|
||||
@@ -360,6 +360,9 @@ int credential_read(struct credential *c, FILE *fp,
|
||||
credential_set_capability(&c->capa_authtype, op_type);
|
||||
else if (!strcmp(value, "state"))
|
||||
credential_set_capability(&c->capa_state, op_type);
|
||||
} else if (!strcmp(key, "ntlm")) {
|
||||
if (!strcmp(value, "allow"))
|
||||
c->ntlm_allow = 1;
|
||||
} else if (!strcmp(key, "continue")) {
|
||||
c->multistage = !!git_config_bool("continue", value);
|
||||
} else if (!strcmp(key, "password_expiry_utc")) {
|
||||
@@ -420,6 +423,8 @@ void credential_write(const struct credential *c, FILE *fp,
|
||||
if (c->ephemeral)
|
||||
credential_write_item(c, fp, "ephemeral", "1", 0);
|
||||
}
|
||||
if (c->ntlm_suppressed)
|
||||
credential_write_item(c, fp, "ntlm", "suppressed", 0);
|
||||
credential_write_item(c, fp, "protocol", c->protocol, 1);
|
||||
credential_write_item(c, fp, "host", c->host, 1);
|
||||
credential_write_item(c, fp, "path", c->path, 0);
|
||||
|
||||
@@ -177,6 +177,9 @@ struct credential {
|
||||
struct credential_capability capa_authtype;
|
||||
struct credential_capability capa_state;
|
||||
|
||||
unsigned ntlm_suppressed:1,
|
||||
ntlm_allow:1;
|
||||
|
||||
char *username;
|
||||
char *password;
|
||||
char *credential;
|
||||
|
||||
14
delta.h
14
delta.h
@@ -14,7 +14,7 @@ struct delta_index;
|
||||
* using free_delta_index().
|
||||
*/
|
||||
struct delta_index *
|
||||
create_delta_index(const void *buf, unsigned long bufsize);
|
||||
create_delta_index(const void *buf, size_t bufsize);
|
||||
|
||||
/*
|
||||
* free_delta_index: free the index created by create_delta_index()
|
||||
@@ -28,7 +28,7 @@ void free_delta_index(struct delta_index *index);
|
||||
*
|
||||
* Given pointer must be what create_delta_index() returned, or NULL.
|
||||
*/
|
||||
unsigned long sizeof_delta_index(struct delta_index *index);
|
||||
size_t sizeof_delta_index(struct delta_index *index);
|
||||
|
||||
/*
|
||||
* create_delta: create a delta from given index for the given buffer
|
||||
@@ -42,8 +42,8 @@ unsigned long sizeof_delta_index(struct delta_index *index);
|
||||
*/
|
||||
void *
|
||||
create_delta(const struct delta_index *index,
|
||||
const void *buf, unsigned long bufsize,
|
||||
unsigned long *delta_size, unsigned long max_delta_size);
|
||||
const void *buf, size_t bufsize,
|
||||
size_t *delta_size, size_t max_delta_size);
|
||||
|
||||
/*
|
||||
* diff_delta: create a delta from source buffer to target buffer
|
||||
@@ -54,9 +54,9 @@ create_delta(const struct delta_index *index,
|
||||
* updated with its size. The returned buffer must be freed by the caller.
|
||||
*/
|
||||
static inline void *
|
||||
diff_delta(const void *src_buf, unsigned long src_bufsize,
|
||||
const void *trg_buf, unsigned long trg_bufsize,
|
||||
unsigned long *delta_size, unsigned long max_delta_size)
|
||||
diff_delta(const void *src_buf, size_t src_bufsize,
|
||||
const void *trg_buf, size_t trg_bufsize,
|
||||
size_t *delta_size, size_t max_delta_size)
|
||||
{
|
||||
struct delta_index *index = create_delta_index(src_buf, src_bufsize);
|
||||
if (index) {
|
||||
|
||||
14
diff-delta.c
14
diff-delta.c
@@ -125,14 +125,14 @@ struct unpacked_index_entry {
|
||||
};
|
||||
|
||||
struct delta_index {
|
||||
unsigned long memsize;
|
||||
size_t memsize;
|
||||
const void *src_buf;
|
||||
unsigned long src_size;
|
||||
size_t src_size;
|
||||
unsigned int hash_mask;
|
||||
struct index_entry *hash[FLEX_ARRAY];
|
||||
};
|
||||
|
||||
struct delta_index * create_delta_index(const void *buf, unsigned long bufsize)
|
||||
struct delta_index * create_delta_index(const void *buf, size_t bufsize)
|
||||
{
|
||||
unsigned int i, hsize, hmask, entries, prev_val, *hash_count;
|
||||
const unsigned char *data, *buffer = buf;
|
||||
@@ -140,7 +140,7 @@ struct delta_index * create_delta_index(const void *buf, unsigned long bufsize)
|
||||
struct unpacked_index_entry *entry, **hash;
|
||||
struct index_entry *packed_entry, **packed_hash;
|
||||
void *mem;
|
||||
unsigned long memsize;
|
||||
size_t memsize;
|
||||
|
||||
if (!buf || !bufsize)
|
||||
return NULL;
|
||||
@@ -302,7 +302,7 @@ void free_delta_index(struct delta_index *index)
|
||||
free(index);
|
||||
}
|
||||
|
||||
unsigned long sizeof_delta_index(struct delta_index *index)
|
||||
size_t sizeof_delta_index(struct delta_index *index)
|
||||
{
|
||||
if (index)
|
||||
return index->memsize;
|
||||
@@ -318,8 +318,8 @@ unsigned long sizeof_delta_index(struct delta_index *index)
|
||||
|
||||
void *
|
||||
create_delta(const struct delta_index *index,
|
||||
const void *trg_buf, unsigned long trg_size,
|
||||
unsigned long *delta_size, unsigned long max_size)
|
||||
const void *trg_buf, size_t trg_size,
|
||||
size_t *delta_size, size_t max_size)
|
||||
{
|
||||
unsigned int i, val;
|
||||
off_t outpos, moff;
|
||||
|
||||
21
diff.c
21
diff.c
@@ -3606,10 +3606,10 @@ static int checkdiff_consume(void *priv, char *line, unsigned long len)
|
||||
}
|
||||
|
||||
static unsigned char *deflate_it(char *data,
|
||||
unsigned long size,
|
||||
unsigned long *result_size)
|
||||
size_t size,
|
||||
size_t *result_size)
|
||||
{
|
||||
int bound;
|
||||
size_t bound;
|
||||
unsigned char *deflated;
|
||||
git_zstream stream;
|
||||
struct repo_config_values *cfg = repo_config_values(the_repository);
|
||||
@@ -3636,10 +3636,10 @@ static void emit_binary_diff_body(struct diff_options *o,
|
||||
void *delta;
|
||||
void *deflated;
|
||||
void *data;
|
||||
unsigned long orig_size;
|
||||
unsigned long delta_size;
|
||||
unsigned long deflate_size;
|
||||
unsigned long data_size;
|
||||
size_t orig_size;
|
||||
size_t delta_size;
|
||||
size_t deflate_size;
|
||||
size_t data_size;
|
||||
|
||||
/* We could do deflated delta, or we could do just deflated two,
|
||||
* whichever is smaller.
|
||||
@@ -4595,9 +4595,8 @@ int diff_populate_filespec(struct repository *r,
|
||||
}
|
||||
}
|
||||
else {
|
||||
size_t size_st = 0;
|
||||
struct object_info info = {
|
||||
.sizep = &size_st
|
||||
.sizep = &s->size
|
||||
};
|
||||
|
||||
if (!(size_only || check_binary))
|
||||
@@ -4619,7 +4618,6 @@ int diff_populate_filespec(struct repository *r,
|
||||
die("unable to read %s", oid_to_hex(&s->oid));
|
||||
|
||||
object_read:
|
||||
s->size = cast_size_t_to_ulong(size_st);
|
||||
if (size_only || check_binary) {
|
||||
if (size_only)
|
||||
return 0;
|
||||
@@ -4634,7 +4632,6 @@ object_read:
|
||||
if (odb_read_object_info_extended(r->objects, &s->oid, &info,
|
||||
OBJECT_INFO_LOOKUP_REPLACE))
|
||||
die("unable to read %s", oid_to_hex(&s->oid));
|
||||
s->size = cast_size_t_to_ulong(size_st);
|
||||
}
|
||||
s->should_free = 1;
|
||||
}
|
||||
@@ -7845,7 +7842,7 @@ int textconv_object(struct repository *r,
|
||||
const struct object_id *oid,
|
||||
int oid_valid,
|
||||
char **buf,
|
||||
unsigned long *buf_size)
|
||||
size_t *buf_size)
|
||||
{
|
||||
struct diff_filespec *df;
|
||||
struct userdiff_driver *textconv;
|
||||
|
||||
2
diff.h
2
diff.h
@@ -757,7 +757,7 @@ int textconv_object(struct repository *repo,
|
||||
const char *path,
|
||||
unsigned mode,
|
||||
const struct object_id *oid, int oid_valid,
|
||||
char **buf, unsigned long *buf_size);
|
||||
char **buf, size_t *buf_size);
|
||||
|
||||
int parse_rename_score(const char **cp_p);
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ struct diff_filespec {
|
||||
char *path;
|
||||
void *data;
|
||||
void *cnt_data;
|
||||
unsigned long size;
|
||||
size_t size;
|
||||
int count; /* Reference count */
|
||||
int rename_used; /* Count of rename users */
|
||||
unsigned short mode; /* file mode */
|
||||
|
||||
7
dir.c
7
dir.c
@@ -3411,6 +3411,13 @@ static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_mount_point(path)) {
|
||||
/* Do not descend and nuke a mount point or junction. */
|
||||
if (kept_up)
|
||||
*kept_up = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
flag &= ~REMOVE_DIR_KEEP_TOPLEVEL;
|
||||
dir = opendir(path->buf);
|
||||
if (!dir) {
|
||||
|
||||
17
entry.c
17
entry.c
@@ -49,10 +49,23 @@ static void create_directories(const char *path, int path_len,
|
||||
*/
|
||||
if (mkdir(buf, 0777)) {
|
||||
if (errno == EEXIST && state->force &&
|
||||
!unlink_or_warn(buf) && !mkdir(buf, 0777))
|
||||
!unlink_or_warn(buf) && !mkdir(buf, 0777)) {
|
||||
flush_fscache();
|
||||
continue;
|
||||
}
|
||||
die_errno("cannot create directory at '%s'", buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush the lstat cache of directory listings so that
|
||||
* subsequent has_dirs_only_path() calls see the
|
||||
* just-created directory. Without this, the Windows
|
||||
* fscache returns stale ENOENT for the new directory,
|
||||
* causing the next entry sharing this parent to
|
||||
* incorrectly hit the mkdir/unlink recovery path
|
||||
* above, which then fails with "Directory not empty".
|
||||
*/
|
||||
flush_fscache();
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
@@ -322,7 +335,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca
|
||||
if (!has_symlinks || to_tempfile)
|
||||
goto write_file_entry;
|
||||
|
||||
ret = symlink(new_blob, path);
|
||||
ret = create_symlink(state->istate, new_blob, path);
|
||||
free(new_blob);
|
||||
if (ret)
|
||||
return error_errno("unable to create symlink %s", path);
|
||||
|
||||
@@ -261,6 +261,13 @@ static inline int git_offset_1st_component(const char *path)
|
||||
#define fspathncmp git_fspathncmp
|
||||
#endif
|
||||
|
||||
#ifndef warn_about_git_lfs_on_windows7
|
||||
static inline void warn_about_git_lfs_on_windows7(int exit_code UNUSED,
|
||||
const char *argv0 UNUSED)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef is_valid_path
|
||||
#define is_valid_path(path) 1
|
||||
#endif
|
||||
@@ -346,10 +353,28 @@ static inline int git_has_dir_sep(const char *path)
|
||||
#define has_dir_sep(path) git_has_dir_sep(path)
|
||||
#endif
|
||||
|
||||
#ifndef is_mount_point
|
||||
#define is_mount_point is_mount_point_via_stat
|
||||
#endif
|
||||
|
||||
#ifndef create_symlink
|
||||
struct index_state;
|
||||
static inline int git_create_symlink(struct index_state *index UNUSED,
|
||||
const char *target, const char *link)
|
||||
{
|
||||
return symlink(target, link);
|
||||
}
|
||||
#define create_symlink git_create_symlink
|
||||
#endif
|
||||
|
||||
#ifndef query_user_email
|
||||
#define query_user_email() NULL
|
||||
#endif
|
||||
|
||||
#ifndef platform_strbuf_realpath
|
||||
#define platform_strbuf_realpath(resolved, path) NULL
|
||||
#endif
|
||||
|
||||
#ifdef __TANDEM
|
||||
#include <floss.h(floss_execl,floss_execlp,floss_execv,floss_execvp)>
|
||||
#include <floss.h(floss_getpwuid)>
|
||||
@@ -597,17 +622,23 @@ static inline bool strip_suffix(const char *str, const char *suffix,
|
||||
* the stack overflow can occur.
|
||||
*/
|
||||
#define DEFAULT_MAX_ALLOWED_TREE_DEPTH 512
|
||||
#elif defined(GIT_WINDOWS_NATIVE) && defined(__clang__) && defined(__aarch64__)
|
||||
#elif defined(GIT_WINDOWS_NATIVE) && defined(__clang__)
|
||||
/*
|
||||
* Similar to Visual C, it seems that on Windows/ARM64 the clang-based
|
||||
* builds have a smaller stack space available. When running out of
|
||||
* that stack space, a `STATUS_STACK_OVERFLOW` is produced. When the
|
||||
* Similar to Visual C, it seems that clang-based builds on Windows
|
||||
* have a smaller stack space available. When running out of that
|
||||
* stack space, a `STATUS_STACK_OVERFLOW` is produced. When the
|
||||
* Git command was run from an MSYS2 Bash, this unfortunately results
|
||||
* in an exit code 127. Let's prevent that by lowering the maximal
|
||||
* tree depth; This value seems to be low enough.
|
||||
* tree depth; Unfortunately, it seems that the exact limit differs
|
||||
* for aarch64 vs x86_64, and the difference is too large to simply
|
||||
* use a single limit.
|
||||
*/
|
||||
#if defined(__aarch64__)
|
||||
#define DEFAULT_MAX_ALLOWED_TREE_DEPTH 1280
|
||||
#else
|
||||
#define DEFAULT_MAX_ALLOWED_TREE_DEPTH 1152
|
||||
#endif
|
||||
#else
|
||||
#define DEFAULT_MAX_ALLOWED_TREE_DEPTH 2048
|
||||
#endif
|
||||
|
||||
@@ -666,15 +697,6 @@ static inline size_t st_left_shift(size_t a, unsigned shift)
|
||||
return a << shift;
|
||||
}
|
||||
|
||||
static inline unsigned long cast_size_t_to_ulong(size_t a)
|
||||
{
|
||||
if (a != (unsigned long)a)
|
||||
die("object too large to read on this platform: %"
|
||||
PRIuMAX" is cut off to %lu",
|
||||
(uintmax_t)a, (unsigned long)a);
|
||||
return (unsigned long)a;
|
||||
}
|
||||
|
||||
static inline uint32_t cast_size_t_to_uint32_t(size_t a)
|
||||
{
|
||||
if (a != (uint32_t)a)
|
||||
|
||||
@@ -45,6 +45,14 @@
|
||||
#define GIT_CURL_HAVE_CURLINFO_RETRY_AFTER 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* CURLSSLOPT_AUTO_CLIENT_CERT was added in 7.77.0, released in May
|
||||
* 2021.
|
||||
*/
|
||||
#if LIBCURL_VERSION_NUM >= 0x074d00
|
||||
#define GIT_CURL_HAVE_CURLSSLOPT_AUTO_CLIENT_CERT
|
||||
#endif
|
||||
|
||||
/**
|
||||
* CURLOPT_PROTOCOLS_STR and CURLOPT_REDIR_PROTOCOLS_STR were added in 7.85.0,
|
||||
* released in August 2022.
|
||||
|
||||
@@ -1991,6 +1991,7 @@ set all_icons(U$ui_index) file_merge
|
||||
set all_icons(T$ui_index) file_statechange
|
||||
|
||||
set all_icons(_$ui_workdir) file_plain
|
||||
set all_icons(A$ui_workdir) file_plain
|
||||
set all_icons(M$ui_workdir) file_mod
|
||||
set all_icons(D$ui_workdir) file_question
|
||||
set all_icons(U$ui_workdir) file_merge
|
||||
@@ -2017,6 +2018,7 @@ foreach i {
|
||||
{A_ {mc "Staged for commit"}}
|
||||
{AM {mc "Portions staged for commit"}}
|
||||
{AD {mc "Staged for commit, missing"}}
|
||||
{AA {mc "Intended to be added"}}
|
||||
|
||||
{_D {mc "Missing"}}
|
||||
{D_ {mc "Staged for removal"}}
|
||||
|
||||
@@ -556,7 +556,8 @@ proc apply_or_revert_hunk {x y revert} {
|
||||
if {$current_diff_side eq $ui_index} {
|
||||
set failed_msg [mc "Failed to unstage selected hunk."]
|
||||
lappend apply_cmd --reverse --cached
|
||||
if {[string index $mi 0] ne {M}} {
|
||||
set file_state [string index $mi 0]
|
||||
if {$file_state ne {M} && $file_state ne {A}} {
|
||||
unlock_index
|
||||
return
|
||||
}
|
||||
@@ -569,7 +570,8 @@ proc apply_or_revert_hunk {x y revert} {
|
||||
lappend apply_cmd --cached
|
||||
}
|
||||
|
||||
if {[string index $mi 1] ne {M}} {
|
||||
set file_state [string index $mi 1]
|
||||
if {$file_state ne {M} && $file_state ne {A}} {
|
||||
unlock_index
|
||||
return
|
||||
}
|
||||
@@ -661,7 +663,8 @@ proc apply_or_revert_range_or_line {x y revert} {
|
||||
set failed_msg [mc "Failed to unstage selected line."]
|
||||
set to_context {+}
|
||||
lappend apply_cmd --reverse --cached
|
||||
if {[string index $mi 0] ne {M}} {
|
||||
set file_state [string index $mi 0]
|
||||
if {$file_state ne {M} && $file_state ne {A}} {
|
||||
unlock_index
|
||||
return
|
||||
}
|
||||
@@ -676,7 +679,8 @@ proc apply_or_revert_range_or_line {x y revert} {
|
||||
lappend apply_cmd --cached
|
||||
}
|
||||
|
||||
if {[string index $mi 1] ne {M}} {
|
||||
set file_state [string index $mi 1]
|
||||
if {$file_state ne {M} && $file_state ne {A}} {
|
||||
unlock_index
|
||||
return
|
||||
}
|
||||
|
||||
16
git-zlib.c
16
git-zlib.c
@@ -167,9 +167,21 @@ int git_inflate(git_zstream *strm, int flush)
|
||||
return status;
|
||||
}
|
||||
|
||||
unsigned long git_deflate_bound(git_zstream *strm, unsigned long size)
|
||||
size_t git_deflate_bound(git_zstream *strm, size_t size)
|
||||
{
|
||||
return deflateBound(&strm->z, size);
|
||||
#if SIZE_MAX > ULONG_MAX
|
||||
if (size > maximum_unsigned_value_of_type(uLong))
|
||||
/*
|
||||
* deflateBound() takes uLong, which is 32-bit on
|
||||
* Windows. For inputs above that range, return zlib's
|
||||
* stored-block formula (the conservative path it would
|
||||
* itself use for an unknown stream state) plus the
|
||||
* worst-case wrapper overhead.
|
||||
*/
|
||||
return size + (size >> 5) + (size >> 7) + (size >> 11)
|
||||
+ 7 + 18;
|
||||
#endif
|
||||
return deflateBound(&strm->z, (uLong)size);
|
||||
}
|
||||
|
||||
void git_deflate_init(git_zstream *strm, int level)
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
typedef struct git_zstream {
|
||||
struct z_stream_s z;
|
||||
unsigned long avail_in;
|
||||
unsigned long avail_out;
|
||||
size_t avail_in;
|
||||
size_t avail_out;
|
||||
size_t total_in;
|
||||
size_t total_out;
|
||||
unsigned char *next_in;
|
||||
@@ -25,6 +25,6 @@ void git_deflate_end(git_zstream *);
|
||||
int git_deflate_abort(git_zstream *);
|
||||
int git_deflate_end_gently(git_zstream *);
|
||||
int git_deflate(git_zstream *, int flush);
|
||||
unsigned long git_deflate_bound(git_zstream *, unsigned long);
|
||||
size_t git_deflate_bound(git_zstream *, size_t);
|
||||
|
||||
#endif /* GIT_ZLIB_H */
|
||||
|
||||
1
git.c
1
git.c
@@ -660,6 +660,7 @@ static struct cmd_struct commands[] = {
|
||||
{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
|
||||
{ "stripspace", cmd_stripspace },
|
||||
{ "submodule--helper", cmd_submodule__helper, RUN_SETUP },
|
||||
{ "survey", cmd_survey, RUN_SETUP },
|
||||
{ "switch", cmd_switch, RUN_SETUP | NEED_WORK_TREE },
|
||||
{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
|
||||
{ "tag", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include<winuser.h>
|
||||
1 VERSIONINFO
|
||||
FILEVERSION @GIT_MAJOR_VERSION@,@GIT_MINOR_VERSION@,@GIT_MICRO_VERSION@,@GIT_PATCH_LEVEL@
|
||||
PRODUCTVERSION @GIT_MAJOR_VERSION@,@GIT_MINOR_VERSION@,@GIT_MICRO_VERSION@,@GIT_PATCH_LEVEL@
|
||||
@@ -12,6 +13,7 @@ BEGIN
|
||||
VALUE "OriginalFilename", "git.exe\0"
|
||||
VALUE "ProductName", "Git\0"
|
||||
VALUE "ProductVersion", "@GIT_VERSION@\0"
|
||||
VALUE "FileVersion", "@GIT_VERSION@\0"
|
||||
END
|
||||
END
|
||||
|
||||
|
||||
18
grep.c
18
grep.c
@@ -864,9 +864,9 @@ void free_grep_patterns(struct grep_opt *opt)
|
||||
free_pattern_expr(opt->pattern_expression);
|
||||
}
|
||||
|
||||
static const char *end_of_line(const char *cp, unsigned long *left)
|
||||
static const char *end_of_line(const char *cp, size_t *left)
|
||||
{
|
||||
unsigned long l = *left;
|
||||
size_t l = *left;
|
||||
while (l && *cp != '\n') {
|
||||
l--;
|
||||
cp++;
|
||||
@@ -1454,7 +1454,7 @@ static int should_lookahead(struct grep_opt *opt)
|
||||
}
|
||||
|
||||
static int look_ahead(struct grep_opt *opt,
|
||||
unsigned long *left_p,
|
||||
size_t *left_p,
|
||||
unsigned *lno_p,
|
||||
const char **bol_p)
|
||||
{
|
||||
@@ -1567,7 +1567,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
|
||||
{
|
||||
const char *bol;
|
||||
const char *peek_bol = NULL;
|
||||
unsigned long left;
|
||||
size_t left;
|
||||
unsigned lno = 1;
|
||||
unsigned last_hit = 0;
|
||||
int binary_match_only = 0;
|
||||
@@ -1737,7 +1737,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
|
||||
goto next_line;
|
||||
}
|
||||
if (show_function && (!peek_bol || peek_bol < bol)) {
|
||||
unsigned long peek_left = left;
|
||||
size_t peek_left = left;
|
||||
const char *peek_eol = eol;
|
||||
|
||||
/*
|
||||
@@ -1856,7 +1856,7 @@ int grep_source(struct grep_opt *opt, struct grep_source *gs)
|
||||
|
||||
static void grep_source_init_buf(struct grep_source *gs,
|
||||
const char *buf,
|
||||
unsigned long size)
|
||||
size_t size)
|
||||
{
|
||||
gs->type = GREP_SOURCE_BUF;
|
||||
gs->name = NULL;
|
||||
@@ -1867,7 +1867,7 @@ static void grep_source_init_buf(struct grep_source *gs,
|
||||
gs->identifier = NULL;
|
||||
}
|
||||
|
||||
int grep_buffer(struct grep_opt *opt, const char *buf, unsigned long size)
|
||||
int grep_buffer(struct grep_opt *opt, const char *buf, size_t size)
|
||||
{
|
||||
struct grep_source gs;
|
||||
int r;
|
||||
@@ -1933,11 +1933,9 @@ void grep_source_clear_data(struct grep_source *gs)
|
||||
static int grep_source_load_oid(struct grep_source *gs)
|
||||
{
|
||||
enum object_type type;
|
||||
size_t size_st = 0;
|
||||
|
||||
gs->buf = odb_read_object(gs->repo->objects, gs->identifier,
|
||||
&type, &size_st);
|
||||
gs->size = cast_size_t_to_ulong(size_st);
|
||||
&type, &gs->size);
|
||||
if (!gs->buf)
|
||||
return error(_("'%s': unable to read %s"),
|
||||
gs->name,
|
||||
|
||||
4
grep.h
4
grep.h
@@ -212,7 +212,7 @@ void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *orig
|
||||
void append_header_grep_pattern(struct grep_opt *, enum grep_header_field, const char *);
|
||||
void compile_grep_patterns(struct grep_opt *opt);
|
||||
void free_grep_patterns(struct grep_opt *opt);
|
||||
int grep_buffer(struct grep_opt *opt, const char *buf, unsigned long size);
|
||||
int grep_buffer(struct grep_opt *opt, const char *buf, size_t size);
|
||||
|
||||
/* The field parameter is only used to filter header patterns
|
||||
* (where appropriate). If filtering isn't desirable
|
||||
@@ -235,7 +235,7 @@ struct grep_source {
|
||||
struct repository *repo; /* if GREP_SOURCE_OID */
|
||||
|
||||
const char *buf;
|
||||
unsigned long size;
|
||||
size_t size;
|
||||
|
||||
char *path; /* for attribute lookups */
|
||||
struct userdiff_driver *driver;
|
||||
|
||||
@@ -367,7 +367,7 @@ static void start_put(struct transfer_request *request)
|
||||
void *unpacked;
|
||||
size_t len;
|
||||
int hdrlen;
|
||||
ssize_t size;
|
||||
size_t size;
|
||||
git_zstream stream;
|
||||
struct repo_config_values *cfg = repo_config_values(the_repository);
|
||||
|
||||
|
||||
89
http.c
89
http.c
@@ -131,7 +131,8 @@ enum http_follow_config http_follow_config = HTTP_FOLLOW_INITIAL;
|
||||
|
||||
static struct credential cert_auth = CREDENTIAL_INIT;
|
||||
static int ssl_cert_password_required;
|
||||
static unsigned long http_auth_methods = CURLAUTH_ANY;
|
||||
static unsigned long http_auth_any = CURLAUTH_ANY & ~CURLAUTH_NTLM;
|
||||
static unsigned long http_auth_methods;
|
||||
static int http_auth_methods_restricted;
|
||||
/* Modes for which empty_auth cannot actually help us. */
|
||||
static unsigned long empty_auth_useless =
|
||||
@@ -151,7 +152,12 @@ static char *cached_accept_language;
|
||||
|
||||
static char *http_ssl_backend;
|
||||
|
||||
static int http_schannel_check_revoke = 1;
|
||||
static long http_schannel_check_revoke_mode =
|
||||
#ifdef CURLSSLOPT_REVOKE_BEST_EFFORT
|
||||
CURLSSLOPT_REVOKE_BEST_EFFORT;
|
||||
#else
|
||||
CURLSSLOPT_NO_REVOKE;
|
||||
#endif
|
||||
|
||||
static long http_retry_after = 0;
|
||||
static long http_max_retries = 0;
|
||||
@@ -164,6 +170,8 @@ static long http_max_retry_time = 300;
|
||||
*/
|
||||
static int http_schannel_use_ssl_cainfo;
|
||||
|
||||
static int http_auto_client_cert;
|
||||
|
||||
static int always_auth_proactively(void)
|
||||
{
|
||||
return http_proactive_auth != PROACTIVE_AUTH_NONE &&
|
||||
@@ -430,8 +438,29 @@ static int http_options(const char *var, const char *value,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp("http.allowntlmauth", var)) {
|
||||
if (git_config_bool(var, value)) {
|
||||
http_auth_any |= CURLAUTH_NTLM;
|
||||
} else {
|
||||
http_auth_any &= ~CURLAUTH_NTLM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp("http.schannelcheckrevoke", var)) {
|
||||
http_schannel_check_revoke = git_config_bool(var, value);
|
||||
if (value && !strcmp(value, "best-effort")) {
|
||||
http_schannel_check_revoke_mode =
|
||||
#ifdef CURLSSLOPT_REVOKE_BEST_EFFORT
|
||||
CURLSSLOPT_REVOKE_BEST_EFFORT;
|
||||
#else
|
||||
CURLSSLOPT_NO_REVOKE;
|
||||
warning(_("%s=%s unsupported by current cURL"),
|
||||
var, value);
|
||||
#endif
|
||||
} else
|
||||
http_schannel_check_revoke_mode =
|
||||
(git_config_bool(var, value) ?
|
||||
0 : CURLSSLOPT_NO_REVOKE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -440,6 +469,11 @@ static int http_options(const char *var, const char *value,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp("http.sslautoclientcert", var)) {
|
||||
http_auto_client_cert = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp("http.minsessions", var)) {
|
||||
min_curl_sessions = git_config_int(var, value, ctx->kvi);
|
||||
if (min_curl_sessions > 1)
|
||||
@@ -651,6 +685,11 @@ static void init_curl_http_auth(CURL *result)
|
||||
|
||||
credential_fill(the_repository, &http_auth, 1);
|
||||
|
||||
if (http_auth.ntlm_allow && !(http_auth_methods & CURLAUTH_NTLM)) {
|
||||
http_auth_methods |= CURLAUTH_NTLM;
|
||||
curl_easy_setopt(result, CURLOPT_HTTPAUTH, http_auth_methods);
|
||||
}
|
||||
|
||||
if (http_auth.password) {
|
||||
if (always_auth_proactively()) {
|
||||
/*
|
||||
@@ -726,11 +765,11 @@ static void init_curl_proxy_auth(CURL *result)
|
||||
if (i == ARRAY_SIZE(proxy_authmethods)) {
|
||||
warning("unsupported proxy authentication method %s: using anyauth",
|
||||
http_proxy_authmethod);
|
||||
curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
|
||||
curl_easy_setopt(result, CURLOPT_PROXYAUTH, http_auth_any);
|
||||
}
|
||||
}
|
||||
else
|
||||
curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
|
||||
curl_easy_setopt(result, CURLOPT_PROXYAUTH, http_auth_any);
|
||||
}
|
||||
|
||||
static int has_cert_password(void)
|
||||
@@ -1140,7 +1179,7 @@ static CURL *get_curl_handle(void)
|
||||
}
|
||||
|
||||
curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
|
||||
curl_easy_setopt(result, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
|
||||
curl_easy_setopt(result, CURLOPT_HTTPAUTH, http_auth_any);
|
||||
|
||||
#ifdef CURLGSSAPI_DELEGATION_FLAG
|
||||
if (curl_deleg) {
|
||||
@@ -1158,9 +1197,20 @@ static CURL *get_curl_handle(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (http_ssl_backend && !strcmp("schannel", http_ssl_backend) &&
|
||||
!http_schannel_check_revoke) {
|
||||
curl_easy_setopt(result, CURLOPT_SSL_OPTIONS, (long)CURLSSLOPT_NO_REVOKE);
|
||||
if (http_ssl_backend && !strcmp("schannel", http_ssl_backend)) {
|
||||
long ssl_options = 0;
|
||||
if (http_schannel_check_revoke_mode) {
|
||||
ssl_options |= http_schannel_check_revoke_mode;
|
||||
}
|
||||
|
||||
if (http_auto_client_cert) {
|
||||
#ifdef GIT_CURL_HAVE_CURLSSLOPT_AUTO_CLIENT_CERT
|
||||
ssl_options |= CURLSSLOPT_AUTO_CLIENT_CERT;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ssl_options)
|
||||
curl_easy_setopt(result, CURLOPT_SSL_OPTIONS, ssl_options);
|
||||
}
|
||||
|
||||
if (http_proactive_auth != PROACTIVE_AUTH_NONE)
|
||||
@@ -1508,6 +1558,8 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
|
||||
set_long_from_env(&http_max_retries, "GIT_HTTP_MAX_RETRIES");
|
||||
set_long_from_env(&http_max_retry_time, "GIT_HTTP_MAX_RETRY_TIME");
|
||||
|
||||
http_auth_methods = http_auth_any;
|
||||
|
||||
curl_default = get_curl_handle();
|
||||
}
|
||||
|
||||
@@ -1939,6 +1991,8 @@ static int handle_curl_result(struct slot_results *results)
|
||||
} else if (missing_target(results))
|
||||
return HTTP_MISSING_TARGET;
|
||||
else if (results->http_code == 401) {
|
||||
http_auth.ntlm_suppressed = (results->auth_avail & CURLAUTH_NTLM) &&
|
||||
!(http_auth_any & CURLAUTH_NTLM);
|
||||
if ((http_auth.username && http_auth.password) ||\
|
||||
(http_auth.authtype && http_auth.credential)) {
|
||||
if (http_auth.multistage) {
|
||||
@@ -1948,6 +2002,16 @@ static int handle_curl_result(struct slot_results *results)
|
||||
credential_reject(the_repository, &http_auth);
|
||||
if (always_auth_proactively())
|
||||
http_proactive_auth = PROACTIVE_AUTH_NONE;
|
||||
if (http_auth.ntlm_suppressed) {
|
||||
warning(_("Due to its cryptographic weaknesses, "
|
||||
"NTLM authentication has been\n"
|
||||
"disabled in Git by default. You can "
|
||||
"re-enable it for trusted servers\n"
|
||||
"by running:\n\n"
|
||||
"git config set "
|
||||
"http.%s://%s.allowNTLMAuth true"),
|
||||
http_auth.protocol, http_auth.host);
|
||||
}
|
||||
return HTTP_NOAUTH;
|
||||
} else {
|
||||
if (curl_empty_auth == -1 &&
|
||||
@@ -2472,6 +2536,13 @@ static int http_request_recoverable(const char *url,
|
||||
http_reauth_prepare(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Re-enable NTLM auth if the helper allows it and we would
|
||||
* otherwise suppress authentication via NTLM.
|
||||
*/
|
||||
if (http_auth.ntlm_suppressed && http_auth.ntlm_allow)
|
||||
http_auth_methods |= CURLAUTH_NTLM;
|
||||
|
||||
ret = http_request(url, result, target, options);
|
||||
}
|
||||
if (ret == HTTP_RATE_LIMITED) {
|
||||
|
||||
15
meson.build
15
meson.build
@@ -692,6 +692,7 @@ builtin_sources = [
|
||||
'builtin/stash.c',
|
||||
'builtin/stripspace.c',
|
||||
'builtin/submodule--helper.c',
|
||||
'builtin/survey.c',
|
||||
'builtin/symbolic-ref.c',
|
||||
'builtin/tag.c',
|
||||
'builtin/unpack-file.c',
|
||||
@@ -1293,12 +1294,12 @@ elif host_machine.system() == 'windows'
|
||||
'compat/win32/path-utils.c',
|
||||
'compat/win32/pthread.c',
|
||||
'compat/win32/syslog.c',
|
||||
'compat/win32/wsl.c',
|
||||
'compat/win32mmap.c',
|
||||
]
|
||||
|
||||
libgit_c_args += [
|
||||
'-DDETECT_MSYS_TTY',
|
||||
'-DENSURE_MSYSTEM_IS_SET',
|
||||
'-DNATIVE_CRLF',
|
||||
'-DNOGDI',
|
||||
'-DNO_POSIX_GOODIES',
|
||||
@@ -1308,6 +1309,18 @@ elif host_machine.system() == 'windows'
|
||||
'-D__USE_MINGW_ANSI_STDIO=0',
|
||||
]
|
||||
|
||||
msystem = get_option('msystem')
|
||||
if msystem != ''
|
||||
mingw_prefix = get_option('mingw_prefix')
|
||||
if mingw_prefix == ''
|
||||
mingw_prefix = '/' + msystem.to_lower()
|
||||
endif
|
||||
libgit_c_args += [
|
||||
'-DENSURE_MSYSTEM_IS_SET="' + msystem + '"',
|
||||
'-DMINGW_PREFIX="' + mingw_prefix + '"'
|
||||
]
|
||||
endif
|
||||
|
||||
libgit_dependencies += compiler.find_library('ntdll')
|
||||
libgit_include_directories += 'compat/win32'
|
||||
if compiler.get_id() == 'msvc'
|
||||
|
||||
@@ -21,6 +21,10 @@ option('runtime_prefix', type: 'boolean', value: false,
|
||||
description: 'Resolve ancillary tooling and support files relative to the location of the runtime binary instead of hard-coding them into the binary.')
|
||||
option('sane_tool_path', type: 'array', value: [],
|
||||
description: 'An array of paths to pick up tools from in case the normal tools are broken or lacking.')
|
||||
option('msystem', type: 'string', value: '',
|
||||
description: 'Fall-back on Windows when MSYSTEM is not set.')
|
||||
option('mingw_prefix', type: 'string', value: '',
|
||||
description: 'Fall-back on Windows when MINGW_PREFIX is not set.')
|
||||
|
||||
# Build information compiled into Git and other parts like documentation.
|
||||
option('build_date', type: 'string', value: '',
|
||||
|
||||
@@ -316,9 +316,9 @@ int parse_loose_header(const char *hdr, struct object_info *oi)
|
||||
}
|
||||
|
||||
static void hash_object_body(const struct git_hash_algo *algo, struct git_hash_ctx *c,
|
||||
const void *buf, unsigned long len,
|
||||
const void *buf, size_t len,
|
||||
struct object_id *oid,
|
||||
char *hdr, int *hdrlen)
|
||||
char *hdr, size_t *hdrlen)
|
||||
{
|
||||
algo->init_fn(c);
|
||||
git_hash_update(c, hdr, *hdrlen);
|
||||
@@ -327,16 +327,16 @@ static void hash_object_body(const struct git_hash_algo *algo, struct git_hash_c
|
||||
}
|
||||
|
||||
void write_object_file_prepare(const struct git_hash_algo *algo,
|
||||
const void *buf, unsigned long len,
|
||||
const void *buf, size_t len,
|
||||
enum object_type type, struct object_id *oid,
|
||||
char *hdr, int *hdrlen)
|
||||
char *hdr, size_t *hdrlen)
|
||||
{
|
||||
struct git_hash_ctx c;
|
||||
|
||||
/* Generate the header */
|
||||
*hdrlen = format_object_header(hdr, *hdrlen, type, len);
|
||||
|
||||
/* Sha1.. */
|
||||
/* Hash (function pointers) computation */
|
||||
hash_object_body(algo, &c, buf, len, oid, hdr, hdrlen);
|
||||
}
|
||||
|
||||
@@ -472,11 +472,11 @@ out:
|
||||
}
|
||||
|
||||
void hash_object_file(const struct git_hash_algo *algo, const void *buf,
|
||||
unsigned long len, enum object_type type,
|
||||
size_t len, enum object_type type,
|
||||
struct object_id *oid)
|
||||
{
|
||||
char hdr[MAX_HEADER_LEN];
|
||||
int hdrlen = sizeof(hdr);
|
||||
size_t hdrlen = sizeof(hdr);
|
||||
|
||||
write_object_file_prepare(algo, buf, len, type, oid, hdr, &hdrlen);
|
||||
}
|
||||
|
||||
@@ -131,12 +131,12 @@ int finalize_object_file_flags(struct repository *repo,
|
||||
enum finalize_object_file_flags flags);
|
||||
|
||||
void hash_object_file(const struct git_hash_algo *algo, const void *buf,
|
||||
unsigned long len, enum object_type type,
|
||||
size_t len, enum object_type type,
|
||||
struct object_id *oid);
|
||||
void write_object_file_prepare(const struct git_hash_algo *algo,
|
||||
const void *buf, unsigned long len,
|
||||
const void *buf, size_t len,
|
||||
enum object_type type, struct object_id *oid,
|
||||
char *hdr, int *hdrlen);
|
||||
char *hdr, size_t *hdrlen);
|
||||
int write_loose_object(struct odb_source_loose *loose,
|
||||
const struct object_id *oid, char *hdr,
|
||||
int hdrlen, const void *buf, unsigned long len,
|
||||
|
||||
@@ -593,7 +593,7 @@ static int odb_source_loose_write_object(struct odb_source *source,
|
||||
const struct git_hash_algo *compat = source->odb->repo->compat_hash_algo;
|
||||
struct object_id compat_oid;
|
||||
char hdr[MAX_HEADER_LEN];
|
||||
int hdrlen = sizeof(hdr);
|
||||
size_t hdrlen = sizeof(hdr);
|
||||
|
||||
/* Generate compat_oid */
|
||||
if (compat) {
|
||||
|
||||
@@ -1853,8 +1853,8 @@ static void filter_bitmap_blob_none(struct bitmap_index *bitmap_git,
|
||||
OBJ_BLOB);
|
||||
}
|
||||
|
||||
static unsigned long get_size_by_pos(struct bitmap_index *bitmap_git,
|
||||
uint32_t pos)
|
||||
static size_t get_size_by_pos(struct bitmap_index *bitmap_git,
|
||||
uint32_t pos)
|
||||
{
|
||||
size_t size;
|
||||
struct object_info oi = OBJECT_INFO_INIT;
|
||||
@@ -1891,7 +1891,7 @@ static unsigned long get_size_by_pos(struct bitmap_index *bitmap_git,
|
||||
die(_("unable to get size of %s"), oid_to_hex(&obj->oid));
|
||||
}
|
||||
|
||||
return cast_size_t_to_ulong(size);
|
||||
return size;
|
||||
}
|
||||
|
||||
static void filter_bitmap_blob_limit(struct bitmap_index *bitmap_git,
|
||||
|
||||
@@ -34,7 +34,7 @@ int check_pack_crc(struct packed_git *p, struct pack_window **w_curs,
|
||||
uint32_t data_crc = crc32(0, NULL, 0);
|
||||
|
||||
do {
|
||||
unsigned long avail;
|
||||
size_t avail;
|
||||
void *data = use_pack(p, w_curs, offset, &avail);
|
||||
if (avail > len)
|
||||
avail = len;
|
||||
@@ -71,7 +71,7 @@ static int verify_packfile(struct repository *r,
|
||||
|
||||
r->hash_algo->init_fn(&ctx);
|
||||
do {
|
||||
unsigned long remaining;
|
||||
size_t remaining;
|
||||
unsigned char *in = use_pack(p, w_curs, offset, &remaining);
|
||||
offset += remaining;
|
||||
if (!pack_sig_ofs)
|
||||
|
||||
@@ -704,7 +704,7 @@ static int in_window(struct repository *r, struct pack_window *win,
|
||||
unsigned char *use_pack(struct packed_git *p,
|
||||
struct pack_window **w_cursor,
|
||||
off_t offset,
|
||||
unsigned long *left)
|
||||
size_t *left)
|
||||
{
|
||||
struct pack_window *win = *w_cursor;
|
||||
|
||||
@@ -1228,7 +1228,7 @@ int unpack_object_header(struct packed_git *p,
|
||||
size_t *sizep)
|
||||
{
|
||||
unsigned char *base;
|
||||
unsigned long left;
|
||||
size_t left;
|
||||
unsigned long used;
|
||||
enum object_type type;
|
||||
|
||||
|
||||
@@ -402,7 +402,8 @@ uint32_t get_pack_fanout(struct packed_git *p, uint32_t value);
|
||||
|
||||
struct object_database;
|
||||
|
||||
unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned long *);
|
||||
unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t,
|
||||
size_t *);
|
||||
void close_pack_windows(struct packed_git *);
|
||||
void close_pack(struct packed_git *);
|
||||
void unuse_pack(struct pack_window **);
|
||||
|
||||
@@ -395,6 +395,13 @@ void write_pc_item(struct parallel_checkout_item *pc_item,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush the Windows fscache so that the lstat() below sees the
|
||||
* file we just wrote. Without this, the cached parent directory
|
||||
* listing may not yet include the new file entry.
|
||||
*/
|
||||
flush_fscache();
|
||||
|
||||
if (state->refresh_cache && !fstat_done && lstat(path.buf, &pc_item->st) < 0) {
|
||||
error_errno("unable to stat just-written file '%s'", path.buf);
|
||||
pc_item->status = PC_ITEM_FAILED;
|
||||
|
||||
62
path.c
62
path.c
@@ -1328,6 +1328,45 @@ char *strip_path_suffix(const char *path, const char *suffix)
|
||||
return offset == -1 ? NULL : xstrndup(path, offset);
|
||||
}
|
||||
|
||||
int is_mount_point_via_stat(struct strbuf *path)
|
||||
{
|
||||
size_t len = path->len;
|
||||
dev_t current_dev;
|
||||
struct stat st;
|
||||
|
||||
if (!strcmp("/", path->buf))
|
||||
return 1;
|
||||
|
||||
strbuf_addstr(path, "/.");
|
||||
if (lstat(path->buf, &st)) {
|
||||
/*
|
||||
* If we cannot access the current directory, we cannot say
|
||||
* that it is a bind mount.
|
||||
*/
|
||||
strbuf_setlen(path, len);
|
||||
return 0;
|
||||
}
|
||||
current_dev = st.st_dev;
|
||||
|
||||
/* Now look at the parent directory */
|
||||
strbuf_addch(path, '.');
|
||||
if (lstat(path->buf, &st)) {
|
||||
/*
|
||||
* If we cannot access the parent directory, we cannot say
|
||||
* that it is a bind mount.
|
||||
*/
|
||||
strbuf_setlen(path, len);
|
||||
return 0;
|
||||
}
|
||||
strbuf_setlen(path, len);
|
||||
|
||||
/*
|
||||
* If the device ID differs between current and parent directory,
|
||||
* then it is a bind mount.
|
||||
*/
|
||||
return current_dev != st.st_dev;
|
||||
}
|
||||
|
||||
int daemon_avoid_alias(const char *p)
|
||||
{
|
||||
int sl, ndot;
|
||||
@@ -1545,6 +1584,7 @@ int looks_like_command_line_option(const char *str)
|
||||
char *xdg_config_home_for(const char *subdir, const char *filename)
|
||||
{
|
||||
const char *home, *config_home;
|
||||
char *home_config = NULL;
|
||||
|
||||
assert(subdir);
|
||||
assert(filename);
|
||||
@@ -1553,10 +1593,26 @@ char *xdg_config_home_for(const char *subdir, const char *filename)
|
||||
return mkpathdup("%s/%s/%s", config_home, subdir, filename);
|
||||
|
||||
home = getenv("HOME");
|
||||
if (home)
|
||||
return mkpathdup("%s/.config/%s/%s", home, subdir, filename);
|
||||
if (home && *home)
|
||||
home_config = mkpathdup("%s/.config/%s/%s", home, subdir, filename);
|
||||
|
||||
return NULL;
|
||||
#ifdef WIN32
|
||||
{
|
||||
const char *appdata = getenv("APPDATA");
|
||||
if (appdata && *appdata) {
|
||||
char *appdata_config = mkpathdup("%s/Git/%s", appdata, filename);
|
||||
if (file_exists(appdata_config)) {
|
||||
if (home_config && file_exists(home_config))
|
||||
warning("'%s' was ignored because '%s' exists.", home_config, appdata_config);
|
||||
free(home_config);
|
||||
return appdata_config;
|
||||
}
|
||||
free(appdata_config);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return home_config;
|
||||
}
|
||||
|
||||
char *xdg_config_home(const char *filename)
|
||||
|
||||
1
path.h
1
path.h
@@ -161,6 +161,7 @@ int normalize_path_copy(char *dst, const char *src);
|
||||
int strbuf_normalize_path(struct strbuf *src);
|
||||
int longest_ancestor_length(const char *path, struct string_list *prefixes);
|
||||
char *strip_path_suffix(const char *path, const char *suffix);
|
||||
int is_mount_point_via_stat(struct strbuf *path);
|
||||
int daemon_avoid_alias(const char *path);
|
||||
|
||||
/*
|
||||
|
||||
@@ -411,7 +411,7 @@ int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip);
|
||||
int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
|
||||
void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
|
||||
int index_name_is_other(struct index_state *, const char *, int);
|
||||
void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);
|
||||
void *read_blob_data_from_index(struct index_state *, const char *, size_t *);
|
||||
|
||||
/* do stat comparison even if CE_VALID is true */
|
||||
#define CE_MATCH_IGNORE_VALID 01
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user