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:
Johannes Schindelin
2018-10-11 13:38:58 +02:00
committed by Git for Windows Build Agent
147 changed files with 4316 additions and 521 deletions

View File

@@ -20,7 +20,7 @@ jobs:
jobname: ClangFormat
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
fetch-depth: 0

View File

@@ -19,7 +19,7 @@ jobs:
check-whitespace:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
fetch-depth: 0

View File

@@ -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

View File

@@ -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
View 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
View File

@@ -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

View File

@@ -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[]

View File

@@ -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.

View File

@@ -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

View 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.

View 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.
--

View 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.

View 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

View File

@@ -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`
^^^^^^^^

View File

@@ -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,

View File

@@ -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

View File

@@ -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);

View File

@@ -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)

View File

@@ -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
View File

@@ -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
View File

@@ -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"),

View File

@@ -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;

View File

@@ -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);

View File

@@ -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)

View File

@@ -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, &quoted, 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, &quoted, 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 */

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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));

View File

@@ -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 ||

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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
View 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;
}

View File

@@ -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));

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View File

@@ -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

View File

@@ -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);

View File

@@ -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.

View File

@@ -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
View 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;
}

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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);

View File

@@ -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;

View File

@@ -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

View File

@@ -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%

View File

@@ -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 {

View 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);

View File

@@ -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] (

View File

@@ -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

View File

@@ -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)
{

View File

@@ -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);
}

View File

@@ -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
View 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
View 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

View File

@@ -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)

View File

@@ -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

View File

@@ -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})

View File

@@ -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)

View File

@@ -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;

View File

@@ -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);

View File

@@ -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
View File

@@ -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) {

View File

@@ -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
View File

@@ -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
View File

@@ -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);

View File

@@ -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
View File

@@ -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
View File

@@ -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);

View File

@@ -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)

View File

@@ -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.

View File

@@ -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"}}

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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
View File

@@ -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 },

View File

@@ -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
View File

@@ -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
View File

@@ -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;

View File

@@ -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
View File

@@ -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) {

View File

@@ -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'

View File

@@ -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: '',

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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)

View File

@@ -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;

View File

@@ -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 **);

View File

@@ -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
View File

@@ -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
View File

@@ -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);
/*

View File

@@ -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