summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2017-10-29 12:08:00 +0100
committerCarlos Martín Nieto <cmn@dwim.me>2017-10-29 12:08:00 +0100
commit1b9cc2ece515aba1d11c48c42c7a62d58a61c3f0 (patch)
tree65cc0b52e659521377150783f5c03dfad70e9ebb
parent5efe9d125f09a44e1581cf7d37cf4d36161f5d4d (diff)
parent524c1d3c9eef1f63d058ca5d4a61af7d5588ebfb (diff)
downloadlibgit2-1b9cc2ece515aba1d11c48c42c7a62d58a61c3f0.tar.gz
Merge remote-tracking branch 'upstream/master' into diff-indent-heuristic
-rw-r--r--.github/ISSUE_TEMPLATE14
-rw-r--r--.travis.yml28
-rw-r--r--AUTHORS1
-rw-r--r--CHANGELOG.md192
-rw-r--r--CMakeLists.txt503
-rw-r--r--CONVENTIONS.md4
-rw-r--r--COPYING33
-rw-r--r--PROJECTS.md8
-rw-r--r--README.md35
-rw-r--r--THREADING.md50
-rw-r--r--appveyor.yml19
-rw-r--r--deps/http-parser/CMakeLists.txt3
-rw-r--r--deps/regex/CMakeLists.txt2
-rw-r--r--deps/winhttp/CMakeLists.txt26
-rw-r--r--deps/zlib/CMakeLists.txt4
-rw-r--r--deps/zlib/zconf.h3
-rw-r--r--examples/CMakeLists.txt3
-rw-r--r--examples/add.c9
-rw-r--r--examples/common.c19
-rw-r--r--examples/common.h9
-rw-r--r--examples/diff.c6
-rw-r--r--examples/general.c1202
-rw-r--r--examples/network/clone.c2
-rw-r--r--examples/network/common.c24
-rw-r--r--examples/network/fetch.c14
-rw-r--r--include/git2/branch.h12
-rw-r--r--include/git2/commit.h9
-rw-r--r--include/git2/common.h71
-rw-r--r--include/git2/describe.h7
-rw-r--r--include/git2/diff.h57
-rw-r--r--include/git2/errors.h4
-rw-r--r--include/git2/global.h2
-rw-r--r--include/git2/index.h13
-rw-r--r--include/git2/merge.h3
-rw-r--r--include/git2/odb.h4
-rw-r--r--include/git2/odb_backend.h2
-rw-r--r--include/git2/oid.h9
-rw-r--r--include/git2/patch.h6
-rw-r--r--include/git2/proxy.h2
-rw-r--r--include/git2/remote.h32
-rw-r--r--include/git2/repository.h91
-rw-r--r--include/git2/reset.h10
-rw-r--r--include/git2/revert.h2
-rw-r--r--include/git2/revwalk.h10
-rw-r--r--include/git2/stash.h4
-rw-r--r--include/git2/submodule.h13
-rw-r--r--include/git2/sys/filter.h11
-rw-r--r--include/git2/sys/merge.h10
-rw-r--r--include/git2/sys/repository.h29
-rw-r--r--include/git2/sys/transport.h10
-rw-r--r--include/git2/transaction.h9
-rw-r--r--include/git2/transport.h12
-rw-r--r--include/git2/tree.h13
-rw-r--r--include/git2/types.h3
-rw-r--r--include/git2/version.h6
-rw-r--r--include/git2/worktree.h220
-rw-r--r--libgit2.pc.in4
-rwxr-xr-xscript/appveyor-mingw.sh6
-rwxr-xr-xscript/cibuild.sh44
-rwxr-xr-xscript/coverity.sh15
-rwxr-xr-xscript/install-deps-linux.sh12
-rwxr-xr-xscript/install-deps-osx.sh3
-rw-r--r--src/CMakeLists.txt400
-rw-r--r--src/annotated_commit.c2
-rw-r--r--src/annotated_commit.h2
-rw-r--r--src/apply.c7
-rw-r--r--src/apply.h2
-rw-r--r--src/attr.c50
-rw-r--r--src/attr.h2
-rw-r--r--src/attr_file.c29
-rw-r--r--src/attr_file.h4
-rw-r--r--src/attrcache.c59
-rw-r--r--src/attrcache.h7
-rw-r--r--src/blame.c1
-rw-r--r--src/blame.h3
-rw-r--r--src/blame_git.c21
-rw-r--r--src/blame_git.h2
-rw-r--r--src/blob.c14
-rw-r--r--src/blob.h2
-rw-r--r--src/branch.c64
-rw-r--r--src/branch.h2
-rw-r--r--src/buf_text.h2
-rw-r--r--src/buffer.c31
-rw-r--r--src/buffer.h7
-rw-r--r--src/cache.c52
-rw-r--r--src/cache.h4
-rw-r--r--src/checkout.c75
-rw-r--r--src/checkout.h2
-rw-r--r--src/cherrypick.c9
-rw-r--r--src/clone.c8
-rw-r--r--src/clone.h4
-rw-r--r--src/commit.c26
-rw-r--r--src/commit.h2
-rw-r--r--src/commit_list.c17
-rw-r--r--src/commit_list.h3
-rw-r--r--src/common.h13
-rw-r--r--src/config.c109
-rw-r--r--src/config.h2
-rw-r--r--src/config_cache.c2
-rw-r--r--src/config_file.c343
-rw-r--r--src/config_file.h3
-rw-r--r--src/crlf.c5
-rw-r--r--src/curl_stream.c23
-rw-r--r--src/curl_stream.h2
-rw-r--r--src/delta.c8
-rw-r--r--src/delta.h1
-rw-r--r--src/describe.c30
-rw-r--r--src/diff.c185
-rw-r--r--src/diff.h2
-rw-r--r--src/diff_driver.c19
-rw-r--r--src/diff_driver.h1
-rw-r--r--src/diff_file.c7
-rw-r--r--src/diff_file.h1
-rw-r--r--src/diff_generate.c9
-rw-r--r--src/diff_generate.h6
-rw-r--r--src/diff_parse.c13
-rw-r--r--src/diff_parse.h2
-rw-r--r--src/diff_print.c12
-rw-r--r--src/diff_stats.c30
-rw-r--r--src/diff_tform.c9
-rw-r--r--src/diff_tform.h4
-rw-r--r--src/diff_xdiff.c9
-rw-r--r--src/diff_xdiff.h2
-rw-r--r--src/errors.c2
-rw-r--r--src/features.h.in36
-rw-r--r--src/fetch.c6
-rw-r--r--src/fetch.h4
-rw-r--r--src/fetchhead.c26
-rw-r--r--src/fetchhead.h3
-rw-r--r--src/filebuf.c34
-rw-r--r--src/filebuf.h6
-rw-r--r--src/fileops.c176
-rw-r--r--src/fileops.h30
-rw-r--r--src/filter.c55
-rw-r--r--src/filter.h1
-rw-r--r--src/fnmatch.c4
-rw-r--r--src/global.c28
-rw-r--r--src/global.h7
-rw-r--r--src/graph.c4
-rw-r--r--src/hash.c1
-rw-r--r--src/hash.h10
-rw-r--r--src/hash/hash_collisiondetect.h47
-rw-r--r--src/hash/hash_generic.c4
-rw-r--r--src/hash/hash_generic.h2
-rw-r--r--src/hash/hash_win32.c4
-rw-r--r--src/hash/hash_win32.h1
-rw-r--r--src/hash/sha1dc/sha1.c1856
-rw-r--r--src/hash/sha1dc/sha1.h110
-rw-r--r--src/hash/sha1dc/ubc_check.c372
-rw-r--r--src/hash/sha1dc/ubc_check.h52
-rw-r--r--src/hashsig.c7
-rw-r--r--src/ident.c2
-rw-r--r--src/idxmap.c133
-rw-r--r--src/idxmap.h76
-rw-r--r--src/ignore.c112
-rw-r--r--src/ignore.h4
-rw-r--r--src/index.c178
-rw-r--r--src/index.h2
-rw-r--r--src/indexer.c109
-rw-r--r--src/indexer.h (renamed from include/git2/sys/remote.h)12
-rw-r--r--src/integer.h12
-rw-r--r--src/iterator.c3
-rw-r--r--src/iterator.h1
-rw-r--r--src/merge.c243
-rw-r--r--src/merge.h2
-rw-r--r--src/merge_driver.c33
-rw-r--r--src/merge_driver.h2
-rw-r--r--src/merge_file.c3
-rw-r--r--src/message.h2
-rw-r--r--src/mwindow.c8
-rw-r--r--src/mwindow.h2
-rw-r--r--src/netops.c12
-rw-r--r--src/netops.h3
-rw-r--r--src/notes.c6
-rw-r--r--src/object.c14
-rw-r--r--src/object.h2
-rw-r--r--src/object_api.c5
-rw-r--r--src/odb.c151
-rw-r--r--src/odb.h30
-rw-r--r--src/odb_loose.c39
-rw-r--r--src/odb_mempack.c33
-rw-r--r--src/odb_pack.c3
-rw-r--r--src/offmap.c83
-rw-r--r--src/offmap.h48
-rw-r--r--src/oid.c13
-rw-r--r--src/oid.h11
-rw-r--r--src/oidarray.c3
-rw-r--r--src/oidarray.h1
-rw-r--r--src/oidmap.c105
-rw-r--r--src/oidmap.h41
-rw-r--r--src/openssl_stream.c93
-rw-r--r--src/openssl_stream.h108
-rw-r--r--src/pack-objects.c39
-rw-r--r--src/pack-objects.h1
-rw-r--r--src/pack.c107
-rw-r--r--src/pack.h4
-rw-r--r--src/patch.c11
-rw-r--r--src/patch.h2
-rw-r--r--src/patch_generate.c100
-rw-r--r--src/patch_generate.h1
-rw-r--r--src/patch_parse.c67
-rw-r--r--src/patch_parse.h4
-rw-r--r--src/path.c121
-rw-r--r--src/path.h1
-rw-r--r--src/pathspec.c7
-rw-r--r--src/pathspec.h3
-rw-r--r--src/pool.c8
-rw-r--r--src/pool.h1
-rw-r--r--src/posix.c9
-rw-r--r--src/posix.h11
-rw-r--r--src/pqueue.c18
-rw-r--r--src/pqueue.h3
-rw-r--r--src/proxy.c3
-rw-r--r--src/proxy.h4
-rw-r--r--src/push.c19
-rw-r--r--src/push.h2
-rw-r--r--src/rebase.c59
-rw-r--r--src/refdb.c13
-rw-r--r--src/refdb.h2
-rw-r--r--src/refdb_fs.c321
-rw-r--r--src/refdb_fs.h4
-rw-r--r--src/reflog.c5
-rw-r--r--src/reflog.h1
-rw-r--r--src/refs.c159
-rw-r--r--src/refs.h18
-rw-r--r--src/refspec.c4
-rw-r--r--src/refspec.h2
-rw-r--r--src/remote.c72
-rw-r--r--src/remote.h2
-rw-r--r--src/repository.c620
-rw-r--r--src/repository.h37
-rw-r--r--src/reset.c13
-rw-r--r--src/revert.c9
-rw-r--r--src/revparse.c40
-rw-r--r--src/revwalk.c463
-rw-r--r--src/revwalk.h2
-rw-r--r--src/settings.c38
-rw-r--r--src/sha1_lookup.c222
-rw-r--r--src/sha1_lookup.h8
-rw-r--r--src/signature.c12
-rw-r--r--src/signature.h2
-rw-r--r--src/socket_stream.c20
-rw-r--r--src/socket_stream.h2
-rw-r--r--src/sortedcache.c42
-rw-r--r--src/sortedcache.h2
-rw-r--r--src/stash.c13
-rw-r--r--src/status.c12
-rw-r--r--src/status.h2
-rw-r--r--src/stransport_stream.c2
-rw-r--r--src/stransport_stream.h2
-rw-r--r--src/strmap.c95
-rw-r--r--src/strmap.h54
-rw-r--r--src/submodule.c335
-rw-r--r--src/submodule.h5
-rw-r--r--src/sysdir.c19
-rw-r--r--src/sysdir.h13
-rw-r--r--src/tag.c32
-rw-r--r--src/tag.h2
-rw-r--r--src/thread-utils.c1
-rw-r--r--src/thread-utils.h6
-rw-r--r--src/tls_stream.c3
-rw-r--r--src/tls_stream.h2
-rw-r--r--src/trace.c6
-rw-r--r--src/trace.h2
-rw-r--r--src/transaction.c25
-rw-r--r--src/transport.c4
-rw-r--r--src/transports/auth.c3
-rw-r--r--src/transports/auth.h2
-rw-r--r--src/transports/auth_negotiate.c11
-rw-r--r--src/transports/auth_negotiate.h1
-rw-r--r--src/transports/cred.c4
-rw-r--r--src/transports/cred.h2
-rw-r--r--src/transports/cred_helpers.c1
-rw-r--r--src/transports/git.c8
-rw-r--r--src/transports/http.c23
-rw-r--r--src/transports/local.c10
-rw-r--r--src/transports/smart.c20
-rw-r--r--src/transports/smart.h5
-rw-r--r--src/transports/smart_pkt.c26
-rw-r--r--src/transports/smart_protocol.c41
-rw-r--r--src/transports/ssh.c35
-rw-r--r--src/transports/ssh.h2
-rw-r--r--src/transports/winhttp.c297
-rw-r--r--src/tree-cache.c5
-rw-r--r--src/tree-cache.h1
-rw-r--r--src/tree.c101
-rw-r--r--src/tree.h2
-rw-r--r--src/tsort.c1
-rw-r--r--src/unix/map.c7
-rw-r--r--src/unix/posix.h25
-rw-r--r--src/unix/pthread.h2
-rw-r--r--src/unix/realpath.c5
-rw-r--r--src/util.c12
-rw-r--r--src/util.h134
-rw-r--r--src/varint.c3
-rw-r--r--src/varint.h2
-rw-r--r--src/vector.c21
-rw-r--r--src/vector.h5
-rw-r--r--src/win32/dir.c9
-rw-r--r--src/win32/dir.h1
-rw-r--r--src/win32/error.c2
-rw-r--r--src/win32/error.h2
-rw-r--r--src/win32/findfile.c5
-rw-r--r--src/win32/findfile.h2
-rw-r--r--src/win32/map.c14
-rw-r--r--src/win32/path_w32.c4
-rw-r--r--src/win32/path_w32.h1
-rw-r--r--src/win32/posix.h6
-rw-r--r--src/win32/posix_w32.c451
-rw-r--r--src/win32/precompiled.h3
-rw-r--r--src/win32/thread.c19
-rw-r--r--src/win32/thread.h4
-rw-r--r--src/win32/utf-conv.c1
-rw-r--r--src/win32/utf-conv.h3
-rw-r--r--src/win32/w32_buffer.c2
-rw-r--r--src/win32/w32_buffer.h2
-rw-r--r--src/win32/w32_crtdbg_stacktrace.c7
-rw-r--r--src/win32/w32_crtdbg_stacktrace.h83
-rw-r--r--src/win32/w32_stack.c3
-rw-r--r--src/win32/w32_stack.h2
-rw-r--r--src/win32/w32_util.c2
-rw-r--r--src/win32/w32_util.h4
-rw-r--r--src/worktree.c557
-rw-r--r--src/worktree.h37
-rw-r--r--src/zstream.c7
-rw-r--r--src/zstream.h3
-rw-r--r--tests/CMakeLists.txt63
-rw-r--r--tests/attr/ignore.c59
-rw-r--r--tests/checkout/head.c78
-rw-r--r--tests/checkout/tree.c35
-rw-r--r--tests/clar_libgit2.c14
-rw-r--r--tests/clar_libgit2.h67
-rw-r--r--tests/clone/local.c2
-rw-r--r--tests/config/include.c103
-rw-r--r--tests/config/readonly.c65
-rw-r--r--tests/core/encoding.c3
-rw-r--r--tests/core/env.c21
-rw-r--r--tests/core/features.c2
-rw-r--r--tests/core/filebuf.c29
-rw-r--r--tests/core/init.c40
-rw-r--r--tests/core/oidmap.c30
-rw-r--r--tests/core/path.c4
-rw-r--r--tests/core/posix.c54
-rw-r--r--tests/core/pqueue.c22
-rw-r--r--tests/core/sha1.c64
-rw-r--r--tests/core/strmap.c4
-rw-r--r--tests/core/structinit.c15
-rw-r--r--tests/core/vector.c31
-rw-r--r--tests/diff/format_email.c4
-rw-r--r--tests/diff/parse.c71
-rw-r--r--tests/diff/patchid.c60
-rw-r--r--tests/diff/stats.c36
-rw-r--r--tests/fetchhead/nonetwork.c4
-rw-r--r--tests/filter/custom.c21
-rw-r--r--tests/filter/custom_helpers.c33
-rw-r--r--tests/filter/custom_helpers.h1
-rw-r--r--tests/generate.py38
-rw-r--r--tests/index/tests.c6
-rw-r--r--tests/index/version.c126
-rw-r--r--tests/iterator/workdir.c4
-rw-r--r--tests/merge/trees/renames.c24
-rw-r--r--tests/network/remote/local.c17
-rw-r--r--tests/object/lookup.c63
-rw-r--r--tests/object/tree/update.c57
-rw-r--r--tests/odb/backend/backend_helpers.c159
-rw-r--r--tests/odb/backend/backend_helpers.h22
-rw-r--r--tests/odb/backend/multiple.c121
-rw-r--r--tests/odb/backend/nobackend.c2
-rw-r--r--tests/odb/backend/nonrefreshing.c177
-rw-r--r--tests/odb/backend/simple.c232
-rw-r--r--tests/odb/foreach.c8
-rw-r--r--tests/odb/freshen.c122
-rw-r--r--tests/odb/loose.c55
-rw-r--r--tests/online/badssl.c38
-rw-r--r--tests/online/clone.c2
-rw-r--r--tests/online/fetchhead.c2
-rw-r--r--tests/online/remotes.c82
-rw-r--r--tests/pack/indexer.c45
-rw-r--r--tests/pack/packbuilder.c45
-rw-r--r--tests/patch/patch_common.h61
-rw-r--r--tests/precompiled.c1
-rw-r--r--tests/precompiled.h4
-rw-r--r--tests/rebase/merge.c54
-rw-r--r--tests/rebase/submodule.c94
-rw-r--r--tests/refs/branches/create.c26
-rw-r--r--tests/refs/branches/upstream.c2
-rw-r--r--tests/refs/crashes.c4
-rw-r--r--tests/refs/create.c127
-rw-r--r--tests/refs/list.c4
-rw-r--r--tests/refs/namespaces.c36
-rw-r--r--tests/refs/reflog/reflog.c46
-rw-r--r--tests/refs/revparse.c35
-rw-r--r--tests/repo/discover.c171
-rw-r--r--tests/repo/env.c12
-rw-r--r--tests/repo/head.c12
-rw-r--r--tests/repo/init.c11
-rw-r--r--tests/repo/open.c3
-rw-r--r--tests/resources/diff_format_email/.gitted/indexbin289 -> 289 bytes
-rw-r--r--tests/resources/diff_format_email/.gitted/objects/06/b7b69a62cbd1e53c6c4e0c3f16473dcfdb4af6bin0 -> 159 bytes
-rw-r--r--tests/resources/diff_format_email/.gitted/objects/52/19b9784f9a92d7bd7cb567a6d6a21bfb86697ebin0 -> 160 bytes
-rw-r--r--tests/resources/diff_format_email/.gitted/objects/53/525d4cc3ef3ba4a5cbf69492fdffb4e4a74558bin0 -> 121 bytes
-rw-r--r--tests/resources/diff_format_email/.gitted/objects/a7/a65f98355b5a7567bcc395f6f7936c9252cf57bin0 -> 28 bytes
-rw-r--r--tests/resources/diff_format_email/.gitted/objects/c7/1a05d36025c806496a74d46d7d596eb23295c4bin0 -> 28 bytes
-rw-r--r--tests/resources/diff_format_email/.gitted/objects/d3/b6b38486f620b5b532a8cc6e0198ab7c3f52e4bin0 -> 121 bytes
-rw-r--r--tests/resources/diff_format_email/.gitted/refs/heads/master2
-rw-r--r--tests/resources/diff_format_email/file3.txt1
-rw-r--r--tests/resources/indexv4/.gitted/HEAD1
-rw-r--r--tests/resources/indexv4/.gitted/config5
-rw-r--r--tests/resources/indexv4/.gitted/indexbin0 -> 572 bytes
-rw-r--r--tests/resources/indexv4/.gitted/objects/4c/9109b3e671d851eec87e0e72f6305b582e7e99bin0 -> 70 bytes
-rw-r--r--tests/resources/indexv4/.gitted/objects/b0/952dbb50bed5f01e03e31b296184cb183e54a7bin0 -> 154 bytes
-rw-r--r--tests/resources/indexv4/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391bin0 -> 15 bytes
-rw-r--r--tests/resources/indexv4/.gitted/refs/heads/master1
-rw-r--r--tests/resources/indexv4/file.tx0
-rw-r--r--tests/resources/indexv4/file.txt0
-rw-r--r--tests/resources/indexv4/file.txz0
-rw-r--r--tests/resources/indexv4/foo0
-rw-r--r--tests/resources/indexv4/zzz0
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/2a/f2d9bcbc73723ac988bb202d4397f72a6ca7a0bin0 -> 105 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/37/f53a5a14f64e91089a39ea58e71c87d81df7651
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/4d/d1ef7569b18d92d93c0a35bb6b93049137b355bin0 -> 30 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/63/ec604d491161ddafdae4179843c26d54bd999abin0 -> 30 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/68/f7c02064019d89e40e51d7776b6f67914420a2bin0 -> 105 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/94/29c05dd6f6f39fc567b4ce923b16df5d3d7a7abin0 -> 94 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/a1/07e18a58f38c46086c8f8f1dcd54c40154eeb63
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/a2/d8d1824c68541cca94ffb90f79291eba495921bin0 -> 30 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/bc/85d1aad435ff3705a8c30ace85f7542c5736cbbin0 -> 104 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/c8/26ef8b17b5cd2c4a0023f265f3a423b3aa0388bin0 -> 157 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/cd/3e8d4aa06bdc781f264171030bc28f2b370feebin0 -> 94 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/e2/6b8888956137218d8589368a3e606cf50fbb56bin0 -> 105 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391bin0 -> 15 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/f9/7da95f156121bea8f978623628f4cbdbf30b361
-rw-r--r--tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename11
-rw-r--r--tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename21
-rw-r--r--tests/resources/rebase-submodule/.gitted/HEAD1
-rw-r--r--tests/resources/rebase-submodule/.gitted/ORIG_HEAD1
-rw-r--r--tests/resources/rebase-submodule/.gitted/config9
-rw-r--r--tests/resources/rebase-submodule/.gitted/description1
-rw-r--r--tests/resources/rebase-submodule/.gitted/indexbin0 -> 681 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/info/exclude6
-rw-r--r--tests/resources/rebase-submodule/.gitted/info/refs4
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/01/971e2453a407e4b9f6c865e2c37f4db21da2941
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/17/f8ae8ebdd08a4bb272f61b897b308ad42b1b121
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/42/cdad903aef3e7b614675e6584a8be417941911bin0 -> 208 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850abin0 -> 615 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/5b/1e8bccf7787e942aecf61912f94a2c274f85a5bin0 -> 368 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598bin0 -> 443 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096bin0 -> 755 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/7c/71f7606bd3bfb25d063c970804e7fc00b9605bbin0 -> 279 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/7c/7bf85e978f1d18c0566f702d2cb7766b9c8d4f1
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/a7/b066537e6be7109abfe4ff97b675d4e077da20bin0 -> 621 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/ab/6cf22b4c67a274aa8d31b5877d92341e8c2a9cbin0 -> 279 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/c4/e6cca3ec6ae0148ed231f97257df8c311e015f1
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/f3/6de77de6f53dddafeb024ecaf375e45c3d9dddbin0 -> 58 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807dbin0 -> 355 bytes
-rw-r--r--tests/resources/rebase-submodule/.gitted/packed-refs2
-rw-r--r--tests/resources/rebase-submodule/.gitted/refs/heads/asparagus1
-rw-r--r--tests/resources/rebase-submodule/.gitted/refs/heads/master1
-rw-r--r--tests/resources/rebase-submodule/asparagus.txt10
-rw-r--r--tests/resources/rebase-submodule/beef.txt22
-rw-r--r--tests/resources/rebase-submodule/bouilli.txt18
-rw-r--r--tests/resources/rebase-submodule/gitmodules3
-rw-r--r--tests/resources/rebase-submodule/gravy.txt8
-rw-r--r--tests/resources/rebase-submodule/oyster.txt13
-rw-r--r--tests/resources/rebase-submodule/veal.txt18
-rw-r--r--tests/resources/sha1/hello_c6
-rw-r--r--tests/resources/sha1/shattered-1.pdfbin0 -> 422435 bytes
-rw-r--r--tests/resources/submodules-worktree-child/.gitted1
-rw-r--r--tests/resources/submodules-worktree-child/README1
-rw-r--r--tests/resources/submodules-worktree-child/branch_file.txt2
-rw-r--r--tests/resources/submodules-worktree-child/new.txt1
-rw-r--r--tests/resources/submodules-worktree-parent/.gitmodules3
-rw-r--r--tests/resources/submodules-worktree-parent/.gitted1
-rw-r--r--tests/resources/submodules-worktree-parent/deleted1
-rw-r--r--tests/resources/submodules-worktree-parent/modified1
-rw-r--r--tests/resources/submodules-worktree-parent/unmodified1
-rw-r--r--tests/resources/submodules.git/HEAD1
-rw-r--r--tests/resources/submodules.git/config4
-rw-r--r--tests/resources/submodules.git/objects/26/a3b32a9b7d97486c5557f5902e8ac94638145e2
-rw-r--r--tests/resources/submodules.git/objects/78/308c9251cf4eee8b25a76c7d2790c73d797357bin0 -> 97 bytes
-rw-r--r--tests/resources/submodules.git/objects/97/896810b3210244a62a82458b8e0819ecfc68503
-rw-r--r--tests/resources/submodules.git/objects/b6/0fd986699ba4e9e68bea07cf8e793f323ef888bin0 -> 138 bytes
-rw-r--r--tests/resources/submodules.git/objects/d5/f7fc3f74f7dec08280f370a975b112e8f60818bin0 -> 21 bytes
-rw-r--r--tests/resources/submodules.git/objects/e3/50052cc767cd1fcb37e84e9a89e701925be4aebin0 -> 120 bytes
-rw-r--r--tests/resources/submodules.git/objects/info/packs2
-rw-r--r--tests/resources/submodules.git/objects/pack/pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.idxbin0 -> 1156 bytes
-rw-r--r--tests/resources/submodules.git/objects/pack/pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.packbin0 -> 228 bytes
-rw-r--r--tests/resources/submodules.git/refs/heads/master1
-rw-r--r--tests/resources/submodules/.gitted/logs/refs/heads/submodules-worktree-parent1
-rw-r--r--tests/resources/submodules/.gitted/refs/heads/submodules-worktree-parent1
-rw-r--r--tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/HEAD1
-rw-r--r--tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/ORIG_HEAD1
-rw-r--r--tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/commondir1
-rw-r--r--tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/gitdir1
-rw-r--r--tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/indexbin0 -> 441 bytes
-rw-r--r--tests/resources/submodules/testrepo/.gitted/config3
-rw-r--r--tests/resources/submodules/testrepo/.gitted/logs/refs/heads/submodules-worktree-child1
-rw-r--r--tests/resources/submodules/testrepo/.gitted/refs/heads/submodules-worktree-child1
-rw-r--r--tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/HEAD1
-rw-r--r--tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/ORIG_HEAD1
-rw-r--r--tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/commondir1
-rw-r--r--tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/gitdir1
-rw-r--r--tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/indexbin0 -> 289 bytes
-rw-r--r--tests/resources/testrepo-worktree/.gitted1
-rw-r--r--tests/resources/testrepo-worktree/README1
-rw-r--r--tests/resources/testrepo-worktree/branch_file.txt2
l---------tests/resources/testrepo-worktree/link_to_new.txt1
-rw-r--r--tests/resources/testrepo-worktree/new.txt1
-rw-r--r--tests/resources/testrepo.git/objects/43/da5ec3274dd061df152ff5e69853d562b018422
-rw-r--r--tests/resources/testrepo.git/objects/43/e968a905a821532069bb413801d35b200631cf4
-rw-r--r--tests/resources/testrepo.git/objects/5d/0f8f7891e872d284beef38254882dc879b2602bin0 -> 149 bytes
-rw-r--r--tests/resources/testrepo.git/objects/5f/34cd6e3285089647165983482cf90873d50940bin0 -> 37 bytes
-rw-r--r--tests/resources/testrepo.git/objects/8e/73b769e97678d684b809b163bebdae2911720f2
-rw-r--r--tests/resources/testrepo.git/objects/b2/04707bbc546a1a770ef6ced37c7089cc3bfe6b2
-rw-r--r--tests/resources/testrepo.git/objects/b2/35959d89084af8d3544fbdf675e47944f86524bin0 -> 77 bytes
-rw-r--r--tests/resources/testrepo.git/objects/b9/1e763008b10db366442469339f90a2b8400d0abin0 -> 206 bytes
-rw-r--r--tests/resources/testrepo.git/objects/bd/758010071961f28336333bc41e9c64c9a64866bin0 -> 162 bytes
-rw-r--r--tests/resources/testrepo.git/objects/db/4df74a2fc340a0d0cb0cafc0db471fdfff10482
-rw-r--r--tests/resources/testrepo.git/objects/db/793a00a5615eca1aac97e42b3a68b1acfa8bfdbin0 -> 193 bytes
-rw-r--r--tests/resources/testrepo.git/objects/db/c0be625bed24b5d8f5d9a927484f2065d321afbin0 -> 175 bytes
-rw-r--r--tests/resources/testrepo.git/objects/f0/a2a10243ca64f935dbe3dccb89ec8bf16bdacebin0 -> 38 bytes
-rw-r--r--tests/resources/testrepo/.gitted/logs/refs/heads/testrepo-worktree1
-rw-r--r--tests/resources/testrepo/.gitted/objects/9b/1719f5cf069568785080a0bbabbe7c377e22aebin0 -> 24 bytes
-rw-r--r--tests/resources/testrepo/.gitted/objects/a3/8d028f71eaa590febb7d716b1ca32350cf70dabin0 -> 155 bytes
-rw-r--r--tests/resources/testrepo/.gitted/objects/ad/edac69457183c8265c8a9614c1c4fed31d1ff3bin0 -> 119 bytes
-rw-r--r--tests/resources/testrepo/.gitted/refs/heads/merge-conflict1
-rw-r--r--tests/resources/testrepo/.gitted/refs/heads/testrepo-worktree1
-rw-r--r--tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/HEAD1
-rw-r--r--tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/commondir1
-rw-r--r--tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/gitdir1
-rw-r--r--tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/indexbin0 -> 369 bytes
-rw-r--r--tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/logs/HEAD1
-rw-r--r--tests/revwalk/basic.c92
-rw-r--r--tests/revwalk/hidecb.c2
-rw-r--r--tests/revwalk/simplify.c1
-rw-r--r--tests/status/ignore.c109
-rw-r--r--tests/submodule/lookup.c57
-rw-r--r--tests/submodule/open.c90
-rw-r--r--tests/submodule/submodule_helpers.c2
-rw-r--r--tests/threads/basic.c27
-rw-r--r--tests/threads/diff.c15
-rw-r--r--tests/threads/refdb.c175
-rw-r--r--tests/worktree/config.c45
-rw-r--r--tests/worktree/merge.c121
-rw-r--r--tests/worktree/open.c143
-rw-r--r--tests/worktree/reflog.c65
-rw-r--r--tests/worktree/refs.c173
-rw-r--r--tests/worktree/repository.c63
-rw-r--r--tests/worktree/submodule.c92
-rw-r--r--tests/worktree/worktree.c583
-rw-r--r--tests/worktree/worktree_helpers.c30
-rw-r--r--tests/worktree/worktree_helpers.h11
552 files changed, 15648 insertions, 4452 deletions
diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE
new file mode 100644
index 000000000..1e432aeef
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE
@@ -0,0 +1,14 @@
+You are opening a _bug report_ against the libgit2 project. If you have a
+question about an API or usage, please ask on StackOverflow:
+http://stackoverflow.com/questions/tagged/libgit2. Please fill out the
+reproduction steps (below) and delete this introductory paragraph. Thanks!
+
+### Reproduction steps
+
+### Expected behavior
+
+### Actual behavior
+
+### Version of libgit2 (release number or SHA1)
+
+### Operating system(s) tested
diff --git a/.travis.yml b/.travis.yml
index bfc0fac48..8bbcb3929 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,6 +2,7 @@
# see travis-ci.org for details
language: c
+dist: trusty
os:
- linux
@@ -17,19 +18,11 @@ env:
- secure: "YnhS+8n6B+uoyaYfaJ3Lei7cSJqHDPiKJCKFIF2c87YDfmCvAJke8QtE7IzjYDs7UFkTCM4ox+ph2bERUrxZbSCyEkHdjIZpKuMJfYWja/jgMqTMxdyOH9y8JLFbZsSXDIXDwqBlC6vVyl1fP90M35wuWcNTs6tctfVWVofEFbs="
- GITTEST_INVASIVE_FS_SIZE=1
matrix:
- - OPTIONS="-DTHREADSAFE=ON -DCMAKE_BUILD_TYPE=Release"
- - OPTIONS="-DTHREADSAFE=OFF -DBUILD_EXAMPLES=ON"
+ - OPTIONS="-DTHREADSAFE=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_WERROR=ON"
+ - OPTIONS="-DTHREADSAFE=OFF -DBUILD_EXAMPLES=ON -DENABLE_WERROR=ON"
-addons:
- apt:
- packages:
- - cmake
- - libssh2-1-dev
- - openssh-client
- - openssh-server
- - valgrind
-
-sudo: false
+dist: trusty
+sudo: true
matrix:
fast_finish: true
@@ -38,21 +31,24 @@ matrix:
compiler: gcc
include:
- compiler: gcc
+ env: PRECISE=1
+ os: linux
+ dist: precise
+ - compiler: gcc
env: COVERITY=1
os: linux
+ dist: trusty
- compiler: gcc
env:
- VALGRIND=1
OPTIONS="-DBUILD_CLAR=ON -DBUILD_EXAMPLES=OFF -DDEBUG_POOL=ON -DCMAKE_BUILD_TYPE=Debug"
os: linux
+ dist: trusty
allow_failures:
- env: COVERITY=1
- - env:
- - VALGRIND=1
- OPTIONS="-DBUILD_CLAR=ON -DBUILD_EXAMPLES=OFF -DDEBUG_POOL=ON -DCMAKE_BUILD_TYPE=Debug"
install:
- - if [ "$TRAVIS_OS_NAME" = "osx" ]; then ./script/install-deps-${TRAVIS_OS_NAME}.sh; fi
+ - ./script/install-deps-${TRAVIS_OS_NAME}.sh
# Run the Build script and tests
script:
diff --git a/AUTHORS b/AUTHORS
index 61e2113ec..458ff06c3 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -22,6 +22,7 @@ Dmitry Kakurin
Dmitry Kovega
Emeric Fermas
Emmanuel Rodriguez
+Eric Myhre
Florian Forster
Holger Weiss
Ingmar Vanhassel
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e4fd68dfe..43724b5f3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,118 @@
-v0.24 + 1
+v0.26 + 1
+---------
+
+### Changes or improvements
+
+* Improved `p_unlink` in `posix_w32.c` to try and make a file writable
+ before sleeping in the retry loop to prevent unnecessary calls to sleep.
+
+### API additions
+
+* `git_remote_create_detached()` creates a remote that is not associated
+ to any repository (and does not apply configuration like 'insteadof' rules).
+ This is mostly useful for e.g. emulating `git ls-remote` behavior.
+
+### API removals
+
+### Breaking API changes
+
+v0.26
+-----
+
+### Changes or improvements
+
+* Support for opening, creating and modifying worktrees.
+
+* We can now detect SHA1 collisions resulting from the SHAttered attack. These
+ checks can be enabled at build time via `-DUSE_SHA1DC`.
+
+* Fix for missing implementation of `git_merge_driver_source` getters.
+
+* Fix for installed pkg-config file being broken when the prefix contains
+ spaces.
+
+* We now detect when the hashsum of on-disk objects does not match their
+ expected hashsum.
+
+* We now support open-ended ranges (e.g. "master..", "...master") in our
+ revision range parsing code.
+
+* We now correctly compute ignores with leading "/" in subdirectories.
+
+* We now optionally call `fsync` on loose objects, packfiles and their indexes,
+ loose references and packed reference files.
+
+* We can now build against OpenSSL v1.1 and against LibreSSL.
+
+* `GIT_MERGE_OPTIONS_INIT` now includes a setting to perform rename detection.
+ This aligns this structure with the default by `git_merge` and
+ `git_merge_trees` when `NULL` was provided for the options.
+
+* Improvements for reading index v4 files.
+
+* Perform additional retries for filesystem operations on Windows when files
+ are temporarily locked by other processes.
+
+### API additions
+
+* New family of functions to handle worktrees:
+
+ * `git_worktree_list()` lets you look up worktrees for a repository.
+ * `git_worktree_lookup()` lets you get a specific worktree.
+ * `git_worktree_open_from_repository()` lets you get the associated worktree
+ of a repository.
+ a worktree.
+ * `git_worktree_add` lets you create new worktrees.
+ * `git_worktree_prune` lets you remove worktrees from disk.
+ * `git_worktree_lock()` and `git_worktree_unlock()` let you lock
+ respectively unlock a worktree.
+ * `git_repository_open_from_worktree()` lets you open a repository via
+ * `git_repository_head_for_worktree()` lets you get the current `HEAD` for a
+ linked worktree.
+ * `git_repository_head_detached_for_worktree()` lets you check whether a
+ linked worktree is in detached HEAD mode.
+
+* `git_repository_item_path()` lets you retrieve paths for various repository
+ files.
+
+* `git_repository_commondir()` lets you retrieve the common directory of a
+ repository.
+
+* `git_branch_is_checked_out()` allows you to check whether a branch is checked
+ out in a repository or any of its worktrees.
+
+* `git_repository_submodule_cache_all()` and
+ `git_repository_submodule_cache_clear()` functions allow you to prime or clear
+ the submodule cache of a repository.
+
+* You can disable strict hash verifications via the
+ `GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION` option with `git_libgit2_opts()`.
+
+* You can enable us calling `fsync` for various files inside the ".git"
+ directory by setting the `GIT_OPT_ENABLE_FSYNC_GITDIR` option with
+ `git_libgit2_opts()`.
+
+* You can now enable "offset deltas" when creating packfiles and negotiating
+ packfiles with a remote server by setting `GIT_OPT_ENABLE_OFS_DELTA` option
+ with `GIT_libgit2_opts()`.
+
+* You can now set the default share mode on Windows for opening files using
+ `GIT_OPT_SET_WINDOWS_SHAREMODE` option with `git_libgit2_opts()`.
+ You can query the current share mode with `GIT_OPT_GET_WINDOWS_SHAREMODE`.
+
+* `git_transport_smart_proxy_options()' enables you to get the proxy options for
+ smart transports.
+
+* The `GIT_FILTER_INIT` macro and the `git_filter_init` function are provided
+ to initialize a `git_filter` structure.
+
+### Breaking API changes
+
+* `clone_checkout_strategy` has been removed from
+ `git_submodule_update_option`. The checkout strategy used to clone will
+ be the same strategy specified in `checkout_opts`.
+
+v0.25
-------
### Changes or improvements
@@ -15,14 +129,39 @@ v0.24 + 1
* Support for reading and writing git index v4 files
+* Improve the performance of the revwalk and bring us closer to git's code.
+
+* The reference db has improved support for concurrency and returns `GIT_ELOCKED`
+ when an operation could not be performed due to locking.
+
+* Nanosecond resolution is now activated by default, following git's change to
+ do this.
+
+* We now restrict the set of ciphers we let OpenSSL use by default.
+
+* Users can now register their own merge drivers for use with `.gitattributes`.
+ The library also gained built-in support for the union merge driver.
+
+* The default for creating references is now to validate that the object does
+ exist.
+
+* Add `git_proxy_options` which is used by the different networking
+ implementations to let the caller specify the proxy settings instead of
+ relying on the environment variables.
+
### API additions
* You can now get the user-agent used by libgit2 using the
`GIT_OPT_GET_USER_AGENT` option with `git_libgit2_opts()`.
It is the counterpart to `GIT_OPT_SET_USER_AGENT`.
+* The `GIT_OPT_SET_SSL_CIPHERS` option for `git_libgit2_opts()` lets you specify
+ a custom list of ciphers to use for OpenSSL.
+
* `git_commit_create_buffer()` creates a commit and writes it into a
- user-provided buffer instead of writing it into the object db.
+ user-provided buffer instead of writing it into the object db. Combine it with
+ `git_commit_create_with_signature()` in order to create a commit with a
+ cryptographic signature.
* `git_blob_create_fromstream()` and
`git_blob_create_fromstream_commit()` allow you to create a blob by
@@ -48,12 +187,48 @@ v0.24 + 1
`git_repository_open_ext` with this flag will error out if either
`$GIT_WORK_TREE` or `$GIT_COMMON_DIR` is set.
-* `git_diff_from_buffer` can create a `git_diff` object from the contents
+* `git_diff_from_buffer()` can create a `git_diff` object from the contents
of a git-style patch file.
* `git_index_version()` and `git_index_set_version()` to get and set
the index version
+* `git_odb_expand_ids()` lets you check for the existence of multiple
+ objects at once.
+
+* The new `git_blob_dup()`, `git_commit_dup()`, `git_tag_dup()` and
+ `git_tree_dup()` functions provide type-specific wrappers for
+ `git_object_dup()` to reduce noise and increase type safety for callers.
+
+* `git_reference_dup()` lets you duplicate a reference to aid in ownership
+ management and cleanup.
+
+* `git_signature_from_buffer()` lets you create a signature from a string in the
+ format that appear in objects.
+
+* `git_tree_create_updated()` lets you create a tree based on another one
+ together with a list of updates. For the covered update cases, it's more
+ efficient than the `git_index` route.
+
+* `git_apply_patch()` applies hunks from a `git_patch` to a buffer.
+
+* `git_diff_to_buf()` lets you print an entire diff directory to a buffer,
+ similar to how `git_patch_to_buf()` works.
+
+* `git_proxy_init_options()` is added to initialize a `git_proxy_options`
+ structure at run-time.
+
+* `git_merge_driver_register()`, `git_merge_driver_unregister()` let you
+ register and unregister a custom merge driver to be used when `.gitattributes`
+ specifies it.
+
+* `git_merge_driver_lookup()` can be used to look up a merge driver by name.
+
+* `git_merge_driver_source_repo()`, `git_merge_driver_source_ancestor()`,
+ `git_merge_driver_source_ours()`, `git_merge_driver_source_theirs()`,
+ `git_merge_driver_source_file_options()` added as accessors to
+ `git_merge_driver_source`.
+
### API removals
* `git_blob_create_fromchunks()` has been removed in favour of
@@ -78,6 +253,13 @@ v0.24 + 1
If this is `NULL`, then it will not be called and the `exists` function
will be used instead.
+* `git_remote_connect()` now accepts `git_proxy_options` argument, and
+ `git_fetch_options` and `git_push_options` each have a `proxy_opts` field.
+
+* `git_merge_options` now provides a `default_driver` that can be used
+ to provide the name of a merge driver to be used to handle files changed
+ during a merge.
+
v0.24
-------
@@ -153,10 +335,6 @@ v0.24
### Breaking API changes
-* `git_merge_options` now provides a `default_driver` that can be used
- to provide the name of a merge driver to be used to handle files changed
- during a merge.
-
* The `git_merge_tree_flag_t` is now `git_merge_flag_t`. Subsequently,
its members are no longer prefixed with `GIT_MERGE_TREE_FLAG` but are
now prefixed with `GIT_MERGE_FLAG`, and the `tree_flags` field of the
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 635842f25..af4c34e3e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,15 +14,20 @@
PROJECT(libgit2 C)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
CMAKE_POLICY(SET CMP0015 NEW)
+IF (CMAKE_VERSION VERSION_GREATER 3.0)
+ CMAKE_POLICY(SET CMP0051 NEW)
+ENDIF()
# Add find modules to the path
-SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/")
+SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
INCLUDE(CheckLibraryExists)
INCLUDE(CheckFunctionExists)
+INCLUDE(CheckSymbolExists)
INCLUDE(CheckStructHasMember)
INCLUDE(AddCFlagIfSupported)
INCLUDE(FindPkgConfig)
+INCLUDE(FindThreads)
# Build options
#
@@ -36,15 +41,17 @@ OPTION( PROFILE "Generate profiling information" OFF )
OPTION( ENABLE_TRACE "Enables tracing support" OFF )
OPTION( LIBGIT2_FILENAME "Name of the produced binary" OFF )
+OPTION( USE_SHA1DC "Use SHA-1 with collision detection" OFF )
OPTION( USE_ICONV "Link with and use iconv library" OFF )
OPTION( USE_SSH "Link with libssh to enable SSH support" ON )
OPTION( USE_GSSAPI "Link with libgssapi for SPNEGO auth" OFF )
OPTION( VALGRIND "Configure build for valgrind" OFF )
OPTION( CURL "Use curl for HTTP if available" ON)
+OPTION( USE_EXT_HTTP_PARSER "Use system HTTP_Parser if available" ON)
OPTION( DEBUG_POOL "Enable debug pool allocator" OFF )
-
-IF(DEBUG_POOL)
- ADD_DEFINITIONS(-DGIT_DEBUG_POOL)
+OPTION( ENABLE_WERROR "Enable compilation with -Werror" OFF )
+IF (UNIX AND NOT APPLE)
+ OPTION( ENABLE_REPRODUCIBLE_BUILDS "Enable reproducible builds" OFF )
ENDIF()
IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
@@ -69,10 +76,6 @@ IF(MSVC)
# If you want to embed a copy of libssh2 into libgit2, pass a
# path to libssh2
OPTION( EMBED_SSH_PATH "Path to libssh2 to embed (Windows)" OFF )
-
- ADD_DEFINITIONS(-D_SCL_SECURE_NO_WARNINGS)
- ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE)
- ADD_DEFINITIONS(-D_CRT_NONSTDC_NO_DEPRECATE)
ENDIF()
@@ -112,64 +115,6 @@ IF (HAVE_STRUCT_STAT_NSEC OR WIN32)
OPTION( USE_NSEC "Care about sub-second file mtimes and ctimes" ON )
ENDIF()
-# This variable will contain the libraries we need to put into
-# libgit2.pc's Requires.private. That is, what we're linking to or
-# what someone who's statically linking us needs to link to.
-SET(LIBGIT2_PC_REQUIRES "")
-# This will be set later if we use the system's http-parser library or
-# use iconv (OSX) and will be written to the Libs.private field in the
-# pc file.
-SET(LIBGIT2_PC_LIBS "")
-
-# Installation paths
-#
-SET(BIN_INSTALL_DIR bin CACHE PATH "Where to install binaries to.")
-SET(LIB_INSTALL_DIR lib CACHE PATH "Where to install libraries to.")
-SET(INCLUDE_INSTALL_DIR include CACHE PATH "Where to install headers to.")
-
-# Set a couple variables to be substituted inside the .pc file.
-# We can't just use LIB_INSTALL_DIR in the .pc file, as passing them as absolue
-# or relative paths is both valid and supported by cmake.
-SET (PKGCONFIG_PREFIX ${CMAKE_INSTALL_PREFIX})
-
-IF(IS_ABSOLUTE ${LIB_INSTALL_DIR})
- SET (PKGCONFIG_LIBDIR ${LIB_INSTALL_DIR})
-ELSE(IS_ABSOLUTE ${LIB_INSTALL_DIR})
- SET (PKGCONFIG_LIBDIR "\${prefix}/${LIB_INSTALL_DIR}")
-ENDIF (IS_ABSOLUTE ${LIB_INSTALL_DIR})
-
-IF(IS_ABSOLUTE ${INCLUDE_INSTALL_DIR})
- SET (PKGCONFIG_INCLUDEDIR ${INCLUDE_INSTALL_DIR})
-ELSE(IS_ABSOLUTE ${INCLUDE_INSTALL_DIR})
- SET (PKGCONFIG_INCLUDEDIR "\${prefix}/${INCLUDE_INSTALL_DIR}")
-ENDIF(IS_ABSOLUTE ${INCLUDE_INSTALL_DIR})
-
-FUNCTION(TARGET_OS_LIBRARIES target)
- IF(WIN32)
- TARGET_LINK_LIBRARIES(${target} ws2_32)
- ELSEIF(CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
- TARGET_LINK_LIBRARIES(${target} socket nsl)
- LIST(APPEND LIBGIT2_PC_LIBS "-lsocket" "-lnsl")
- SET(LIBGIT2_PC_LIBS ${LIBGIT2_PC_LIBS} PARENT_SCOPE)
- ELSEIF(CMAKE_SYSTEM_NAME MATCHES "Haiku")
- TARGET_LINK_LIBRARIES(${target} network)
- LIST(APPEND LIBGIT2_PC_LIBS "-lnetwork")
- SET(LIBGIT2_PC_LIBS ${LIBGIT2_PC_LIBS} PARENT_SCOPE)
- ENDIF()
- CHECK_LIBRARY_EXISTS(rt clock_gettime "time.h" NEED_LIBRT)
- IF(NEED_LIBRT)
- TARGET_LINK_LIBRARIES(${target} rt)
- LIST(APPEND LIBGIT2_PC_LIBS "-lrt")
- SET(LIBGIT2_PC_LIBS ${LIBGIT2_PC_LIBS} PARENT_SCOPE)
- ENDIF()
-
- IF(THREADSAFE)
- TARGET_LINK_LIBRARIES(${target} ${CMAKE_THREAD_LIBS_INIT})
- LIST(APPEND LIBGIT2_PC_LIBS ${CMAKE_THREAD_LIBS_INIT})
- SET(LIBGIT2_PC_LIBS ${LIBGIT2_PC_LIBS} PARENT_SCOPE)
- ENDIF()
-ENDFUNCTION()
-
# This function splits the sources files up into their appropriate
# subdirectories. This is especially useful for IDEs like Xcode and
# Visual Studio, so that you can navigate into the libgit2_clar project,
@@ -180,7 +125,7 @@ FUNCTION(IDE_SPLIT_SOURCES target)
GET_TARGET_PROPERTY(sources ${target} SOURCES)
FOREACH(source ${sources})
IF(source MATCHES ".*/")
- STRING(REPLACE ${CMAKE_CURRENT_SOURCE_DIR}/ "" rel ${source})
+ STRING(REPLACE ${CMAKE_SOURCE_DIR}/ "" rel ${source})
IF(rel)
STRING(REGEX REPLACE "/([^/]*)$" "" rel ${rel})
IF(rel)
@@ -193,201 +138,21 @@ FUNCTION(IDE_SPLIT_SOURCES target)
ENDIF()
ENDFUNCTION()
-FILE(STRINGS "include/git2/version.h" GIT2_HEADER REGEX "^#define LIBGIT2_VERSION \"[^\"]*\"$")
+FILE(STRINGS "${CMAKE_SOURCE_DIR}/include/git2/version.h" GIT2_HEADER REGEX "^#define LIBGIT2_VERSION \"[^\"]*\"$")
STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"([0-9]+).*$" "\\1" LIBGIT2_VERSION_MAJOR "${GIT2_HEADER}")
STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_VERSION_MINOR "${GIT2_HEADER}")
STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_VERSION_REV "${GIT2_HEADER}")
SET(LIBGIT2_VERSION_STRING "${LIBGIT2_VERSION_MAJOR}.${LIBGIT2_VERSION_MINOR}.${LIBGIT2_VERSION_REV}")
-FILE(STRINGS "include/git2/version.h" GIT2_HEADER_SOVERSION REGEX "^#define LIBGIT2_SOVERSION [0-9]+$")
+FILE(STRINGS "${CMAKE_SOURCE_DIR}/include/git2/version.h" GIT2_HEADER_SOVERSION REGEX "^#define LIBGIT2_SOVERSION [0-9]+$")
STRING(REGEX REPLACE "^.*LIBGIT2_SOVERSION ([0-9]+)$" "\\1" LIBGIT2_SOVERSION "${GIT2_HEADER_SOVERSION}")
-# Find required dependencies
-INCLUDE_DIRECTORIES(src include)
-
-IF (SECURITY_FOUND)
- # OS X 10.7 and older do not have some functions we use, fall back to OpenSSL there
- CHECK_LIBRARY_EXISTS("${SECURITY_DIRS}" SSLCreateContext "Security/SecureTransport.h" HAVE_NEWER_SECURITY)
- IF (HAVE_NEWER_SECURITY)
- MESSAGE("-- Found Security ${SECURITY_DIRS}")
- LIST(APPEND LIBGIT2_PC_LIBS "-framework Security")
- ELSE()
- MESSAGE("-- Security framework is too old, falling back to OpenSSL")
- SET(SECURITY_FOUND "NO")
- SET(SECURITY_DIRS "")
- SET(SECURITY_DIR "")
- SET(USE_OPENSSL "ON")
- ENDIF()
-ENDIF()
-
-IF (COREFOUNDATION_FOUND)
- MESSAGE("-- Found CoreFoundation ${COREFOUNDATION_DIRS}")
- LIST(APPEND LIBGIT2_PC_LIBS "-framework CoreFoundation")
-ENDIF()
-
-
-IF (WIN32 AND EMBED_SSH_PATH)
- FILE(GLOB SRC_SSH "${EMBED_SSH_PATH}/src/*.c")
- INCLUDE_DIRECTORIES("${EMBED_SSH_PATH}/include")
- FILE(WRITE "${EMBED_SSH_PATH}/src/libssh2_config.h" "#define HAVE_WINCNG\n#define LIBSSH2_WINCNG\n#include \"../win32/libssh2_config.h\"")
- ADD_DEFINITIONS(-DGIT_SSH)
-ENDIF()
-
-IF (WIN32 AND WINHTTP)
- ADD_DEFINITIONS(-DGIT_WINHTTP)
- INCLUDE_DIRECTORIES(deps/http-parser)
- FILE(GLOB SRC_HTTP deps/http-parser/*.c deps/http-parser/*.h)
-
- # Since MinGW does not come with headers or an import library for winhttp,
- # we have to include a private header and generate our own import library
- IF (MINGW)
- FIND_PROGRAM(DLLTOOL dlltool CMAKE_FIND_ROOT_PATH_BOTH)
- IF (NOT DLLTOOL)
- MESSAGE(FATAL_ERROR "Could not find dlltool command")
- ENDIF ()
-
- SET(LIBWINHTTP_PATH "${CMAKE_CURRENT_BINARY_DIR}/deps/winhttp")
- FILE(MAKE_DIRECTORY ${LIBWINHTTP_PATH})
-
- IF (CMAKE_SIZEOF_VOID_P EQUAL 8)
- set(WINHTTP_DEF "${CMAKE_CURRENT_SOURCE_DIR}/deps/winhttp/winhttp64.def")
- ELSE()
- set(WINHTTP_DEF "${CMAKE_CURRENT_SOURCE_DIR}/deps/winhttp/winhttp.def")
- ENDIF()
-
- ADD_CUSTOM_COMMAND(
- OUTPUT ${LIBWINHTTP_PATH}/libwinhttp.a
- COMMAND ${DLLTOOL} -d ${WINHTTP_DEF} -k -D winhttp.dll -l libwinhttp.a
- DEPENDS ${WINHTTP_DEF}
- WORKING_DIRECTORY ${LIBWINHTTP_PATH}
- )
-
- SET_SOURCE_FILES_PROPERTIES(
- ${CMAKE_CURRENT_SOURCE_DIR}/src/transports/winhttp.c
- PROPERTIES OBJECT_DEPENDS ${LIBWINHTTP_PATH}/libwinhttp.a
- )
-
- INCLUDE_DIRECTORIES(deps/winhttp)
- LINK_DIRECTORIES(${LIBWINHTTP_PATH})
- ENDIF ()
-
- LINK_LIBRARIES(winhttp rpcrt4 crypt32 ole32)
- LIST(APPEND LIBGIT2_PC_LIBS "-lwinhttp" "-lrpcrt4" "-lcrypt32" "-lole32")
-ELSE ()
- IF (CURL)
- PKG_CHECK_MODULES(CURL libcurl)
- ENDIF ()
-
- IF (NOT AMIGA AND USE_OPENSSL)
- FIND_PACKAGE(OpenSSL)
- ENDIF ()
-
- IF (CURL_FOUND)
- ADD_DEFINITIONS(-DGIT_CURL)
- INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIRS})
- LINK_DIRECTORIES(${CURL_LIBRARY_DIRS})
- LINK_LIBRARIES(${CURL_LIBRARIES})
- LIST(APPEND LIBGIT2_PC_LIBS ${CURL_LDFLAGS})
- ENDIF()
-
- FIND_PACKAGE(HTTP_Parser)
- IF (HTTP_PARSER_FOUND AND HTTP_PARSER_VERSION_MAJOR EQUAL 2)
- INCLUDE_DIRECTORIES(${HTTP_PARSER_INCLUDE_DIRS})
- LINK_LIBRARIES(${HTTP_PARSER_LIBRARIES})
- LIST(APPEND LIBGIT2_PC_LIBS "-lhttp_parser")
- ELSE()
- MESSAGE(STATUS "http-parser was not found or is too old; using bundled 3rd-party sources.")
- INCLUDE_DIRECTORIES(deps/http-parser)
- FILE(GLOB SRC_HTTP deps/http-parser/*.c deps/http-parser/*.h)
- ENDIF()
-ENDIF()
-
-# Specify sha1 implementation
-IF (WIN32 AND NOT MINGW AND NOT SHA1_TYPE STREQUAL "builtin")
- ADD_DEFINITIONS(-DWIN32_SHA1)
- FILE(GLOB SRC_SHA1 src/hash/hash_win32.c)
-ELSEIF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
- ADD_DEFINITIONS(-DGIT_COMMON_CRYPTO)
-ELSEIF (OPENSSL_FOUND AND NOT SHA1_TYPE STREQUAL "builtin")
- ADD_DEFINITIONS(-DOPENSSL_SHA1)
- IF (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
- LIST(APPEND LIBGIT2_PC_LIBS "-lssl")
- ELSE()
- SET(LIBGIT2_PC_REQUIRES "${LIBGIT2_PC_REQUIRES} openssl")
- ENDIF ()
-ELSE()
- FILE(GLOB SRC_SHA1 src/hash/hash_generic.c)
-ENDIF()
-
-# Enable tracing
-IF (ENABLE_TRACE STREQUAL "ON")
- ADD_DEFINITIONS(-DGIT_TRACE)
-ENDIF()
-
-# Include POSIX regex when it is required
-IF(WIN32 OR AMIGA OR CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
- INCLUDE_DIRECTORIES(deps/regex)
- SET(SRC_REGEX deps/regex/regex.c)
-ENDIF()
-
-# Optional external dependency: zlib
-FIND_PACKAGE(ZLIB)
-IF (ZLIB_FOUND)
- INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIRS})
- LINK_LIBRARIES(${ZLIB_LIBRARIES})
- IF(APPLE OR CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
- LIST(APPEND LIBGIT2_PC_LIBS "-lz")
- ELSE()
- SET(LIBGIT2_PC_REQUIRES "${LIBGIT2_PC_REQUIRES} zlib")
- ENDIF()
-ELSE()
- MESSAGE(STATUS "zlib was not found; using bundled 3rd-party sources." )
- INCLUDE_DIRECTORIES(deps/zlib)
- ADD_DEFINITIONS(-DNO_VIZ -DSTDC -DNO_GZIP)
- FILE(GLOB SRC_ZLIB deps/zlib/*.c deps/zlib/*.h)
-ENDIF()
-
-# Optional external dependency: libssh2
-IF (USE_SSH)
- PKG_CHECK_MODULES(LIBSSH2 libssh2)
-ENDIF()
-IF (LIBSSH2_FOUND)
- ADD_DEFINITIONS(-DGIT_SSH)
- INCLUDE_DIRECTORIES(${LIBSSH2_INCLUDE_DIRS})
- LINK_DIRECTORIES(${LIBSSH2_LIBRARY_DIRS})
- LIST(APPEND LIBGIT2_PC_LIBS ${LIBSSH2_LDFLAGS})
- #SET(LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS} ${LIBSSH2_LDFLAGS}")
- SET(SSH_LIBRARIES ${LIBSSH2_LIBRARIES})
-
- CHECK_LIBRARY_EXISTS("${LIBSSH2_LIBRARIES}" libssh2_userauth_publickey_frommemory "${LIBSSH2_LIBRARY_DIRS}" HAVE_LIBSSH2_MEMORY_CREDENTIALS)
- IF (HAVE_LIBSSH2_MEMORY_CREDENTIALS)
- ADD_DEFINITIONS(-DGIT_SSH_MEMORY_CREDENTIALS)
- ENDIF()
-ELSE()
- MESSAGE(STATUS "LIBSSH2 not found. Set CMAKE_PREFIX_PATH if it is installed outside of the default search path.")
-ENDIF()
-
-# Optional external dependency: libgssapi
-IF (USE_GSSAPI)
- FIND_PACKAGE(GSSAPI)
-ENDIF()
-IF (GSSAPI_FOUND)
- ADD_DEFINITIONS(-DGIT_GSSAPI)
-ENDIF()
-
-# Optional external dependency: iconv
-IF (USE_ICONV)
- FIND_PACKAGE(Iconv)
-ENDIF()
-IF (ICONV_FOUND)
- ADD_DEFINITIONS(-DGIT_USE_ICONV)
- INCLUDE_DIRECTORIES(${ICONV_INCLUDE_DIR})
- LIST(APPEND LIBGIT2_PC_LIBS ${ICONV_LIBRARIES})
-ENDIF()
-
# Platform specific compilation flags
IF (MSVC)
+ ADD_DEFINITIONS(-D_SCL_SECURE_NO_WARNINGS)
+ ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE)
+ ADD_DEFINITIONS(-D_CRT_NONSTDC_NO_DEPRECATE)
STRING(REPLACE "/Zm1000" " " CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
@@ -409,8 +174,9 @@ IF (MSVC)
ENDIF()
IF (MSVC_CRTDBG)
- SET(CRT_FLAG_DEBUG "${CRT_FLAG_DEBUG} /DGIT_MSVC_CRTDBG")
- SET(CMAKE_C_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES}" "Dbghelp.lib")
+ SET(GIT_MSVC_CRTDBG 1)
+ SET(CRT_FLAG_DEBUG "${CRT_FLAG_DEBUG}")
+ SET(CMAKE_C_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES} Dbghelp.lib")
ENDIF()
# /Zi - Create debugging information
@@ -458,21 +224,38 @@ IF (MSVC)
SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
SET(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
SET(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL}")
+ELSE ()
+ IF (ENABLE_REPRODUCIBLE_BUILDS)
+ SET(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> Dqc <TARGET> <LINK_FLAGS> <OBJECTS>")
+ SET(CMAKE_C_ARCHIVE_APPEND "<CMAKE_AR> Dq <TARGET> <LINK_FLAGS> <OBJECTS>")
+ SET(CMAKE_C_ARCHIVE_FINISH "<CMAKE_RANLIB> -D <TARGET>")
+ ENDIF()
- SET(WIN_RC "src/win32/git2.rc")
+ SET(CMAKE_C_FLAGS "-D_GNU_SOURCE ${CMAKE_C_FLAGS}")
- # Precompiled headers
+ MACRO(ENABLE_WARNINGS flag)
+ IF(ENABLE_WERROR)
+ ADD_C_FLAG_IF_SUPPORTED(-Werror=${flag})
+ ELSE()
+ ADD_C_FLAG_IF_SUPPORTED(-W${flag})
+ ENDIF()
+ ENDMACRO()
-ELSE ()
- SET(CMAKE_C_FLAGS "-D_GNU_SOURCE -Wall -Wextra ${CMAKE_C_FLAGS}")
+ MACRO(DISABLE_WARNINGS flag)
+ ADD_C_FLAG_IF_SUPPORTED(-Wno-${flag})
+ IF(ENABLE_WERROR)
+ ADD_C_FLAG_IF_SUPPORTED(-Wno-error=${flag})
+ ENDIF()
+ ENDMACRO()
+
+ ENABLE_WARNINGS(all)
+ ENABLE_WARNINGS(extra)
IF (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
SET(CMAKE_C_FLAGS "-std=c99 -D_POSIX_C_SOURCE=200112L -D__EXTENSIONS__ -D_POSIX_PTHREAD_SEMANTICS ${CMAKE_C_FLAGS}")
ENDIF()
- IF (WIN32 AND NOT CYGWIN)
- SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
- ENDIF ()
+ SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG -O0")
IF (MINGW OR MSYS) # MinGW and MSYS always do PIC and complain if we tell them to
STRING(REGEX REPLACE "-fPIC" "" CMAKE_SHARED_LIBRARY_C_FLAGS "${CMAKE_SHARED_LIBRARY_C_FLAGS}")
@@ -489,16 +272,16 @@ ELSE ()
ADD_DEFINITIONS(-D__USE_MINGW_ANSI_STDIO=1)
ENDIF ()
- ADD_C_FLAG_IF_SUPPORTED(-Wdocumentation)
- ADD_C_FLAG_IF_SUPPORTED(-Wno-missing-field-initializers)
- ADD_C_FLAG_IF_SUPPORTED(-Wstrict-aliasing=2)
- ADD_C_FLAG_IF_SUPPORTED(-Wstrict-prototypes)
- ADD_C_FLAG_IF_SUPPORTED(-Wdeclaration-after-statement)
- ADD_C_FLAG_IF_SUPPORTED(-Wno-unused-const-variable)
- ADD_C_FLAG_IF_SUPPORTED(-Wno-unused-function)
+ ENABLE_WARNINGS(documentation)
+ DISABLE_WARNINGS(missing-field-initializers)
+ ENABLE_WARNINGS(strict-aliasing=2)
+ ENABLE_WARNINGS(strict-prototypes)
+ ENABLE_WARNINGS(declaration-after-statement)
+ DISABLE_WARNINGS(unused-const-variable)
+ DISABLE_WARNINGS(unused-function)
IF (APPLE) # Apple deprecated OpenSSL
- ADD_C_FLAG_IF_SUPPORTED(-Wno-deprecated-declarations)
+ DISABLE_WARNINGS(deprecated-declarations)
ENDIF()
IF (PROFILE)
@@ -507,21 +290,6 @@ ELSE ()
ENDIF ()
ENDIF()
-CHECK_FUNCTION_EXISTS(futimens HAVE_FUTIMENS)
-IF (HAVE_FUTIMENS)
- ADD_DEFINITIONS(-DHAVE_FUTIMENS)
-ENDIF ()
-
-CHECK_FUNCTION_EXISTS(qsort_r HAVE_QSORT_R)
-IF (HAVE_QSORT_R)
- ADD_DEFINITIONS(-DHAVE_QSORT_R)
-ENDIF ()
-
-CHECK_FUNCTION_EXISTS(qsort_s HAVE_QSORT_S)
-IF (HAVE_QSORT_S)
- ADD_DEFINITIONS(-DHAVE_QSORT_S)
-ENDIF ()
-
IF( NOT CMAKE_CONFIGURATION_TYPES )
# Build Debug by default
IF (NOT CMAKE_BUILD_TYPE)
@@ -532,175 +300,12 @@ ELSE()
# that uses CMAKE_CONFIGURATION_TYPES and not CMAKE_BUILD_TYPE
ENDIF()
-IF (SECURITY_FOUND)
- ADD_DEFINITIONS(-DGIT_SECURE_TRANSPORT)
- INCLUDE_DIRECTORIES(${SECURITY_INCLUDE_DIR})
-ENDIF ()
-
-IF (OPENSSL_FOUND)
- ADD_DEFINITIONS(-DGIT_OPENSSL)
- INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
- SET(SSL_LIBRARIES ${OPENSSL_LIBRARIES})
-ENDIF()
-
-
-
-IF (THREADSAFE)
- IF (NOT WIN32)
- FIND_PACKAGE(Threads REQUIRED)
- ENDIF()
-
- ADD_DEFINITIONS(-DGIT_THREADS)
-ENDIF()
-
-IF (USE_NSEC)
- ADD_DEFINITIONS(-DGIT_USE_NSEC)
-ENDIF()
-
-IF (HAVE_STRUCT_STAT_ST_MTIM)
- ADD_DEFINITIONS(-DGIT_USE_STAT_MTIM)
-ELSEIF (HAVE_STRUCT_STAT_ST_MTIMESPEC)
- ADD_DEFINITIONS(-DGIT_USE_STAT_MTIMESPEC)
-ELSEIF (HAVE_STRUCT_STAT_ST_MTIME_NSEC)
- ADD_DEFINITIONS(-DGIT_USE_STAT_MTIME_NSEC)
-ENDIF()
-
-ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64)
-
-# Collect sourcefiles
-FILE(GLOB SRC_H include/git2.h include/git2/*.h include/git2/sys/*.h)
-
-# On Windows use specific platform sources
-IF (WIN32 AND NOT CYGWIN)
- ADD_DEFINITIONS(-DWIN32 -D_WIN32_WINNT=0x0501)
- FILE(GLOB SRC_OS src/win32/*.c src/win32/*.h)
-ELSEIF (AMIGA)
- ADD_DEFINITIONS(-DNO_ADDRINFO -DNO_READDIR_R -DNO_MMAP)
-ELSE()
- IF (VALGRIND)
- ADD_DEFINITIONS(-DNO_MMAP)
- ENDIF()
- FILE(GLOB SRC_OS src/unix/*.c src/unix/*.h)
-ENDIF()
-FILE(GLOB SRC_GIT2 src/*.c src/*.h src/transports/*.c src/transports/*.h src/xdiff/*.c src/xdiff/*.h)
-
-# Determine architecture of the machine
-IF (CMAKE_SIZEOF_VOID_P EQUAL 8)
- ADD_DEFINITIONS(-DGIT_ARCH_64)
-ELSEIF (CMAKE_SIZEOF_VOID_P EQUAL 4)
- ADD_DEFINITIONS(-DGIT_ARCH_32)
-ELSEIF (CMAKE_SIZEOF_VOID_P)
- MESSAGE(FATAL_ERROR "Unsupported architecture (pointer size is ${CMAKE_SIZEOF_VOID_P} bytes)")
-ELSE()
- MESSAGE(FATAL_ERROR "Unsupported architecture (CMAKE_SIZEOF_VOID_P is unset)")
-ENDIF()
-
-# Compile and link libgit2
-ADD_LIBRARY(git2 ${SRC_H} ${SRC_GIT2} ${SRC_OS} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX} ${SRC_SSH} ${SRC_SHA1} ${WIN_RC})
-TARGET_LINK_LIBRARIES(git2 ${SECURITY_DIRS})
-TARGET_LINK_LIBRARIES(git2 ${COREFOUNDATION_DIRS})
-TARGET_LINK_LIBRARIES(git2 ${SSL_LIBRARIES})
-TARGET_LINK_LIBRARIES(git2 ${SSH_LIBRARIES})
-TARGET_LINK_LIBRARIES(git2 ${GSSAPI_LIBRARIES})
-TARGET_LINK_LIBRARIES(git2 ${ICONV_LIBRARIES})
-TARGET_OS_LIBRARIES(git2)
-
-# Workaround for Cmake bug #0011240 (see http://public.kitware.com/Bug/view.php?id=11240)
-# Win64+MSVC+static libs = linker error
-IF(MSVC AND GIT_ARCH_64 AND NOT BUILD_SHARED_LIBS)
- SET_TARGET_PROPERTIES(git2 PROPERTIES STATIC_LIBRARY_FLAGS "/MACHINE:x64")
-ENDIF()
-
-IDE_SPLIT_SOURCES(git2)
-
-IF (SONAME)
- SET_TARGET_PROPERTIES(git2 PROPERTIES VERSION ${LIBGIT2_VERSION_STRING})
- SET_TARGET_PROPERTIES(git2 PROPERTIES SOVERSION ${LIBGIT2_SOVERSION})
- IF (LIBGIT2_FILENAME)
- ADD_DEFINITIONS(-DLIBGIT2_FILENAME=\"${LIBGIT2_FILENAME}\")
- SET_TARGET_PROPERTIES(git2 PROPERTIES OUTPUT_NAME ${LIBGIT2_FILENAME})
- ELSEIF (DEFINED LIBGIT2_PREFIX)
- SET_TARGET_PROPERTIES(git2 PROPERTIES PREFIX "${LIBGIT2_PREFIX}")
- ENDIF()
-ENDIF()
-STRING(REPLACE ";" " " LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS}")
-CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/libgit2.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libgit2.pc @ONLY)
-
-IF (MSVC_IDE)
- # Precompiled headers
- SET_TARGET_PROPERTIES(git2 PROPERTIES COMPILE_FLAGS "/Yuprecompiled.h /FIprecompiled.h")
- SET_SOURCE_FILES_PROPERTIES(src/win32/precompiled.c COMPILE_FLAGS "/Ycprecompiled.h")
-ENDIF ()
-
-# Install
-INSTALL(TARGETS git2
- RUNTIME DESTINATION ${BIN_INSTALL_DIR}
- LIBRARY DESTINATION ${LIB_INSTALL_DIR}
- ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
-)
-INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libgit2.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig )
-INSTALL(DIRECTORY include/git2 DESTINATION ${INCLUDE_INSTALL_DIR} )
-INSTALL(FILES include/git2.h DESTINATION ${INCLUDE_INSTALL_DIR} )
+ADD_SUBDIRECTORY(src)
# Tests
IF (BUILD_CLAR)
- FIND_PACKAGE(PythonInterp)
-
- IF(NOT PYTHONINTERP_FOUND)
- MESSAGE(FATAL_ERROR "Could not find a python interpeter, which is needed to build the tests. "
- "Make sure python is available, or pass -DBUILD_CLAR=OFF to skip building the tests")
- ENDIF()
-
- SET(CLAR_FIXTURES "${CMAKE_CURRENT_SOURCE_DIR}/tests/resources/")
- SET(CLAR_PATH "${CMAKE_CURRENT_SOURCE_DIR}/tests")
- SET(CLAR_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/tests/resources" CACHE PATH "Path to test resources.")
- ADD_DEFINITIONS(-DCLAR_FIXTURE_PATH=\"${CLAR_FIXTURES}\")
- ADD_DEFINITIONS(-DCLAR_RESOURCES=\"${TEST_RESOURCES}\")
- ADD_DEFINITIONS(-DCLAR_TMPDIR=\"libgit2_tests\")
-
- INCLUDE_DIRECTORIES(${CLAR_PATH})
- FILE(GLOB_RECURSE SRC_TEST ${CLAR_PATH}/*/*.c ${CLAR_PATH}/*/*.h)
- SET(SRC_CLAR "${CLAR_PATH}/main.c" "${CLAR_PATH}/clar_libgit2.c" "${CLAR_PATH}/clar_libgit2_trace.c" "${CLAR_PATH}/clar_libgit2_timer.c" "${CLAR_PATH}/clar.c")
-
- ADD_CUSTOM_COMMAND(
- OUTPUT ${CLAR_PATH}/clar.suite
- COMMAND ${PYTHON_EXECUTABLE} generate.py -f -xonline -xstress .
- DEPENDS ${SRC_TEST}
- WORKING_DIRECTORY ${CLAR_PATH}
- )
-
- SET_SOURCE_FILES_PROPERTIES(
- ${CLAR_PATH}/clar.c
- PROPERTIES OBJECT_DEPENDS ${CLAR_PATH}/clar.suite)
-
- ADD_EXECUTABLE(libgit2_clar ${SRC_H} ${SRC_GIT2} ${SRC_OS} ${SRC_CLAR} ${SRC_TEST} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX} ${SRC_SSH} ${SRC_SHA1})
-
- TARGET_LINK_LIBRARIES(libgit2_clar ${COREFOUNDATION_DIRS})
- TARGET_LINK_LIBRARIES(libgit2_clar ${SECURITY_DIRS})
- TARGET_LINK_LIBRARIES(libgit2_clar ${SSL_LIBRARIES})
- TARGET_LINK_LIBRARIES(libgit2_clar ${SSH_LIBRARIES})
- TARGET_LINK_LIBRARIES(libgit2_clar ${GSSAPI_LIBRARIES})
- TARGET_LINK_LIBRARIES(libgit2_clar ${ICONV_LIBRARIES})
- TARGET_OS_LIBRARIES(libgit2_clar)
- IDE_SPLIT_SOURCES(libgit2_clar)
-
- IF (MSVC_IDE)
- # Precompiled headers
- SET_TARGET_PROPERTIES(libgit2_clar PROPERTIES COMPILE_FLAGS "/Yuprecompiled.h /FIprecompiled.h")
- ENDIF ()
-
ENABLE_TESTING()
- IF (WINHTTP OR OPENSSL_FOUND OR SECURITY_FOUND)
- ADD_TEST(libgit2_clar libgit2_clar -ionline)
- ELSE ()
- ADD_TEST(libgit2_clar libgit2_clar -v)
- ENDIF ()
-
- # Add a test target which runs the cred callback tests, to be
- # called after setting the url and user
- ADD_TEST(libgit2_clar-cred_callback libgit2_clar -v -sonline::clone::cred_callback)
- ADD_TEST(libgit2_clar-proxy_credentials_in_url libgit2_clar -v -sonline::clone::proxy_credentials_in_url)
- ADD_TEST(libgit2_clar-proxy_credentials_request libgit2_clar -v -sonline::clone::proxy_credentials_request)
+ ADD_SUBDIRECTORY(tests)
ENDIF ()
IF (TAGS)
diff --git a/CONVENTIONS.md b/CONVENTIONS.md
index 0be4b33cc..ffb696a4d 100644
--- a/CONVENTIONS.md
+++ b/CONVENTIONS.md
@@ -18,11 +18,11 @@ other's toes.
- If a function returns an object as a return value, that function is
a getter and the object's lifetime is tied to the parent
object. Objects which are returned as the first argument as a
- pointer-to-pointer are owned by the caller and it is repsponsible
+ pointer-to-pointer are owned by the caller and it is responsible
for freeing it. Strings are returned via `git_buf` in order to
allow for re-use and safe freeing.
- - Most of what libgit2 does relates to I/O so you as a general rule
+ - Most of what libgit2 does relates to I/O so as a general rule
you should assume that any function can fail due to errors as even
getting data from the filesystem can result in all sorts of errors
and complex failure cases.
diff --git a/COPYING b/COPYING
index 1b88b9b8e..da695ebdb 100644
--- a/COPYING
+++ b/COPYING
@@ -958,3 +958,36 @@ necessary. Here is a sample; alter the names:
That's all there is to it!
----------------------------------------------------------------------
+
+The bundled SHA1 collision detection code is licensed under the MIT license:
+
+MIT License
+
+Copyright (c) 2017:
+ Marc Stevens
+ Cryptology Group
+ Centrum Wiskunde & Informatica
+ P.O. Box 94079, 1090 GB Amsterdam, Netherlands
+ marc@marc-stevens.nl
+
+ Dan Shumow
+ Microsoft Research
+ danshu@microsoft.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/PROJECTS.md b/PROJECTS.md
index 87ce78f02..f53a2e120 100644
--- a/PROJECTS.md
+++ b/PROJECTS.md
@@ -5,7 +5,7 @@ So, you want to start helping out with `libgit2`? That's fantastic! We
welcome contributions and we promise we'll try to be nice.
This is a list of libgit2 related projects that new contributors can take
-on. It includes a number of good starter projects and well as some larger
+on. It includes a number of good starter projects as well as some larger
ideas that no one is actively working on.
## Before You Start
@@ -70,11 +70,11 @@ some incremental steps listed towards the larger goal. Those steps
might make good smaller projects by themselves.
* Port part of the Git test suite to run against the command line emulation
- in examples/
- * Pick a Git command that is emulated in our examples/ area
+ in `examples/`
+ * Pick a Git command that is emulated in our `examples/` area
* Extract the Git tests that exercise that command
* Convert the tests to call our emulation
- * These tests could go in examples/tests/...
+ * These tests could go in `examples/tests/`...
* Add hooks API to enumerate and manage hooks (not run them at this point)
* Enumeration of available hooks
* Lookup API to see which hooks have a script and get the script
diff --git a/README.md b/README.md
index e656a460c..0d2305957 100644
--- a/README.md
+++ b/README.md
@@ -43,9 +43,16 @@ We ask that you not open a GitHub Issue for help, only for bug reports.
What It Can Do
==============
-`libgit2` is already very usable and is being used in production for many
-applications including the GitHub.com site, in Plastic SCM and also powering
-Microsoft's Visual Studio tools for Git. The library provides:
+libgit2 provides you with the ability to manage Git repositories in the
+programming language of your choice. It's used in production to power many
+applications including GitHub.com, Plastic SCM and Visual Studio Team Services.
+
+It does not aim to replace the git tool or its user-facing commands. Some APIs
+resemble the plumbing commands as those align closely with the concepts of the
+Git system, but most commands a user would type are out of scope for this
+library to implement directly.
+
+The library provides:
* SHA conversions, formatting and shortening
* abstracted ODB backend system
@@ -60,6 +67,16 @@ Microsoft's Visual Studio tools for Git. The library provides:
* descriptive and detailed error messages
* ...and more (over 175 different API calls)
+As libgit2 is purely a consumer of the Git system, we have to
+adjust to changes made upstream. This has two major consequences:
+
+* Some changes may require us to change provided interfaces. While we try to
+ implement functions in a generic way so that no future changes are required,
+ we cannot promise a completely stable API.
+* As we have to keep up with changes in behavior made upstream, we may lag
+ behind in some areas. We usually to document these incompatibilities in our
+ issue tracker with the label "git change".
+
Optional dependencies
=====================
@@ -116,6 +133,14 @@ On most systems you can build the library using the following commands
Alternatively you can point the CMake GUI tool to the CMakeLists.txt file and generate platform specific build project or IDE workspace.
+Once built, you can run the tests from the `build` directory with the command
+
+ $ make test
+
+Alternatively you can run the test suite directly using,
+
+ $ ./libgit2_clar
+
To install the library you can specify the install prefix by setting:
$ cmake .. -DCMAKE_INSTALL_PREFIX=/install/prefix
@@ -203,6 +228,8 @@ Here are the bindings to libgit2 that are currently available:
* git2go <https://github.com/libgit2/git2go>
* GObject
* libgit2-glib <https://wiki.gnome.org/Projects/Libgit2-glib>
+* Guile
+ * Guile-Git <https://gitlab.com/guile-git/guile-git>
* Haskell
* hgit2 <https://github.com/jwiegley/gitlib>
* Java
@@ -236,7 +263,7 @@ Here are the bindings to libgit2 that are currently available:
* Rust
* git2-rs <https://github.com/alexcrichton/git2-rs>
* Swift
- * Gift <https://github.com/modocache/Gift>
+ * SwiftGit2 <https://github.com/SwiftGit2/SwiftGit2>
* Vala
* libgit2.vapi <https://github.com/apmasell/vapis/blob/master/libgit2.vapi>
diff --git a/THREADING.md b/THREADING.md
index 0b9e50286..430bca858 100644
--- a/THREADING.md
+++ b/THREADING.md
@@ -62,33 +62,38 @@ general case still affects you if you use ssh.
General Case
------------
-By default we use libcurl, which has its own ![recommendations for
-thread safety](http://curl.haxx.se/libcurl/c/libcurl-tutorial.html#Multi-threading).
-
-If libcurl was not found or was disabled, libgit2 uses OpenSSL to be
-able to use HTTPS as a transport. This library is made to be
-thread-implementation agnostic, and the users of the library must set
-which locking function it should use. This means that libgit2 cannot
-know what to set as the user of libgit2 may use OpenSSL independently
-and the locking settings must survive libgit2 shutting down.
-
-Even if libgit2 doesn't use OpenSSL directly, OpenSSL can still be used
-by libssh2 depending on the configuration. If OpenSSL is used both by
-libgit2 and libssh2, you only need to set up threading for OpenSSL once.
-
-libgit2 does provide a last-resort convenience function
+If it's available, by default we use libcurl to provide HTTP tunneling support,
+which may be linked against a number of cryptographic libraries and has its
+own
+[recommendations for thread safety](https://curl.haxx.se/libcurl/c/threadsafe.html).
+
+If there are no alternative TLS implementations (currently only
+SecureTransport), libgit2 uses OpenSSL in order to use HTTPS as a transport.
+OpenSSL is thread-safe starting at version 1.1.0. If your copy of libgit2 is
+linked against that version, you do not need to take any further steps.
+
+Older versions of OpenSSL are made to be thread-implementation agnostic, and the
+users of the library must set which locking function it should use. libgit2
+cannot know what to set as the user of libgit2 may also be using OpenSSL independently and
+the locking settings must then live outside the lifetime of libgit2.
+
+Even if libgit2 doesn't use OpenSSL directly, OpenSSL can still be used by
+libssh2 or libcurl depending on the configuration. If OpenSSL is used by
+more than one library, you only need to set up threading for OpenSSL once.
+
+If libgit2 is linked against OpenSSL, it provides a last-resort convenience function
`git_openssl_set_locking()` (available in `sys/openssl.h`) to use the
-platform-native mutex mechanisms to perform the locking, which you may
-rely on if you do not want to use OpenSSL outside of libgit2, or you
-know that libgit2 will outlive the rest of the operations. It is not
+platform-native mutex mechanisms to perform the locking, which you can use
+if you do not want to use OpenSSL outside of libgit2, or you
+know that libgit2 will outlive the rest of the operations. It is then not
safe to use OpenSSL multi-threaded after libgit2's shutdown function
has been called. Note `git_openssl_set_locking()` only works if
libgit2 uses OpenSSL directly - if OpenSSL is only used as a dependency
-of libssh2 as described above, `git_openssl_set_locking()` is a no-op.
+of libssh2 or libcurl as described above, `git_openssl_set_locking()` is a no-op.
If your programming language offers a package/bindings for OpenSSL,
you should very strongly prefer to use that in order to set up
-locking, as they provide a level of coördination which is impossible
+locking, as they provide a level of coordination which is impossible
when using this function.
See the
@@ -96,13 +101,10 @@ See the
on threading for more details, and http://trac.libssh2.org/wiki/MultiThreading
for a specific example of providing the threading callbacks.
-Be also aware that libgit2 does not always link against OpenSSL
-if there are alternatives provided by the system.
-
libssh2 may be linked against OpenSSL or libgcrypt. If it uses OpenSSL,
see the above paragraphs. If it uses libgcrypt, then you need to
set up its locking before using it multi-threaded. libgit2 has no
-direct connection to libgcrypt and thus has not convenience functions for
+direct connection to libgcrypt and thus has no convenience functions for
it (but libgcrypt has macros). Read libgcrypt's
[threading documentation for more information](http://www.gnupg.org/documentation/manuals/gcrypt/Multi_002dThreading.html)
diff --git a/appveyor.yml b/appveyor.yml
index 9e94c0726..1ba8abbd1 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -2,19 +2,30 @@ version: '{build}'
branches:
only:
- master
+ - appveyor
- /^maint.*/
environment:
GITTEST_INVASIVE_FS_STRUCTURE: 1
GITTEST_INVASIVE_FS_SIZE: 1
matrix:
- - GENERATOR: "Visual Studio 11"
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
+ GENERATOR: "Visual Studio 10 2010"
ARCH: 32
- - GENERATOR: "Visual Studio 11 Win64"
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
+ GENERATOR: "Visual Studio 10 2010 Win64"
ARCH: 64
- - GENERATOR: "MSYS Makefiles"
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+ GENERATOR: "Visual Studio 14 2015"
+ ARCH: 32
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+ GENERATOR: "Visual Studio 14 2015 Win64"
+ ARCH: 64
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+ GENERATOR: "MSYS Makefiles"
ARCH: i686 # this is for 32-bit MinGW-w64
- - GENERATOR: "MSYS Makefiles"
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+ GENERATOR: "MSYS Makefiles"
ARCH: 64
cache:
- i686-4.9.2-release-win32-sjlj-rt_v3-rev1.7z
diff --git a/deps/http-parser/CMakeLists.txt b/deps/http-parser/CMakeLists.txt
new file mode 100644
index 000000000..9309841db
--- /dev/null
+++ b/deps/http-parser/CMakeLists.txt
@@ -0,0 +1,3 @@
+FILE(GLOB SRC_HTTP "*.c" "*.h")
+
+ADD_LIBRARY(http-parser STATIC ${SRC_HTTP})
diff --git a/deps/regex/CMakeLists.txt b/deps/regex/CMakeLists.txt
new file mode 100644
index 000000000..6ef8a270f
--- /dev/null
+++ b/deps/regex/CMakeLists.txt
@@ -0,0 +1,2 @@
+INCLUDE_DIRECTORIES(".")
+ADD_LIBRARY(regex STATIC "regex.c" "regex.h")
diff --git a/deps/winhttp/CMakeLists.txt b/deps/winhttp/CMakeLists.txt
new file mode 100644
index 000000000..baa9fe2f0
--- /dev/null
+++ b/deps/winhttp/CMakeLists.txt
@@ -0,0 +1,26 @@
+FIND_PROGRAM(DLLTOOL dlltool CMAKE_FIND_ROOT_PATH_BOTH)
+IF (NOT DLLTOOL)
+ MESSAGE(FATAL_ERROR "Could not find dlltool command")
+ENDIF ()
+
+SET(LIBWINHTTP_PATH "${CMAKE_BINARY_DIR}/deps/winhttp")
+SET(LIBWINHTTP_PATH ${LIBWINHTTP_PATH} PARENT_SCOPE)
+FILE(MAKE_DIRECTORY ${LIBWINHTTP_PATH})
+
+IF (CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(WINHTTP_DEF "winhttp64.def")
+ELSE()
+ set(WINHTTP_DEF "winhttp.def")
+ENDIF()
+
+ADD_CUSTOM_COMMAND(
+ OUTPUT ${LIBWINHTTP_PATH}/libwinhttp.a
+ COMMAND ${DLLTOOL} -d ${WINHTTP_DEF} -k -D winhttp.dll -l libwinhttp.a
+ DEPENDS ${WINHTTP_DEF}
+ WORKING_DIRECTORY ${LIBWINHTTP_PATH}
+)
+
+SET_SOURCE_FILES_PROPERTIES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/transports/winhttp.c
+ PROPERTIES OBJECT_DEPENDS ${LIBWINHTTP_PATH}/libwinhttp.a
+)
diff --git a/deps/zlib/CMakeLists.txt b/deps/zlib/CMakeLists.txt
new file mode 100644
index 000000000..ca50d80c4
--- /dev/null
+++ b/deps/zlib/CMakeLists.txt
@@ -0,0 +1,4 @@
+ADD_DEFINITIONS(-DNO_VIZ -DSTDC -DNO_GZIP)
+FILE(GLOB SRC_ZLIB "*.c" "*.h")
+INCLUDE_DIRECTORIES(".")
+ADD_LIBRARY(zlib STATIC ${SRC_ZLIB})
diff --git a/deps/zlib/zconf.h b/deps/zlib/zconf.h
index 229c40024..3cd7ab158 100644
--- a/deps/zlib/zconf.h
+++ b/deps/zlib/zconf.h
@@ -8,7 +8,8 @@
#ifndef ZCONF_H
#define ZCONF_H
-#include "../../src/common.h"
+#include "../../include/git2/types.h"
+#include <stdarg.h>
/* Jeez, don't complain about non-prototype
* forms, we didn't write zlib */
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 596be45ed..a6f26c7a6 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,3 +1,6 @@
+LINK_DIRECTORIES(${LIBGIT2_LIBDIRS})
+INCLUDE_DIRECTORIES(${LIBGIT2_INCLUDES})
+
FILE(GLOB_RECURSE SRC_EXAMPLE_GIT2 network/*.c network/*.h)
ADD_EXECUTABLE(cgit2 ${SRC_EXAMPLE_GIT2})
IF(WIN32 OR ANDROID)
diff --git a/examples/add.c b/examples/add.c
index 0101ab9ae..e5849892e 100644
--- a/examples/add.c
+++ b/examples/add.c
@@ -75,15 +75,14 @@ int print_matched_cb(const char *path, const char *matched_pathspec, void *paylo
{
struct print_payload p = *(struct print_payload*)(payload);
int ret;
- git_status_t status;
+ unsigned status;
(void)matched_pathspec;
- if (git_status_file((unsigned int*)(&status), p.repo, path)) {
- return -1; //abort
+ if (git_status_file(&status, p.repo, path)) {
+ return -1;
}
- if (status & GIT_STATUS_WT_MODIFIED ||
- status & GIT_STATUS_WT_NEW) {
+ if (status & GIT_STATUS_WT_MODIFIED || status & GIT_STATUS_WT_NEW) {
printf("add '%s'\n", path);
ret = 0;
} else {
diff --git a/examples/common.c b/examples/common.c
index 0f25f3787..96f5eaa8e 100644
--- a/examples/common.c
+++ b/examples/common.c
@@ -146,6 +146,25 @@ int match_uint16_arg(
return 1;
}
+int match_uint32_arg(
+ uint32_t *out, struct args_info *args, const char *opt)
+{
+ const char *found = match_numeric_arg(args, opt);
+ uint16_t val;
+ char *endptr = NULL;
+
+ if (!found)
+ return 0;
+
+ val = (uint32_t)strtoul(found, &endptr, 0);
+ if (!endptr || *endptr != '\0')
+ fatal("expected number after argument", opt);
+
+ if (out)
+ *out = val;
+ return 1;
+}
+
static int match_int_internal(
int *out, const char *str, int allow_negative, const char *opt)
{
diff --git a/examples/common.h b/examples/common.h
index b9fa37ce9..adea0d318 100644
--- a/examples/common.h
+++ b/examples/common.h
@@ -73,6 +73,15 @@ extern int match_uint16_arg(
uint16_t *out, struct args_info *args, const char *opt);
/**
+ * Check current `args` entry against `opt` string parsing as uint32. If
+ * `opt` matches exactly, take the next arg as a uint16_t value; if `opt`
+ * is a prefix (equal sign optional), take the remainder of the arg as a
+ * uint32_t value; otherwise return 0.
+ */
+extern int match_uint32_arg(
+ uint32_t *out, struct args_info *args, const char *opt);
+
+/**
* Check current `args` entry against `opt` string parsing as int. If
* `opt` matches exactly, take the next arg as an int value; if it matches
* as a prefix (equal sign optional), take the remainder of the arg as a
diff --git a/examples/diff.c b/examples/diff.c
index b69cb2218..9a4f7a59f 100644
--- a/examples/diff.c
+++ b/examples/diff.c
@@ -293,11 +293,11 @@ static void parse_opts(struct opts *o, int argc, char *argv[])
else if (is_prefixed(a, "-B") || is_prefixed(a, "--break-rewrites"))
/* TODO: parse thresholds */
o->findopts.flags |= GIT_DIFF_FIND_REWRITES;
- else if (!match_uint16_arg(
+ else if (!match_uint32_arg(
&o->diffopts.context_lines, &args, "-U") &&
- !match_uint16_arg(
+ !match_uint32_arg(
&o->diffopts.context_lines, &args, "--unified") &&
- !match_uint16_arg(
+ !match_uint32_arg(
&o->diffopts.interhunk_lines, &args, "--inter-hunk-context") &&
!match_uint16_arg(
&o->diffopts.id_abbrev, &args, "--abbrev") &&
diff --git a/examples/general.c b/examples/general.c
index 32fdaf407..ff984a36c 100644
--- a/examples/general.c
+++ b/examples/general.c
@@ -12,39 +12,58 @@
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
-// [**libgit2**][lg] is a portable, pure C implementation of the Git core
-// methods provided as a re-entrant linkable library with a solid API,
-// allowing you to write native speed custom Git applications in any
-// language which supports C bindings.
-//
-// This file is an example of using that API in a real, compilable C file.
-// As the API is updated, this file will be updated to demonstrate the new
-// functionality.
-//
-// If you're trying to write something in C using [libgit2][lg], you should
-// also check out the generated [API documentation][ap]. We try to link to
-// the relevant sections of the API docs in each section in this file.
-//
-// **libgit2** (for the most part) only implements the core plumbing
-// functions, not really the higher level porcelain stuff. For a primer on
-// Git Internals that you will need to know to work with Git at this level,
-// check out [Chapter 10][pg] of the Pro Git book.
-//
-// [lg]: http://libgit2.github.com
-// [ap]: http://libgit2.github.com/libgit2
-// [pg]: https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain
-
-// ### Includes
-
-// Including the `git2.h` header will include all the other libgit2 headers
-// that you need. It should be the only thing you need to include in order
-// to compile properly and get all the libgit2 API.
+/**
+ * [**libgit2**][lg] is a portable, pure C implementation of the Git core
+ * methods provided as a re-entrant linkable library with a solid API,
+ * allowing you to write native speed custom Git applications in any
+ * language which supports C bindings.
+ *
+ * This file is an example of using that API in a real, compilable C file.
+ * As the API is updated, this file will be updated to demonstrate the new
+ * functionality.
+ *
+ * If you're trying to write something in C using [libgit2][lg], you should
+ * also check out the generated [API documentation][ap]. We try to link to
+ * the relevant sections of the API docs in each section in this file.
+ *
+ * **libgit2** (for the most part) only implements the core plumbing
+ * functions, not really the higher level porcelain stuff. For a primer on
+ * Git Internals that you will need to know to work with Git at this level,
+ * check out [Chapter 10][pg] of the Pro Git book.
+ *
+ * [lg]: http://libgit2.github.com
+ * [ap]: http://libgit2.github.com/libgit2
+ * [pg]: https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain
+ */
+
+/**
+ * ### Includes
+ *
+ * Including the `git2.h` header will include all the other libgit2 headers
+ * that you need. It should be the only thing you need to include in order
+ * to compile properly and get all the libgit2 API.
+ */
#include <git2.h>
#include <stdio.h>
-
-// Almost all libgit2 functions return 0 on success or negative on error.
-// This is not production quality error checking, but should be sufficient
-// as an example.
+#include <string.h>
+
+static void oid_parsing(git_oid *out);
+static void object_database(git_repository *repo, git_oid *oid);
+static void commit_writing(git_repository *repo);
+static void commit_parsing(git_repository *repo);
+static void tag_parsing(git_repository *repo);
+static void tree_parsing(git_repository *repo);
+static void blob_parsing(git_repository *repo);
+static void revwalking(git_repository *repo);
+static void index_walking(git_repository *repo);
+static void reference_listing(git_repository *repo);
+static void config_files(const char *repo_path, git_repository *repo);
+
+/**
+ * Almost all libgit2 functions return 0 on success or negative on error.
+ * This is not production quality error checking, but should be sufficient
+ * as an example.
+ */
static void check_error(int error_code, const char *action)
{
const git_error *error = giterr_last();
@@ -52,479 +71,678 @@ static void check_error(int error_code, const char *action)
return;
printf("Error %d %s - %s\n", error_code, action,
- (error && error->message) ? error->message : "???");
+ (error && error->message) ? error->message : "???");
exit(1);
}
int main (int argc, char** argv)
{
- // Initialize the library, this will set up any global state which libgit2 needs
- // including threading and crypto
- git_libgit2_init();
-
- // ### Opening the Repository
-
- // There are a couple of methods for opening a repository, this being the
- // simplest. There are also [methods][me] for specifying the index file
- // and work tree locations, here we assume they are in the normal places.
- //
- // (Try running this program against tests/resources/testrepo.git.)
- //
- // [me]: http://libgit2.github.com/libgit2/#HEAD/group/repository
- int error;
- const char *repo_path = (argc > 1) ? argv[1] : "/opt/libgit2-test/.git";
- git_repository *repo;
-
- error = git_repository_open(&repo, repo_path);
- check_error(error, "opening repository");
-
- // ### SHA-1 Value Conversions
-
- // For our first example, we will convert a 40 character hex value to the
- // 20 byte raw SHA1 value.
- printf("*Hex to Raw*\n");
- char hex[] = "4a202b346bb0fb0db7eff3cffeb3c70babbd2045";
-
- // The `git_oid` is the structure that keeps the SHA value. We will use
- // this throughout the example for storing the value of the current SHA
- // key we're working with.
- git_oid oid;
- git_oid_fromstr(&oid, hex);
-
- // Once we've converted the string into the oid value, we can get the raw
- // value of the SHA by accessing `oid.id`
-
- // Next we will convert the 20 byte raw SHA1 value to a human readable 40
- // char hex value.
- printf("\n*Raw to Hex*\n");
- char out[GIT_OID_HEXSZ+1];
- out[GIT_OID_HEXSZ] = '\0';
-
- // If you have a oid, you can easily get the hex value of the SHA as well.
- git_oid_fmt(out, &oid);
- printf("SHA hex string: %s\n", out);
-
- // ### Working with the Object Database
-
- // **libgit2** provides [direct access][odb] to the object database. The
- // object database is where the actual objects are stored in Git. For
- // working with raw objects, we'll need to get this structure from the
- // repository.
- //
- // [odb]: http://libgit2.github.com/libgit2/#HEAD/group/odb
- git_odb *odb;
- git_repository_odb(&odb, repo);
-
- // #### Raw Object Reading
-
- printf("\n*Raw Object Read*\n");
- git_odb_object *obj;
- git_otype otype;
- const unsigned char *data;
- const char *str_type;
-
- // We can read raw objects directly from the object database if we have
- // the oid (SHA) of the object. This allows us to access objects without
- // knowing their type and inspect the raw bytes unparsed.
- error = git_odb_read(&obj, odb, &oid);
- check_error(error, "finding object in repository");
-
- // A raw object only has three properties - the type (commit, blob, tree
- // or tag), the size of the raw data and the raw, unparsed data itself.
- // For a commit or tag, that raw data is human readable plain ASCII
- // text. For a blob it is just file contents, so it could be text or
- // binary data. For a tree it is a special binary format, so it's unlikely
- // to be hugely helpful as a raw object.
- data = (const unsigned char *)git_odb_object_data(obj);
- otype = git_odb_object_type(obj);
-
- // We provide methods to convert from the object type which is an enum, to
- // a string representation of that value (and vice-versa).
- str_type = git_object_type2string(otype);
- printf("object length and type: %d, %s\n",
- (int)git_odb_object_size(obj),
- str_type);
-
- // For proper memory management, close the object when you are done with
- // it or it will leak memory.
- git_odb_object_free(obj);
-
- // #### Raw Object Writing
-
- printf("\n*Raw Object Write*\n");
-
- // You can also write raw object data to Git. This is pretty cool because
- // it gives you direct access to the key/value properties of Git. Here
- // we'll write a new blob object that just contains a simple string.
- // Notice that we have to specify the object type as the `git_otype` enum.
- git_odb_write(&oid, odb, "test data", sizeof("test data") - 1, GIT_OBJ_BLOB);
-
- // Now that we've written the object, we can check out what SHA1 was
- // generated when the object was written to our database.
- git_oid_fmt(out, &oid);
- printf("Written Object: %s\n", out);
-
- // ### Object Parsing
-
- // libgit2 has methods to parse every object type in Git so you don't have
- // to work directly with the raw data. This is much faster and simpler
- // than trying to deal with the raw data yourself.
-
- // #### Commit Parsing
-
- // [Parsing commit objects][pco] is simple and gives you access to all the
- // data in the commit - the author (name, email, datetime), committer
- // (same), tree, message, encoding and parent(s).
- //
- // [pco]: http://libgit2.github.com/libgit2/#HEAD/group/commit
-
- printf("\n*Commit Parsing*\n");
-
- git_commit *commit;
- git_oid_fromstr(&oid, "8496071c1b46c854b31185ea97743be6a8774479");
-
- error = git_commit_lookup(&commit, repo, &oid);
- check_error(error, "looking up commit");
-
- const git_signature *author, *cmtter;
- const char *message;
- time_t ctime;
- unsigned int parents, p;
-
- // Each of the properties of the commit object are accessible via methods,
- // including commonly needed variations, such as `git_commit_time` which
- // returns the author time and `git_commit_message` which gives you the
- // commit message (as a NUL-terminated string).
- message = git_commit_message(commit);
- author = git_commit_author(commit);
- cmtter = git_commit_committer(commit);
- ctime = git_commit_time(commit);
-
- // The author and committer methods return [git_signature] structures,
- // which give you name, email and `when`, which is a `git_time` structure,
- // giving you a timestamp and timezone offset.
- printf("Author: %s (%s)\n", author->name, author->email);
-
- // Commits can have zero or more parents. The first (root) commit will
- // have no parents, most commits will have one (i.e. the commit it was
- // based on) and merge commits will have two or more. Commits can
- // technically have any number, though it's rare to have more than two.
- parents = git_commit_parentcount(commit);
- for (p = 0;p < parents;p++) {
- git_commit *parent;
- git_commit_parent(&parent, commit, p);
- git_oid_fmt(out, git_commit_id(parent));
- printf("Parent: %s\n", out);
- git_commit_free(parent);
- }
-
- // Don't forget to close the object to prevent memory leaks. You will have
- // to do this for all the objects you open and parse.
- git_commit_free(commit);
-
- // #### Writing Commits
-
- // libgit2 provides a couple of methods to create commit objects easily as
- // well. There are four different create signatures, we'll just show one
- // of them here. You can read about the other ones in the [commit API
- // docs][cd].
- //
- // [cd]: http://libgit2.github.com/libgit2/#HEAD/group/commit
-
- printf("\n*Commit Writing*\n");
- git_oid tree_id, parent_id, commit_id;
- git_tree *tree;
- git_commit *parent;
-
- // Creating signatures for an authoring identity and time is simple. You
- // will need to do this to specify who created a commit and when. Default
- // values for the name and email should be found in the `user.name` and
- // `user.email` configuration options. See the `config` section of this
- // example file to see how to access config values.
- git_signature_new((git_signature **)&author,
- "Scott Chacon", "schacon@gmail.com", 123456789, 60);
- git_signature_new((git_signature **)&cmtter,
- "Scott A Chacon", "scott@github.com", 987654321, 90);
-
- // Commit objects need a tree to point to and optionally one or more
- // parents. Here we're creating oid objects to create the commit with,
- // but you can also use
- git_oid_fromstr(&tree_id, "f60079018b664e4e79329a7ef9559c8d9e0378d1");
- git_tree_lookup(&tree, repo, &tree_id);
- git_oid_fromstr(&parent_id, "5b5b025afb0b4c913b4c338a42934a3863bf3644");
- git_commit_lookup(&parent, repo, &parent_id);
-
- // Here we actually create the commit object with a single call with all
- // the values we need to create the commit. The SHA key is written to the
- // `commit_id` variable here.
- git_commit_create_v(
- &commit_id, /* out id */
- repo,
- NULL, /* do not update the HEAD */
- author,
- cmtter,
- NULL, /* use default message encoding */
- "example commit",
- tree,
- 1, parent);
-
- // Now we can take a look at the commit SHA we've generated.
- git_oid_fmt(out, &commit_id);
- printf("New Commit: %s\n", out);
-
- // #### Tag Parsing
-
- // You can parse and create tags with the [tag management API][tm], which
- // functions very similarly to the commit lookup, parsing and creation
- // methods, since the objects themselves are very similar.
- //
- // [tm]: http://libgit2.github.com/libgit2/#HEAD/group/tag
- printf("\n*Tag Parsing*\n");
- git_tag *tag;
- const char *tmessage, *tname;
- git_otype ttype;
-
- // We create an oid for the tag object if we know the SHA and look it up
- // the same way that we would a commit (or any other object).
- git_oid_fromstr(&oid, "b25fa35b38051e4ae45d4222e795f9df2e43f1d1");
-
- error = git_tag_lookup(&tag, repo, &oid);
- check_error(error, "looking up tag");
-
- // Now that we have the tag object, we can extract the information it
- // generally contains: the target (usually a commit object), the type of
- // the target object (usually 'commit'), the name ('v1.0'), the tagger (a
- // git_signature - name, email, timestamp), and the tag message.
- git_tag_target((git_object **)&commit, tag);
- tname = git_tag_name(tag); // "test"
- ttype = git_tag_target_type(tag); // GIT_OBJ_COMMIT (otype enum)
- tmessage = git_tag_message(tag); // "tag message\n"
- printf("Tag Message: %s\n", tmessage);
-
- git_commit_free(commit);
-
- // #### Tree Parsing
-
- // [Tree parsing][tp] is a bit different than the other objects, in that
- // we have a subtype which is the tree entry. This is not an actual
- // object type in Git, but a useful structure for parsing and traversing
- // tree entries.
- //
- // [tp]: http://libgit2.github.com/libgit2/#HEAD/group/tree
- printf("\n*Tree Parsing*\n");
-
- const git_tree_entry *entry;
- git_object *objt;
-
- // Create the oid and lookup the tree object just like the other objects.
- git_oid_fromstr(&oid, "2a741c18ac5ff082a7caaec6e74db3075a1906b5");
- git_tree_lookup(&tree, repo, &oid);
-
- // Getting the count of entries in the tree so you can iterate over them
- // if you want to.
- size_t cnt = git_tree_entrycount(tree); // 3
- printf("tree entries: %d\n", (int)cnt);
-
- entry = git_tree_entry_byindex(tree, 0);
- printf("Entry name: %s\n", git_tree_entry_name(entry)); // "hello.c"
-
- // You can also access tree entries by name if you know the name of the
- // entry you're looking for.
- entry = git_tree_entry_byname(tree, "README");
- git_tree_entry_name(entry); // "hello.c"
-
- // Once you have the entry object, you can access the content or subtree
- // (or commit, in the case of submodules) that it points to. You can also
- // get the mode if you want.
- git_tree_entry_to_object(&objt, repo, entry); // blob
-
- // Remember to close the looked-up object once you are done using it
- git_object_free(objt);
-
- // #### Blob Parsing
-
- // The last object type is the simplest and requires the least parsing
- // help. Blobs are just file contents and can contain anything, there is
- // no structure to it. The main advantage to using the [simple blob
- // api][ba] is that when you're creating blobs you don't have to calculate
- // the size of the content. There is also a helper for reading a file
- // from disk and writing it to the db and getting the oid back so you
- // don't have to do all those steps yourself.
- //
- // [ba]: http://libgit2.github.com/libgit2/#HEAD/group/blob
-
- printf("\n*Blob Parsing*\n");
- git_blob *blob;
-
- git_oid_fromstr(&oid, "1385f264afb75a56a5bec74243be9b367ba4ca08");
- git_blob_lookup(&blob, repo, &oid);
-
- // You can access a buffer with the raw contents of the blob directly.
- // Note that this buffer may not be contain ASCII data for certain blobs
- // (e.g. binary files): do not consider the buffer a NULL-terminated
- // string, and use the `git_blob_rawsize` attribute to find out its exact
- // size in bytes
- printf("Blob Size: %ld\n", (long)git_blob_rawsize(blob)); // 8
- git_blob_rawcontent(blob); // "content"
-
- // ### Revwalking
-
- // The libgit2 [revision walking api][rw] provides methods to traverse the
- // directed graph created by the parent pointers of the commit objects.
- // Since all commits point back to the commit that came directly before
- // them, you can walk this parentage as a graph and find all the commits
- // that were ancestors of (reachable from) a given starting point. This
- // can allow you to create `git log` type functionality.
- //
- // [rw]: http://libgit2.github.com/libgit2/#HEAD/group/revwalk
-
- printf("\n*Revwalking*\n");
- git_revwalk *walk;
- git_commit *wcommit;
-
- git_oid_fromstr(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644");
-
- // To use the revwalker, create a new walker, tell it how you want to sort
- // the output and then push one or more starting points onto the walker.
- // If you want to emulate the output of `git log` you would push the SHA
- // of the commit that HEAD points to into the walker and then start
- // traversing them. You can also 'hide' commits that you want to stop at
- // or not see any of their ancestors. So if you want to emulate `git log
- // branch1..branch2`, you would push the oid of `branch2` and hide the oid
- // of `branch1`.
- git_revwalk_new(&walk, repo);
- git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL | GIT_SORT_REVERSE);
- git_revwalk_push(walk, &oid);
-
- const git_signature *cauth;
- const char *cmsg;
-
- // Now that we have the starting point pushed onto the walker, we start
- // asking for ancestors. It will return them in the sorting order we asked
- // for as commit oids. We can then lookup and parse the committed pointed
- // at by the returned OID; note that this operation is specially fast
- // since the raw contents of the commit object will be cached in memory
- while ((git_revwalk_next(&oid, walk)) == 0) {
- error = git_commit_lookup(&wcommit, repo, &oid);
- check_error(error, "looking up commit during revwalk");
-
- cmsg = git_commit_message(wcommit);
- cauth = git_commit_author(wcommit);
- printf("%s (%s)\n", cmsg, cauth->email);
-
- git_commit_free(wcommit);
- }
-
- // Like the other objects, be sure to free the revwalker when you're done
- // to prevent memory leaks. Also, make sure that the repository being
- // walked it not deallocated while the walk is in progress, or it will
- // result in undefined behavior
- git_revwalk_free(walk);
-
- // ### Index File Manipulation
-
- // The [index file API][gi] allows you to read, traverse, update and write
- // the Git index file (sometimes thought of as the staging area).
- //
- // [gi]: http://libgit2.github.com/libgit2/#HEAD/group/index
-
- printf("\n*Index Walking*\n");
-
- git_index *index;
- unsigned int i, ecount;
-
- // You can either open the index from the standard location in an open
- // repository, as we're doing here, or you can open and manipulate any
- // index file with `git_index_open_bare()`. The index for the repository
- // will be located and loaded from disk.
- git_repository_index(&index, repo);
-
- // For each entry in the index, you can get a bunch of information
- // including the SHA (oid), path and mode which map to the tree objects
- // that are written out. It also has filesystem properties to help
- // determine what to inspect for changes (ctime, mtime, dev, ino, uid,
- // gid, file_size and flags) All these properties are exported publicly in
- // the `git_index_entry` struct
- ecount = git_index_entrycount(index);
- for (i = 0; i < ecount; ++i) {
- const git_index_entry *e = git_index_get_byindex(index, i);
-
- printf("path: %s\n", e->path);
- printf("mtime: %d\n", (int)e->mtime.seconds);
- printf("fs: %d\n", (int)e->file_size);
- }
-
- git_index_free(index);
-
- // ### References
-
- // The [reference API][ref] allows you to list, resolve, create and update
- // references such as branches, tags and remote references (everything in
- // the .git/refs directory).
- //
- // [ref]: http://libgit2.github.com/libgit2/#HEAD/group/reference
-
- printf("\n*Reference Listing*\n");
-
- // Here we will implement something like `git for-each-ref` simply listing
- // out all available references and the object SHA they resolve to.
- git_strarray ref_list;
- git_reference_list(&ref_list, repo);
-
- const char *refname;
- git_reference *ref;
-
- // Now that we have the list of reference names, we can lookup each ref
- // one at a time and resolve them to the SHA, then print both values out.
- for (i = 0; i < ref_list.count; ++i) {
- refname = ref_list.strings[i];
- git_reference_lookup(&ref, repo, refname);
-
- switch (git_reference_type(ref)) {
- case GIT_REF_OID:
- git_oid_fmt(out, git_reference_target(ref));
- printf("%s [%s]\n", refname, out);
- break;
-
- case GIT_REF_SYMBOLIC:
- printf("%s => %s\n", refname, git_reference_symbolic_target(ref));
- break;
- default:
- fprintf(stderr, "Unexpected reference type\n");
- exit(1);
- }
- }
-
- git_strarray_free(&ref_list);
-
- // ### Config Files
-
- // The [config API][config] allows you to list and updatee config values
- // in any of the accessible config file locations (system, global, local).
- //
- // [config]: http://libgit2.github.com/libgit2/#HEAD/group/config
+ int error;
+ git_oid oid;
+ char *repo_path;
+ git_repository *repo;
+
+ /**
+ * Initialize the library, this will set up any global state which libgit2 needs
+ * including threading and crypto
+ */
+ git_libgit2_init();
+
+ /**
+ * ### Opening the Repository
+ *
+ * There are a couple of methods for opening a repository, this being the
+ * simplest. There are also [methods][me] for specifying the index file
+ * and work tree locations, here we assume they are in the normal places.
+ *
+ * (Try running this program against tests/resources/testrepo.git.)
+ *
+ * [me]: http://libgit2.github.com/libgit2/#HEAD/group/repository
+ */
+ repo_path = (argc > 1) ? argv[1] : "/opt/libgit2-test/.git";
+
+ error = git_repository_open(&repo, repo_path);
+ check_error(error, "opening repository");
+
+ oid_parsing(&oid);
+ object_database(repo, &oid);
+ commit_writing(repo);
+ commit_parsing(repo);
+ tag_parsing(repo);
+ tree_parsing(repo);
+ blob_parsing(repo);
+ revwalking(repo);
+ index_walking(repo);
+ reference_listing(repo);
+ config_files(repo_path, repo);
+
+ /**
+ * Finally, when you're done with the repository, you can free it as well.
+ */
+ git_repository_free(repo);
+
+ return 0;
+}
+
+/**
+ * ### SHA-1 Value Conversions
+ */
+static void oid_parsing(git_oid *oid)
+{
+ char out[GIT_OID_HEXSZ+1];
+ char hex[] = "4a202b346bb0fb0db7eff3cffeb3c70babbd2045";
+
+ printf("*Hex to Raw*\n");
+
+ /**
+ * For our first example, we will convert a 40 character hex value to the
+ * 20 byte raw SHA1 value.
+ *
+ * The `git_oid` is the structure that keeps the SHA value. We will use
+ * this throughout the example for storing the value of the current SHA
+ * key we're working with.
+ */
+ git_oid_fromstr(oid, hex);
+
+ // Once we've converted the string into the oid value, we can get the raw
+ // value of the SHA by accessing `oid.id`
+
+ // Next we will convert the 20 byte raw SHA1 value to a human readable 40
+ // char hex value.
+ printf("\n*Raw to Hex*\n");
+ out[GIT_OID_HEXSZ] = '\0';
+
+ /**
+ * If you have a oid, you can easily get the hex value of the SHA as well.
+ */
+ git_oid_fmt(out, oid);
+
+ /**
+ * If you have a oid, you can easily get the hex value of the SHA as well.
+ */
+ git_oid_fmt(out, oid);
+ printf("SHA hex string: %s\n", out);
+}
+
+/**
+ * ### Working with the Object Database
+ *
+ * **libgit2** provides [direct access][odb] to the object database. The
+ * object database is where the actual objects are stored in Git. For
+ * working with raw objects, we'll need to get this structure from the
+ * repository.
+ *
+ * [odb]: http://libgit2.github.com/libgit2/#HEAD/group/odb
+ */
+static void object_database(git_repository *repo, git_oid *oid)
+{
+ char oid_hex[GIT_OID_HEXSZ+1] = { 0 };
+ const unsigned char *data;
+ const char *str_type;
+ int error;
+ git_odb_object *obj;
+ git_odb *odb;
+ git_otype otype;
+
+ git_repository_odb(&odb, repo);
+
+ /**
+ * #### Raw Object Reading
+ */
+
+ printf("\n*Raw Object Read*\n");
+
+ /**
+ * We can read raw objects directly from the object database if we have
+ * the oid (SHA) of the object. This allows us to access objects without
+ * knowing their type and inspect the raw bytes unparsed.
+ */
+ error = git_odb_read(&obj, odb, oid);
+ check_error(error, "finding object in repository");
+
+ /**
+ * A raw object only has three properties - the type (commit, blob, tree
+ * or tag), the size of the raw data and the raw, unparsed data itself.
+ * For a commit or tag, that raw data is human readable plain ASCII
+ * text. For a blob it is just file contents, so it could be text or
+ * binary data. For a tree it is a special binary format, so it's unlikely
+ * to be hugely helpful as a raw object.
+ */
+ data = (const unsigned char *)git_odb_object_data(obj);
+ otype = git_odb_object_type(obj);
+
+ /**
+ * We provide methods to convert from the object type which is an enum, to
+ * a string representation of that value (and vice-versa).
+ */
+ str_type = git_object_type2string(otype);
+ printf("object length and type: %d, %s\nobject data: %s\n",
+ (int)git_odb_object_size(obj),
+ str_type, data);
+
+ /**
+ * For proper memory management, close the object when you are done with
+ * it or it will leak memory.
+ */
+ git_odb_object_free(obj);
+
+ /**
+ * #### Raw Object Writing
+ */
+
+ printf("\n*Raw Object Write*\n");
+
+ /**
+ * You can also write raw object data to Git. This is pretty cool because
+ * it gives you direct access to the key/value properties of Git. Here
+ * we'll write a new blob object that just contains a simple string.
+ * Notice that we have to specify the object type as the `git_otype` enum.
+ */
+ git_odb_write(oid, odb, "test data", sizeof("test data") - 1, GIT_OBJ_BLOB);
+
+ /**
+ * Now that we've written the object, we can check out what SHA1 was
+ * generated when the object was written to our database.
+ */
+ git_oid_fmt(oid_hex, oid);
+ printf("Written Object: %s\n", oid_hex);
+
+ /**
+ * Free the object database after usage.
+ */
+ git_odb_free(odb);
+}
- printf("\n*Config Listing*\n");
+/**
+ * #### Writing Commits
+ *
+ * libgit2 provides a couple of methods to create commit objects easily as
+ * well. There are four different create signatures, we'll just show one
+ * of them here. You can read about the other ones in the [commit API
+ * docs][cd].
+ *
+ * [cd]: http://libgit2.github.com/libgit2/#HEAD/group/commit
+ */
+static void commit_writing(git_repository *repo)
+{
+ git_oid tree_id, parent_id, commit_id;
+ git_tree *tree;
+ git_commit *parent;
+ git_signature *author, *committer;
+ char oid_hex[GIT_OID_HEXSZ+1] = { 0 };
+
+ printf("\n*Commit Writing*\n");
+
+ /**
+ * Creating signatures for an authoring identity and time is simple. You
+ * will need to do this to specify who created a commit and when. Default
+ * values for the name and email should be found in the `user.name` and
+ * `user.email` configuration options. See the `config` section of this
+ * example file to see how to access config values.
+ */
+ git_signature_new(&author,
+ "Scott Chacon", "schacon@gmail.com", 123456789, 60);
+ git_signature_new(&committer,
+ "Scott A Chacon", "scott@github.com", 987654321, 90);
+
+ /**
+ * Commit objects need a tree to point to and optionally one or more
+ * parents. Here we're creating oid objects to create the commit with,
+ * but you can also use
+ */
+ git_oid_fromstr(&tree_id, "f60079018b664e4e79329a7ef9559c8d9e0378d1");
+ git_tree_lookup(&tree, repo, &tree_id);
+ git_oid_fromstr(&parent_id, "5b5b025afb0b4c913b4c338a42934a3863bf3644");
+ git_commit_lookup(&parent, repo, &parent_id);
+
+ /**
+ * Here we actually create the commit object with a single call with all
+ * the values we need to create the commit. The SHA key is written to the
+ * `commit_id` variable here.
+ */
+ git_commit_create_v(
+ &commit_id, /* out id */
+ repo,
+ NULL, /* do not update the HEAD */
+ author,
+ committer,
+ NULL, /* use default message encoding */
+ "example commit",
+ tree,
+ 1, parent);
+
+ /**
+ * Now we can take a look at the commit SHA we've generated.
+ */
+ git_oid_fmt(oid_hex, &commit_id);
+ printf("New Commit: %s\n", oid_hex);
+
+ /**
+ * Free all objects used in the meanwhile.
+ */
+ git_tree_free(tree);
+ git_commit_free(parent);
+ git_signature_free(author);
+ git_signature_free(committer);
+}
+
+/**
+ * ### Object Parsing
+ *
+ * libgit2 has methods to parse every object type in Git so you don't have
+ * to work directly with the raw data. This is much faster and simpler
+ * than trying to deal with the raw data yourself.
+ */
+
+/**
+ * #### Commit Parsing
+ *
+ * [Parsing commit objects][pco] is simple and gives you access to all the
+ * data in the commit - the author (name, email, datetime), committer
+ * (same), tree, message, encoding and parent(s).
+ *
+ * [pco]: http://libgit2.github.com/libgit2/#HEAD/group/commit
+ */
+static void commit_parsing(git_repository *repo)
+{
+ const git_signature *author, *cmtter;
+ git_commit *commit, *parent;
+ git_oid oid;
+ char oid_hex[GIT_OID_HEXSZ+1];
+ const char *message;
+ unsigned int parents, p;
+ int error;
+ time_t time;
+
+ printf("\n*Commit Parsing*\n");
+
+ git_oid_fromstr(&oid, "8496071c1b46c854b31185ea97743be6a8774479");
+
+ error = git_commit_lookup(&commit, repo, &oid);
+ check_error(error, "looking up commit");
+
+ /**
+ * Each of the properties of the commit object are accessible via methods,
+ * including commonly needed variations, such as `git_commit_time` which
+ * returns the author time and `git_commit_message` which gives you the
+ * commit message (as a NUL-terminated string).
+ */
+ message = git_commit_message(commit);
+ author = git_commit_author(commit);
+ cmtter = git_commit_committer(commit);
+ time = git_commit_time(commit);
+
+ /**
+ * The author and committer methods return [git_signature] structures,
+ * which give you name, email and `when`, which is a `git_time` structure,
+ * giving you a timestamp and timezone offset.
+ */
+ printf("Author: %s (%s)\nCommitter: %s (%s)\nDate: %s\nMessage: %s\n",
+ author->name, author->email,
+ cmtter->name, cmtter->email,
+ ctime(&time), message);
+
+ /**
+ * Commits can have zero or more parents. The first (root) commit will
+ * have no parents, most commits will have one (i.e. the commit it was
+ * based on) and merge commits will have two or more. Commits can
+ * technically have any number, though it's rare to have more than two.
+ */
+ parents = git_commit_parentcount(commit);
+ for (p = 0;p < parents;p++) {
+ memset(oid_hex, 0, sizeof(oid_hex));
+
+ git_commit_parent(&parent, commit, p);
+ git_oid_fmt(oid_hex, git_commit_id(parent));
+ printf("Parent: %s\n", oid_hex);
+ git_commit_free(parent);
+ }
+
+ git_commit_free(commit);
+}
- const char *email;
- int32_t j;
+/**
+ * #### Tag Parsing
+ *
+ * You can parse and create tags with the [tag management API][tm], which
+ * functions very similarly to the commit lookup, parsing and creation
+ * methods, since the objects themselves are very similar.
+ *
+ * [tm]: http://libgit2.github.com/libgit2/#HEAD/group/tag
+ */
+static void tag_parsing(git_repository *repo)
+{
+ git_commit *commit;
+ git_otype type;
+ git_tag *tag;
+ git_oid oid;
+ const char *name, *message;
+ int error;
+
+ printf("\n*Tag Parsing*\n");
+
+ /**
+ * We create an oid for the tag object if we know the SHA and look it up
+ * the same way that we would a commit (or any other object).
+ */
+ git_oid_fromstr(&oid, "b25fa35b38051e4ae45d4222e795f9df2e43f1d1");
+
+ error = git_tag_lookup(&tag, repo, &oid);
+ check_error(error, "looking up tag");
+
+ /**
+ * Now that we have the tag object, we can extract the information it
+ * generally contains: the target (usually a commit object), the type of
+ * the target object (usually 'commit'), the name ('v1.0'), the tagger (a
+ * git_signature - name, email, timestamp), and the tag message.
+ */
+ git_tag_target((git_object **)&commit, tag);
+ name = git_tag_name(tag); /* "test" */
+ type = git_tag_target_type(tag); /* GIT_OBJ_COMMIT (otype enum) */
+ message = git_tag_message(tag); /* "tag message\n" */
+ printf("Tag Name: %s\nTag Type: %s\nTag Message: %s\n",
+ name, git_object_type2string(type), message);
+
+ /**
+ * Free both the commit and tag after usage.
+ */
+ git_commit_free(commit);
+ git_tag_free(tag);
+}
- git_config *cfg;
+/**
+ * #### Tree Parsing
+ *
+ * [Tree parsing][tp] is a bit different than the other objects, in that
+ * we have a subtype which is the tree entry. This is not an actual
+ * object type in Git, but a useful structure for parsing and traversing
+ * tree entries.
+ *
+ * [tp]: http://libgit2.github.com/libgit2/#HEAD/group/tree
+ */
+static void tree_parsing(git_repository *repo)
+{
+ const git_tree_entry *entry;
+ size_t cnt;
+ git_object *obj;
+ git_tree *tree;
+ git_oid oid;
+
+ printf("\n*Tree Parsing*\n");
+
+ /**
+ * Create the oid and lookup the tree object just like the other objects.
+ */
+ git_oid_fromstr(&oid, "f60079018b664e4e79329a7ef9559c8d9e0378d1");
+ git_tree_lookup(&tree, repo, &oid);
+
+ /**
+ * Getting the count of entries in the tree so you can iterate over them
+ * if you want to.
+ */
+ cnt = git_tree_entrycount(tree); /* 2 */
+ printf("tree entries: %d\n", (int) cnt);
+
+ entry = git_tree_entry_byindex(tree, 0);
+ printf("Entry name: %s\n", git_tree_entry_name(entry)); /* "README" */
+
+ /**
+ * You can also access tree entries by name if you know the name of the
+ * entry you're looking for.
+ */
+ entry = git_tree_entry_byname(tree, "README");
+ git_tree_entry_name(entry); /* "README" */
+
+ /**
+ * Once you have the entry object, you can access the content or subtree
+ * (or commit, in the case of submodules) that it points to. You can also
+ * get the mode if you want.
+ */
+ git_tree_entry_to_object(&obj, repo, entry); /* blob */
+
+ /**
+ * Remember to close the looked-up object and tree once you are done using it
+ */
+ git_object_free(obj);
+ git_tree_free(tree);
+}
- // Open a config object so we can read global values from it.
- char config_path[256];
- sprintf(config_path, "%s/config", repo_path);
- check_error(git_config_open_ondisk(&cfg, config_path), "opening config");
+/**
+ * #### Blob Parsing
+ *
+ * The last object type is the simplest and requires the least parsing
+ * help. Blobs are just file contents and can contain anything, there is
+ * no structure to it. The main advantage to using the [simple blob
+ * api][ba] is that when you're creating blobs you don't have to calculate
+ * the size of the content. There is also a helper for reading a file
+ * from disk and writing it to the db and getting the oid back so you
+ * don't have to do all those steps yourself.
+ *
+ * [ba]: http://libgit2.github.com/libgit2/#HEAD/group/blob
+ */
+static void blob_parsing(git_repository *repo)
+{
+ git_blob *blob;
+ git_oid oid;
+
+ printf("\n*Blob Parsing*\n");
+
+ git_oid_fromstr(&oid, "1385f264afb75a56a5bec74243be9b367ba4ca08");
+ git_blob_lookup(&blob, repo, &oid);
+
+ /**
+ * You can access a buffer with the raw contents of the blob directly.
+ * Note that this buffer may not be contain ASCII data for certain blobs
+ * (e.g. binary files): do not consider the buffer a NULL-terminated
+ * string, and use the `git_blob_rawsize` attribute to find out its exact
+ * size in bytes
+ * */
+ printf("Blob Size: %ld\n", (long)git_blob_rawsize(blob)); /* 8 */
+ git_blob_rawcontent(blob); /* "content" */
+
+ /**
+ * Free the blob after usage.
+ */
+ git_blob_free(blob);
+}
- git_config_get_int32(&j, cfg, "help.autocorrect");
- printf("Autocorrect: %d\n", j);
+/**
+ * ### Revwalking
+ *
+ * The libgit2 [revision walking api][rw] provides methods to traverse the
+ * directed graph created by the parent pointers of the commit objects.
+ * Since all commits point back to the commit that came directly before
+ * them, you can walk this parentage as a graph and find all the commits
+ * that were ancestors of (reachable from) a given starting point. This
+ * can allow you to create `git log` type functionality.
+ *
+ * [rw]: http://libgit2.github.com/libgit2/#HEAD/group/revwalk
+ */
+static void revwalking(git_repository *repo)
+{
+ const git_signature *cauth;
+ const char *cmsg;
+ int error;
+ git_revwalk *walk;
+ git_commit *wcommit;
+ git_oid oid;
+
+ printf("\n*Revwalking*\n");
+
+ git_oid_fromstr(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644");
+
+ /**
+ * To use the revwalker, create a new walker, tell it how you want to sort
+ * the output and then push one or more starting points onto the walker.
+ * If you want to emulate the output of `git log` you would push the SHA
+ * of the commit that HEAD points to into the walker and then start
+ * traversing them. You can also 'hide' commits that you want to stop at
+ * or not see any of their ancestors. So if you want to emulate `git log
+ * branch1..branch2`, you would push the oid of `branch2` and hide the oid
+ * of `branch1`.
+ */
+ git_revwalk_new(&walk, repo);
+ git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL | GIT_SORT_REVERSE);
+ git_revwalk_push(walk, &oid);
+
+ /**
+ * Now that we have the starting point pushed onto the walker, we start
+ * asking for ancestors. It will return them in the sorting order we asked
+ * for as commit oids. We can then lookup and parse the committed pointed
+ * at by the returned OID; note that this operation is specially fast
+ * since the raw contents of the commit object will be cached in memory
+ */
+ while ((git_revwalk_next(&oid, walk)) == 0) {
+ error = git_commit_lookup(&wcommit, repo, &oid);
+ check_error(error, "looking up commit during revwalk");
+
+ cmsg = git_commit_message(wcommit);
+ cauth = git_commit_author(wcommit);
+ printf("%s (%s)\n", cmsg, cauth->email);
+
+ git_commit_free(wcommit);
+ }
+
+ /**
+ * Like the other objects, be sure to free the revwalker when you're done
+ * to prevent memory leaks. Also, make sure that the repository being
+ * walked it not deallocated while the walk is in progress, or it will
+ * result in undefined behavior
+ */
+ git_revwalk_free(walk);
+}
- git_config_get_string(&email, cfg, "user.email");
- printf("Email: %s\n", email);
+/**
+ * ### Index File Manipulation *
+ * The [index file API][gi] allows you to read, traverse, update and write
+ * the Git index file (sometimes thought of as the staging area).
+ *
+ * [gi]: http://libgit2.github.com/libgit2/#HEAD/group/index
+ */
+static void index_walking(git_repository *repo)
+{
+ git_index *index;
+ unsigned int i, ecount;
+
+ printf("\n*Index Walking*\n");
+
+ /**
+ * You can either open the index from the standard location in an open
+ * repository, as we're doing here, or you can open and manipulate any
+ * index file with `git_index_open_bare()`. The index for the repository
+ * will be located and loaded from disk.
+ */
+ git_repository_index(&index, repo);
+
+ /**
+ * For each entry in the index, you can get a bunch of information
+ * including the SHA (oid), path and mode which map to the tree objects
+ * that are written out. It also has filesystem properties to help
+ * determine what to inspect for changes (ctime, mtime, dev, ino, uid,
+ * gid, file_size and flags) All these properties are exported publicly in
+ * the `git_index_entry` struct
+ */
+ ecount = git_index_entrycount(index);
+ for (i = 0; i < ecount; ++i) {
+ const git_index_entry *e = git_index_get_byindex(index, i);
+
+ printf("path: %s\n", e->path);
+ printf("mtime: %d\n", (int)e->mtime.seconds);
+ printf("fs: %d\n", (int)e->file_size);
+ }
+
+ git_index_free(index);
+}
- // Finally, when you're done with the repository, you can free it as well.
- git_repository_free(repo);
+/**
+ * ### References
+ *
+ * The [reference API][ref] allows you to list, resolve, create and update
+ * references such as branches, tags and remote references (everything in
+ * the .git/refs directory).
+ *
+ * [ref]: http://libgit2.github.com/libgit2/#HEAD/group/reference
+ */
+static void reference_listing(git_repository *repo)
+{
+ git_strarray ref_list;
+ unsigned i;
+
+ printf("\n*Reference Listing*\n");
+
+ /**
+ * Here we will implement something like `git for-each-ref` simply listing
+ * out all available references and the object SHA they resolve to.
+ *
+ * Now that we have the list of reference names, we can lookup each ref
+ * one at a time and resolve them to the SHA, then print both values out.
+ */
+
+ git_reference_list(&ref_list, repo);
+
+ for (i = 0; i < ref_list.count; ++i) {
+ git_reference *ref;
+ char oid_hex[GIT_OID_HEXSZ+1] = GIT_OID_HEX_ZERO;
+ const char *refname;
+
+ refname = ref_list.strings[i];
+ git_reference_lookup(&ref, repo, refname);
+
+ switch (git_reference_type(ref)) {
+ case GIT_REF_OID:
+ git_oid_fmt(oid_hex, git_reference_target(ref));
+ printf("%s [%s]\n", refname, oid_hex);
+ break;
+
+ case GIT_REF_SYMBOLIC:
+ printf("%s => %s\n", refname, git_reference_symbolic_target(ref));
+ break;
+ default:
+ fprintf(stderr, "Unexpected reference type\n");
+ exit(1);
+ }
+
+ git_reference_free(ref);
+ }
+
+ git_strarray_free(&ref_list);
+}
- return 0;
+/**
+ * ### Config Files
+ *
+ * The [config API][config] allows you to list and updatee config values
+ * in any of the accessible config file locations (system, global, local).
+ *
+ * [config]: http://libgit2.github.com/libgit2/#HEAD/group/config
+ */
+static void config_files(const char *repo_path, git_repository* repo)
+{
+ const char *email;
+ char config_path[256];
+ int32_t autocorrect;
+ git_config *cfg;
+ git_config *snap_cfg;
+
+ printf("\n*Config Listing*\n");
+
+ /**
+ * Open a config object so we can read global values from it.
+ */
+ sprintf(config_path, "%s/config", repo_path);
+ check_error(git_config_open_ondisk(&cfg, config_path), "opening config");
+
+ if (git_config_get_int32(&autocorrect, cfg, "help.autocorrect") == 0)
+ printf("Autocorrect: %d\n", autocorrect);
+
+ check_error(git_repository_config_snapshot(&snap_cfg, repo), "config snapshot");
+ git_config_get_string(&email, snap_cfg, "user.email");
+ printf("Email: %s\n", email);
+
+ /**
+ * Remember to free the configurations after usage.
+ */
+ git_config_free(cfg);
+ git_config_free(snap_cfg);
}
diff --git a/examples/network/clone.c b/examples/network/clone.c
index caf41cca8..540000bfd 100644
--- a/examples/network/clone.c
+++ b/examples/network/clone.c
@@ -50,7 +50,7 @@ static int sideband_progress(const char *str, int len, void *payload)
{
(void)payload; // unused
- printf("remote: %*s", len, str);
+ printf("remote: %.*s", len, str);
fflush(stdout);
return 0;
}
diff --git a/examples/network/common.c b/examples/network/common.c
index d123eedbd..1a81a10f8 100644
--- a/examples/network/common.c
+++ b/examples/network/common.c
@@ -1,5 +1,7 @@
#include "common.h"
#include <stdio.h>
+#include <string.h>
+#include <errno.h>
/* Shamelessly borrowed from http://stackoverflow.com/questions/3417837/
* with permission of the original author, Martin Pool.
@@ -20,15 +22,27 @@ int cred_acquire_cb(git_cred **out,
unsigned int UNUSED(allowed_types),
void * UNUSED(payload))
{
- char username[128] = {0};
- char password[128] = {0};
+ char *username = NULL, *password = NULL;
+ int error;
printf("Username: ");
- scanf("%s", username);
+ if (getline(&username, NULL, stdin) < 0) {
+ fprintf(stderr, "Unable to read username: %s", strerror(errno));
+ return -1;
+ }
/* Yup. Right there on your terminal. Careful where you copy/paste output. */
printf("Password: ");
- scanf("%s", password);
+ if (getline(&password, NULL, stdin) < 0) {
+ fprintf(stderr, "Unable to read password: %s", strerror(errno));
+ free(username);
+ return -1;
+ }
- return git_cred_userpass_plaintext_new(out, username, password);
+ error = git_cred_userpass_plaintext_new(out, username, password);
+
+ free(username);
+ free(password);
+
+ return error;
}
diff --git a/examples/network/fetch.c b/examples/network/fetch.c
index 177359b88..10974a9f1 100644
--- a/examples/network/fetch.c
+++ b/examples/network/fetch.c
@@ -55,6 +55,8 @@ static int update_cb(const char *refname, const git_oid *a, const git_oid *b, vo
*/
static int transfer_progress_cb(const git_transfer_progress *stats, void *payload)
{
+ (void)payload;
+
if (stats->received_objects == stats->total_objects) {
printf("Resolving deltas %d/%d\r",
stats->indexed_deltas, stats->total_deltas);
@@ -71,7 +73,6 @@ int fetch(git_repository *repo, int argc, char **argv)
{
git_remote *remote = NULL;
const git_transfer_progress *stats;
- struct dl_data data;
git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT;
if (argc < 2) {
@@ -79,14 +80,13 @@ int fetch(git_repository *repo, int argc, char **argv)
return EXIT_FAILURE;
}
- // Figure out whether it's a named remote or a URL
+ /* Figure out whether it's a named remote or a URL */
printf("Fetching %s for repo %p\n", argv[1], repo);
- if (git_remote_lookup(&remote, repo, argv[1]) < 0) {
+ if (git_remote_lookup(&remote, repo, argv[1]) < 0)
if (git_remote_create_anonymous(&remote, repo, argv[1]) < 0)
- return -1;
- }
+ goto on_error;
- // Set up the callbacks (only update_tips for now)
+ /* Set up the callbacks (only update_tips for now) */
fetch_opts.callbacks.update_tips = &update_cb;
fetch_opts.callbacks.sideband_progress = &progress_cb;
fetch_opts.callbacks.transfer_progress = transfer_progress_cb;
@@ -98,7 +98,7 @@ int fetch(git_repository *repo, int argc, char **argv)
* "fetch".
*/
if (git_remote_fetch(remote, NULL, &fetch_opts, "fetch") < 0)
- return -1;
+ goto on_error;
/**
* If there are local objects (we got a thin pack), then tell
diff --git a/include/git2/branch.h b/include/git2/branch.h
index 34354f4e5..88fe723a0 100644
--- a/include/git2/branch.h
+++ b/include/git2/branch.h
@@ -246,6 +246,18 @@ GIT_EXTERN(int) git_branch_is_head(
const git_reference *branch);
/**
+ * Determine if the current branch is checked out in any linked
+ * repository.
+ *
+ * @param branch Reference to the branch.
+ *
+ * @return 1 if branch is checked out, 0 if it isn't,
+ * error code otherwise.
+ */
+GIT_EXTERN(int) git_branch_is_checked_out(
+ const git_reference *branch);
+
+/**
* Return the name of remote that the remote tracking branch belongs to.
*
* @param out Pointer to the user-allocated git_buf which will be filled with the name of the remote.
diff --git a/include/git2/commit.h b/include/git2/commit.h
index 4cc637466..692b3bdd9 100644
--- a/include/git2/commit.h
+++ b/include/git2/commit.h
@@ -255,7 +255,8 @@ GIT_EXTERN(int) git_commit_nth_gen_ancestor(
/**
* Get an arbitrary header field
*
- * @param out the buffer to fill
+ * @param out the buffer to fill; existing content will be
+ * overwritten
* @param commit the commit to look in
* @param field the header field to return
* @return 0 on succeess, GIT_ENOTFOUND if the field does not exist,
@@ -270,8 +271,10 @@ GIT_EXTERN(int) git_commit_header_field(git_buf *out, const git_commit *commit,
* `GITERR_INVALID`. If the commit does not have a signature, the
* error class will be `GITERR_OBJECT`.
*
- * @param signature the signature block
- * @param signed_data signed data; this is the commit contents minus the signature block
+ * @param signature the signature block; existing content will be
+ * overwritten
+ * @param signed_data signed data; this is the commit contents minus the signature block;
+ * existing content will be overwritten
* @param repo the repository in which the commit exists
* @param commit_id the commit from which to extract the data
* @param field the name of the header field containing the signature
diff --git a/include/git2/common.h b/include/git2/common.h
index 18abe46b3..f65cfdd01 100644
--- a/include/git2/common.h
+++ b/include/git2/common.h
@@ -109,9 +109,27 @@ GIT_EXTERN(void) git_libgit2_version(int *major, int *minor, int *rev);
* was compiled
*/
typedef enum {
+ /**
+ * If set, libgit2 was built thread-aware and can be safely used from multiple
+ * threads.
+ */
GIT_FEATURE_THREADS = (1 << 0),
+ /**
+ * If set, libgit2 was built with and linked against a TLS implementation.
+ * Custom TLS streams may still be added by the user to support HTTPS
+ * regardless of this.
+ */
GIT_FEATURE_HTTPS = (1 << 1),
+ /**
+ * If set, libgit2 was built with and linked against libssh2. A custom
+ * transport may still be added by the user to support libssh2 regardless of
+ * this.
+ */
GIT_FEATURE_SSH = (1 << 2),
+ /**
+ * If set, libgit2 was built with support for sub-second resolution in file
+ * modification times.
+ */
GIT_FEATURE_NSEC = (1 << 3),
} git_feature_t;
@@ -157,8 +175,14 @@ typedef enum {
GIT_OPT_SET_SSL_CERT_LOCATIONS,
GIT_OPT_SET_USER_AGENT,
GIT_OPT_ENABLE_STRICT_OBJECT_CREATION,
+ GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION,
GIT_OPT_SET_SSL_CIPHERS,
GIT_OPT_GET_USER_AGENT,
+ GIT_OPT_ENABLE_OFS_DELTA,
+ GIT_OPT_ENABLE_FSYNC_GITDIR,
+ GIT_OPT_GET_WINDOWS_SHAREMODE,
+ GIT_OPT_SET_WINDOWS_SHAREMODE,
+ GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION,
} git_libgit2_opt_t;
/**
@@ -263,19 +287,64 @@ typedef enum {
* > - `user_agent` is the value that will be delivered as the
* > User-Agent header on HTTP requests.
*
+ * * opts(GIT_OPT_SET_WINDOWS_SHAREMODE, unsigned long value)
+ *
+ * > Set the share mode used when opening files on Windows.
+ * > For more information, see the documentation for CreateFile.
+ * > The default is: FILE_SHARE_READ | FILE_SHARE_WRITE. This is
+ * > ignored and unused on non-Windows platforms.
+ *
+ * * opts(GIT_OPT_GET_WINDOWS_SHAREMODE, unsigned long *value)
+ *
+ * > Get the share mode used when opening files on Windows.
+ *
* * opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, int enabled)
*
* > Enable strict input validation when creating new objects
* > to ensure that all inputs to the new objects are valid. For
* > example, when this is enabled, the parent(s) and tree inputs
* > will be validated when creating a new commit. This defaults
- * > to disabled.
+ * > to enabled.
+ *
+ * * opts(GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, int enabled)
+ *
+ * > Validate the target of a symbolic ref when creating it. For
+ * > example, `foobar` is not a valid ref, therefore `foobar` is
+ * > not a valid target for a symbolic ref by default, whereas
+ * > `refs/heads/foobar` is. Disabling this bypasses validation
+ * > so that an arbitrary strings such as `foobar` can be used
+ * > for a symbolic ref target. This defaults to enabled.
+ *
* * opts(GIT_OPT_SET_SSL_CIPHERS, const char *ciphers)
*
* > Set the SSL ciphers use for HTTPS connections.
* >
* > - `ciphers` is the list of ciphers that are eanbled.
*
+ * * opts(GIT_OPT_ENABLE_OFS_DELTA, int enabled)
+ *
+ * > Enable or disable the use of "offset deltas" when creating packfiles,
+ * > and the negotiation of them when talking to a remote server.
+ * > Offset deltas store a delta base location as an offset into the
+ * > packfile from the current location, which provides a shorter encoding
+ * > and thus smaller resultant packfiles.
+ * > Packfiles containing offset deltas can still be read.
+ * > This defaults to enabled.
+ *
+ * * opts(GIT_OPT_ENABLE_FSYNC_GITDIR, int enabled)
+ *
+ * > Enable synchronized writes of files in the gitdir using `fsync`
+ * > (or the platform equivalent) to ensure that new object data
+ * > is written to permanent storage, not simply cached. This
+ * > defaults to disabled.
+ *
+ * opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, int enabled)
+ *
+ * > Enable strict verification of object hashsums when reading
+ * > objects from disk. This may impact performance due to an
+ * > additional checksum calculation on each object. This defaults
+ * > to enabled.
+ *
* @param option Option key
* @param ... value to set the option
* @return 0 on success, <0 on failure
diff --git a/include/git2/describe.h b/include/git2/describe.h
index 3044d9165..971eb350c 100644
--- a/include/git2/describe.h
+++ b/include/git2/describe.h
@@ -44,8 +44,8 @@ typedef enum {
typedef struct git_describe_options {
unsigned int version;
- unsigned int max_candidates_tags; /** default: 10 */
- unsigned int describe_strategy; /** default: GIT_DESCRIBE_DEFAULT */
+ unsigned int max_candidates_tags; /**< default: 10 */
+ unsigned int describe_strategy; /**< default: GIT_DESCRIBE_DEFAULT */
const char *pattern;
/**
* When calculating the distance from the matching tag or
@@ -105,6 +105,9 @@ typedef struct {
GIT_EXTERN(int) git_describe_init_format_options(git_describe_format_options *opts, unsigned int version);
+/**
+ * A struct that stores the result of a describe operation.
+ */
typedef struct git_describe_result git_describe_result;
/**
diff --git a/include/git2/diff.h b/include/git2/diff.h
index 4f0871dab..75f1e1975 100644
--- a/include/git2/diff.h
+++ b/include/git2/diff.h
@@ -515,12 +515,12 @@ typedef int(*git_diff_binary_cb)(
* Structure describing a hunk of a diff.
*/
typedef struct {
- int old_start; /** Starting line number in old_file */
- int old_lines; /** Number of lines in old_file */
- int new_start; /** Starting line number in new_file */
- int new_lines; /** Number of lines in new_file */
- size_t header_len; /** Number of bytes in header text */
- char header[GIT_DIFF_HUNK_HEADER_SIZE]; /** Header text, NUL-byte terminated */
+ int old_start; /**< Starting line number in old_file */
+ int old_lines; /**< Number of lines in old_file */
+ int new_start; /**< Starting line number in new_file */
+ int new_lines; /**< Number of lines in new_file */
+ size_t header_len; /**< Number of bytes in header text */
+ char header[GIT_DIFF_HUNK_HEADER_SIZE]; /**< Header text, NUL-byte terminated */
} git_diff_hunk;
/**
@@ -1400,6 +1400,51 @@ GIT_EXTERN(int) git_diff_format_email_init_options(
git_diff_format_email_options *opts,
unsigned int version);
+/**
+ * Patch ID options structure
+ *
+ * Initialize with `GIT_DIFF_PATCHID_OPTIONS_INIT` macro to
+ * correctly set the default values and version.
+ */
+typedef struct git_diff_patchid_options {
+ unsigned int version;
+} git_diff_patchid_options;
+
+#define GIT_DIFF_PATCHID_OPTIONS_VERSION 1
+#define GIT_DIFF_PATCHID_OPTIONS_INIT { GIT_DIFF_PATCHID_OPTIONS_VERSION }
+
+/**
+ * Initialize `git_diff_patchid_options` structure.
+ *
+ * Initializes the structure with default values. Equivalent to
+ * creating an instance with `GIT_DIFF_PATCHID_OPTIONS_INIT`.
+ */
+GIT_EXTERN(int) git_diff_patchid_init_options(
+ git_diff_patchid_options *opts,
+ unsigned int version);
+
+/**
+ * Calculate the patch ID for the given patch.
+ *
+ * Calculate a stable patch ID for the given patch by summing the
+ * hash of the file diffs, ignoring whitespace and line numbers.
+ * This can be used to derive whether two diffs are the same with
+ * a high probability.
+ *
+ * Currently, this function only calculates stable patch IDs, as
+ * defined in git-patch-id(1), and should in fact generate the
+ * same IDs as the upstream git project does.
+ *
+ * @param out Pointer where the calculated patch ID shoul be
+ * stored
+ * @param diff The diff to calculate the ID for
+ * @param opts Options for how to calculate the patch ID. This is
+ * intended for future changes, as currently no options are
+ * available.
+ * @return 0 on success, an error code otherwise.
+ */
+GIT_EXTERN(int) git_diff_patchid(git_oid *out, git_diff *diff, git_diff_patchid_options *opts);
+
GIT_END_DECL
/** @} */
diff --git a/include/git2/errors.h b/include/git2/errors.h
index e959ffd8a..6f5580253 100644
--- a/include/git2/errors.h
+++ b/include/git2/errors.h
@@ -53,6 +53,8 @@ typedef enum {
GIT_PASSTHROUGH = -30, /**< Internal only */
GIT_ITEROVER = -31, /**< Signals end of iteration with iterator */
+ GIT_RETRY = -32, /**< Internal only */
+ GIT_EMISMATCH = -33, /**< Hashsum mismatch in object */
} git_error_code;
/**
@@ -100,6 +102,8 @@ typedef enum {
GITERR_REBASE,
GITERR_FILESYSTEM,
GITERR_PATCH,
+ GITERR_WORKTREE,
+ GITERR_SHA1
} git_error_t;
/**
diff --git a/include/git2/global.h b/include/git2/global.h
index ce5bdf444..2a87e10c6 100644
--- a/include/git2/global.h
+++ b/include/git2/global.h
@@ -14,7 +14,7 @@ GIT_BEGIN_DECL
/**
* Init the global state
*
- * This function must the called before any other libgit2 function in
+ * This function must be called before any other libgit2 function in
* order to set up global state and threading.
*
* This function may be called multiple times - it will return the number
diff --git a/include/git2/index.h b/include/git2/index.h
index e58b3287e..35af2e5bf 100644
--- a/include/git2/index.h
+++ b/include/git2/index.h
@@ -575,15 +575,16 @@ GIT_EXTERN(int) git_index_remove_bypath(git_index *index, const char *path);
* This method will fail in bare index instances.
*
* The `pathspec` is a list of file names or shell glob patterns that will
- * matched against files in the repository's working directory. Each file
- * that matches will be added to the index (either updating an existing
- * entry or adding a new entry). You can disable glob expansion and force
- * exact matching with the `GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH` flag.
+ * be matched against files in the repository's working directory. Each
+ * file that matches will be added to the index (either updating an
+ * existing entry or adding a new entry). You can disable glob expansion
+ * and force exact matching with the `GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH`
+ * flag.
*
* Files that are ignored will be skipped (unlike `git_index_add_bypath`).
* If a file is already tracked in the index, then it *will* be updated
- * even if it is ignored. Pass the `GIT_INDEX_ADD_FORCE` flag to
- * skip the checking of ignore rules.
+ * even if it is ignored. Pass the `GIT_INDEX_ADD_FORCE` flag to skip
+ * the checking of ignore rules.
*
* To emulate `git add -A` and generate an error if the pathspec contains
* the exact path of an ignored file (when not using FORCE), add the
diff --git a/include/git2/merge.h b/include/git2/merge.h
index c6f6cba6c..94ac8b5c5 100644
--- a/include/git2/merge.h
+++ b/include/git2/merge.h
@@ -290,7 +290,8 @@ typedef struct {
} git_merge_options;
#define GIT_MERGE_OPTIONS_VERSION 1
-#define GIT_MERGE_OPTIONS_INIT {GIT_MERGE_OPTIONS_VERSION}
+#define GIT_MERGE_OPTIONS_INIT { \
+ GIT_MERGE_OPTIONS_VERSION, GIT_MERGE_FIND_RENAMES }
/**
* Initializes a `git_merge_options` with default values. Equivalent to
diff --git a/include/git2/odb.h b/include/git2/odb.h
index b3ed2706c..b7dc0c5f3 100644
--- a/include/git2/odb.h
+++ b/include/git2/odb.h
@@ -488,7 +488,7 @@ GIT_EXTERN(git_otype) git_odb_object_type(git_odb_object *object);
* The backends are checked in relative ordering, based on the
* value of the `priority` parameter.
*
- * Read <odb_backends.h> for more information.
+ * Read <sys/odb_backend.h> for more information.
*
* @param odb database to add the backend to
* @param backend pointer to a git_odb_backend instance
@@ -509,7 +509,7 @@ GIT_EXTERN(int) git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int
*
* Writing is disabled on alternate backends.
*
- * Read <odb_backends.h> for more information.
+ * Read <sys/odb_backend.h> for more information.
*
* @param odb database to add the backend to
* @param backend pointer to a git_odb_backend instance
diff --git a/include/git2/odb_backend.h b/include/git2/odb_backend.h
index b17cfd8ba..9199538ce 100644
--- a/include/git2/odb_backend.h
+++ b/include/git2/odb_backend.h
@@ -39,7 +39,7 @@ GIT_EXTERN(int) git_odb_backend_pack(git_odb_backend **out, const char *objects_
* @param out location to store the odb backend pointer
* @param objects_dir the Git repository's objects directory
* @param compression_level zlib compression level to use
- * @param do_fsync whether to do an fsync() after writing (currently ignored)
+ * @param do_fsync whether to do an fsync() after writing
* @param dir_mode permissions to use creating a directory or 0 for defaults
* @param file_mode permissions to use creating a file or 0 for defaults
*
diff --git a/include/git2/oid.h b/include/git2/oid.h
index 8ad51c8ba..aaa678cc0 100644
--- a/include/git2/oid.h
+++ b/include/git2/oid.h
@@ -50,17 +50,16 @@ GIT_EXTERN(int) git_oid_fromstr(git_oid *out, const char *str);
* Parse a hex formatted null-terminated string into a git_oid.
*
* @param out oid structure the result is written into.
- * @param str input hex string; must be at least 4 characters
- * long and null-terminated.
+ * @param str input hex string; must be null-terminated.
* @return 0 or an error code
*/
GIT_EXTERN(int) git_oid_fromstrp(git_oid *out, const char *str);
/**
- * Parse N characters of a hex formatted object id into a git_oid
+ * Parse N characters of a hex formatted object id into a git_oid.
*
- * If N is odd, N-1 characters will be parsed instead.
- * The remaining space in the git_oid will be set to zero.
+ * If N is odd, the last byte's high nibble will be read in and the
+ * low nibble set to zero.
*
* @param out oid structure the result is written into.
* @param str input hex string of at least size `length`
diff --git a/include/git2/patch.h b/include/git2/patch.h
index 790cb74fc..b177798e6 100644
--- a/include/git2/patch.h
+++ b/include/git2/patch.h
@@ -96,7 +96,7 @@ GIT_EXTERN(int) git_patch_from_blob_and_buffer(
git_patch **out,
const git_blob *old_blob,
const char *old_as_path,
- const char *buffer,
+ const void *buffer,
size_t buffer_len,
const char *buffer_as_path,
const git_diff_options *opts);
@@ -124,7 +124,7 @@ GIT_EXTERN(int) git_patch_from_buffers(
const void *old_buffer,
size_t old_len,
const char *old_as_path,
- const char *new_buffer,
+ const void *new_buffer,
size_t new_len,
const char *new_as_path,
const git_diff_options *opts);
@@ -191,7 +191,7 @@ GIT_EXTERN(int) git_patch_get_hunk(
*
* @param patch The git_patch object
* @param hunk_idx Index of the hunk
- * @return Number of lines in hunk or -1 if invalid hunk index
+ * @return Number of lines in hunk or GIT_ENOTFOUND if invalid hunk index
*/
GIT_EXTERN(int) git_patch_num_lines_in_hunk(
const git_patch *patch,
diff --git a/include/git2/proxy.h b/include/git2/proxy.h
index dcd615633..194cbb651 100644
--- a/include/git2/proxy.h
+++ b/include/git2/proxy.h
@@ -19,7 +19,7 @@ typedef enum {
/**
* Do not attempt to connect through a proxy
*
- * If built against lbicurl, it itself may attempt to connect
+ * If built against libcurl, it itself may attempt to connect
* to a proxy if the environment variables specify it.
*/
GIT_PROXY_NONE,
diff --git a/include/git2/remote.h b/include/git2/remote.h
index c459f42cc..b1e04d557 100644
--- a/include/git2/remote.h
+++ b/include/git2/remote.h
@@ -26,8 +26,6 @@
*/
GIT_BEGIN_DECL
-typedef int (*git_remote_rename_problem_cb)(const char *problematic_refspec, void *payload);
-
/**
* Add a remote with the default fetch refspec to the repository's configuration.
*
@@ -78,6 +76,24 @@ GIT_EXTERN(int) git_remote_create_anonymous(
const char *url);
/**
+ * Create a remote without a connected local repo
+ *
+ * Create a remote with the given url in-memory. You can use this when
+ * you have a URL instead of a remote's name.
+ *
+ * Contrasted with git_remote_create_anonymous, a detached remote
+ * will not consider any repo configuration values (such as insteadof url
+ * substitutions).
+ *
+ * @param out pointer to the new remote objects
+ * @param url the remote repository's URL
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_remote_create_detached(
+ git_remote **out,
+ const char *url);
+
+/**
* Get the information for a particular remote
*
* The name will be checked for validity.
@@ -360,6 +376,8 @@ typedef struct {
} git_push_update;
/**
+ * Callback used to inform of upcoming updates.
+ *
* @param updates an array containing the updates which will be sent
* as commands to the destination.
* @param len number of elements in `updates`
@@ -403,7 +421,7 @@ struct git_remote_callbacks {
* connection to proceed. Returns 1 to allow the connection, 0
* to disallow it or a negative value to indicate an error.
*/
- git_transport_certificate_check_cb certificate_check;
+ git_transport_certificate_check_cb certificate_check;
/**
* During the download of new data, this will be regularly
@@ -569,7 +587,7 @@ typedef struct {
* Initializes a `git_fetch_options` with default values. Equivalent to
* creating an instance with GIT_FETCH_OPTIONS_INIT.
*
- * @param opts the `git_push_options` instance to initialize.
+ * @param opts the `git_fetch_options` instance to initialize.
* @param version the version of the struct; you should pass
* `GIT_FETCH_OPTIONS_VERSION` here.
* @return Zero on success; -1 on failure.
@@ -715,8 +733,8 @@ GIT_EXTERN(int) git_remote_prune(git_remote *remote, const git_remote_callbacks
* Peform all the steps from a push.
*
* @param remote the remote to push to
- * @param refspecs the refspecs to use for pushing. If none are
- * passed, the configured refspecs will be used
+ * @param refspecs the refspecs to use for pushing. If NULL or an empty
+ * array, the configured refspecs will be used
* @param opts options to use for this push
*/
GIT_EXTERN(int) git_remote_push(git_remote *remote,
@@ -796,7 +814,7 @@ GIT_EXTERN(int) git_remote_is_valid_name(const char *remote_name);
* for the remote will be removed.
*
* @param repo the repository in which to act
-* @param name the name of the remove to delete
+* @param name the name of the remote to delete
* @return 0 on success, or an error code.
*/
GIT_EXTERN(int) git_remote_delete(git_repository *repo, const char *name);
diff --git a/include/git2/repository.h b/include/git2/repository.h
index 3d70d1b89..8aac0b3f7 100644
--- a/include/git2/repository.h
+++ b/include/git2/repository.h
@@ -35,6 +35,17 @@ GIT_BEGIN_DECL
* @return 0 or an error code
*/
GIT_EXTERN(int) git_repository_open(git_repository **out, const char *path);
+/**
+ * Open working tree as a repository
+ *
+ * Open the working directory of the working tree as a normal
+ * repository that can then be worked on.
+ *
+ * @param out Output pointer containing opened repository
+ * @param wt Working tree to open
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_repository_open_from_worktree(git_repository **out, git_worktree *wt);
/**
* Create a "fake" repository to wrap an object database
@@ -335,6 +346,17 @@ GIT_EXTERN(int) git_repository_init_ext(
GIT_EXTERN(int) git_repository_head(git_reference **out, git_repository *repo);
/**
+ * Retrieve the referenced HEAD for the worktree
+ *
+ * @param out pointer to the reference which will be retrieved
+ * @param repo a repository object
+ * @param name name of the worktree to retrieve HEAD for
+ * @return 0 when successful, error-code otherwise
+ */
+GIT_EXTERN(int) git_repository_head_for_worktree(git_reference **out, git_repository *repo,
+ const char *name);
+
+/**
* Check if a repository's HEAD is detached
*
* A repository's HEAD is detached when it points directly to a commit
@@ -346,6 +368,20 @@ GIT_EXTERN(int) git_repository_head(git_reference **out, git_repository *repo);
*/
GIT_EXTERN(int) git_repository_head_detached(git_repository *repo);
+/*
+ * Check if a worktree's HEAD is detached
+ *
+ * A worktree's HEAD is detached when it points directly to a
+ * commit instead of a branch.
+ *
+ * @param repo a repository object
+ * @param name name of the worktree to retrieve HEAD for
+ * @return 1 if HEAD is detached, 0 if its not; error code if
+ * there was an error
+ */
+GIT_EXTERN(int) git_repository_head_detached_for_worktree(git_repository *repo,
+ const char *name);
+
/**
* Check if the current branch is unborn
*
@@ -371,6 +407,42 @@ GIT_EXTERN(int) git_repository_head_unborn(git_repository *repo);
GIT_EXTERN(int) git_repository_is_empty(git_repository *repo);
/**
+ * List of items which belong to the git repository layout
+ */
+typedef enum {
+ GIT_REPOSITORY_ITEM_GITDIR,
+ GIT_REPOSITORY_ITEM_WORKDIR,
+ GIT_REPOSITORY_ITEM_COMMONDIR,
+ GIT_REPOSITORY_ITEM_INDEX,
+ GIT_REPOSITORY_ITEM_OBJECTS,
+ GIT_REPOSITORY_ITEM_REFS,
+ GIT_REPOSITORY_ITEM_PACKED_REFS,
+ GIT_REPOSITORY_ITEM_REMOTES,
+ GIT_REPOSITORY_ITEM_CONFIG,
+ GIT_REPOSITORY_ITEM_INFO,
+ GIT_REPOSITORY_ITEM_HOOKS,
+ GIT_REPOSITORY_ITEM_LOGS,
+ GIT_REPOSITORY_ITEM_MODULES,
+ GIT_REPOSITORY_ITEM_WORKTREES
+} git_repository_item_t;
+
+/**
+ * Get the location of a specific repository file or directory
+ *
+ * This function will retrieve the path of a specific repository
+ * item. It will thereby honor things like the repository's
+ * common directory, gitdir, etc. In case a file path cannot
+ * exist for a given item (e.g. the working directory of a bare
+ * repository), GIT_ENOTFOUND is returned.
+ *
+ * @param out Buffer to store the path at
+ * @param repo Repository to get path for
+ * @param item The repository item for which to retrieve the path
+ * @return 0, GIT_ENOTFOUND if the path cannot exist or an error code
+ */
+GIT_EXTERN(int) git_repository_item_path(git_buf *out, git_repository *repo, git_repository_item_t item);
+
+/**
* Get the path of this repository
*
* This is the path of the `.git` folder for normal repositories,
@@ -393,6 +465,17 @@ GIT_EXTERN(const char *) git_repository_path(git_repository *repo);
GIT_EXTERN(const char *) git_repository_workdir(git_repository *repo);
/**
+ * Get the path of the shared common directory for this repository
+ *
+ * If the repository is bare is not a worktree, the git directory
+ * path is returned.
+ *
+ * @param repo A repository object
+ * @return the path to the common dir
+ */
+GIT_EXTERN(const char *) git_repository_commondir(git_repository *repo);
+
+/**
* Set the path to the working directory for this repository
*
* The working directory doesn't need to be the same one
@@ -421,6 +504,14 @@ GIT_EXTERN(int) git_repository_set_workdir(
GIT_EXTERN(int) git_repository_is_bare(git_repository *repo);
/**
+ * Check if a repository is a linked work tree
+ *
+ * @param repo Repo to test
+ * @return 1 if the repository is a linked work tree, 0 otherwise.
+ */
+GIT_EXTERN(int) git_repository_is_worktree(git_repository *repo);
+
+/**
* Get the configuration file for this repository.
*
* If a configuration file has not been set, the default
diff --git a/include/git2/reset.h b/include/git2/reset.h
index 79075291f..be2541433 100644
--- a/include/git2/reset.h
+++ b/include/git2/reset.h
@@ -53,7 +53,7 @@ typedef enum {
*
* @param reset_type Kind of reset operation to perform.
*
- * @param checkout_opts Checkout options to be used for a HARD reset.
+ * @param checkout_opts Optional checkout options to be used for a HARD reset.
* The checkout_strategy field will be overridden (based on reset_type).
* This parameter can be used to propagate notify and progress callbacks.
*
@@ -61,7 +61,7 @@ typedef enum {
*/
GIT_EXTERN(int) git_reset(
git_repository *repo,
- git_object *target,
+ const git_object *target,
git_reset_t reset_type,
const git_checkout_options *checkout_opts);
@@ -79,7 +79,7 @@ GIT_EXTERN(int) git_reset(
*/
GIT_EXTERN(int) git_reset_from_annotated(
git_repository *repo,
- git_annotated_commit *commit,
+ const git_annotated_commit *commit,
git_reset_t reset_type,
const git_checkout_options *checkout_opts);
@@ -103,8 +103,8 @@ GIT_EXTERN(int) git_reset_from_annotated(
*/
GIT_EXTERN(int) git_reset_default(
git_repository *repo,
- git_object *target,
- git_strarray* pathspecs);
+ const git_object *target,
+ const git_strarray* pathspecs);
/** @} */
GIT_END_DECL
diff --git a/include/git2/revert.h b/include/git2/revert.h
index 2de194219..82dbadcfc 100644
--- a/include/git2/revert.h
+++ b/include/git2/revert.h
@@ -75,7 +75,7 @@ GIT_EXTERN(int) git_revert_commit(
*
* @param repo the repository to revert
* @param commit the commit to revert
- * @param given_opts merge flags
+ * @param given_opts the revert options (or null for defaults)
* @return zero on success, -1 on failure.
*/
GIT_EXTERN(int) git_revert(
diff --git a/include/git2/revwalk.h b/include/git2/revwalk.h
index 2cc00536e..d9376ceea 100644
--- a/include/git2/revwalk.h
+++ b/include/git2/revwalk.h
@@ -25,17 +25,15 @@ GIT_BEGIN_DECL
*/
typedef enum {
/**
- * Sort the repository contents in no particular ordering;
- * this sorting is arbitrary, implementation-specific
- * and subject to change at any time.
+ * Sort the output with the same default time-order method from git.
* This is the default sorting for new walkers.
*/
GIT_SORT_NONE = 0,
/**
- * Sort the repository contents in topological order
- * (parents before children); this sorting mode
- * can be combined with time sorting.
+ * Sort the repository contents in topological order (parents before
+ * children); this sorting mode can be combined with time sorting to
+ * produce git's "time-order".
*/
GIT_SORT_TOPOLOGICAL = 1 << 0,
diff --git a/include/git2/stash.h b/include/git2/stash.h
index 733d75a7f..3af9cde38 100644
--- a/include/git2/stash.h
+++ b/include/git2/stash.h
@@ -173,7 +173,7 @@ GIT_EXTERN(int) git_stash_apply_init_options(
* @param repo The owning repository.
* @param index The position within the stash list. 0 points to the
* most recent stashed state.
- * @param options Options to control how stashes are applied.
+ * @param options Optional options to control how stashes are applied.
*
* @return 0 on success, GIT_ENOTFOUND if there's no stashed state for the
* given index, GIT_EMERGECONFLICT if changes exist in the working
@@ -242,7 +242,7 @@ GIT_EXTERN(int) git_stash_drop(
* @param repo The owning repository.
* @param index The position within the stash list. 0 points to the
* most recent stashed state.
- * @param options Options to control how stashes are applied.
+ * @param options Optional options to control how stashes are applied.
*
* @return 0 on success, GIT_ENOTFOUND if there's no stashed state for the given
* index, or error code. (see git_stash_apply() above for details)
diff --git a/include/git2/submodule.h b/include/git2/submodule.h
index 540ecf5c7..b2b3039fe 100644
--- a/include/git2/submodule.h
+++ b/include/git2/submodule.h
@@ -134,9 +134,7 @@ typedef struct git_submodule_update_options {
* checkout, set the `checkout_strategy` to
* `GIT_CHECKOUT_NONE`. Generally you will want the use
* GIT_CHECKOUT_SAFE to update files in the working
- * directory. Use the `clone_checkout_strategy` field
- * to set the checkout strategy that will be used in
- * the case where update needs to clone the repository.
+ * directory.
*/
git_checkout_options checkout_opts;
@@ -149,13 +147,6 @@ typedef struct git_submodule_update_options {
git_fetch_options fetch_opts;
/**
- * The checkout strategy to use when the sub repository needs to
- * be cloned. Use GIT_CHECKOUT_SAFE to create all files
- * in the working directory for the newly cloned repository.
- */
- unsigned int clone_checkout_strategy;
-
- /**
* Allow fetching from the submodule's default remote if the target
* commit isn't found. Enabled by default.
*/
@@ -166,7 +157,7 @@ typedef struct git_submodule_update_options {
#define GIT_SUBMODULE_UPDATE_OPTIONS_INIT \
{ GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, \
{ GIT_CHECKOUT_OPTIONS_VERSION, GIT_CHECKOUT_SAFE }, \
- GIT_FETCH_OPTIONS_INIT, GIT_CHECKOUT_SAFE, 1 }
+ GIT_FETCH_OPTIONS_INIT, 1 }
/**
* Initializes a `git_submodule_update_options` with default values.
diff --git a/include/git2/sys/filter.h b/include/git2/sys/filter.h
index d0e5d4d6f..6d575d4fd 100644
--- a/include/git2/sys/filter.h
+++ b/include/git2/sys/filter.h
@@ -271,6 +271,17 @@ struct git_filter {
};
#define GIT_FILTER_VERSION 1
+#define GIT_FILTER_INIT {GIT_FILTER_VERSION}
+
+/**
+ * Initializes a `git_filter` with default values. Equivalent to
+ * creating an instance with GIT_FILTER_INIT.
+ *
+ * @param filter the `git_filter` struct to initialize.
+ * @param version Version the struct; pass `GIT_FILTER_VERSION`
+ * @return Zero on success; -1 on failure.
+ */
+GIT_EXTERN(int) git_filter_init(git_filter *filter, unsigned int version);
/**
* Register a filter under a given name with a given priority.
diff --git a/include/git2/sys/merge.h b/include/git2/sys/merge.h
index 031941042..eed106c07 100644
--- a/include/git2/sys/merge.h
+++ b/include/git2/sys/merge.h
@@ -36,23 +36,23 @@ GIT_EXTERN(git_merge_driver *) git_merge_driver_lookup(const char *name);
typedef struct git_merge_driver_source git_merge_driver_source;
/** Get the repository that the source data is coming from. */
-GIT_EXTERN(git_repository *) git_merge_driver_source_repo(
+GIT_EXTERN(const git_repository *) git_merge_driver_source_repo(
const git_merge_driver_source *src);
/** Gets the ancestor of the file to merge. */
-GIT_EXTERN(git_index_entry *) git_merge_driver_source_ancestor(
+GIT_EXTERN(const git_index_entry *) git_merge_driver_source_ancestor(
const git_merge_driver_source *src);
/** Gets the ours side of the file to merge. */
-GIT_EXTERN(git_index_entry *) git_merge_driver_source_ours(
+GIT_EXTERN(const git_index_entry *) git_merge_driver_source_ours(
const git_merge_driver_source *src);
/** Gets the theirs side of the file to merge. */
-GIT_EXTERN(git_index_entry *) git_merge_driver_source_theirs(
+GIT_EXTERN(const git_index_entry *) git_merge_driver_source_theirs(
const git_merge_driver_source *src);
/** Gets the merge file options that the merge was invoked with */
-GIT_EXTERN(git_merge_file_options *) git_merge_driver_source_file_options(
+GIT_EXTERN(const git_merge_file_options *) git_merge_driver_source_file_options(
const git_merge_driver_source *src);
diff --git a/include/git2/sys/repository.h b/include/git2/sys/repository.h
index 800396c86..0c9142143 100644
--- a/include/git2/sys/repository.h
+++ b/include/git2/sys/repository.h
@@ -135,6 +135,35 @@ GIT_EXTERN(void) git_repository_set_index(git_repository *repo, git_index *index
*/
GIT_EXTERN(int) git_repository_set_bare(git_repository *repo);
+/**
+ * Load and cache all submodules.
+ *
+ * Because the `.gitmodules` file is unstructured, loading submodules is an
+ * O(N) operation. Any operation (such as `git_rebase_init`) that requires
+ * accessing all submodules is O(N^2) in the number of submodules, if it
+ * has to look each one up individually. This function loads all submodules
+ * and caches them so that subsequent calls to `git_submodule_lookup` are O(1).
+ *
+ * @param repo the repository whose submodules will be cached.
+ */
+GIT_EXTERN(int) git_repository_submodule_cache_all(
+ git_repository *repo);
+
+/**
+ * Clear the submodule cache.
+ *
+ * Clear the submodule cache populated by `git_repository_submodule_cache_all`.
+ * If there is no cache, do nothing.
+ *
+ * The cache incorporates data from the repository's configuration, as well
+ * as the state of the working tree, the index, and HEAD. So any time any
+ * of these has changed, the cache might become invalid.
+ *
+ * @param repo the repository whose submodule cache will be cleared
+ */
+GIT_EXTERN(int) git_repository_submodule_cache_clear(
+ git_repository *repo);
+
/** @} */
GIT_END_DECL
#endif
diff --git a/include/git2/sys/transport.h b/include/git2/sys/transport.h
index 60e38b21a..a395de5ed 100644
--- a/include/git2/sys/transport.h
+++ b/include/git2/sys/transport.h
@@ -241,6 +241,16 @@ GIT_EXTERN(int) git_transport_smart_certificate_check(git_transport *transport,
*/
GIT_EXTERN(int) git_transport_smart_credentials(git_cred **out, git_transport *transport, const char *user, int methods);
+/**
+ * Get a copy of the proxy options
+ *
+ * The url is copied and must be freed by the caller.
+ *
+ * @param out options struct to fill
+ * @param transport the transport to extract the data from.
+ */
+GIT_EXTERN(int) git_transport_smart_proxy_options(git_proxy_options *out, git_transport *transport);
+
/*
*** End of base transport interface ***
*** Begin interface for subtransports for the smart transport ***
diff --git a/include/git2/transaction.h b/include/git2/transaction.h
index 64abb0c69..00ca13993 100644
--- a/include/git2/transaction.h
+++ b/include/git2/transaction.h
@@ -8,6 +8,14 @@
#define INCLUDE_git_transaction_h__
#include "common.h"
+
+/**
+ * @file git2/transaction.h
+ * @brief Git transactional reference routines
+ * @defgroup git_transaction Git transactional reference routines
+ * @ingroup Git
+ * @{
+ */
GIT_BEGIN_DECL
/**
@@ -107,5 +115,6 @@ GIT_EXTERN(int) git_transaction_commit(git_transaction *tx);
*/
GIT_EXTERN(void) git_transaction_free(git_transaction *tx);
+/** @} */
GIT_END_DECL
#endif
diff --git a/include/git2/transport.h b/include/git2/transport.h
index 0ec241699..0c371bf4b 100644
--- a/include/git2/transport.h
+++ b/include/git2/transport.h
@@ -321,13 +321,13 @@ GIT_EXTERN(void) git_cred_free(git_cred *cred);
/**
* Signature of a function which acquires a credential object.
*
- * - cred: The newly created credential object.
- * - url: The resource for which we are demanding a credential.
- * - username_from_url: The username that was embedded in a "user\@host"
+ * @param cred The newly created credential object.
+ * @param url The resource for which we are demanding a credential.
+ * @param username_from_url The username that was embedded in a "user\@host"
* remote url, or NULL if not included.
- * - allowed_types: A bitmask stating which cred types are OK to return.
- * - payload: The payload provided when specifying this callback.
- * - returns 0 for success, < 0 to indicate an error, > 0 to indicate
+ * @param allowed_types A bitmask stating which cred types are OK to return.
+ * @param payload The payload provided when specifying this callback.
+ * @return 0 for success, < 0 to indicate an error, > 0 to indicate
* no credential was acquired
*/
typedef int (*git_cred_acquire_cb)(
diff --git a/include/git2/tree.h b/include/git2/tree.h
index 2e4735c4b..4740b1ffa 100644
--- a/include/git2/tree.h
+++ b/include/git2/tree.h
@@ -375,6 +375,19 @@ GIT_EXTERN(void) git_treebuilder_filter(
GIT_EXTERN(int) git_treebuilder_write(
git_oid *id, git_treebuilder *bld);
+/**
+ * Write the contents of the tree builder as a tree object
+ * using a shared git_buf.
+ *
+ * @see git_treebuilder_write
+ *
+ * @param oid Pointer to store the OID of the newly written tree
+ * @param bld Tree builder to write
+ * @param tree Shared buffer for writing the tree. Will be grown as necessary.
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_treebuilder_write_with_buffer(
+ git_oid *oid, git_treebuilder *bld, git_buf *tree);
/** Callback for the tree traversal method */
typedef int (*git_treewalk_cb)(
diff --git a/include/git2/types.h b/include/git2/types.h
index 6f41014b3..dfdaa2920 100644
--- a/include/git2/types.h
+++ b/include/git2/types.h
@@ -104,6 +104,9 @@ typedef struct git_refdb_backend git_refdb_backend;
*/
typedef struct git_repository git_repository;
+/** Representation of a working tree */
+typedef struct git_worktree git_worktree;
+
/** Representation of a generic object in a repository */
typedef struct git_object git_object;
diff --git a/include/git2/version.h b/include/git2/version.h
index 66a6623cd..becf97bd5 100644
--- a/include/git2/version.h
+++ b/include/git2/version.h
@@ -7,12 +7,12 @@
#ifndef INCLUDE_git_version_h__
#define INCLUDE_git_version_h__
-#define LIBGIT2_VERSION "0.24.0"
+#define LIBGIT2_VERSION "0.26.0"
#define LIBGIT2_VER_MAJOR 0
-#define LIBGIT2_VER_MINOR 24
+#define LIBGIT2_VER_MINOR 26
#define LIBGIT2_VER_REVISION 0
#define LIBGIT2_VER_PATCH 0
-#define LIBGIT2_SOVERSION 24
+#define LIBGIT2_SOVERSION 26
#endif
diff --git a/include/git2/worktree.h b/include/git2/worktree.h
new file mode 100644
index 000000000..d3fa88e3f
--- /dev/null
+++ b/include/git2/worktree.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_git_worktree_h__
+#define INCLUDE_git_worktree_h__
+
+#include "common.h"
+#include "buffer.h"
+#include "types.h"
+#include "strarray.h"
+
+/**
+ * @file git2/worktrees.h
+ * @brief Git worktree related functions
+ * @defgroup git_commit Git worktree related functions
+ * @ingroup Git
+ * @{
+ */
+GIT_BEGIN_DECL
+
+/**
+ * List names of linked working trees
+ *
+ * The returned list should be released with `git_strarray_free`
+ * when no longer needed.
+ *
+ * @param out pointer to the array of working tree names
+ * @param repo the repo to use when listing working trees
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_worktree_list(git_strarray *out, git_repository *repo);
+
+/**
+ * Lookup a working tree by its name for a given repository
+ *
+ * @param out Output pointer to looked up worktree or `NULL`
+ * @param repo The repository containing worktrees
+ * @param name Name of the working tree to look up
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_worktree_lookup(git_worktree **out, git_repository *repo, const char *name);
+
+/**
+ * Open a worktree of a given repository
+ *
+ * If a repository is not the main tree but a worktree, this
+ * function will look up the worktree inside the parent
+ * repository and create a new `git_worktree` structure.
+ *
+ * @param out Out-pointer for the newly allocated worktree
+ * @param repo Repository to look up worktree for
+ */
+GIT_EXTERN(int) git_worktree_open_from_repository(git_worktree **out, git_repository *repo);
+
+/**
+ * Free a previously allocated worktree
+ *
+ * @param wt worktree handle to close. If NULL nothing occurs.
+ */
+GIT_EXTERN(void) git_worktree_free(git_worktree *wt);
+
+/**
+ * Check if worktree is valid
+ *
+ * A valid worktree requires both the git data structures inside
+ * the linked parent repository and the linked working copy to be
+ * present.
+ *
+ * @param wt Worktree to check
+ * @return 0 when worktree is valid, error-code otherwise
+ */
+GIT_EXTERN(int) git_worktree_validate(const git_worktree *wt);
+
+typedef struct git_worktree_add_options {
+ unsigned int version;
+
+ int lock; /**< lock newly created worktree */
+} git_worktree_add_options;
+
+#define GIT_WORKTREE_ADD_OPTIONS_VERSION 1
+#define GIT_WORKTREE_ADD_OPTIONS_INIT {GIT_WORKTREE_ADD_OPTIONS_VERSION,0}
+
+/**
+ * Initializes a `git_worktree_add_options` with default vaules.
+ * Equivalent to creating an instance with
+ * GIT_WORKTREE_ADD_OPTIONS_INIT.
+ *
+ * @param opts the struct to initialize
+ * @param version Verison of struct; pass `GIT_WORKTREE_ADD_OPTIONS_VERSION`
+ * @return Zero on success; -1 on failure.
+ */
+int git_worktree_add_init_options(git_worktree_add_options *opts,
+ unsigned int version);
+
+/**
+ * Add a new working tree
+ *
+ * Add a new working tree for the repository, that is create the
+ * required data structures inside the repository and check out
+ * the current HEAD at `path`
+ *
+ * @param out Output pointer containing new working tree
+ * @param repo Repository to create working tree for
+ * @param name Name of the working tree
+ * @param path Path to create working tree at
+ * @param opts Options to modify default behavior. May be NULL
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_worktree_add(git_worktree **out, git_repository *repo,
+ const char *name, const char *path,
+ const git_worktree_add_options *opts);
+
+/**
+ * Lock worktree if not already locked
+ *
+ * Lock a worktree, optionally specifying a reason why the linked
+ * working tree is being locked.
+ *
+ * @param wt Worktree to lock
+ * @param reason Reason why the working tree is being locked
+ * @return 0 on success, non-zero otherwise
+ */
+GIT_EXTERN(int) git_worktree_lock(git_worktree *wt, char *reason);
+
+/**
+ * Unlock a locked worktree
+ *
+ * @param wt Worktree to unlock
+ * @return 0 on success, 1 if worktree was not locked, error-code
+ * otherwise
+ */
+GIT_EXTERN(int) git_worktree_unlock(git_worktree *wt);
+
+/**
+ * Check if worktree is locked
+ *
+ * A worktree may be locked if the linked working tree is stored
+ * on a portable device which is not available.
+ *
+ * @param reason Buffer to store reason in. If NULL no reason is stored.
+ * @param wt Worktree to check
+ * @return 0 when the working tree not locked, a value greater
+ * than zero if it is locked, less than zero if there was an
+ * error
+ */
+GIT_EXTERN(int) git_worktree_is_locked(git_buf *reason, const git_worktree *wt);
+
+/**
+ * Flags which can be passed to git_worktree_prune to alter its
+ * behavior.
+ */
+typedef enum {
+ /* Prune working tree even if working tree is valid */
+ GIT_WORKTREE_PRUNE_VALID = 1u << 0,
+ /* Prune working tree even if it is locked */
+ GIT_WORKTREE_PRUNE_LOCKED = 1u << 1,
+ /* Prune checked out working tree */
+ GIT_WORKTREE_PRUNE_WORKING_TREE = 1u << 2,
+} git_worktree_prune_t;
+
+typedef struct git_worktree_prune_options {
+ unsigned int version;
+
+ uint32_t flags;
+} git_worktree_prune_options;
+
+#define GIT_WORKTREE_PRUNE_OPTIONS_VERSION 1
+#define GIT_WORKTREE_PRUNE_OPTIONS_INIT {GIT_WORKTREE_PRUNE_OPTIONS_VERSION,0}
+
+/**
+ * Initializes a `git_worktree_prune_options` with default vaules.
+ * Equivalent to creating an instance with
+ * GIT_WORKTREE_PRUNE_OPTIONS_INIT.
+ *
+ * @param opts the struct to initialize
+ * @param version Verison of struct; pass `GIT_WORKTREE_PRUNE_OPTIONS_VERSION`
+ * @return Zero on success; -1 on failure.
+ */
+GIT_EXTERN(int) git_worktree_prune_init_options(
+ git_worktree_prune_options *opts,
+ unsigned int version);
+
+/**
+ * Is the worktree prunable with the given options?
+ *
+ * A worktree is not prunable in the following scenarios:
+ *
+ * - the worktree is linking to a valid on-disk worktree. The
+ * `valid` member will cause this check to be ignored.
+ * - the worktree is locked. The `locked` flag will cause this
+ * check to be ignored.
+ *
+ * If the worktree is not valid and not locked or if the above
+ * flags have been passed in, this function will return a
+ * positive value.
+ */
+GIT_EXTERN(int) git_worktree_is_prunable(git_worktree *wt,
+ git_worktree_prune_options *opts);
+
+/**
+ * Prune working tree
+ *
+ * Prune the working tree, that is remove the git data
+ * structures on disk. The repository will only be pruned of
+ * `git_worktree_is_prunable` succeeds.
+ *
+ * @param wt Worktree to prune
+ * @param opts Specifies which checks to override. See
+ * `git_worktree_is_prunable`. May be NULL
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_worktree_prune(git_worktree *wt,
+ git_worktree_prune_options *opts);
+
+/** @} */
+GIT_END_DECL
+#endif
diff --git a/libgit2.pc.in b/libgit2.pc.in
index 329a560a7..96b965955 100644
--- a/libgit2.pc.in
+++ b/libgit2.pc.in
@@ -1,4 +1,4 @@
-prefix=@PKGCONFIG_PREFIX@
+prefix="@PKGCONFIG_PREFIX@"
libdir=@PKGCONFIG_LIBDIR@
includedir=@PKGCONFIG_INCLUDEDIR@
@@ -6,7 +6,7 @@ Name: libgit2
Description: The git library, take 2
Version: @LIBGIT2_VERSION_STRING@
-Libs: -L"${libdir}" -lgit2
+Libs: -L${libdir} -lgit2
Libs.private: @LIBGIT2_PC_LIBS@
Requires.private: @LIBGIT2_PC_REQUIRES@
diff --git a/script/appveyor-mingw.sh b/script/appveyor-mingw.sh
index 198801875..d171a72d5 100755
--- a/script/appveyor-mingw.sh
+++ b/script/appveyor-mingw.sh
@@ -7,15 +7,17 @@ if [ "$ARCH" = "i686" ]; then
curl -LsSO http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/4.9.2/threads-win32/sjlj/$f
fi
7z x $f > /dev/null
- mv mingw32 /MinGW
+ export PATH=`pwd`/mingw32/bin:$PATH
else
f=x86_64-4.9.2-release-win32-seh-rt_v3-rev1.7z
if ! [ -e $f ]; then
curl -LsSO http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/4.9.2/threads-win32/seh/$f
fi
7z x $f > /dev/null
- mv mingw64 /MinGW
+ export PATH=`pwd`/mingw64/bin:$PATH
fi
cd build
+gcc --version
+cmake --version
cmake -D ENABLE_TRACE=ON -D BUILD_CLAR=ON .. -G"$GENERATOR"
cmake --build . --config RelWithDebInfo
diff --git a/script/cibuild.sh b/script/cibuild.sh
index 979eb0ce4..74946db0a 100755
--- a/script/cibuild.sh
+++ b/script/cibuild.sh
@@ -1,5 +1,7 @@
#!/bin/sh
+set -x
+
if [ -n "$COVERITY" ];
then
./script/coverity.sh;
@@ -18,7 +20,7 @@ java -jar poxyproxy.jar -d --port 8080 --credentials foo:bar &
mkdir _build
cd _build
# shellcheck disable=SC2086
-cmake .. -DCMAKE_INSTALL_PREFIX=../_install $OPTIONS || exit $?
+cmake .. -DBUILD_EXAMPLES=ON -DCMAKE_INSTALL_PREFIX=../_install $OPTIONS || exit $?
make -j2 install || exit $?
# If this platform doesn't support test execution, bail out now
@@ -41,18 +43,40 @@ ctest -V -R libgit2_clar || exit $?
killall git-daemon
-if [ "$TRAVIS_OS_NAME" = "osx" ]; then
- echo 'PasswordAuthentication yes' | sudo tee -a /etc/sshd_config
-fi
-
+# Set up sshd
+mkdir ~/sshd/
+cat >~/sshd/sshd_config<<-EOF
+ Port 2222
+ ListenAddress 0.0.0.0
+ Protocol 2
+ HostKey ${HOME}/sshd/id_rsa
+ PidFile ${HOME}/sshd/pid
+ RSAAuthentication yes
+ PasswordAuthentication yes
+ PubkeyAuthentication yes
+ ChallengeResponseAuthentication no
+ # Required here as sshd will simply close connection otherwise
+ UsePAM no
+EOF
+ssh-keygen -t rsa -f ~/sshd/id_rsa -N "" -q
+/usr/sbin/sshd -f ~/sshd/sshd_config
+
+# Set up keys
ssh-keygen -t rsa -f ~/.ssh/id_rsa -N "" -q
cat ~/.ssh/id_rsa.pub >>~/.ssh/authorized_keys
-ssh-keyscan -t rsa localhost >>~/.ssh/known_hosts
+while read algorithm key comment; do
+ echo "[localhost]:2222 $algorithm $key" >>~/.ssh/known_hosts
+done <~/sshd/id_rsa.pub
-# Get the fingerprint for localhost and remove the colons so we can parse it as a hex number
-export GITTEST_REMOTE_SSH_FINGERPRINT=$(ssh-keygen -F localhost -l | tail -n 1 | cut -d ' ' -f 2 | tr -d ':')
+# Get the fingerprint for localhost and remove the colons so we can parse it as
+# a hex number. The Mac version is newer so it has a different output format.
+if [ "$TRAVIS_OS_NAME" = "osx" ]; then
+ export GITTEST_REMOTE_SSH_FINGERPRINT=$(ssh-keygen -E md5 -F '[localhost]:2222' -l | tail -n 1 | cut -d ' ' -f 3 | cut -d : -f2- | tr -d :)
+else
+ export GITTEST_REMOTE_SSH_FINGERPRINT=$(ssh-keygen -F '[localhost]:2222' -l | tail -n 1 | cut -d ' ' -f 2 | tr -d ':')
+fi
-export GITTEST_REMOTE_URL="ssh://localhost/$HOME/_temp/test.git"
+export GITTEST_REMOTE_URL="ssh://localhost:2222/$HOME/_temp/test.git"
export GITTEST_REMOTE_USER=$USER
export GITTEST_REMOTE_SSH_KEY="$HOME/.ssh/id_rsa"
export GITTEST_REMOTE_SSH_PUBKEY="$HOME/.ssh/id_rsa.pub"
@@ -76,6 +100,8 @@ if [ -e ./libgit2_clar ]; then
fi
+kill $(cat "$HOME/sshd/pid")
+
export GITTEST_REMOTE_URL="https://github.com/libgit2/non-existent"
export GITTEST_REMOTE_USER="libgit2test"
ctest -V -R libgit2_clar-cred_callback
diff --git a/script/coverity.sh b/script/coverity.sh
index 7fe9eb4c7..5fe16c031 100755
--- a/script/coverity.sh
+++ b/script/coverity.sh
@@ -1,23 +1,22 @@
#!/bin/bash
set -e
-# Environment check
-[ -z "$COVERITY_TOKEN" ] && echo "Need to set a coverity token" && exit 1
-
# Only run this on our branches
-echo "Pull request: $TRAVIS_PULL_REQUEST | Slug: $TRAVIS_REPO_SLUG"
-if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_REPO_SLUG" != "libgit2/libgit2" ];
+echo "Branch: $TRAVIS_BRANCH | Pull request: $TRAVIS_PULL_REQUEST | Slug: $TRAVIS_REPO_SLUG"
+if [ "$TRAVIS_BRANCH" != "master" -o "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_REPO_SLUG" != "libgit2/libgit2" ];
then
- echo "Only analyzing 'development' on the main repo."
+ echo "Only analyzing the 'master' brach of the main repository."
exit 0
fi
-COV_VERSION=6.6.1
+# Environment check
+[ -z "$COVERITY_TOKEN" ] && echo "Need to set a coverity token" && exit 1
+
case $(uname -m) in
i?86) BITS=32 ;;
amd64|x86_64) BITS=64 ;;
esac
-SCAN_TOOL=https://scan.coverity.com/download/linux-${BITS}
+SCAN_TOOL=https://scan.coverity.com/download/cxx/linux${BITS}
TOOL_BASE=$(pwd)/_coverity-scan
# Install coverity tools
diff --git a/script/install-deps-linux.sh b/script/install-deps-linux.sh
new file mode 100755
index 000000000..15bac4d08
--- /dev/null
+++ b/script/install-deps-linux.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+set -x
+
+if [ -z "$PRECISE" ]; then
+ echo "deb http://libgit2deps.edwardthomson.com trusty libgit2deps" | sudo tee -a /etc/apt/sources.list
+ sudo apt-key adv --keyserver pgp.mit.edu --recv 99131CD5
+ sudo apt-get update -qq
+ sudo apt-get install -y curl libcurl3 libcurl3-gnutls libcurl4-gnutls-dev
+fi
+
+sudo apt-get install -y cmake libssh2-1-dev openssh-client openssh-server valgrind
diff --git a/script/install-deps-osx.sh b/script/install-deps-osx.sh
index 4b8393b19..94314dbaa 100755
--- a/script/install-deps-osx.sh
+++ b/script/install-deps-osx.sh
@@ -3,6 +3,7 @@
set -x
brew update
-brew install homebrew/dupes/zlib
+brew install zlib
brew install curl
+brew install openssl
brew install libssh2
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 000000000..3392a4218
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,400 @@
+IF(DEBUG_POOL)
+ SET(GIT_DEBUG_POOL 1)
+ENDIF()
+
+# This variable will contain the libraries we need to put into
+# libgit2.pc's Requires.private. That is, what we're linking to or
+# what someone who's statically linking us needs to link to.
+SET(LIBGIT2_PC_REQUIRES "")
+# This will be set later if we use the system's http-parser library or
+# use iconv (OSX) and will be written to the Libs.private field in the
+# pc file.
+SET(LIBGIT2_PC_LIBS "")
+
+SET(LIBGIT2_INCLUDES
+ "${CMAKE_CURRENT_BINARY_DIR}"
+ "${CMAKE_SOURCE_DIR}/src"
+ "${CMAKE_SOURCE_DIR}/include")
+SET(LIBGIT2_LIBS "")
+SET(LIBGIT2_LIBDIRS "")
+
+# Installation paths
+#
+SET(BIN_INSTALL_DIR bin CACHE PATH "Where to install binaries to.")
+SET(LIB_INSTALL_DIR lib CACHE PATH "Where to install libraries to.")
+SET(INCLUDE_INSTALL_DIR include CACHE PATH "Where to install headers to.")
+
+# Set a couple variables to be substituted inside the .pc file.
+# We can't just use LIB_INSTALL_DIR in the .pc file, as passing them as absolue
+# or relative paths is both valid and supported by cmake.
+SET (PKGCONFIG_PREFIX ${CMAKE_INSTALL_PREFIX})
+
+IF(IS_ABSOLUTE ${LIB_INSTALL_DIR})
+ SET (PKGCONFIG_LIBDIR ${LIB_INSTALL_DIR})
+ELSE(IS_ABSOLUTE ${LIB_INSTALL_DIR})
+ SET (PKGCONFIG_LIBDIR "\${prefix}/${LIB_INSTALL_DIR}")
+ENDIF (IS_ABSOLUTE ${LIB_INSTALL_DIR})
+
+IF(IS_ABSOLUTE ${INCLUDE_INSTALL_DIR})
+ SET (PKGCONFIG_INCLUDEDIR ${INCLUDE_INSTALL_DIR})
+ELSE(IS_ABSOLUTE ${INCLUDE_INSTALL_DIR})
+ SET (PKGCONFIG_INCLUDEDIR "\${prefix}/${INCLUDE_INSTALL_DIR}")
+ENDIF(IS_ABSOLUTE ${INCLUDE_INSTALL_DIR})
+
+# Enable tracing
+IF (ENABLE_TRACE STREQUAL "ON")
+ SET(GIT_TRACE 1)
+ENDIF()
+
+CHECK_SYMBOL_EXISTS(regcomp_l "regex.h;xlocale.h" HAVE_REGCOMP_L)
+IF (HAVE_REGCOMP_L)
+ SET(GIT_USE_REGCOMP_L 1)
+ENDIF ()
+
+CHECK_FUNCTION_EXISTS(futimens HAVE_FUTIMENS)
+IF (HAVE_FUTIMENS)
+ SET(GIT_USE_FUTIMENS 1)
+ENDIF ()
+
+CHECK_FUNCTION_EXISTS(qsort_r HAVE_QSORT_R)
+IF (HAVE_QSORT_R)
+ ADD_DEFINITIONS(-DHAVE_QSORT_R)
+ENDIF ()
+
+CHECK_FUNCTION_EXISTS(qsort_s HAVE_QSORT_S)
+IF (HAVE_QSORT_S)
+ ADD_DEFINITIONS(-DHAVE_QSORT_S)
+ENDIF ()
+
+# Find required dependencies
+
+IF(WIN32)
+ LIST(APPEND LIBGIT2_LIBS ws2_32)
+ELSEIF(CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
+ LIST(APPEND LIBGIT2_LIBS socket nsl)
+ LIST(APPEND LIBGIT2_PC_LIBS "-lsocket" "-lnsl")
+ELSEIF(CMAKE_SYSTEM_NAME MATCHES "Haiku")
+ LIST(APPEND LIBGIT2_LIBS network)
+ LIST(APPEND LIBGIT2_PC_LIBS "-lnetwork")
+ENDIF()
+
+CHECK_LIBRARY_EXISTS(rt clock_gettime "time.h" NEED_LIBRT)
+IF(NEED_LIBRT)
+ LIST(APPEND LIBGIT2_LIBS rt)
+ LIST(APPEND LIBGIT2_PC_LIBS "-lrt")
+ENDIF()
+
+IF(THREADSAFE)
+ LIST(APPEND LIBGIT2_LIBS ${CMAKE_THREAD_LIBS_INIT})
+ LIST(APPEND LIBGIT2_PC_LIBS ${CMAKE_THREAD_LIBS_INIT})
+ENDIF()
+
+IF (SECURITY_FOUND)
+ # OS X 10.7 and older do not have some functions we use, fall back to OpenSSL there
+ CHECK_LIBRARY_EXISTS("${SECURITY_DIRS}" SSLCreateContext "Security/SecureTransport.h" HAVE_NEWER_SECURITY)
+ IF (HAVE_NEWER_SECURITY)
+ MESSAGE("-- Found Security ${SECURITY_DIRS}")
+ LIST(APPEND LIBGIT2_PC_LIBS "-framework Security")
+ LIST(APPEND LIBGIT2_LIBS ${SECURITY_DIRS})
+ ELSE()
+ MESSAGE("-- Security framework is too old, falling back to OpenSSL")
+ SET(SECURITY_FOUND "NO")
+ SET(USE_OPENSSL "ON")
+ ENDIF()
+ENDIF()
+
+IF (COREFOUNDATION_FOUND)
+ MESSAGE("-- Found CoreFoundation ${COREFOUNDATION_DIRS}")
+ LIST(APPEND LIBGIT2_PC_LIBS "-framework CoreFoundation")
+ LIST(APPEND LIBGIT2_LIBS ${COREFOUNDATION_DIRS})
+ENDIF()
+
+
+IF (WIN32 AND EMBED_SSH_PATH)
+ FILE(GLOB SRC_SSH "${EMBED_SSH_PATH}/src/*.c")
+ LIST(APPEND LIBGIT2_INCLUDES "${EMBED_SSH_PATH}/include")
+ FILE(WRITE "${EMBED_SSH_PATH}/src/libssh2_config.h" "#define HAVE_WINCNG\n#define LIBSSH2_WINCNG\n#include \"../win32/libssh2_config.h\"")
+ SET(GIT_SSH 1)
+ENDIF()
+
+IF (WIN32 AND WINHTTP)
+ SET(GIT_WINHTTP 1)
+ SET(GIT_HTTPS 1)
+
+ # Since MinGW does not come with headers or an import library for winhttp,
+ # we have to include a private header and generate our own import library
+ IF (MINGW)
+ ADD_SUBDIRECTORY("${CMAKE_SOURCE_DIR}/deps/winhttp" "${CMAKE_BINARY_DIR}/deps/winhttp")
+ LIST(APPEND LIBGIT2_LIBS winhttp)
+ LIST(APPEND LIBGIT2_INCLUDES "${CMAKE_SOURCE_DIR}/deps/winhttp")
+ LIST(APPEND LIBGIT2_LIBDIRS ${LIBWINHTTP_PATH})
+ ELSE()
+ LIST(APPEND LIBGIT2_LIBS "winhttp")
+ LIST(APPEND LIBGIT2_PC_LIBS "-lwinhttp")
+ ENDIF ()
+
+ LIST(APPEND LIBGIT2_LIBS "rpcrt4" "crypt32" "ole32")
+ LIST(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32")
+ELSE ()
+ IF (CURL)
+ PKG_CHECK_MODULES(CURL libcurl)
+ ENDIF ()
+
+ IF (NOT AMIGA AND USE_OPENSSL)
+ FIND_PACKAGE(OpenSSL)
+ ENDIF ()
+
+ IF (CURL_FOUND)
+ SET(GIT_CURL 1)
+ LIST(APPEND LIBGIT2_INCLUDES ${CURL_INCLUDE_DIRS})
+ LIST(APPEND LIBGIT2_LIBDIRS ${CURL_LIBRARY_DIRS})
+ LIST(APPEND LIBGIT2_LIBS ${CURL_LIBRARIES})
+ LIST(APPEND LIBGIT2_PC_LIBS ${CURL_LDFLAGS})
+ ENDIF()
+ENDIF()
+
+# Specify sha1 implementation
+IF (USE_SHA1DC)
+ SET(GIT_SHA1_COLLISIONDETECT 1)
+ ADD_DEFINITIONS(-DSHA1DC_NO_STANDARD_INCLUDES=1)
+ ADD_DEFINITIONS(-DSHA1DC_CUSTOM_INCLUDE_SHA1_C=\"common.h\")
+ ADD_DEFINITIONS(-DSHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C=\"common.h\")
+ FILE(GLOB SRC_SHA1 hash/hash_collisiondetect.c hash/sha1dc/*)
+ELSEIF (WIN32 AND NOT MINGW)
+ SET(GIT_SHA1_WIN32 1)
+ FILE(GLOB SRC_SHA1 hash/hash_win32.c)
+ELSEIF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ SET(GIT_SHA1_COMMON_CRYPTO 1)
+ELSEIF (OPENSSL_FOUND)
+ SET(GIT_SHA1_OPENSSL 1)
+ IF (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+ LIST(APPEND LIBGIT2_PC_LIBS "-lssl")
+ ELSE()
+ SET(LIBGIT2_PC_REQUIRES "${LIBGIT2_PC_REQUIRES} openssl")
+ ENDIF ()
+ELSE()
+ FILE(GLOB SRC_SHA1 hash/hash_generic.c)
+ENDIF()
+
+
+# Include POSIX regex when it is required
+IF(WIN32 OR AMIGA OR CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
+ ADD_SUBDIRECTORY("${CMAKE_SOURCE_DIR}/deps/regex" "${CMAKE_BINARY_DIR}/deps/regex")
+ LIST(APPEND LIBGIT2_INCLUDES "${CMAKE_SOURCE_DIR}/deps/regex")
+ LIST(APPEND LIBGIT2_LIBS regex)
+ENDIF()
+
+# Optional external dependency: http-parser
+FIND_PACKAGE(HTTP_Parser)
+IF (USE_EXT_HTTP_PARSER AND HTTP_PARSER_FOUND AND HTTP_PARSER_VERSION_MAJOR EQUAL 2)
+ LIST(APPEND LIBGIT2_INCLUDES ${HTTP_PARSER_INCLUDE_DIRS})
+ LIST(APPEND LIBGIT2_LIBS ${HTTP_PARSER_LIBRARIES})
+ LIST(APPEND LIBGIT2_PC_LIBS "-lhttp_parser")
+ELSE()
+ MESSAGE(STATUS "http-parser version 2 was not found or disabled; using bundled 3rd-party sources.")
+ ADD_SUBDIRECTORY("${CMAKE_SOURCE_DIR}/deps/http-parser" "${CMAKE_BINARY_DIR}/deps/http-parser")
+ LIST(APPEND LIBGIT2_INCLUDES "${CMAKE_SOURCE_DIR}/deps/http-parser")
+ LIST(APPEND LIBGIT2_LIBS http-parser)
+ENDIF()
+
+# Optional external dependency: zlib
+FIND_PACKAGE(ZLIB)
+IF (ZLIB_FOUND)
+ LIST(APPEND LIBGIT2_INCLUDES ${ZLIB_INCLUDE_DIRS})
+ LIST(APPEND LIBGIT2_LIBS ${ZLIB_LIBRARIES})
+ IF(APPLE OR CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+ LIST(APPEND LIBGIT2_LIBS "z")
+ LIST(APPEND LIBGIT2_PC_LIBS "-lz")
+ ELSE()
+ SET(LIBGIT2_PC_REQUIRES "${LIBGIT2_PC_REQUIRES} zlib")
+ ENDIF()
+ELSE()
+ MESSAGE(STATUS "zlib was not found; using bundled 3rd-party sources." )
+ ADD_SUBDIRECTORY("${CMAKE_SOURCE_DIR}/deps/zlib" "${CMAKE_BINARY_DIR}/deps/zlib")
+ LIST(APPEND LIBGIT2_INCLUDES "${CMAKE_SOURCE_DIR}/deps/zlib")
+ LIST(APPEND LIBGIT2_LIBS zlib)
+ENDIF()
+
+# Optional external dependency: libssh2
+IF (USE_SSH)
+ PKG_CHECK_MODULES(LIBSSH2 libssh2)
+ENDIF()
+IF (LIBSSH2_FOUND)
+ SET(GIT_SSH 1)
+ LIST(APPEND LIBGIT2_INCLUDES ${LIBSSH2_INCLUDE_DIRS})
+ LIST(APPEND LIBGIT2_LIBS ${LIBSSH2_LIBRARIES})
+ LIST(APPEND LIBGIT2_LIBDIRS ${LIBSSH2_LIBRARY_DIRS})
+ LIST(APPEND LIBGIT2_PC_LIBS ${LIBSSH2_LDFLAGS})
+ #SET(LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS} ${LIBSSH2_LDFLAGS}")
+
+ CHECK_LIBRARY_EXISTS("${LIBSSH2_LIBRARIES}" libssh2_userauth_publickey_frommemory "${LIBSSH2_LIBRARY_DIRS}" HAVE_LIBSSH2_MEMORY_CREDENTIALS)
+ IF (HAVE_LIBSSH2_MEMORY_CREDENTIALS)
+ SET(GIT_SSH_MEMORY_CREDENTIALS 1)
+ ENDIF()
+ELSE()
+ MESSAGE(STATUS "LIBSSH2 not found. Set CMAKE_PREFIX_PATH if it is installed outside of the default search path.")
+ENDIF()
+
+# Optional external dependency: libgssapi
+IF (USE_GSSAPI)
+ FIND_PACKAGE(GSSAPI)
+ENDIF()
+IF (GSSAPI_FOUND)
+ SET(GIT_GSSAPI 1)
+ LIST(APPEND LIBGIT2_LIBS ${GSSAPI_LIBRARIES})
+ENDIF()
+
+# Optional external dependency: iconv
+IF (USE_ICONV)
+ FIND_PACKAGE(Iconv)
+ENDIF()
+IF (ICONV_FOUND)
+ SET(GIT_USE_ICONV 1)
+ LIST(APPEND LIBGIT2_INCLUDES ${ICONV_INCLUDE_DIR})
+ LIST(APPEND LIBGIT2_LIBS ${ICONV_LIBRARIES})
+ LIST(APPEND LIBGIT2_PC_LIBS ${ICONV_LIBRARIES})
+ENDIF()
+
+IF (SECURITY_FOUND)
+ SET(GIT_SECURE_TRANSPORT 1)
+ SET(GIT_HTTPS 1)
+ LIST(APPEND LIBGIT2_INCLUDES ${SECURITY_INCLUDE_DIR})
+ENDIF ()
+
+IF (OPENSSL_FOUND)
+ SET(GIT_OPENSSL 1)
+ SET(GIT_HTTPS 1)
+ LIST(APPEND LIBGIT2_INCLUDES ${OPENSSL_INCLUDE_DIR})
+ LIST(APPEND LIBGIT2_LIBS ${OPENSSL_LIBRARIES})
+ENDIF()
+
+
+
+IF (THREADSAFE)
+ IF (NOT WIN32)
+ FIND_PACKAGE(Threads REQUIRED)
+ ENDIF()
+
+ SET(GIT_THREADS 1)
+ENDIF()
+
+IF (USE_NSEC)
+ SET(GIT_USE_NSEC 1)
+ENDIF()
+
+IF (HAVE_STRUCT_STAT_ST_MTIM)
+ SET(GIT_USE_STAT_MTIM 1)
+ELSEIF (HAVE_STRUCT_STAT_ST_MTIMESPEC)
+ SET(GIT_USE_STAT_MTIMESPEC 1)
+ELSEIF (HAVE_STRUCT_STAT_ST_MTIME_NSEC)
+ SET(GIT_USE_STAT_MTIME_NSEC 1)
+ENDIF()
+
+ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64)
+
+# Collect sourcefiles
+FILE(GLOB SRC_H
+ "${CMAKE_SOURCE_DIR}/include/git2.h"
+ "${CMAKE_SOURCE_DIR}/include/git2/*.h"
+ "${CMAKE_SOURCE_DIR}/include/git2/sys/*.h")
+
+# On Windows use specific platform sources
+IF (WIN32 AND NOT CYGWIN)
+ ADD_DEFINITIONS(-DWIN32 -D_WIN32_WINNT=0x0501)
+
+ IF(MSVC)
+ SET(WIN_RC "win32/git2.rc")
+ ENDIF()
+
+ FILE(GLOB SRC_OS win32/*.c win32/*.h)
+ELSEIF (AMIGA)
+ ADD_DEFINITIONS(-DNO_ADDRINFO -DNO_READDIR_R -DNO_MMAP)
+ELSE()
+ IF (VALGRIND)
+ ADD_DEFINITIONS(-DNO_MMAP)
+ ENDIF()
+ FILE(GLOB SRC_OS unix/*.c unix/*.h)
+ENDIF()
+FILE(GLOB SRC_GIT2 *.c *.h transports/*.c transports/*.h xdiff/*.c xdiff/*.h)
+
+# Determine architecture of the machine
+IF (CMAKE_SIZEOF_VOID_P EQUAL 8)
+ SET(GIT_ARCH_64 1)
+ELSEIF (CMAKE_SIZEOF_VOID_P EQUAL 4)
+ SET(GIT_ARCH_32 1)
+ELSEIF (CMAKE_SIZEOF_VOID_P)
+ MESSAGE(FATAL_ERROR "Unsupported architecture (pointer size is ${CMAKE_SIZEOF_VOID_P} bytes)")
+ELSE()
+ MESSAGE(FATAL_ERROR "Unsupported architecture (CMAKE_SIZEOF_VOID_P is unset)")
+ENDIF()
+
+CONFIGURE_FILE(features.h.in git2/sys/features.h)
+
+SET(GIT2INTERNAL_OBJECTS ${SRC_H} ${SRC_GIT2} ${SRC_OS} ${SRC_SSH} ${SRC_SHA1})
+
+IF (CMAKE_VERSION VERSION_GREATER 2.8.7)
+ ADD_LIBRARY(git2internal OBJECT ${GIT2INTERNAL_OBJECTS})
+ IDE_SPLIT_SOURCES(git2internal)
+ SET(GIT2INTERNAL_OBJECTS $<TARGET_OBJECTS:git2internal>)
+
+ IF (${CMAKE_VERSION} VERSION_LESS 2.8.12)
+ INCLUDE_DIRECTORIES(${LIBGIT2_INCLUDES})
+ ELSE()
+ TARGET_INCLUDE_DIRECTORIES(git2internal
+ PRIVATE ${LIBGIT2_INCLUDES}
+ PUBLIC ${CMAKE_SOURCE_DIR}/include)
+ ENDIF()
+ELSE()
+ INCLUDE_DIRECTORIES(${LIBGIT2_INCLUDES})
+ENDIF()
+
+SET(GIT2INTERNAL_OBJECTS ${GIT2INTERNAL_OBJECTS} PARENT_SCOPE)
+SET(LIBGIT2_INCLUDES ${LIBGIT2_INCLUDES} PARENT_SCOPE)
+SET(LIBGIT2_LIBS ${LIBGIT2_LIBS} PARENT_SCOPE)
+SET(LIBGIT2_LIBDIRS ${LIBGIT2_LIBDIRS} PARENT_SCOPE)
+
+# Compile and link libgit2
+LINK_DIRECTORIES(${LIBGIT2_LIBDIRS})
+ADD_LIBRARY(git2 ${WIN_RC} ${GIT2INTERNAL_OBJECTS})
+TARGET_LINK_LIBRARIES(git2 ${LIBGIT2_LIBS})
+
+SET_TARGET_PROPERTIES(git2 PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
+SET_TARGET_PROPERTIES(git2 PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
+SET_TARGET_PROPERTIES(git2 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
+
+# Workaround for Cmake bug #0011240 (see http://public.kitware.com/Bug/view.php?id=11240)
+# Win64+MSVC+static libs = linker error
+IF(MSVC AND GIT_ARCH_64 AND NOT BUILD_SHARED_LIBS)
+ SET_TARGET_PROPERTIES(git2 PROPERTIES STATIC_LIBRARY_FLAGS "/MACHINE:x64")
+ENDIF()
+
+IDE_SPLIT_SOURCES(git2)
+
+IF (SONAME)
+ SET_TARGET_PROPERTIES(git2 PROPERTIES VERSION ${LIBGIT2_VERSION_STRING})
+ SET_TARGET_PROPERTIES(git2 PROPERTIES SOVERSION ${LIBGIT2_SOVERSION})
+ IF (LIBGIT2_FILENAME)
+ ADD_DEFINITIONS(-DLIBGIT2_FILENAME=\"${LIBGIT2_FILENAME}\")
+ SET_TARGET_PROPERTIES(git2 PROPERTIES OUTPUT_NAME ${LIBGIT2_FILENAME})
+ ELSEIF (DEFINED LIBGIT2_PREFIX)
+ SET_TARGET_PROPERTIES(git2 PROPERTIES PREFIX "${LIBGIT2_PREFIX}")
+ ENDIF()
+ENDIF()
+STRING(REPLACE ";" " " LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS}")
+CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/libgit2.pc.in ${CMAKE_BINARY_DIR}/libgit2.pc @ONLY)
+
+IF (MSVC_IDE)
+ # Precompiled headers
+ SET_TARGET_PROPERTIES(git2 PROPERTIES COMPILE_FLAGS "/Yuprecompiled.h /FIprecompiled.h")
+ SET_SOURCE_FILES_PROPERTIES(win32/precompiled.c COMPILE_FLAGS "/Ycprecompiled.h")
+ENDIF ()
+
+# Install
+INSTALL(TARGETS git2
+ RUNTIME DESTINATION ${BIN_INSTALL_DIR}
+ LIBRARY DESTINATION ${LIB_INSTALL_DIR}
+ ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
+)
+INSTALL(FILES ${CMAKE_BINARY_DIR}/libgit2.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig )
+INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/include/git2 DESTINATION ${INCLUDE_INSTALL_DIR} )
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/include/git2.h DESTINATION ${INCLUDE_INSTALL_DIR} )
diff --git a/src/annotated_commit.c b/src/annotated_commit.c
index c2c770cba..72ba80a22 100644
--- a/src/annotated_commit.c
+++ b/src/annotated_commit.c
@@ -5,8 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
#include "annotated_commit.h"
+
#include "refs.h"
#include "cache.h"
diff --git a/src/annotated_commit.h b/src/annotated_commit.h
index 3ac8b5f69..b390066b2 100644
--- a/src/annotated_commit.h
+++ b/src/annotated_commit.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_annotated_commit_h__
#define INCLUDE_annotated_commit_h__
+#include "common.h"
+
#include "oidarray.h"
#include "git2/oid.h"
diff --git a/src/apply.c b/src/apply.c
index f70172469..7801a0a54 100644
--- a/src/apply.c
+++ b/src/apply.c
@@ -5,6 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "apply.h"
+
#include <assert.h>
#include "git2/patch.h"
@@ -12,7 +14,6 @@
#include "array.h"
#include "patch.h"
#include "fileops.h"
-#include "apply.h"
#include "delta.h"
#include "zstream.h"
@@ -173,7 +174,7 @@ static int apply_hunk(
git_diff_line *line = git_array_get(patch->lines, linenum);
if (!line) {
- error = apply_err("Preimage does not contain line %d", linenum);
+ error = apply_err("preimage does not contain line %"PRIuZ, linenum);
goto done;
}
@@ -193,7 +194,7 @@ static int apply_hunk(
line_num = hunk->hunk.new_start ? hunk->hunk.new_start - 1 : 0;
if (!find_hunk_linenum(&line_num, image, &preimage, line_num)) {
- error = apply_err("Hunk at line %d did not apply",
+ error = apply_err("hunk at line %d did not apply",
hunk->hunk.new_start);
goto done;
}
diff --git a/src/apply.h b/src/apply.h
index 96e0f55b5..b29460c0b 100644
--- a/src/apply.h
+++ b/src/apply.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_apply_h__
#define INCLUDE_apply_h__
+#include "common.h"
+
#include "git2/patch.h"
#include "buffer.h"
diff --git a/src/attr.c b/src/attr.c
index d43a15f50..17309d0eb 100644
--- a/src/attr.c
+++ b/src/attr.c
@@ -1,4 +1,12 @@
-#include "common.h"
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "attr.h"
+
#include "repository.h"
#include "sysdir.h"
#include "config.h"
@@ -7,8 +15,6 @@
#include "git2/oid.h"
#include <ctype.h>
-GIT__USE_STRMAP
-
const char *git_attr__true = "[internal]__TRUE__";
const char *git_attr__false = "[internal]__FALSE__";
const char *git_attr__unset = "[internal]__UNSET__";
@@ -209,7 +215,7 @@ int git_attr_foreach(
if (git_strmap_exists(seen, assign->name))
continue;
- git_strmap_insert(seen, assign->name, assign, error);
+ git_strmap_insert(seen, assign->name, assign, &error);
if (error < 0)
goto cleanup;
@@ -292,7 +298,7 @@ static int attr_setup(git_repository *repo, git_attr_session *attr_session)
int error = 0;
const char *workdir = git_repository_workdir(repo);
git_index *idx = NULL;
- git_buf sys = GIT_BUF_INIT;
+ git_buf path = GIT_BUF_INIT;
if (attr_session && attr_session->init_setup)
return 0;
@@ -304,40 +310,45 @@ static int attr_setup(git_repository *repo, git_attr_session *attr_session)
* definitions will be available for later file parsing
*/
- error = system_attr_file(&sys, attr_session);
+ error = system_attr_file(&path, attr_session);
if (error == 0)
error = preload_attr_file(
- repo, attr_session, GIT_ATTR_FILE__FROM_FILE, NULL, sys.ptr);
+ repo, attr_session, GIT_ATTR_FILE__FROM_FILE, NULL, path.ptr);
if (error != GIT_ENOTFOUND)
- return error;
-
- git_buf_free(&sys);
+ goto out;
if ((error = preload_attr_file(
repo, attr_session, GIT_ATTR_FILE__FROM_FILE,
NULL, git_repository_attr_cache(repo)->cfg_attr_file)) < 0)
- return error;
+ goto out;
+
+ if ((error = git_repository_item_path(&path,
+ repo, GIT_REPOSITORY_ITEM_INFO)) < 0)
+ goto out;
if ((error = preload_attr_file(
repo, attr_session, GIT_ATTR_FILE__FROM_FILE,
- git_repository_path(repo), GIT_ATTR_FILE_INREPO)) < 0)
- return error;
+ path.ptr, GIT_ATTR_FILE_INREPO)) < 0)
+ goto out;
if (workdir != NULL &&
(error = preload_attr_file(
repo, attr_session, GIT_ATTR_FILE__FROM_FILE, workdir, GIT_ATTR_FILE)) < 0)
- return error;
+ goto out;
if ((error = git_repository_index__weakptr(&idx, repo)) < 0 ||
(error = preload_attr_file(
repo, attr_session, GIT_ATTR_FILE__FROM_INDEX, NULL, GIT_ATTR_FILE)) < 0)
- return error;
+ goto out;
if (attr_session)
attr_session->init_setup = 1;
+out:
+ git_buf_free(&path);
+
return error;
}
@@ -472,7 +483,7 @@ static int collect_attr_files(
git_vector *files)
{
int error = 0;
- git_buf dir = GIT_BUF_INIT;
+ git_buf dir = GIT_BUF_INIT, attrfile = GIT_BUF_INIT;
const char *workdir = git_repository_workdir(repo);
attr_walk_up_info info = { NULL };
@@ -494,9 +505,13 @@ static int collect_attr_files(
* - $GIT_PREFIX/etc/gitattributes
*/
+ error = git_repository_item_path(&attrfile, repo, GIT_REPOSITORY_ITEM_INFO);
+ if (error < 0)
+ goto cleanup;
+
error = push_attr_file(
repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE,
- git_repository_path(repo), GIT_ATTR_FILE_INREPO);
+ attrfile.ptr, GIT_ATTR_FILE_INREPO);
if (error < 0)
goto cleanup;
@@ -538,6 +553,7 @@ static int collect_attr_files(
cleanup:
if (error < 0)
release_attr_files(files);
+ git_buf_free(&attrfile);
git_buf_free(&dir);
return error;
diff --git a/src/attr.h b/src/attr.h
index f9f216d07..977565205 100644
--- a/src/attr.h
+++ b/src/attr.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_attr_h__
#define INCLUDE_attr_h__
+#include "common.h"
+
#include "attr_file.h"
#include "attrcache.h"
diff --git a/src/attr_file.c b/src/attr_file.c
index 11d149358..55d0c3865 100644
--- a/src/attr_file.c
+++ b/src/attr_file.c
@@ -1,7 +1,14 @@
-#include "common.h"
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "attr_file.h"
+
#include "repository.h"
#include "filebuf.h"
-#include "attr_file.h"
#include "attrcache.h"
#include "git2/blob.h"
#include "git2/tree.h"
@@ -30,7 +37,7 @@ int git_attr_file__new(
GITERR_CHECK_ALLOC(attrs);
if (git_mutex_init(&attrs->lock) < 0) {
- giterr_set(GITERR_OS, "Failed to initialize lock");
+ giterr_set(GITERR_OS, "failed to initialize lock");
git__free(attrs);
return -1;
}
@@ -49,7 +56,7 @@ int git_attr_file__clear_rules(git_attr_file *file, bool need_lock)
git_attr_rule *rule;
if (need_lock && git_mutex_lock(&file->lock) < 0) {
- giterr_set(GITERR_OS, "Failed to lock attribute file");
+ giterr_set(GITERR_OS, "failed to lock attribute file");
return -1;
}
@@ -140,7 +147,7 @@ int git_attr_file__load(
break;
}
default:
- giterr_set(GITERR_INVALID, "Unknown file source %d", source);
+ giterr_set(GITERR_INVALID, "unknown file source %d", source);
return -1;
}
@@ -212,7 +219,7 @@ int git_attr_file__out_of_date(
}
default:
- giterr_set(GITERR_INVALID, "Invalid file type %d", file->source);
+ giterr_set(GITERR_INVALID, "invalid file type %d", file->source);
return -1;
}
}
@@ -238,7 +245,7 @@ int git_attr_file__parse_buffer(
context = attrs->entry->path;
if (git_mutex_lock(&attrs->lock) < 0) {
- giterr_set(GITERR_OS, "Failed to lock attribute file");
+ giterr_set(GITERR_OS, "failed to lock attribute file");
return -1;
}
@@ -395,9 +402,13 @@ bool git_attr_fnmatch__match(
if ((match->flags & GIT_ATTR_FNMATCH_DIRECTORY) && !path->is_dir) {
bool samename;
- /* for attribute checks or root ignore checks, fail match */
+ /*
+ * for attribute checks or checks at the root of this match's
+ * containing_dir (or root of the repository if no containing_dir),
+ * do not match.
+ */
if (!(match->flags & GIT_ATTR_FNMATCH_IGNORE) ||
- path->basename == path->path)
+ path->basename == relpath)
return false;
flags |= FNM_LEADING_DIR;
diff --git a/src/attr_file.h b/src/attr_file.h
index 388ecf4c0..fedf55af5 100644
--- a/src/attr_file.h
+++ b/src/attr_file.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_attr_file_h__
#define INCLUDE_attr_file_h__
+#include "common.h"
+
#include "git2/oid.h"
#include "git2/attr.h"
#include "vector.h"
@@ -15,7 +17,7 @@
#include "fileops.h"
#define GIT_ATTR_FILE ".gitattributes"
-#define GIT_ATTR_FILE_INREPO "info/attributes"
+#define GIT_ATTR_FILE_INREPO "attributes"
#define GIT_ATTR_FILE_SYSTEM "gitattributes"
#define GIT_ATTR_FILE_XDG "attributes"
diff --git a/src/attrcache.c b/src/attrcache.c
index a57110684..65e7b4655 100644
--- a/src/attrcache.c
+++ b/src/attrcache.c
@@ -1,18 +1,24 @@
-#include "common.h"
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "attrcache.h"
+
#include "repository.h"
#include "attr_file.h"
#include "config.h"
#include "sysdir.h"
#include "ignore.h"
-GIT__USE_STRMAP
-
GIT_INLINE(int) attr_cache_lock(git_attr_cache *cache)
{
GIT_UNUSED(cache); /* avoid warning if threading is off */
if (git_mutex_lock(&cache->lock) < 0) {
- giterr_set(GITERR_OS, "Unable to get attr cache lock");
+ giterr_set(GITERR_OS, "unable to get attr cache lock");
return -1;
}
return 0;
@@ -82,7 +88,7 @@ static int attr_cache_make_entry(
&entry, git_repository_workdir(repo), path, &cache->pool);
if (!error) {
- git_strmap_insert(cache->files, entry->path, entry, error);
+ git_strmap_insert(cache->files, entry->path, entry, &error);
if (error > 0)
error = 0;
}
@@ -105,8 +111,11 @@ static int attr_cache_upsert(git_attr_cache *cache, git_attr_file *file)
GIT_REFCOUNT_OWN(file, entry);
GIT_REFCOUNT_INC(file);
- old = git__compare_and_swap(
- &entry->file[file->source], entry->file[file->source], file);
+ /*
+ * Replace the existing value if another thread has
+ * created it in the meantime.
+ */
+ old = git__swap(entry->file[file->source], file);
if (old) {
GIT_REFCOUNT_OWN(old, NULL);
@@ -121,20 +130,22 @@ static int attr_cache_remove(git_attr_cache *cache, git_attr_file *file)
{
int error = 0;
git_attr_file_entry *entry;
+ git_attr_file *old = NULL;
if (!file)
return 0;
+
if ((error = attr_cache_lock(cache)) < 0)
return error;
if ((entry = attr_cache_lookup_entry(cache, file->entry->path)) != NULL)
- file = git__compare_and_swap(&entry->file[file->source], file, NULL);
+ old = git__compare_and_swap(&entry->file[file->source], file, NULL);
attr_cache_unlock(cache);
- if (file) {
- GIT_REFCOUNT_OWN(file, NULL);
- git_attr_file__free(file);
+ if (old) {
+ GIT_REFCOUNT_OWN(old, NULL);
+ git_attr_file__free(old);
}
return error;
@@ -287,14 +298,16 @@ static int attr_cache__lookup_path(
const char *cfgval = entry->value;
/* expand leading ~/ as needed */
- if (cfgval && cfgval[0] == '~' && cfgval[1] == '/' &&
- !git_sysdir_find_global_file(&buf, &cfgval[2]))
- *out = git_buf_detach(&buf);
- else if (cfgval)
+ if (cfgval && cfgval[0] == '~' && cfgval[1] == '/') {
+ if (! (error = git_sysdir_expand_global_file(&buf, &cfgval[2])))
+ *out = git_buf_detach(&buf);
+ } else if (cfgval) {
*out = git__strdup(cfgval);
+ }
}
- else if (!git_sysdir_find_xdg_file(&buf, fallback))
+ else if (!git_sysdir_find_xdg_file(&buf, fallback)) {
*out = git_buf_detach(&buf);
+ }
git_config_entry_free(entry);
git_buf_free(&buf);
@@ -309,7 +322,7 @@ static void attr_cache__free(git_attr_cache *cache)
if (!cache)
return;
- unlock = (git_mutex_lock(&cache->lock) == 0);
+ unlock = (attr_cache_lock(cache) == 0);
if (cache->files != NULL) {
git_attr_file_entry *entry;
@@ -345,13 +358,13 @@ static void attr_cache__free(git_attr_cache *cache)
cache->cfg_excl_file = NULL;
if (unlock)
- git_mutex_unlock(&cache->lock);
+ attr_cache_unlock(cache);
git_mutex_free(&cache->lock);
git__free(cache);
}
-int git_attr_cache__do_init(git_repository *repo)
+int git_attr_cache__init(git_repository *repo)
{
int ret = 0;
git_attr_cache *cache = git_repository_attr_cache(repo);
@@ -365,7 +378,7 @@ int git_attr_cache__do_init(git_repository *repo)
/* set up lock */
if (git_mutex_init(&cache->lock) < 0) {
- giterr_set(GITERR_OS, "Unable to initialize lock for attr cache");
+ giterr_set(GITERR_OS, "unable to initialize lock for attr cache");
git__free(cache);
return -1;
}
@@ -429,11 +442,11 @@ int git_attr_cache__insert_macro(git_repository *repo, git_attr_rule *macro)
if (macro->assigns.length == 0)
return 0;
- if (git_mutex_lock(&cache->lock) < 0) {
- giterr_set(GITERR_OS, "Unable to get attr cache lock");
+ if (attr_cache_lock(cache) < 0) {
+ giterr_set(GITERR_OS, "unable to get attr cache lock");
error = -1;
} else {
- git_strmap_insert(macros, macro->match.pattern, macro, error);
+ git_strmap_insert(macros, macro->match.pattern, macro, &error);
git_mutex_unlock(&cache->lock);
}
diff --git a/src/attrcache.h b/src/attrcache.h
index 44e1ffdce..f528911ea 100644
--- a/src/attrcache.h
+++ b/src/attrcache.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_attrcache_h__
#define INCLUDE_attrcache_h__
+#include "common.h"
+
#include "attr_file.h"
#include "strmap.h"
@@ -22,10 +24,7 @@ typedef struct {
git_pool pool;
} git_attr_cache;
-extern int git_attr_cache__do_init(git_repository *repo);
-
-#define git_attr_cache__init(REPO) \
- (git_repository_attr_cache(REPO) ? 0 : git_attr_cache__do_init(REPO))
+extern int git_attr_cache__init(git_repository *repo);
/* get file - loading and reload as needed */
extern int git_attr_cache__get(
diff --git a/src/blame.c b/src/blame.c
index 2c8584ba5..a923bf003 100644
--- a/src/blame.c
+++ b/src/blame.c
@@ -6,6 +6,7 @@
*/
#include "blame.h"
+
#include "git2/commit.h"
#include "git2/revparse.h"
#include "git2/revwalk.h"
diff --git a/src/blame.h b/src/blame.h
index d8db8d5c1..8fd3ee5b1 100644
--- a/src/blame.h
+++ b/src/blame.h
@@ -1,8 +1,9 @@
#ifndef INCLUDE_blame_h__
#define INCLUDE_blame_h__
-#include "git2/blame.h"
#include "common.h"
+
+#include "git2/blame.h"
#include "vector.h"
#include "diff.h"
#include "array.h"
diff --git a/src/blame_git.c b/src/blame_git.c
index 96785c75b..3c221b318 100644
--- a/src/blame_git.c
+++ b/src/blame_git.c
@@ -6,6 +6,7 @@
*/
#include "blame_git.h"
+
#include "commit.h"
#include "blob.h"
#include "xdiff/xinclude.h"
@@ -478,14 +479,15 @@ cleanup:
* The blobs of origin and porigin exactly match, so everything origin is
* suspected for can be blamed on the parent.
*/
-static void pass_whole_blame(git_blame *blame,
+static int pass_whole_blame(git_blame *blame,
git_blame__origin *origin, git_blame__origin *porigin)
{
git_blame__entry *e;
- if (!porigin->blob)
- git_object_lookup((git_object**)&porigin->blob, blame->repository,
- git_blob_id(origin->blob), GIT_OBJ_BLOB);
+ if (!porigin->blob &&
+ git_object_lookup((git_object**)&porigin->blob, blame->repository,
+ git_blob_id(origin->blob), GIT_OBJ_BLOB) < 0)
+ return -1;
for (e=blame->ent; e; e=e->next) {
if (!same_suspect(e->suspect, origin))
continue;
@@ -493,6 +495,8 @@ static void pass_whole_blame(git_blame *blame,
origin_decref(e->suspect);
e->suspect = porigin;
}
+
+ return 0;
}
static int pass_blame(git_blame *blame, git_blame__origin *origin, uint32_t opt)
@@ -514,11 +518,12 @@ static int pass_blame(git_blame *blame, git_blame__origin *origin, uint32_t opt)
if (!num_parents) {
git_oid_cpy(&blame->options.oldest_commit, git_commit_id(commit));
goto finish;
- }
- else if (num_parents < (int)ARRAY_SIZE(sg_buf))
+ } else if (num_parents < (int)ARRAY_SIZE(sg_buf))
memset(sg_buf, 0, sizeof(sg_buf));
- else
+ else {
sg_origin = git__calloc(num_parents, sizeof(*sg_origin));
+ GITERR_CHECK_ALLOC(sg_origin);
+ }
for (i=0; i<num_parents; i++) {
git_commit *p;
@@ -543,7 +548,7 @@ static int pass_blame(git_blame *blame, git_blame__origin *origin, uint32_t opt)
}
if (porigin->blob && origin->blob &&
!git_oid_cmp(git_blob_id(porigin->blob), git_blob_id(origin->blob))) {
- pass_whole_blame(blame, origin, porigin);
+ error = pass_whole_blame(blame, origin, porigin);
origin_decref(porigin);
goto finish;
}
diff --git a/src/blame_git.h b/src/blame_git.h
index 1891b0e1f..48b85a20d 100644
--- a/src/blame_git.h
+++ b/src/blame_git.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_blame_git__
#define INCLUDE_blame_git__
+#include "common.h"
+
#include "blame.h"
int git_blame__get_origin(
diff --git a/src/blob.c b/src/blob.c
index 1926c9e58..3396fe74f 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -5,14 +5,14 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "blob.h"
+
#include "git2/common.h"
#include "git2/object.h"
#include "git2/repository.h"
#include "git2/odb_backend.h"
-#include "common.h"
#include "filebuf.h"
-#include "blob.h"
#include "filter.h"
#include "buf_text.h"
@@ -96,7 +96,7 @@ static int write_file_stream(
p_close(fd);
if (written != file_size || read_len < 0) {
- giterr_set(GITERR_OS, "Failed to read file into stream");
+ giterr_set(GITERR_OS, "failed to read file into stream");
error = -1;
}
@@ -142,7 +142,7 @@ static int write_symlink(
read_len = p_readlink(path, link_data, link_size);
if (read_len != (ssize_t)link_size) {
- giterr_set(GITERR_OS, "Failed to create blob. Can't read symlink '%s'", path);
+ giterr_set(GITERR_OS, "failed to create blob: cannot read symlink '%s'", path);
git__free(link_data);
return -1;
}
@@ -186,7 +186,7 @@ int git_blob__create_from_paths(
goto done;
if (S_ISDIR(st.st_mode)) {
- giterr_set(GITERR_ODB, "cannot create blob from '%s'; it is a directory", content_path);
+ giterr_set(GITERR_ODB, "cannot create blob from '%s': it is a directory", content_path);
error = GIT_EDIRECTORY;
goto done;
}
@@ -326,8 +326,8 @@ int git_blob_create_fromstream(git_writestream **out, git_repository *repo, cons
stream->parent.close = blob_writestream_close;
stream->parent.free = blob_writestream_free;
- if ((error = git_buf_joinpath(&path,
- git_repository_path(repo), GIT_OBJECTS_DIR "streamed")) < 0)
+ if ((error = git_repository_item_path(&path, repo, GIT_REPOSITORY_ITEM_OBJECTS)) < 0
+ || (error = git_buf_joinpath(&path, path.ptr, "streamed")) < 0)
goto cleanup;
if ((error = git_filebuf_open_withsize(&stream->fbuf, git_buf_cstr(&path), GIT_FILEBUF_TEMPORARY,
diff --git a/src/blob.h b/src/blob.h
index 4cd9f1e0c..3f1f97719 100644
--- a/src/blob.h
+++ b/src/blob.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_blob_h__
#define INCLUDE_blob_h__
+#include "common.h"
+
#include "git2/blob.h"
#include "repository.h"
#include "odb.h"
diff --git a/src/branch.c b/src/branch.c
index 51c35d7ff..0697a77fb 100644
--- a/src/branch.c
+++ b/src/branch.c
@@ -5,7 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+#include "branch.h"
+
#include "commit.h"
#include "tag.h"
#include "config.h"
@@ -13,6 +14,7 @@
#include "refs.h"
#include "remote.h"
#include "annotated_commit.h"
+#include "worktree.h"
#include "git2/branch.h"
@@ -33,7 +35,7 @@ static int retrieve_branch_reference(
/* OOM */;
else if ((error = git_reference_lookup(&branch, repo, ref_name.ptr)) < 0)
giterr_set(
- GITERR_REFERENCE, "Cannot locate %s branch '%s'",
+ GITERR_REFERENCE, "cannot locate %s branch '%s'",
is_remote ? "remote-tracking" : "local", branch_name);
*branch_reference_out = branch; /* will be NULL on error */
@@ -46,7 +48,7 @@ static int not_a_local_branch(const char *reference_name)
{
giterr_set(
GITERR_INVALID,
- "Reference '%s' is not a local branch.", reference_name);
+ "reference '%s' is not a local branch.", reference_name);
return -1;
}
@@ -58,16 +60,17 @@ static int create_branch(
const char *from,
int force)
{
- int is_head = 0;
+ int is_unmovable_head = 0;
git_reference *branch = NULL;
git_buf canonical_branch_name = GIT_BUF_INIT,
log_message = GIT_BUF_INIT;
int error = -1;
+ int bare = git_repository_is_bare(repository);
assert(branch_name && commit && ref_out);
assert(git_object_owner((const git_object *)commit) == repository);
- if (force && git_branch_lookup(&branch, repository, branch_name, GIT_BRANCH_LOCAL) == 0) {
+ if (force && !bare && git_branch_lookup(&branch, repository, branch_name, GIT_BRANCH_LOCAL) == 0) {
error = git_branch_is_head(branch);
git_reference_free(branch);
branch = NULL;
@@ -75,11 +78,11 @@ static int create_branch(
if (error < 0)
goto cleanup;
- is_head = error;
+ is_unmovable_head = error;
}
- if (is_head && force) {
- giterr_set(GITERR_REFERENCE, "Cannot force update branch '%s' as it is "
+ if (is_unmovable_head && force) {
+ giterr_set(GITERR_REFERENCE, "cannot force update branch '%s' as it is "
"the current HEAD of the repository.", branch_name);
error = -1;
goto cleanup;
@@ -125,6 +128,31 @@ int git_branch_create_from_annotated(
repository, branch_name, commit->commit, commit->description, force);
}
+static int branch_equals(git_repository *repo, const char *path, void *payload)
+{
+ git_reference *branch = (git_reference *) payload;
+ git_reference *head = NULL;
+ int equal = 0;
+
+ if (git_reference__read_head(&head, repo, path) < 0 ||
+ git_reference_type(head) != GIT_REF_SYMBOLIC)
+ goto done;
+
+ equal = !git__strcmp(head->target.symbolic, branch->name);
+
+done:
+ git_reference_free(head);
+ return equal;
+}
+
+int git_branch_is_checked_out(const git_reference *branch)
+{
+ assert(branch && git_reference_is_branch(branch));
+
+ return git_repository_foreach_head(git_reference_owner(branch),
+ branch_equals, (void *) branch) == 1;
+}
+
int git_branch_delete(git_reference *branch)
{
int is_head;
@@ -134,7 +162,7 @@ int git_branch_delete(git_reference *branch)
assert(branch);
if (!git_reference_is_branch(branch) && !git_reference_is_remote(branch)) {
- giterr_set(GITERR_INVALID, "Reference '%s' is not a valid branch.",
+ giterr_set(GITERR_INVALID, "reference '%s' is not a valid branch.",
git_reference_name(branch));
return GIT_ENOTFOUND;
}
@@ -143,11 +171,17 @@ int git_branch_delete(git_reference *branch)
return is_head;
if (is_head) {
- giterr_set(GITERR_REFERENCE, "Cannot delete branch '%s' as it is "
+ giterr_set(GITERR_REFERENCE, "cannot delete branch '%s' as it is "
"the current HEAD of the repository.", git_reference_name(branch));
return -1;
}
+ if (git_reference_is_branch(branch) && git_branch_is_checked_out(branch)) {
+ giterr_set(GITERR_REFERENCE, "Cannot delete branch '%s' as it is "
+ "the current HEAD of a linked repository.", git_reference_name(branch));
+ return -1;
+ }
+
if (git_buf_join(&config_section, '.', "branch",
git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0)
goto on_error;
@@ -305,7 +339,7 @@ int git_branch_name(
branch_name += strlen(GIT_REFS_REMOTES_DIR);
} else {
giterr_set(GITERR_INVALID,
- "Reference '%s' is neither a local nor a remote branch.", ref->name);
+ "reference '%s' is neither a local nor a remote branch.", ref->name);
return -1;
}
*out = branch_name;
@@ -435,7 +469,7 @@ int git_branch_remote_name(git_buf *buf, git_repository *repo, const char *refna
/* Verify that this is a remote branch */
if (!git_reference__is_remote(refname)) {
- giterr_set(GITERR_INVALID, "Reference '%s' is not a remote branch.",
+ giterr_set(GITERR_INVALID, "reference '%s' is not a remote branch.",
refname);
error = GIT_ERROR;
goto cleanup;
@@ -462,7 +496,7 @@ int git_branch_remote_name(git_buf *buf, git_repository *repo, const char *refna
git_remote_free(remote);
giterr_set(GITERR_REFERENCE,
- "Reference '%s' is ambiguous", refname);
+ "reference '%s' is ambiguous", refname);
error = GIT_EAMBIGUOUS;
goto cleanup;
}
@@ -476,7 +510,7 @@ int git_branch_remote_name(git_buf *buf, git_repository *repo, const char *refna
error = git_buf_puts(buf, remote_name);
} else {
giterr_set(GITERR_REFERENCE,
- "Could not determine remote for '%s'", refname);
+ "could not determine remote for '%s'", refname);
error = GIT_ENOTFOUND;
}
@@ -565,7 +599,7 @@ int git_branch_set_upstream(git_reference *branch, const char *upstream_name)
local = 0;
else {
giterr_set(GITERR_REFERENCE,
- "Cannot set upstream for branch '%s'", shortname);
+ "cannot set upstream for branch '%s'", shortname);
return GIT_ENOTFOUND;
}
diff --git a/src/branch.h b/src/branch.h
index d02f2af0d..5ae227c05 100644
--- a/src/branch.h
+++ b/src/branch.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_branch_h__
#define INCLUDE_branch_h__
+#include "common.h"
+
#include "buffer.h"
int git_branch_upstream__name(
diff --git a/src/buf_text.h b/src/buf_text.h
index c9c55af89..163bef1ad 100644
--- a/src/buf_text.h
+++ b/src/buf_text.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_buf_text_h__
#define INCLUDE_buf_text_h__
+#include "common.h"
+
#include "buffer.h"
typedef enum {
diff --git a/src/buffer.c b/src/buffer.c
index d135ebe4a..6dfcbfbe6 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -18,18 +18,19 @@ char git_buf__initbuf[1];
char git_buf__oom[1];
#define ENSURE_SIZE(b, d) \
- if ((d) > buf->asize && git_buf_grow(b, (d)) < 0)\
+ if ((d) > (b)->asize && git_buf_grow((b), (d)) < 0)\
return -1;
-void git_buf_init(git_buf *buf, size_t initial_size)
+int git_buf_init(git_buf *buf, size_t initial_size)
{
buf->asize = 0;
buf->size = 0;
buf->ptr = git_buf__initbuf;
- if (initial_size)
- git_buf_grow(buf, initial_size);
+ ENSURE_SIZE(buf, initial_size);
+
+ return 0;
}
int git_buf_try_grow(
@@ -577,7 +578,7 @@ char *git_buf_detach(git_buf *buf)
return data;
}
-void git_buf_attach(git_buf *buf, char *ptr, size_t asize)
+int git_buf_attach(git_buf *buf, char *ptr, size_t asize)
{
git_buf_free(buf);
@@ -588,9 +589,10 @@ void git_buf_attach(git_buf *buf, char *ptr, size_t asize)
buf->asize = (asize < buf->size) ? buf->size + 1 : asize;
else /* pass 0 to fall back on strlen + 1 */
buf->asize = buf->size + 1;
- } else {
- git_buf_grow(buf, asize);
}
+
+ ENSURE_SIZE(buf, asize);
+ return 0;
}
void git_buf_attach_notowned(git_buf *buf, const char *ptr, size_t size)
@@ -724,9 +726,7 @@ int git_buf_join(
GITERR_CHECK_ALLOC_ADD(&alloc_len, strlen_a, strlen_b);
GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, need_sep);
GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 1);
- if (git_buf_grow(buf, alloc_len) < 0)
- return -1;
- assert(buf->ptr);
+ ENSURE_SIZE(buf, alloc_len);
/* fix up internal pointers */
if (offset_a >= 0)
@@ -780,8 +780,7 @@ int git_buf_join3(
GITERR_CHECK_ALLOC_ADD(&len_total, len_total, sep_b);
GITERR_CHECK_ALLOC_ADD(&len_total, len_total, len_c);
GITERR_CHECK_ALLOC_ADD(&len_total, len_total, 1);
- if (git_buf_grow(buf, len_total) < 0)
- return -1;
+ ENSURE_SIZE(buf, len_total);
tgt = buf->ptr;
@@ -962,14 +961,14 @@ int git_buf_unquote(git_buf *buf)
case '0': case '1': case '2': case '3':
if (j == buf->size-3) {
giterr_set(GITERR_INVALID,
- "Truncated quoted character \\%c", ch);
+ "truncated quoted character \\%c", ch);
return -1;
}
if (buf->ptr[j+1] < '0' || buf->ptr[j+1] > '7' ||
buf->ptr[j+2] < '0' || buf->ptr[j+2] > '7') {
giterr_set(GITERR_INVALID,
- "Truncated quoted character \\%c%c%c",
+ "truncated quoted character \\%c%c%c",
buf->ptr[j], buf->ptr[j+1], buf->ptr[j+2]);
return -1;
}
@@ -981,7 +980,7 @@ int git_buf_unquote(git_buf *buf)
break;
default:
- giterr_set(GITERR_INVALID, "Invalid quoted character \\%c", ch);
+ giterr_set(GITERR_INVALID, "invalid quoted character \\%c", ch);
return -1;
}
}
@@ -995,6 +994,6 @@ int git_buf_unquote(git_buf *buf)
return 0;
invalid:
- giterr_set(GITERR_INVALID, "Invalid quoted line");
+ giterr_set(GITERR_INVALID, "invalid quoted line");
return -1;
}
diff --git a/src/buffer.h b/src/buffer.h
index cdfca6d99..b0aece488 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -34,7 +34,7 @@ GIT_INLINE(bool) git_buf_is_allocated(const git_buf *buf)
* For the cases where GIT_BUF_INIT cannot be used to do static
* initialization.
*/
-extern void git_buf_init(git_buf *buf, size_t initial_size);
+extern int git_buf_init(git_buf *buf, size_t initial_size);
/**
* Resize the buffer allocation to make more space.
@@ -66,13 +66,14 @@ extern int git_buf_try_grow(
* library, when providing git_buf's, may wish to provide a NULL ptr for
* ease of handling. The buffer routines, however, expect a non-NULL ptr
* always. This helper method simply handles NULL input, converting to a
- * git_buf__initbuf.
+ * git_buf__initbuf. If a buffer with a non-NULL ptr is passed in, this method
+ * assures that the buffer is '\0'-terminated.
*/
extern void git_buf_sanitize(git_buf *buf);
extern void git_buf_swap(git_buf *buf_a, git_buf *buf_b);
extern char *git_buf_detach(git_buf *buf);
-extern void git_buf_attach(git_buf *buf, char *ptr, size_t asize);
+extern int git_buf_attach(git_buf *buf, char *ptr, size_t asize);
/* Populates a `git_buf` where the contents are not "owned" by the
* buffer, and calls to `git_buf_free` will not free the given buf.
diff --git a/src/cache.c b/src/cache.c
index ca5173c0d..cdd12979f 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -5,18 +5,16 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+#include "cache.h"
+
#include "repository.h"
#include "commit.h"
#include "thread-utils.h"
#include "util.h"
-#include "cache.h"
#include "odb.h"
#include "object.h"
#include "git2/oid.h"
-GIT__USE_OIDMAP
-
bool git_cache__enabled = true;
ssize_t git_cache__max_storage = (256 * 1024 * 1024);
git_atomic_ssize git_cache__current_storage = {0};
@@ -47,13 +45,13 @@ void git_cache_dump_stats(git_cache *cache)
{
git_cached_obj *object;
- if (kh_size(cache->map) == 0)
+ if (git_cache_size(cache) == 0)
return;
- printf("Cache %p: %d items cached, %"PRIdZ" bytes\n",
- cache, kh_size(cache->map), cache->used_memory);
+ printf("Cache %p: %"PRIuZ" items cached, %"PRIdZ" bytes\n",
+ cache, git_cache_size(cache), cache->used_memory);
- kh_foreach_value(cache->map, object, {
+ git_oidmap_foreach_value(cache->map, object, {
char oid_str[9];
printf(" %s%c %s (%"PRIuZ")\n",
git_object_type2string(object->type),
@@ -70,7 +68,7 @@ int git_cache_init(git_cache *cache)
cache->map = git_oidmap_alloc();
GITERR_CHECK_ALLOC(cache->map);
if (git_rwlock_init(&cache->lock)) {
- giterr_set(GITERR_OS, "Failed to initialize cache rwlock");
+ giterr_set(GITERR_OS, "failed to initialize cache rwlock");
return -1;
}
return 0;
@@ -81,14 +79,14 @@ static void clear_cache(git_cache *cache)
{
git_cached_obj *evict = NULL;
- if (kh_size(cache->map) == 0)
+ if (git_cache_size(cache) == 0)
return;
- kh_foreach_value(cache->map, evict, {
+ git_oidmap_foreach_value(cache->map, evict, {
git_cached_obj_decref(evict);
});
- kh_clear(oid, cache->map);
+ git_oidmap_clear(cache->map);
git_atomic_ssize_add(&git_cache__current_storage, -cache->used_memory);
cache->used_memory = 0;
}
@@ -119,22 +117,22 @@ static void cache_evict_entries(git_cache *cache)
ssize_t evicted_memory = 0;
/* do not infinite loop if there's not enough entries to evict */
- if (evict_count > kh_size(cache->map)) {
+ if (evict_count > git_cache_size(cache)) {
clear_cache(cache);
return;
}
while (evict_count > 0) {
- khiter_t pos = seed++ % kh_end(cache->map);
+ khiter_t pos = seed++ % git_oidmap_end(cache->map);
- if (kh_exist(cache->map, pos)) {
- git_cached_obj *evict = kh_val(cache->map, pos);
+ if (git_oidmap_has_data(cache->map, pos)) {
+ git_cached_obj *evict = git_oidmap_value_at(cache->map, pos);
evict_count--;
evicted_memory += evict->size;
git_cached_obj_decref(evict);
- kh_del(oid, cache->map, pos);
+ git_oidmap_delete_at(cache->map, pos);
}
}
@@ -156,9 +154,9 @@ static void *cache_get(git_cache *cache, const git_oid *oid, unsigned int flags)
if (!git_cache__enabled || git_rwlock_rdlock(&cache->lock) < 0)
return NULL;
- pos = kh_get(oid, cache->map, oid);
- if (pos != kh_end(cache->map)) {
- entry = kh_val(cache->map, pos);
+ pos = git_oidmap_lookup_index(cache->map, oid);
+ if (git_oidmap_valid_index(cache->map, pos)) {
+ entry = git_oidmap_value_at(cache->map, pos);
if (flags && entry->flags != flags) {
entry = NULL;
@@ -193,16 +191,14 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry)
if (git_cache__current_storage.val > git_cache__max_storage)
cache_evict_entries(cache);
- pos = kh_get(oid, cache->map, &entry->oid);
+ pos = git_oidmap_lookup_index(cache->map, &entry->oid);
/* not found */
- if (pos == kh_end(cache->map)) {
+ if (!git_oidmap_valid_index(cache->map, pos)) {
int rval;
- pos = kh_put(oid, cache->map, &entry->oid, &rval);
+ git_oidmap_insert(cache->map, &entry->oid, entry, &rval);
if (rval >= 0) {
- kh_key(cache->map, pos) = &entry->oid;
- kh_val(cache->map, pos) = entry;
git_cached_obj_incref(entry);
cache->used_memory += entry->size;
git_atomic_ssize_add(&git_cache__current_storage, (ssize_t)entry->size);
@@ -210,7 +206,7 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry)
}
/* found */
else {
- git_cached_obj *stored_entry = kh_val(cache->map, pos);
+ git_cached_obj *stored_entry = git_oidmap_value_at(cache->map, pos);
if (stored_entry->flags == entry->flags) {
git_cached_obj_decref(entry);
@@ -221,8 +217,8 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry)
git_cached_obj_decref(stored_entry);
git_cached_obj_incref(entry);
- kh_key(cache->map, pos) = &entry->oid;
- kh_val(cache->map, pos) = entry;
+ git_oidmap_set_key_at(cache->map, pos, &entry->oid);
+ git_oidmap_set_value_at(cache->map, pos, entry);
} else {
/* NO OP */
}
diff --git a/src/cache.h b/src/cache.h
index 697123739..9c09954ae 100644
--- a/src/cache.h
+++ b/src/cache.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_cache_h__
#define INCLUDE_cache_h__
+#include "common.h"
+
#include "git2/common.h"
#include "git2/oid.h"
#include "git2/odb.h"
@@ -53,7 +55,7 @@ void *git_cache_get_any(git_cache *cache, const git_oid *oid);
GIT_INLINE(size_t) git_cache_size(git_cache *cache)
{
- return (size_t)kh_size(cache->map);
+ return (size_t)git_oidmap_size(cache->map);
}
GIT_INLINE(void) git_cached_obj_incref(void *_obj)
diff --git a/src/checkout.c b/src/checkout.c
index f11102c8b..6c7a94441 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -5,10 +5,10 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include <assert.h>
-
#include "checkout.h"
+#include <assert.h>
+
#include "git2/repository.h"
#include "git2/refs.h"
#include "git2/tree.h"
@@ -35,8 +35,6 @@
#include "pool.h"
#include "strmap.h"
-GIT__USE_STRMAP
-
/* See docs/checkout-internals.md for more information */
enum {
@@ -212,6 +210,10 @@ static bool checkout_is_workdir_modified(
if (baseitem->size && wditem->file_size != baseitem->size)
return true;
+ /* if the workdir item is a directory, it cannot be a modified file */
+ if (S_ISDIR(wditem->mode))
+ return false;
+
if (git_diff__oid_for_entry(&oid, data->diff, wditem, wditem->mode, NULL) < 0)
return false;
@@ -368,10 +370,8 @@ static int checkout_action_wd_only(
*/
const git_index_entry *e = git_index_get_byindex(data->index, pos);
- if (e != NULL && data->diff->pfxcomp(e->path, wd->path) == 0) {
- notify = GIT_CHECKOUT_NOTIFY_DIRTY;
- remove = ((data->strategy & GIT_CHECKOUT_FORCE) != 0);
- }
+ if (e != NULL && data->diff->pfxcomp(e->path, wd->path) == 0)
+ return git_iterator_advance_into(wditem, workdir);
}
}
@@ -1017,13 +1017,13 @@ static int checkout_conflicts_load_byname_entry(
*theirs_out = NULL;
if (!name_entry->ancestor) {
- giterr_set(GITERR_INDEX, "A NAME entry exists without an ancestor");
+ giterr_set(GITERR_INDEX, "a NAME entry exists without an ancestor");
error = -1;
goto done;
}
if (!name_entry->ours && !name_entry->theirs) {
- giterr_set(GITERR_INDEX, "A NAME entry exists without an ours or theirs");
+ giterr_set(GITERR_INDEX, "a NAME entry exists without an ours or theirs");
error = -1;
goto done;
}
@@ -1031,7 +1031,7 @@ static int checkout_conflicts_load_byname_entry(
if ((ancestor = checkout_conflicts_search_ancestor(data,
name_entry->ancestor)) == NULL) {
giterr_set(GITERR_INDEX,
- "A NAME entry referenced ancestor entry '%s' which does not exist in the main index",
+ "a NAME entry referenced ancestor entry '%s' which does not exist in the main index",
name_entry->ancestor);
error = -1;
goto done;
@@ -1043,7 +1043,7 @@ static int checkout_conflicts_load_byname_entry(
else if ((ours = checkout_conflicts_search_branch(data, name_entry->ours)) == NULL ||
ours->ours == NULL) {
giterr_set(GITERR_INDEX,
- "A NAME entry referenced our entry '%s' which does not exist in the main index",
+ "a NAME entry referenced our entry '%s' which does not exist in the main index",
name_entry->ours);
error = -1;
goto done;
@@ -1058,7 +1058,7 @@ static int checkout_conflicts_load_byname_entry(
else if ((theirs = checkout_conflicts_search_branch(data, name_entry->theirs)) == NULL ||
theirs->theirs == NULL) {
giterr_set(GITERR_INDEX,
- "A NAME entry referenced their entry '%s' which does not exist in the main index",
+ "a NAME entry referenced their entry '%s' which does not exist in the main index",
name_entry->theirs);
error = -1;
goto done;
@@ -1157,7 +1157,7 @@ static int checkout_conflicts_mark_directoryfile(
if ((error = git_index_find(&j, index, path)) < 0) {
if (error == GIT_ENOTFOUND)
giterr_set(GITERR_INDEX,
- "Index inconsistency, could not find entry for expected conflict '%s'", path);
+ "index inconsistency, could not find entry for expected conflict '%s'", path);
goto done;
}
@@ -1165,7 +1165,7 @@ static int checkout_conflicts_mark_directoryfile(
for (; j < len; j++) {
if ((entry = git_index_get_byindex(index, j)) == NULL) {
giterr_set(GITERR_INDEX,
- "Index inconsistency, truncated index while loading expected conflict '%s'", path);
+ "index inconsistency, truncated index while loading expected conflict '%s'", path);
error = -1;
goto done;
}
@@ -1250,14 +1250,14 @@ static int checkout_verify_paths(
if (action & CHECKOUT_ACTION__REMOVE) {
if (!git_path_isvalid(repo, delta->old_file.path, flags)) {
- giterr_set(GITERR_CHECKOUT, "Cannot remove invalid path '%s'", delta->old_file.path);
+ giterr_set(GITERR_CHECKOUT, "cannot remove invalid path '%s'", delta->old_file.path);
return -1;
}
}
if (action & ~CHECKOUT_ACTION__REMOVE) {
if (!git_path_isvalid(repo, delta->new_file.path, flags)) {
- giterr_set(GITERR_CHECKOUT, "Cannot checkout to invalid path '%s'", delta->new_file.path);
+ giterr_set(GITERR_CHECKOUT, "cannot checkout to invalid path '%s'", delta->new_file.path);
return -1;
}
}
@@ -1426,7 +1426,7 @@ static int mkpath2file(
*/
error = git_futils_rmdir_r(path, NULL, GIT_RMDIR_REMOVE_FILES);
} else if (errno != ENOENT) {
- giterr_set(GITERR_OS, "Failed to stat file '%s'", path);
+ giterr_set(GITERR_OS, "failed to stat '%s'", path);
return GIT_EEXISTS;
} else {
giterr_clear();
@@ -1450,7 +1450,7 @@ static int checkout_stream_write(
int ret;
if ((ret = p_write(stream->fd, buffer, len)) < 0)
- giterr_set(GITERR_OS, "Could not write to '%s'", stream->path);
+ giterr_set(GITERR_OS, "could not write to '%s'", stream->path);
return ret;
}
@@ -1499,7 +1499,7 @@ static int blob_content_to_file(
mode = GIT_FILEMODE_BLOB;
if ((fd = p_open(path, flags, mode)) < 0) {
- giterr_set(GITERR_OS, "Could not open '%s' for writing", path);
+ giterr_set(GITERR_OS, "could not open '%s' for writing", path);
return fd;
}
@@ -1536,7 +1536,7 @@ static int blob_content_to_file(
data->perfdata.stat_calls++;
if ((error = p_stat(path, st)) < 0) {
- giterr_set(GITERR_OS, "Error statting '%s'", path);
+ giterr_set(GITERR_OS, "failed to stat '%s'", path);
return error;
}
@@ -1563,7 +1563,7 @@ static int blob_content_to_link(
if (data->can_symlink) {
if ((error = p_symlink(git_buf_cstr(&linktarget), path)) < 0)
- giterr_set(GITERR_OS, "Could not create symlink %s", path);
+ giterr_set(GITERR_OS, "could not create symlink %s", path);
} else {
error = git_futils_fake_symlink(git_buf_cstr(&linktarget), path);
}
@@ -1572,7 +1572,7 @@ static int blob_content_to_link(
data->perfdata.stat_calls++;
if ((error = p_lstat(path, st)) < 0)
- giterr_set(GITERR_CHECKOUT, "Could not stat symlink %s", path);
+ giterr_set(GITERR_CHECKOUT, "could not stat symlink %s", path);
st->st_mode = GIT_FILEMODE_LINK;
}
@@ -1617,7 +1617,7 @@ static int checkout_submodule_update_index(
data->perfdata.stat_calls++;
if (p_stat(fullpath->ptr, &st) < 0) {
giterr_set(
- GITERR_CHECKOUT, "Could not stat submodule %s\n", file->path);
+ GITERR_CHECKOUT, "could not stat submodule %s\n", file->path);
return GIT_ENOTFOUND;
}
@@ -1690,7 +1690,7 @@ static int checkout_safe_for_update_only(
return 0;
/* otherwise, stat error and no update */
- giterr_set(GITERR_OS, "Failed to stat file '%s'", path);
+ giterr_set(GITERR_OS, "failed to stat '%s'", path);
return -1;
}
@@ -1962,7 +1962,7 @@ static int checkout_path_suffixed(git_buf *path, const char *suffix)
if (i == INT_MAX) {
git_buf_truncate(path, path_len);
- giterr_set(GITERR_CHECKOUT, "Could not write '%s': working directory file exists", path);
+ giterr_set(GITERR_CHECKOUT, "could not write '%s': working directory file exists", path->ptr);
return GIT_EEXISTS;
}
@@ -2093,7 +2093,7 @@ static int checkout_write_merge(
goto done;
if (result.path == NULL || result.mode == 0) {
- giterr_set(GITERR_CHECKOUT, "Could not merge contents of file");
+ giterr_set(GITERR_CHECKOUT, "could not merge contents of file");
error = GIT_ECONFLICT;
goto done;
}
@@ -2317,8 +2317,6 @@ static void checkout_data_clear(checkout_data *data)
git__free(data->pfx);
data->pfx = NULL;
- git_strmap_free(data->mkdir_map);
-
git_buf_free(&data->target_path);
git_buf_free(&data->tmp);
@@ -2326,6 +2324,7 @@ static void checkout_data_clear(checkout_data *data)
data->index = NULL;
git_strmap_free(data->mkdir_map);
+ data->mkdir_map = NULL;
git_attr_session__free(&data->attr_session);
}
@@ -2341,7 +2340,7 @@ static int checkout_data_init(
memset(data, 0, sizeof(*data));
if (!repo) {
- giterr_set(GITERR_CHECKOUT, "Cannot checkout nothing");
+ giterr_set(GITERR_CHECKOUT, "cannot checkout nothing");
return -1;
}
@@ -2465,7 +2464,7 @@ static int checkout_data_init(
data->opts.checkout_strategy |= GIT_CHECKOUT_CONFLICT_STYLE_DIFF3;
else {
giterr_set(GITERR_CHECKOUT, "unknown style '%s' given for 'merge.conflictstyle'",
- conflict_style);
+ conflict_style->value);
error = -1;
git_config_entry_free(conflict_style);
goto cleanup;
@@ -2549,6 +2548,10 @@ int git_checkout_iterator(
GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE;
baseline_opts.start = data.pfx;
baseline_opts.end = data.pfx;
+ if (opts && (opts->checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)) {
+ baseline_opts.pathlist.count = opts->paths.count;
+ baseline_opts.pathlist.strings = opts->paths.strings;
+ }
if (data.opts.baseline_index) {
if ((error = git_iterator_for_index(
@@ -2643,7 +2646,7 @@ int git_checkout_index(
if (!index && !repo) {
giterr_set(GITERR_CHECKOUT,
- "Must provide either repository or index to checkout");
+ "must provide either repository or index to checkout");
return -1;
}
@@ -2651,7 +2654,7 @@ int git_checkout_index(
git_index_owner(index) &&
git_index_owner(index) != repo) {
giterr_set(GITERR_CHECKOUT,
- "Index to checkout does not match repository");
+ "index to checkout does not match repository");
return -1;
} else if(index && repo && !git_index_owner(index)) {
GIT_REFCOUNT_OWN(index, repo);
@@ -2690,12 +2693,12 @@ int git_checkout_tree(
if (!treeish && !repo) {
giterr_set(GITERR_CHECKOUT,
- "Must provide either repository or tree to checkout");
+ "must provide either repository or tree to checkout");
return -1;
}
if (treeish && repo && git_object_owner(treeish) != repo) {
giterr_set(GITERR_CHECKOUT,
- "Object to checkout does not match repository");
+ "object to checkout does not match repository");
return -1;
}
@@ -2705,7 +2708,7 @@ int git_checkout_tree(
if (treeish) {
if (git_object_peel((git_object **)&tree, treeish, GIT_OBJ_TREE) < 0) {
giterr_set(
- GITERR_CHECKOUT, "Provided object cannot be peeled to a tree");
+ GITERR_CHECKOUT, "provided object cannot be peeled to a tree");
return -1;
}
}
diff --git a/src/checkout.h b/src/checkout.h
index 60aa29b26..517fbf3b1 100644
--- a/src/checkout.h
+++ b/src/checkout.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_checkout_h__
#define INCLUDE_checkout_h__
+#include "common.h"
+
#include "git2/checkout.h"
#include "iterator.h"
diff --git a/src/cherrypick.c b/src/cherrypick.c
index c92975194..e42b74815 100644
--- a/src/cherrypick.c
+++ b/src/cherrypick.c
@@ -6,6 +6,7 @@
*/
#include "common.h"
+
#include "repository.h"
#include "filebuf.h"
#include "merge.h"
@@ -28,7 +29,7 @@ static int write_cherrypick_head(
git_buf file_path = GIT_BUF_INIT;
int error = 0;
- if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_CHERRYPICK_HEAD_FILE)) >= 0 &&
+ if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_CHERRYPICK_HEAD_FILE)) >= 0 &&
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_CHERRYPICK_FILE_MODE)) >= 0 &&
(error = git_filebuf_printf(&file, "%s\n", commit_oidstr)) >= 0)
error = git_filebuf_commit(&file);
@@ -49,7 +50,7 @@ static int write_merge_msg(
git_buf file_path = GIT_BUF_INIT;
int error = 0;
- if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_MSG_FILE)) < 0 ||
+ if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MSG_FILE)) < 0 ||
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_CHERRYPICK_FILE_MODE)) < 0 ||
(error = git_filebuf_printf(&file, "%s", commit_msg)) < 0)
goto cleanup;
@@ -130,13 +131,13 @@ int git_cherrypick_commit(
if (git_commit_parentcount(cherrypick_commit) > 1) {
if (!mainline)
return cherrypick_seterr(cherrypick_commit,
- "Mainline branch is not specified but %s is a merge commit");
+ "mainline branch is not specified but %s is a merge commit");
parent = mainline;
} else {
if (mainline)
return cherrypick_seterr(cherrypick_commit,
- "Mainline branch specified but %s is not a merge commit");
+ "mainline branch specified but %s is not a merge commit");
parent = git_commit_parentcount(cherrypick_commit);
}
diff --git a/src/clone.c b/src/clone.c
index 0d4756e28..8764bb728 100644
--- a/src/clone.c
+++ b/src/clone.c
@@ -5,6 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "clone.h"
+
#include <assert.h>
#include "git2/clone.h"
@@ -16,7 +18,6 @@
#include "git2/commit.h"
#include "git2/tree.h"
-#include "common.h"
#include "remote.h"
#include "fileops.h"
#include "refs.h"
@@ -513,9 +514,8 @@ static int clone_local_into(git_repository *repo, git_remote *remote, const git_
return error;
}
- git_buf_joinpath(&src_odb, git_repository_path(src), GIT_OBJECTS_DIR);
- git_buf_joinpath(&dst_odb, git_repository_path(repo), GIT_OBJECTS_DIR);
- if (git_buf_oom(&src_odb) || git_buf_oom(&dst_odb)) {
+ if (git_repository_item_path(&src_odb, src, GIT_REPOSITORY_ITEM_OBJECTS) < 0
+ || git_repository_item_path(&dst_odb, repo, GIT_REPOSITORY_ITEM_OBJECTS) < 0) {
error = -1;
goto cleanup;
}
diff --git a/src/clone.h b/src/clone.h
index 14ca5d44c..864b59029 100644
--- a/src/clone.h
+++ b/src/clone.h
@@ -7,6 +7,10 @@
#ifndef INCLUDE_clone_h__
#define INCLUDE_clone_h__
+#include "common.h"
+
+#include "git2/clone.h"
+
extern int git_clone__should_clone_local(const char *url, git_clone_local_t local);
#endif
diff --git a/src/commit.c b/src/commit.c
index 99a80855c..838688bb8 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -5,13 +5,14 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "commit.h"
+
#include "git2/common.h"
#include "git2/object.h"
#include "git2/repository.h"
#include "git2/signature.h"
#include "git2/sys/commit.h"
-#include "common.h"
#include "odb.h"
#include "commit.h"
#include "signature.h"
@@ -159,6 +160,9 @@ static int git_commit__create_internal(
if (git_repository_odb__weakptr(&odb, repo) < 0)
goto cleanup;
+ if (git_odb__freshen(odb, tree) < 0)
+ goto cleanup;
+
if (git_odb_write(id, odb, buf.ptr, buf.size, GIT_OBJ_COMMIT) < 0)
goto cleanup;
@@ -459,15 +463,16 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj)
buffer = buffer_start + header_len + 1;
/* extract commit message */
- if (buffer <= buffer_end) {
+ if (buffer <= buffer_end)
commit->raw_message = git__strndup(buffer, buffer_end - buffer);
- GITERR_CHECK_ALLOC(commit->raw_message);
- }
+ else
+ commit->raw_message = git__strdup("");
+ GITERR_CHECK_ALLOC(commit->raw_message);
return 0;
bad_buffer:
- giterr_set(GITERR_OBJECT, "Failed to parse bad commit object");
+ giterr_set(GITERR_OBJECT, "failed to parse bad commit object");
return -1;
}
@@ -597,7 +602,7 @@ int git_commit_parent(
parent_id = git_commit_parent_id(commit, n);
if (parent_id == NULL) {
- giterr_set(GITERR_INVALID, "Parent %u does not exist", n);
+ giterr_set(GITERR_INVALID, "parent %u does not exist", n);
return GIT_ENOTFOUND;
}
@@ -641,7 +646,7 @@ int git_commit_header_field(git_buf *out, const git_commit *commit, const char *
{
const char *eol, *buf = commit->raw_header;
- git_buf_sanitize(out);
+ git_buf_clear(out);
while ((eol = strchr(buf, '\n'))) {
/* We can skip continuations here */
@@ -705,8 +710,8 @@ int git_commit_extract_signature(git_buf *signature, git_buf *signed_data, git_r
const char *h, *eol;
int error;
- git_buf_sanitize(signature);
- git_buf_sanitize(signed_data);
+ git_buf_clear(signature);
+ git_buf_clear(signed_data);
if (!field)
field = "gpgsig";
@@ -765,8 +770,9 @@ int git_commit_extract_signature(git_buf *signature, git_buf *signed_data, git_r
if (git_buf_oom(signature))
goto oom;
+ error = git_buf_puts(signed_data, eol+1);
git_odb_object_free(obj);
- return git_buf_puts(signed_data, eol+1);
+ return error;
}
giterr_set(GITERR_OBJECT, "this commit is not signed");
diff --git a/src/commit.h b/src/commit.h
index d01ac2b2f..781809d70 100644
--- a/src/commit.h
+++ b/src/commit.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_commit_h__
#define INCLUDE_commit_h__
+#include "common.h"
+
#include "git2/commit.h"
#include "tree.h"
#include "repository.h"
diff --git a/src/commit_list.c b/src/commit_list.c
index 28948c88b..96bd9dc15 100644
--- a/src/commit_list.c
+++ b/src/commit_list.c
@@ -6,17 +6,22 @@
*/
#include "commit_list.h"
-#include "common.h"
+
#include "revwalk.h"
#include "pool.h"
#include "odb.h"
int git_commit_list_time_cmp(const void *a, const void *b)
{
- const git_commit_list_node *commit_a = a;
- const git_commit_list_node *commit_b = b;
+ int64_t time_a = ((git_commit_list_node *) a)->time;
+ int64_t time_b = ((git_commit_list_node *) b)->time;
+
+ if (time_a < time_b)
+ return 1;
+ if (time_a > time_b)
+ return -1;
- return (commit_a->time < commit_b->time);
+ return 0;
}
git_commit_list *git_commit_list_insert(git_commit_list_node *item, git_commit_list **list_p)
@@ -56,7 +61,7 @@ static int commit_error(git_commit_list_node *commit, const char *msg)
git_oid_fmt(commit_oid, &commit->oid);
commit_oid[GIT_OID_HEXSZ] = '\0';
- giterr_set(GITERR_ODB, "Failed to parse commit %s - %s", commit_oid, msg);
+ giterr_set(GITERR_ODB, "failed to parse commit %s - %s", commit_oid, msg);
return -1;
}
@@ -186,7 +191,7 @@ int git_commit_list_parse(git_revwalk *walk, git_commit_list_node *commit)
return error;
if (obj->cached.type != GIT_OBJ_COMMIT) {
- giterr_set(GITERR_INVALID, "Object is no commit object");
+ giterr_set(GITERR_INVALID, "object is no commit object");
error = -1;
} else
error = commit_quick_parse(
diff --git a/src/commit_list.h b/src/commit_list.h
index a6967bcef..a7551a2bc 100644
--- a/src/commit_list.h
+++ b/src/commit_list.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_commit_list_h__
#define INCLUDE_commit_list_h__
+#include "common.h"
+
#include "git2/oid.h"
#define PARENT1 (1 << 0)
@@ -28,6 +30,7 @@ typedef struct git_commit_list_node {
uninteresting:1,
topo_delay:1,
parsed:1,
+ added:1,
flags : FLAG_BITS;
unsigned short in_degree;
diff --git a/src/common.h b/src/common.h
index 51fb9186e..d3622d3eb 100644
--- a/src/common.h
+++ b/src/common.h
@@ -7,6 +7,10 @@
#ifndef INCLUDE_common_h__
#define INCLUDE_common_h__
+#ifndef LIBGIT2_NO_FEATURES_H
+# include "git2/sys/features.h"
+#endif
+
#include "git2/common.h"
#include "cc-compat.h"
@@ -47,10 +51,6 @@
# ifdef GIT_THREADS
# include "win32/thread.h"
# endif
-# if defined(GIT_MSVC_CRTDBG)
-# include "win32/w32_stack.h"
-# include "win32/w32_crtdbg_stacktrace.h"
-# endif
#else
@@ -103,7 +103,8 @@
/**
* Set the error message for this thread, formatting as needed.
*/
-void giterr_set(int error_class, const char *string, ...);
+
+void giterr_set(int error_class, const char *string, ...) GIT_FORMAT_PRINTF(2, 3);
/**
* Set the error message for a regex failure, using the internal regex
@@ -187,7 +188,7 @@ GIT_INLINE(int) giterr__check_version(const void *structure, unsigned int expect
if (actual > 0 && actual <= expected_max)
return 0;
- giterr_set(GITERR_INVALID, "Invalid version %d on %s", actual, name);
+ giterr_set(GITERR_INVALID, "invalid version %d on %s", actual, name);
return -1;
}
#define GITERR_CHECK_VERSION(S,V,N) if (giterr__check_version(S,V,N) < 0) return -1
diff --git a/src/config.c b/src/config.c
index f4d4cb2b9..602e0e827 100644
--- a/src/config.c
+++ b/src/config.c
@@ -5,9 +5,9 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
-#include "sysdir.h"
#include "config.h"
+
+#include "sysdir.h"
#include "git2/config.h"
#include "git2/sys/config.h"
#include "vector.h"
@@ -109,7 +109,7 @@ int git_config_add_file_ondisk(
res = p_stat(path, &st);
if (res < 0 && errno != ENOENT) {
- giterr_set(GITERR_CONFIG, "Error stat'ing config file '%s'", path);
+ giterr_set(GITERR_CONFIG, "failed to stat '%s'", path);
return -1;
}
@@ -203,7 +203,7 @@ static int find_internal_file_by_level(
if (pos == -1) {
giterr_set(GITERR_CONFIG,
- "No config file exists for the given level '%i'", (int)level);
+ "no config file exists for the given level '%i'", (int)level);
return GIT_ENOTFOUND;
}
@@ -218,7 +218,7 @@ static int duplicate_level(void **old_raw, void *new_raw)
GIT_UNUSED(new_raw);
- giterr_set(GITERR_CONFIG, "A file with the same level (%i) has already been added to the config", (int)(*old)->level);
+ giterr_set(GITERR_CONFIG, "a file with the same level (%i) has already been added to the config", (int)(*old)->level);
return GIT_EEXISTS;
}
@@ -478,7 +478,7 @@ int git_config_iterator_glob_new(git_config_iterator **out, const git_config *cf
iter = git__calloc(1, sizeof(all_iter));
GITERR_CHECK_ALLOC(iter);
- if ((result = regcomp(&iter->regex, regexp, REG_EXTENDED)) != 0) {
+ if ((result = p_regcomp(&iter->regex, regexp, REG_EXTENDED)) != 0) {
giterr_set_regex(&iter->regex, result);
git__free(iter);
return -1;
@@ -512,7 +512,7 @@ int git_config_backend_foreach_match(
int error = 0;
if (regexp != NULL) {
- if ((error = regcomp(&regex, regexp, REG_EXTENDED)) != 0) {
+ if ((error = p_regcomp(&regex, regexp, REG_EXTENDED)) != 0) {
giterr_set_regex(&regex, error);
regfree(&regex);
return -1;
@@ -576,22 +576,50 @@ int git_config_foreach_match(
* Setters
**************/
-static int config_error_nofiles(const char *name)
+typedef enum {
+ BACKEND_USE_SET,
+ BACKEND_USE_DELETE
+} backend_use;
+
+static const char *uses[] = {
+ "set",
+ "delete"
+};
+
+static int get_backend_for_use(git_config_backend **out,
+ git_config *cfg, const char *name, backend_use use)
{
+ size_t i;
+ file_internal *f;
+
+ *out = NULL;
+
+ if (git_vector_length(&cfg->files) == 0) {
+ giterr_set(GITERR_CONFIG,
+ "cannot %s value for '%s' when no config files exist",
+ uses[use], name);
+ return GIT_ENOTFOUND;
+ }
+
+ git_vector_foreach(&cfg->files, i, f) {
+ if (!f->file->readonly) {
+ *out = f->file;
+ return 0;
+ }
+ }
+
giterr_set(GITERR_CONFIG,
- "Cannot set value for '%s' when no config files exist", name);
+ "cannot %s value for '%s' when all config files are readonly",
+ uses[use], name);
return GIT_ENOTFOUND;
}
int git_config_delete_entry(git_config *cfg, const char *name)
{
git_config_backend *file;
- file_internal *internal;
- internal = git_vector_get(&cfg->files, 0);
- if (!internal || !internal->file)
- return config_error_nofiles(name);
- file = internal->file;
+ if (get_backend_for_use(&file, cfg, name, BACKEND_USE_DELETE) < 0)
+ return GIT_ENOTFOUND;
return file->del(file, name);
}
@@ -617,17 +645,14 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value)
{
int error;
git_config_backend *file;
- file_internal *internal;
if (!value) {
- giterr_set(GITERR_CONFIG, "The value to set cannot be NULL");
+ giterr_set(GITERR_CONFIG, "the value to set cannot be NULL");
return -1;
}
- internal = git_vector_get(&cfg->files, 0);
- if (!internal || !internal->file)
- return config_error_nofiles(name);
- file = internal->file;
+ if (get_backend_for_use(&file, cfg, name, BACKEND_USE_SET) < 0)
+ return GIT_ENOTFOUND;
error = file->set(file, name, value);
@@ -674,7 +699,7 @@ int git_config__update_entry(
static int config_error_notfound(const char *name)
{
- giterr_set(GITERR_CONFIG, "Config value '%s' was not found", name);
+ giterr_set(GITERR_CONFIG, "config value '%s' was not found", name);
return GIT_ENOTFOUND;
}
@@ -1003,7 +1028,7 @@ int git_config_multivar_iterator_new(git_config_iterator **out, const git_config
goto on_error;
if (regexp != NULL) {
- error = regcomp(&iter->regex, regexp, REG_EXTENDED);
+ error = p_regcomp(&iter->regex, regexp, REG_EXTENDED);
if (error != 0) {
giterr_set_regex(&iter->regex, error);
error = -1;
@@ -1032,12 +1057,9 @@ on_error:
int git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value)
{
git_config_backend *file;
- file_internal *internal;
- internal = git_vector_get(&cfg->files, 0);
- if (!internal || !internal->file)
- return config_error_nofiles(name);
- file = internal->file;
+ if (get_backend_for_use(&file, cfg, name, BACKEND_USE_DELETE) < 0)
+ return GIT_ENOTFOUND;
return file->set_multivar(file, name, regexp, value);
}
@@ -1045,12 +1067,9 @@ int git_config_set_multivar(git_config *cfg, const char *name, const char *regex
int git_config_delete_multivar(git_config *cfg, const char *name, const char *regexp)
{
git_config_backend *file;
- file_internal *internal;
- internal = git_vector_get(&cfg->files, 0);
- if (!internal || !internal->file)
- return config_error_nofiles(name);
- file = internal->file;
+ if (get_backend_for_use(&file, cfg, name, BACKEND_USE_DELETE) < 0)
+ return GIT_ENOTFOUND;
return file->del_multivar(file, name, regexp);
}
@@ -1236,7 +1255,7 @@ int git_config_lookup_map_value(
}
fail_parse:
- giterr_set(GITERR_CONFIG, "Failed to map '%s'", value);
+ giterr_set(GITERR_CONFIG, "failed to map '%s'", value);
return -1;
}
@@ -1270,7 +1289,7 @@ int git_config_parse_bool(int *out, const char *value)
return 0;
}
- giterr_set(GITERR_CONFIG, "Failed to parse '%s' as a boolean value", value);
+ giterr_set(GITERR_CONFIG, "failed to parse '%s' as a boolean value", value);
return -1;
}
@@ -1313,7 +1332,7 @@ int git_config_parse_int64(int64_t *out, const char *value)
}
fail_parse:
- giterr_set(GITERR_CONFIG, "Failed to parse '%s' as an integer", value ? value : "(null)");
+ giterr_set(GITERR_CONFIG, "failed to parse '%s' as an integer", value ? value : "(null)");
return -1;
}
@@ -1333,15 +1352,12 @@ int git_config_parse_int32(int32_t *out, const char *value)
return 0;
fail_parse:
- giterr_set(GITERR_CONFIG, "Failed to parse '%s' as a 32-bit integer", value ? value : "(null)");
+ giterr_set(GITERR_CONFIG, "failed to parse '%s' as a 32-bit integer", value ? value : "(null)");
return -1;
}
int git_config_parse_path(git_buf *out, const char *value)
{
- int error = 0;
- const git_buf *home;
-
assert(out && value);
git_buf_sanitize(out);
@@ -1352,16 +1368,7 @@ int git_config_parse_path(git_buf *out, const char *value)
return -1;
}
- if ((error = git_sysdir_get(&home, GIT_SYSDIR_GLOBAL)) < 0)
- return error;
-
- git_buf_sets(out, home->ptr);
- git_buf_puts(out, value + 1);
-
- if (git_buf_oom(out))
- return -1;
-
- return 0;
+ return git_sysdir_expand_global_file(out, value[1] ? &value[2] : NULL);
}
return git_buf_sets(out, value);
@@ -1398,7 +1405,7 @@ int git_config__normalize_name(const char *in, char **out)
invalid:
git__free(name);
- giterr_set(GITERR_CONFIG, "Invalid config item name '%s'", in);
+ giterr_set(GITERR_CONFIG, "invalid config item name '%s'", in);
return GIT_EINVALIDSPEC;
}
@@ -1461,7 +1468,7 @@ int git_config_rename_section(
replace.ptr, strchr(replace.ptr, '.'))) < 0)
{
giterr_set(
- GITERR_CONFIG, "Invalid config section '%s'", new_section_name);
+ GITERR_CONFIG, "invalid config section '%s'", new_section_name);
goto cleanup;
}
diff --git a/src/config.h b/src/config.h
index 00c12b50d..a5fcf2e84 100644
--- a/src/config.h
+++ b/src/config.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_config_h__
#define INCLUDE_config_h__
+#include "common.h"
+
#include "git2.h"
#include "git2/config.h"
#include "vector.h"
diff --git a/src/config_cache.c b/src/config_cache.c
index dbea871b9..0efb1a789 100644
--- a/src/config_cache.c
+++ b/src/config_cache.c
@@ -6,6 +6,7 @@
*/
#include "common.h"
+
#include "fileops.h"
#include "repository.h"
#include "config.h"
@@ -78,6 +79,7 @@ static struct map_data _cvar_maps[] = {
{"core.logallrefupdates", NULL, 0, GIT_LOGALLREFUPDATES_DEFAULT },
{"core.protecthfs", NULL, 0, GIT_PROTECTHFS_DEFAULT },
{"core.protectntfs", NULL, 0, GIT_PROTECTNTFS_DEFAULT },
+ {"core.fsyncobjectfiles", NULL, 0, GIT_FSYNCOBJECTFILES_DEFAULT },
};
int git_config__cvar(int *out, git_config *config, git_cvar_cached cvar)
diff --git a/src/config_file.c b/src/config_file.c
index e33b83738..00d6d9e13 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -5,7 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+#include "config_file.h"
+
#include "config.h"
#include "filebuf.h"
#include "sysdir.h"
@@ -21,8 +22,6 @@
#include <sys/types.h>
#include <regex.h>
-GIT__USE_STRMAP
-
typedef struct cvar_t {
struct cvar_t *next;
git_config_entry *entry;
@@ -76,9 +75,14 @@ typedef struct git_config_file_iter {
(iter) && (((tmp) = CVAR_LIST_NEXT(iter) || 1));\
(iter) = (tmp))
-struct reader {
+struct config_file {
git_oid checksum;
- char *file_path;
+ char *path;
+ git_array_t(struct config_file) includes;
+};
+
+struct reader {
+ struct config_file *file;
git_buf buffer;
char *read_ptr;
int line_number;
@@ -102,13 +106,11 @@ typedef struct {
git_config_level_t level;
- git_array_t(struct reader) readers;
-
bool locked;
git_filebuf locked_buf;
git_buf locked_content;
- char *file_path;
+ struct config_file file;
} diskfile_backend;
typedef struct {
@@ -117,7 +119,7 @@ typedef struct {
diskfile_backend *snapshot_from;
} diskfile_readonly_backend;
-static int config_read(git_strmap *values, diskfile_backend *cfg_file, struct reader *reader, git_config_level_t level, int depth);
+static int config_read(git_strmap *values, struct config_file *file, git_config_level_t level, int depth);
static int config_write(diskfile_backend *cfg, const char *key, const regex_t *preg, const char *value);
static char *escape_value(const char *ptr);
@@ -126,8 +128,8 @@ static int config_snapshot(git_config_backend **out, git_config_backend *in);
static void set_parse_error(struct reader *reader, int col, const char *error_str)
{
- giterr_set(GITERR_CONFIG, "Failed to parse config file: %s (in %s:%d, column %d)",
- error_str, reader->file_path, reader->line_number, col);
+ giterr_set(GITERR_CONFIG, "failed to parse config file: %s (in %s:%d, column %d)",
+ error_str, reader->file->path, reader->line_number, col);
}
static int config_error_readonly(void)
@@ -179,7 +181,7 @@ static int append_entry(git_strmap *values, cvar_t *var)
pos = git_strmap_lookup_index(values, var->entry->name);
if (!git_strmap_valid_index(values, pos)) {
- git_strmap_insert(values, var->entry->name, var, error);
+ git_strmap_insert(values, var->entry->name, var, &error);
} else {
existing = git_strmap_value_at(values, pos);
while (existing->next != NULL) {
@@ -233,7 +235,7 @@ static refcounted_strmap *refcounted_strmap_take(diskfile_header *h)
refcounted_strmap *map;
if (git_mutex_lock(&h->values_mutex) < 0) {
- giterr_set(GITERR_OS, "Failed to lock config backend");
+ giterr_set(GITERR_OS, "failed to lock config backend");
return NULL;
}
@@ -263,10 +265,25 @@ static int refcounted_strmap_alloc(refcounted_strmap **out)
return error;
}
+static void config_file_clear(struct config_file *file)
+{
+ struct config_file *include;
+ uint32_t i;
+
+ if (file == NULL)
+ return;
+
+ git_array_foreach(file->includes, i, include) {
+ config_file_clear(include);
+ }
+ git_array_clear(file->includes);
+
+ git__free(file->path);
+}
+
static int config_open(git_config_backend *cfg, git_config_level_t level)
{
int res;
- struct reader *reader;
diskfile_backend *b = (diskfile_backend *)cfg;
b->level = level;
@@ -274,112 +291,102 @@ static int config_open(git_config_backend *cfg, git_config_level_t level)
if ((res = refcounted_strmap_alloc(&b->header.values)) < 0)
return res;
- git_array_init(b->readers);
- reader = git_array_alloc(b->readers);
- if (!reader) {
- refcounted_strmap_free(b->header.values);
- return -1;
- }
- memset(reader, 0, sizeof(struct reader));
-
- reader->file_path = git__strdup(b->file_path);
- GITERR_CHECK_ALLOC(reader->file_path);
-
- git_buf_init(&reader->buffer, 0);
- res = git_futils_readbuffer_updated(
- &reader->buffer, b->file_path, &reader->checksum, NULL);
-
/* It's fine if the file doesn't exist */
- if (res == GIT_ENOTFOUND)
+ if (!git_path_exists(b->file.path))
return 0;
- if (res < 0 || (res = config_read(b->header.values->values, b, reader, level, 0)) < 0) {
+ if (res < 0 || (res = config_read(b->header.values->values, &b->file, level, 0)) < 0) {
refcounted_strmap_free(b->header.values);
b->header.values = NULL;
}
- reader = git_array_get(b->readers, 0);
- git_buf_free(&reader->buffer);
-
return res;
}
-/* The meat of the refresh, as we want to use it in different places */
-static int config__refresh(git_config_backend *cfg)
+static int config_is_modified(int *modified, struct config_file *file)
{
- refcounted_strmap *values = NULL, *tmp;
- diskfile_backend *b = (diskfile_backend *)cfg;
- struct reader *reader = NULL;
- int error = 0;
+ struct config_file *include;
+ git_buf buf = GIT_BUF_INIT;
+ git_oid hash;
+ uint32_t i;
+ int error;
- if ((error = refcounted_strmap_alloc(&values)) < 0)
- goto out;
+ *modified = 0;
- reader = git_array_get(b->readers, git_array_size(b->readers) - 1);
- GITERR_CHECK_ALLOC(reader);
+ if ((error = git_futils_readbuffer(&buf, file->path)) < 0)
+ goto out;
- if ((error = config_read(values->values, b, reader, b->level, 0)) < 0)
+ if ((error = git_hash_buf(&hash, buf.ptr, buf.size)) < 0)
goto out;
- if ((error = git_mutex_lock(&b->header.values_mutex)) < 0) {
- giterr_set(GITERR_OS, "Failed to lock config backend");
+ if (!git_oid_equal(&hash, &file->checksum)) {
+ *modified = 1;
goto out;
}
- tmp = b->header.values;
- b->header.values = values;
- values = tmp;
-
- git_mutex_unlock(&b->header.values_mutex);
+ git_array_foreach(file->includes, i, include) {
+ if ((error = config_is_modified(modified, include)) < 0 || *modified)
+ goto out;
+ }
out:
- refcounted_strmap_free(values);
- if (reader)
- git_buf_free(&reader->buffer);
+ git_buf_free(&buf);
+
return error;
}
static int config_refresh(git_config_backend *cfg)
{
- int error = 0, updated = 0, any_updated = 0;
diskfile_backend *b = (diskfile_backend *)cfg;
- struct reader *reader = NULL;
+ refcounted_strmap *values = NULL, *tmp;
+ struct config_file *include;
+ int error, modified;
uint32_t i;
- for (i = 0; i < git_array_size(b->readers); i++) {
- reader = git_array_get(b->readers, i);
- error = git_futils_readbuffer_updated(
- &reader->buffer, reader->file_path,
- &reader->checksum, &updated);
+ error = config_is_modified(&modified, &b->file);
+ if (error < 0 && error != GIT_ENOTFOUND)
+ goto out;
- if (error < 0 && error != GIT_ENOTFOUND)
- return error;
+ if (!modified)
+ return 0;
- if (updated)
- any_updated = 1;
+ if ((error = refcounted_strmap_alloc(&values)) < 0)
+ goto out;
+
+ /* Reparse the current configuration */
+ git_array_foreach(b->file.includes, i, include) {
+ config_file_clear(include);
}
+ git_array_clear(b->file.includes);
- if (!any_updated)
- return (error == GIT_ENOTFOUND) ? 0 : error;
+ if ((error = config_read(values->values, &b->file, b->level, 0)) < 0)
+ goto out;
- return config__refresh(cfg);
+ if ((error = git_mutex_lock(&b->header.values_mutex)) < 0) {
+ giterr_set(GITERR_OS, "failed to lock config backend");
+ goto out;
+ }
+
+ tmp = b->header.values;
+ b->header.values = values;
+ values = tmp;
+
+ git_mutex_unlock(&b->header.values_mutex);
+
+out:
+ refcounted_strmap_free(values);
+
+ return (error == GIT_ENOTFOUND) ? 0 : error;
}
static void backend_free(git_config_backend *_backend)
{
diskfile_backend *backend = (diskfile_backend *)_backend;
- uint32_t i;
if (backend == NULL)
return;
- for (i = 0; i < git_array_size(backend->readers); i++) {
- struct reader *r = git_array_get(backend->readers, i);
- git__free(r->file_path);
- }
- git_array_clear(backend->readers);
-
- git__free(backend->file_path);
+ config_file_clear(&backend->file);
refcounted_strmap_free(backend->header.values);
git_mutex_free(&backend->header.values_mutex);
git__free(backend);
@@ -479,7 +486,13 @@ static int config_set(git_config_backend *cfg, const char *name, const char *val
cvar_t *existing = git_strmap_value_at(values, pos);
if (existing->next != NULL) {
- giterr_set(GITERR_CONFIG, "Multivar incompatible with simple set");
+ giterr_set(GITERR_CONFIG, "multivar incompatible with simple set");
+ ret = -1;
+ goto out;
+ }
+
+ if (existing->included) {
+ giterr_set(GITERR_CONFIG, "modifying included variable is not supported");
ret = -1;
goto out;
}
@@ -570,7 +583,7 @@ static int config_set_multivar(
if ((result = git_config__normalize_name(name, &key)) < 0)
return result;
- result = regcomp(&preg, regexp, REG_EXTENDED);
+ result = p_regcomp(&preg, regexp, REG_EXTENDED);
if (result != 0) {
giterr_set_regex(&preg, result);
result = -1;
@@ -611,15 +624,20 @@ static int config_delete(git_config_backend *cfg, const char *name)
if (!git_strmap_valid_index(values, pos)) {
refcounted_strmap_free(map);
- giterr_set(GITERR_CONFIG, "Could not find key '%s' to delete", name);
+ giterr_set(GITERR_CONFIG, "could not find key '%s' to delete", name);
return GIT_ENOTFOUND;
}
var = git_strmap_value_at(values, pos);
refcounted_strmap_free(map);
+ if (var->included) {
+ giterr_set(GITERR_CONFIG, "cannot delete included variable");
+ return -1;
+ }
+
if (var->next != NULL) {
- giterr_set(GITERR_CONFIG, "Cannot delete multivar with a single delete");
+ giterr_set(GITERR_CONFIG, "cannot delete multivar with a single delete");
return -1;
}
@@ -651,13 +669,13 @@ static int config_delete_multivar(git_config_backend *cfg, const char *name, con
if (!git_strmap_valid_index(values, pos)) {
refcounted_strmap_free(map);
git__free(key);
- giterr_set(GITERR_CONFIG, "Could not find key '%s' to delete", name);
+ giterr_set(GITERR_CONFIG, "could not find key '%s' to delete", name);
return GIT_ENOTFOUND;
}
refcounted_strmap_free(map);
- result = regcomp(&preg, regexp, REG_EXTENDED);
+ result = p_regcomp(&preg, regexp, REG_EXTENDED);
if (result != 0) {
giterr_set_regex(&preg, result);
result = -1;
@@ -687,10 +705,10 @@ static int config_lock(git_config_backend *_cfg)
diskfile_backend *cfg = (diskfile_backend *) _cfg;
int error;
- if ((error = git_filebuf_open(&cfg->locked_buf, cfg->file_path, 0, GIT_CONFIG_FILE_MODE)) < 0)
+ if ((error = git_filebuf_open(&cfg->locked_buf, cfg->file.path, 0, GIT_CONFIG_FILE_MODE)) < 0)
return error;
- error = git_futils_readbuffer(&cfg->locked_content, cfg->file_path);
+ error = git_futils_readbuffer(&cfg->locked_content, cfg->file.path);
if (error < 0 && error != GIT_ENOTFOUND) {
git_filebuf_cleanup(&cfg->locked_buf);
return error;
@@ -728,8 +746,9 @@ int git_config_file__ondisk(git_config_backend **out, const char *path)
backend->header.parent.version = GIT_CONFIG_BACKEND_VERSION;
git_mutex_init(&backend->header.values_mutex);
- backend->file_path = git__strdup(path);
- GITERR_CHECK_ALLOC(backend->file_path);
+ backend->file.path = git__strdup(path);
+ GITERR_CHECK_ALLOC(backend->file.path);
+ git_array_init(backend->file.includes);
backend->header.parent.open = config_open;
backend->header.parent.get = config_get;
@@ -1029,7 +1048,7 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con
first_quote = strchr(line, '"');
if (first_quote == NULL) {
set_parse_error(reader, 0, "Missing quotation marks in section header");
- return -1;
+ goto end_error;
}
last_quote = strrchr(line, '"');
@@ -1037,14 +1056,15 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con
if (quoted_len == 0) {
set_parse_error(reader, 0, "Missing closing quotation mark in section header");
- return -1;
+ goto end_error;
}
GITERR_CHECK_ALLOC_ADD(&alloc_len, base_name_len, quoted_len);
GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 2);
- git_buf_grow(&buf, alloc_len);
- git_buf_printf(&buf, "%s.", base_name);
+ if (git_buf_grow(&buf, alloc_len) < 0 ||
+ git_buf_printf(&buf, "%s.", base_name) < 0)
+ goto end_error;
rpos = 0;
@@ -1060,8 +1080,7 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con
switch (c) {
case 0:
set_parse_error(reader, 0, "Unexpected end-of-line in section header");
- git_buf_free(&buf);
- return -1;
+ goto end_error;
case '"':
goto end_parse;
@@ -1071,8 +1090,7 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con
if (c == 0) {
set_parse_error(reader, rpos, "Unexpected end-of-line in section header");
- git_buf_free(&buf);
- return -1;
+ goto end_error;
}
default:
@@ -1084,6 +1102,9 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con
} while (line + rpos < last_quote);
end_parse:
+ if (git_buf_oom(&buf))
+ goto end_error;
+
if (line[rpos] != '"' || line[rpos + 1] != ']') {
set_parse_error(reader, rpos, "Unexpected text after closing quotes");
git_buf_free(&buf);
@@ -1092,6 +1113,11 @@ end_parse:
*section_name = git_buf_detach(&buf);
return 0;
+
+end_error:
+ git_buf_free(&buf);
+
+ return -1;
}
static int parse_section_header(struct reader *reader, char **section_out)
@@ -1251,7 +1277,7 @@ static int included_path(git_buf *out, const char *dir, const char *path)
{
/* From the user's home */
if (path[0] == '~' && path[1] == '/')
- return git_sysdir_find_global_file(out, &path[1]);
+ return git_sysdir_expand_global_file(out, &path[1]);
return git_path_join_unrooted(out, path, dir, NULL);
}
@@ -1262,7 +1288,7 @@ static const char *escaped = "\n\t\b\"\\";
/* Escape the values to write them to the file */
static char *escape_value(const char *ptr)
{
- git_buf buf = GIT_BUF_INIT;
+ git_buf buf;
size_t len;
const char *esc;
@@ -1272,7 +1298,8 @@ static char *escape_value(const char *ptr)
if (!len)
return git__calloc(1, sizeof(char));
- git_buf_grow(&buf, len);
+ if (git_buf_init(&buf, len) < 0)
+ return NULL;
while (*ptr != '\0') {
if ((esc = strchr(escaped, *ptr)) != NULL) {
@@ -1325,7 +1352,7 @@ static int unescape_line(
*fixed++ = escaped[esc - escapes];
} else {
git__free(str);
- giterr_set(GITERR_CONFIG, "Invalid escape at %s", ptr);
+ giterr_set(GITERR_CONFIG, "invalid escape at %s", ptr);
return -1;
}
}
@@ -1480,10 +1507,10 @@ on_error:
static int config_parse(
struct reader *reader,
- int (*on_section)(struct reader **reader, const char *current_section, const char *line, size_t line_len, void *data),
- int (*on_variable)(struct reader **reader, const char *current_section, char *var_name, char *var_value, const char *line, size_t line_len, void *data),
- int (*on_comment)(struct reader **reader, const char *line, size_t line_len, void *data),
- int (*on_eof)(struct reader **reader, const char *current_section, void *data),
+ int (*on_section)(struct reader *reader, const char *current_section, const char *line, size_t line_len, void *data),
+ int (*on_variable)(struct reader *reader, const char *current_section, char *var_name, char *var_value, const char *line, size_t line_len, void *data),
+ int (*on_comment)(struct reader *reader, const char *line, size_t line_len, void *data),
+ int (*on_eof)(struct reader *reader, const char *current_section, void *data),
void *data)
{
char *current_section = NULL, *var_name, *var_value, *line_start;
@@ -1509,7 +1536,7 @@ static int config_parse(
if ((result = parse_section_header(reader, &current_section)) == 0 && on_section) {
line_len = reader->read_ptr - line_start;
- result = on_section(&reader, current_section, line_start, line_len, data);
+ result = on_section(reader, current_section, line_start, line_len, data);
}
break;
@@ -1520,21 +1547,21 @@ static int config_parse(
if (on_comment) {
line_len = reader->read_ptr - line_start;
- result = on_comment(&reader, line_start, line_len, data);
+ result = on_comment(reader, line_start, line_len, data);
}
break;
default: /* assume variable declaration */
if ((result = parse_variable(reader, &var_name, &var_value)) == 0 && on_variable) {
line_len = reader->read_ptr - line_start;
- result = on_variable(&reader, current_section, var_name, var_value, line_start, line_len, data);
+ result = on_variable(reader, current_section, var_name, var_value, line_start, line_len, data);
}
break;
}
}
if (on_eof)
- result = on_eof(&reader, current_section, data);
+ result = on_eof(reader, current_section, data);
git__free(current_section);
return result;
@@ -1542,14 +1569,12 @@ static int config_parse(
struct parse_data {
git_strmap *values;
- diskfile_backend *cfg_file;
- uint32_t reader_idx;
git_config_level_t level;
int depth;
};
static int read_on_variable(
- struct reader **reader,
+ struct reader *reader,
const char *current_section,
char *var_name,
char *var_value,
@@ -1591,21 +1616,13 @@ static int read_on_variable(
/* Add or append the new config option */
if (!git__strcmp(var->entry->name, "include.path")) {
- struct reader *r;
+ struct config_file *include;
git_buf path = GIT_BUF_INIT;
char *dir;
- uint32_t index;
- r = git_array_alloc(parse_data->cfg_file->readers);
- /* The reader may have been reallocated */
- *reader = git_array_get(parse_data->cfg_file->readers, parse_data->reader_idx);
- memset(r, 0, sizeof(struct reader));
-
- if ((result = git_path_dirname_r(&path, (*reader)->file_path)) < 0)
+ if ((result = git_path_dirname_r(&path, reader->file->path)) < 0)
return result;
- /* We need to know our index in the array, as the next config_parse call may realloc */
- index = git_array_size(parse_data->cfg_file->readers) - 1;
dir = git_buf_detach(&path);
result = included_path(&path, dir, var->entry->value);
git__free(dir);
@@ -1613,51 +1630,60 @@ static int read_on_variable(
if (result < 0)
return result;
- r->file_path = git_buf_detach(&path);
- git_buf_init(&r->buffer, 0);
+ include = git_array_alloc(reader->file->includes);
+ memset(include, 0, sizeof(*include));
+ git_array_init(include->includes);
+ include->path = git_buf_detach(&path);
- result = git_futils_readbuffer_updated(
- &r->buffer, r->file_path, &r->checksum, NULL);
+ result = config_read(parse_data->values, include, parse_data->level, parse_data->depth+1);
- if (result == 0) {
- result = config_read(parse_data->values, parse_data->cfg_file, r, parse_data->level, parse_data->depth+1);
- r = git_array_get(parse_data->cfg_file->readers, index);
- *reader = git_array_get(parse_data->cfg_file->readers, parse_data->reader_idx);
- } else if (result == GIT_ENOTFOUND) {
+ if (result == GIT_ENOTFOUND) {
giterr_clear();
result = 0;
}
-
- git_buf_free(&r->buffer);
}
return result;
}
-static int config_read(git_strmap *values, diskfile_backend *cfg_file, struct reader *reader, git_config_level_t level, int depth)
+static int config_read(git_strmap *values, struct config_file *file, git_config_level_t level, int depth)
{
struct parse_data parse_data;
+ struct reader reader;
+ int error;
if (depth >= MAX_INCLUDE_DEPTH) {
- giterr_set(GITERR_CONFIG, "Maximum config include depth reached");
+ giterr_set(GITERR_CONFIG, "maximum config include depth reached");
return -1;
}
+ git_buf_init(&reader.buffer, 0);
+
+ if ((error = git_futils_readbuffer(&reader.buffer, file->path)) < 0)
+ goto out;
+
+ if ((error = git_hash_buf(&file->checksum, reader.buffer.ptr, reader.buffer.size)) < 0)
+ goto out;
+
/* Initialize the reading position */
- reader->read_ptr = reader->buffer.ptr;
- reader->eof = 0;
+ reader.file = file;
+ reader.line_number = 0;
+ reader.read_ptr = reader.buffer.ptr;
+ reader.eof = 0;
/* If the file is empty, there's nothing for us to do */
- if (*reader->read_ptr == '\0')
- return 0;
+ if (*reader.read_ptr == '\0')
+ goto out;
parse_data.values = values;
- parse_data.cfg_file = cfg_file;
- parse_data.reader_idx = git_array_size(cfg_file->readers) - 1;
parse_data.level = level;
parse_data.depth = depth;
- return config_parse(reader, NULL, read_on_variable, NULL, NULL, &parse_data);
+ error = config_parse(&reader, NULL, read_on_variable, NULL, NULL, &parse_data);
+
+out:
+ git_buf_free(&reader.buffer);
+ return error;
}
static int write_section(git_buf *fbuf, const char *key)
@@ -1754,7 +1780,7 @@ static int write_value(struct write_data *write_data)
}
static int write_on_section(
- struct reader **reader,
+ struct reader *reader,
const char *current_section,
const char *line,
size_t line_len,
@@ -1790,7 +1816,7 @@ static int write_on_section(
}
static int write_on_variable(
- struct reader **reader,
+ struct reader *reader,
const char *current_section,
char *var_name,
char *var_value,
@@ -1840,7 +1866,7 @@ static int write_on_variable(
return write_value(write_data);
}
-static int write_on_comment(struct reader **reader, const char *line, size_t line_len, void *data)
+static int write_on_comment(struct reader *reader, const char *line, size_t line_len, void *data)
{
struct write_data *write_data;
@@ -1851,7 +1877,7 @@ static int write_on_comment(struct reader **reader, const char *line, size_t lin
}
static int write_on_eof(
- struct reader **reader, const char *current_section, void *data)
+ struct reader *reader, const char *current_section, void *data)
{
struct write_data *write_data = (struct write_data *)data;
int result = 0;
@@ -1890,31 +1916,35 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
char *section, *name, *ldot;
git_filebuf file = GIT_FILEBUF_INIT;
git_buf buf = GIT_BUF_INIT;
- struct reader *reader = git_array_get(cfg->readers, 0);
+ struct reader reader;
struct write_data write_data;
+ memset(&reader, 0, sizeof(reader));
+ git_buf_init(&reader.buffer, 0);
+ reader.file = &cfg->file;
+
if (cfg->locked) {
- result = git_buf_puts(&reader->buffer, git_buf_cstr(&cfg->locked_content));
+ result = git_buf_puts(&reader.buffer, git_buf_cstr(&cfg->locked_content));
} else {
/* Lock the file */
if ((result = git_filebuf_open(
- &file, cfg->file_path, GIT_FILEBUF_HASH_CONTENTS, GIT_CONFIG_FILE_MODE)) < 0) {
- git_buf_free(&reader->buffer);
+ &file, cfg->file.path, GIT_FILEBUF_HASH_CONTENTS, GIT_CONFIG_FILE_MODE)) < 0) {
+ git_buf_free(&reader.buffer);
return result;
}
/* We need to read in our own config file */
- result = git_futils_readbuffer(&reader->buffer, cfg->file_path);
+ result = git_futils_readbuffer(&reader.buffer, cfg->file.path);
}
/* Initialise the reading position */
if (result == GIT_ENOTFOUND) {
- reader->read_ptr = NULL;
- reader->eof = 1;
- git_buf_clear(&reader->buffer);
+ reader.read_ptr = NULL;
+ reader.eof = 1;
+ git_buf_clear(&reader.buffer);
} else if (result == 0) {
- reader->read_ptr = reader->buffer.ptr;
- reader->eof = 0;
+ reader.read_ptr = reader.buffer.ptr;
+ reader.eof = 0;
} else {
git_filebuf_cleanup(&file);
return -1; /* OS error when reading the file */
@@ -1933,7 +1963,7 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
write_data.preg = preg;
write_data.value = value;
- result = config_parse(reader, write_on_section, write_on_variable, write_on_comment, write_on_eof, &write_data);
+ result = config_parse(&reader, write_on_section, write_on_variable, write_on_comment, write_on_eof, &write_data);
git__free(section);
git_buf_free(&write_data.buffered_comment);
@@ -1954,7 +1984,6 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
done:
git_buf_free(&buf);
- git_buf_free(&reader->buffer);
+ git_buf_free(&reader.buffer);
return result;
}
-
diff --git a/src/config_file.h b/src/config_file.h
index 1c52892c3..11b8118f5 100644
--- a/src/config_file.h
+++ b/src/config_file.h
@@ -7,6 +7,9 @@
#ifndef INCLUDE_config_file_h__
#define INCLUDE_config_file_h__
+#include "common.h"
+
+#include "git2/sys/config.h"
#include "git2/config.h"
GIT_INLINE(int) git_config_file_open(git_config_backend *cfg, unsigned int level)
diff --git a/src/crlf.c b/src/crlf.c
index 11895b19f..9af60076d 100644
--- a/src/crlf.c
+++ b/src/crlf.c
@@ -5,12 +5,13 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "common.h"
+
#include "git2/attr.h"
#include "git2/blob.h"
#include "git2/index.h"
#include "git2/sys/filter.h"
-#include "common.h"
#include "fileops.h"
#include "hash.h"
#include "filter.h"
@@ -218,7 +219,7 @@ static const char *line_ending(struct crlf_attrs *ca)
return "\r\n";
line_ending_error:
- giterr_set(GITERR_INVALID, "Invalid input to line ending filter");
+ giterr_set(GITERR_INVALID, "invalid input to line ending filter");
return NULL;
}
diff --git a/src/curl_stream.c b/src/curl_stream.c
index 98de187dd..24bf62635 100644
--- a/src/curl_stream.c
+++ b/src/curl_stream.c
@@ -5,6 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "curl_stream.h"
+
#ifdef GIT_CURL
#include <curl/curl.h>
@@ -15,6 +17,16 @@
#include "vector.h"
#include "proxy.h"
+/* This is for backwards compatibility with curl<7.45.0. */
+#ifndef CURLINFO_ACTIVESOCKET
+# define CURLINFO_ACTIVESOCKET CURLINFO_LASTSOCKET
+# define GIT_CURL_BADSOCKET -1
+# define git_activesocket_t long
+#else
+# define GIT_CURL_BADSOCKET CURL_SOCKET_BAD
+# define git_activesocket_t curl_socket_t
+#endif
+
typedef struct {
git_stream parent;
CURL *handle;
@@ -87,7 +99,8 @@ static int ask_and_apply_proxy_creds(curl_stream *s)
static int curls_connect(git_stream *stream)
{
curl_stream *s = (curl_stream *) stream;
- long sockextr, connect_last = 0;
+ git_activesocket_t sockextr;
+ long connect_last = 0;
int failed_cert = 0, error;
bool retry_connect;
CURLcode res;
@@ -117,10 +130,15 @@ static int curls_connect(git_stream *stream)
if (res == CURLE_PEER_FAILED_VERIFICATION)
failed_cert = 1;
- if ((res = curl_easy_getinfo(s->handle, CURLINFO_LASTSOCKET, &sockextr)) != CURLE_OK) {
+ if ((res = curl_easy_getinfo(s->handle, CURLINFO_ACTIVESOCKET, &sockextr)) != CURLE_OK) {
return seterr_curl(s);
}
+ if (sockextr == GIT_CURL_BADSOCKET) {
+ giterr_set(GITERR_NET, "curl socket is no longer valid");
+ return -1;
+ }
+
s->socket = sockextr;
if (s->parent.encrypted && failed_cert)
@@ -198,6 +216,7 @@ static int wait_for(curl_socket_t fd, bool reading)
FD_ZERO(&outfd);
FD_ZERO(&errfd);
+ assert(fd >= 0);
FD_SET(fd, &errfd);
if (reading)
FD_SET(fd, &infd);
diff --git a/src/curl_stream.h b/src/curl_stream.h
index 283f0fe40..debade7e2 100644
--- a/src/curl_stream.h
+++ b/src/curl_stream.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_curl_stream_h__
#define INCLUDE_curl_stream_h__
+#include "common.h"
+
#include "git2/sys/stream.h"
extern int git_curl_stream_new(git_stream **out, const char *host, const char *port);
diff --git a/src/delta.c b/src/delta.c
index dc45697b6..073cba7c6 100644
--- a/src/delta.c
+++ b/src/delta.c
@@ -131,7 +131,7 @@ static int lookup_index_alloc(
GITERR_CHECK_ALLOC_ADD(&index_len, index_len, hash_len);
if (!git__is_ulong(index_len)) {
- giterr_set(GITERR_NOMEMORY, "Overly large delta");
+ giterr_set(GITERR_NOMEMORY, "overly large delta");
return -1;
}
@@ -544,12 +544,12 @@ int git_delta_apply(
* base object, resulting in data corruption or segfault.
*/
if ((hdr_sz(&base_sz, &delta, delta_end) < 0) || (base_sz != base_len)) {
- giterr_set(GITERR_INVALID, "Failed to apply delta. Base size does not match given data");
+ giterr_set(GITERR_INVALID, "failed to apply delta: base size does not match given data");
return -1;
}
if (hdr_sz(&res_sz, &delta, delta_end) < 0) {
- giterr_set(GITERR_INVALID, "Failed to apply delta. Base size does not match given data");
+ giterr_set(GITERR_INVALID, "failed to apply delta: base size does not match given data");
return -1;
}
@@ -614,6 +614,6 @@ fail:
*out = NULL;
*out_len = 0;
- giterr_set(GITERR_INVALID, "Failed to apply delta");
+ giterr_set(GITERR_INVALID, "failed to apply delta");
return -1;
}
diff --git a/src/delta.h b/src/delta.h
index cc9372922..f61987304 100644
--- a/src/delta.h
+++ b/src/delta.h
@@ -6,6 +6,7 @@
#define INCLUDE_git_delta_h__
#include "common.h"
+
#include "pack.h"
typedef struct git_delta_index git_delta_index;
diff --git a/src/describe.c b/src/describe.c
index fc48fbde4..edf8edfd1 100644
--- a/src/describe.c
+++ b/src/describe.c
@@ -4,12 +4,14 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
+
+#include "common.h"
+
#include "git2/describe.h"
#include "git2/strarray.h"
#include "git2/diff.h"
#include "git2/status.h"
-#include "common.h"
#include "commit.h"
#include "commit_list.h"
#include "oidmap.h"
@@ -19,8 +21,6 @@
#include "vector.h"
#include "repository.h"
-GIT__USE_OIDMAP
-
/* Ported from https://github.com/git/git/blob/89dde7882f71f846ccd0359756d27bebc31108de/builtin/describe.c */
struct commit_name {
@@ -127,7 +127,7 @@ static int add_to_known_names(
if (!found) {
int ret;
- git_oidmap_insert(names, &e->peeled, e, ret);
+ git_oidmap_insert(names, &e->peeled, e, &ret);
if (ret < 0)
return -1;
}
@@ -335,14 +335,14 @@ static int display_name(git_buf *buf, git_repository *repo, struct commit_name *
{
if (n->prio == 2 && !n->tag) {
if (git_tag_lookup(&n->tag, repo, &n->sha1) < 0) {
- giterr_set(GITERR_TAG, "Annotated tag '%s' not available", n->path);
+ giterr_set(GITERR_TAG, "annotated tag '%s' not available", n->path);
return -1;
}
}
if (n->tag && !n->name_checked) {
if (!git_tag_name(n->tag)) {
- giterr_set(GITERR_TAG, "Annotated tag '%s' has no embedded name", n->path);
+ giterr_set(GITERR_TAG, "annotated tag '%s' has no embedded name", n->path);
return -1;
}
@@ -471,7 +471,7 @@ static int describe(
if (!data->opts->max_candidates_tags) {
error = describe_not_found(
git_commit_id(commit),
- "Cannot describe - no tag exactly matches '%s'");
+ "cannot describe - no tag exactly matches '%s'");
goto cleanup;
}
@@ -564,15 +564,15 @@ static int describe(
}
if (unannotated_cnt) {
error = describe_not_found(git_commit_id(commit),
- "Cannot describe - "
- "No annotated tags can describe '%s'."
- "However, there were unannotated tags.");
+ "cannot describe - "
+ "no annotated tags can describe '%s'; "
+ "however, there were unannotated tags.");
goto cleanup;
}
else {
error = describe_not_found(git_commit_id(commit),
- "Cannot describe - "
- "No tags can describe '%s'.");
+ "cannot describe - "
+ "no tags can describe '%s'.");
goto cleanup;
}
}
@@ -695,8 +695,8 @@ int git_describe_commit(
goto cleanup;
if (git_oidmap_size(data.names) == 0 && !opts->show_commit_oid_as_fallback) {
- giterr_set(GITERR_DESCRIBE, "Cannot describe - "
- "No reference found, cannot describe anything.");
+ giterr_set(GITERR_DESCRIBE, "cannot describe - "
+ "no reference found, cannot describe anything.");
error = -1;
goto cleanup;
}
@@ -793,7 +793,7 @@ int git_describe_format(git_buf *out, const git_describe_result *result, const g
if (opts.always_use_long_format && opts.abbreviated_size == 0) {
- giterr_set(GITERR_DESCRIBE, "Cannot describe - "
+ giterr_set(GITERR_DESCRIBE, "cannot describe - "
"'always_use_long_format' is incompatible with a zero"
"'abbreviated_size'");
return -1;
diff --git a/src/diff.c b/src/diff.c
index 317d49597..b2a5ff947 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -4,9 +4,10 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "git2/version.h"
-#include "common.h"
+
#include "diff.h"
+
+#include "git2/version.h"
#include "diff_generate.h"
#include "patch.h"
#include "commit.h"
@@ -19,6 +20,12 @@
#define DIFF_FLAG_SET(DIFF,FLAG,VAL) (DIFF)->opts.flags = \
(VAL) ? ((DIFF)->opts.flags | (FLAG)) : ((DIFF)->opts.flags & ~(VAL))
+struct patch_id_args {
+ git_hash_ctx ctx;
+ git_oid result;
+ int first_file;
+};
+
GIT_INLINE(const char *) diff_delta__path(const git_diff_delta *delta)
{
const char *str = delta->old_file.path;
@@ -120,6 +127,41 @@ int git_diff_get_perfdata(git_diff_perfdata *out, const git_diff *diff)
return 0;
}
+int git_diff_foreach(
+ git_diff *diff,
+ git_diff_file_cb file_cb,
+ git_diff_binary_cb binary_cb,
+ git_diff_hunk_cb hunk_cb,
+ git_diff_line_cb data_cb,
+ void *payload)
+{
+ int error = 0;
+ git_diff_delta *delta;
+ size_t idx;
+
+ assert(diff);
+
+ git_vector_foreach(&diff->deltas, idx, delta) {
+ git_patch *patch;
+
+ /* check flags against patch status */
+ if (git_diff_delta__should_skip(&diff->opts, delta))
+ continue;
+
+ if ((error = git_patch_from_diff(&patch, diff, idx)) != 0)
+ break;
+
+ error = git_patch__invoke_callbacks(patch, file_cb, binary_cb,
+ hunk_cb, data_cb, payload);
+ git_patch_free(patch);
+
+ if (error)
+ break;
+ }
+
+ return error;
+}
+
int git_diff_format_email__append_header_tobuf(
git_buf *out,
const git_oid *id,
@@ -339,3 +381,142 @@ int git_diff_format_email_init_options(
return 0;
}
+static int flush_hunk(git_oid *result, git_hash_ctx *ctx)
+{
+ git_oid hash;
+ unsigned short carry = 0;
+ int error, i;
+
+ if ((error = git_hash_final(&hash, ctx)) < 0 ||
+ (error = git_hash_init(ctx)) < 0)
+ return error;
+
+ for (i = 0; i < GIT_OID_RAWSZ; i++) {
+ carry += result->id[i] + hash.id[i];
+ result->id[i] = carry;
+ carry >>= 8;
+ }
+
+ return 0;
+}
+
+static void strip_spaces(git_buf *buf)
+{
+ char *src = buf->ptr, *dst = buf->ptr;
+ char c;
+ size_t len = 0;
+
+ while ((c = *src++) != '\0') {
+ if (!git__isspace(c)) {
+ *dst++ = c;
+ len++;
+ }
+ }
+
+ git_buf_truncate(buf, len);
+}
+
+static int file_cb(
+ const git_diff_delta *delta,
+ float progress,
+ void *payload)
+{
+ struct patch_id_args *args = (struct patch_id_args *) payload;
+ git_buf buf = GIT_BUF_INIT;
+ int error;
+
+ GIT_UNUSED(progress);
+
+ if (!args->first_file &&
+ (error = flush_hunk(&args->result, &args->ctx)) < 0)
+ goto out;
+ args->first_file = 0;
+
+ if ((error = git_buf_printf(&buf,
+ "diff--gita/%sb/%s---a/%s+++b/%s",
+ delta->old_file.path,
+ delta->new_file.path,
+ delta->old_file.path,
+ delta->new_file.path)) < 0)
+ goto out;
+
+ strip_spaces(&buf);
+
+ if ((error = git_hash_update(&args->ctx, buf.ptr, buf.size)) < 0)
+ goto out;
+
+out:
+ git_buf_free(&buf);
+ return error;
+}
+
+static int line_cb(
+ const git_diff_delta *delta,
+ const git_diff_hunk *hunk,
+ const git_diff_line *line,
+ void *payload)
+{
+ struct patch_id_args *args = (struct patch_id_args *) payload;
+ git_buf buf = GIT_BUF_INIT;
+ int error;
+
+ GIT_UNUSED(delta);
+ GIT_UNUSED(hunk);
+
+ switch (line->origin) {
+ case GIT_DIFF_LINE_ADDITION:
+ git_buf_putc(&buf, '+');
+ break;
+ case GIT_DIFF_LINE_DELETION:
+ git_buf_putc(&buf, '-');
+ break;
+ case GIT_DIFF_LINE_CONTEXT:
+ break;
+ default:
+ giterr_set(GITERR_PATCH, "invalid line origin for patch");
+ return -1;
+ }
+
+ git_buf_put(&buf, line->content, line->content_len);
+ strip_spaces(&buf);
+
+ if ((error = git_hash_update(&args->ctx, buf.ptr, buf.size)) < 0)
+ goto out;
+
+out:
+ git_buf_free(&buf);
+ return error;
+}
+
+int git_diff_patchid_init_options(git_diff_patchid_options *opts, unsigned int version)
+{
+ GIT_INIT_STRUCTURE_FROM_TEMPLATE(
+ opts, version, git_diff_patchid_options, GIT_DIFF_PATCHID_OPTIONS_INIT);
+ return 0;
+}
+
+int git_diff_patchid(git_oid *out, git_diff *diff, git_diff_patchid_options *opts)
+{
+ struct patch_id_args args;
+ int error;
+
+ GITERR_CHECK_VERSION(
+ opts, GIT_DIFF_PATCHID_OPTIONS_VERSION, "git_diff_patchid_options");
+
+ memset(&args, 0, sizeof(args));
+ args.first_file = 1;
+ if ((error = git_hash_ctx_init(&args.ctx)) < 0)
+ goto out;
+
+ if ((error = git_diff_foreach(diff, file_cb, NULL, NULL, line_cb, &args)) < 0)
+ goto out;
+
+ if ((error = (flush_hunk(&args.result, &args.ctx))) < 0)
+ goto out;
+
+ git_oid_cpy(out, &args.result);
+
+out:
+ git_hash_ctx_cleanup(&args.ctx);
+ return error;
+}
diff --git a/src/diff.h b/src/diff.h
index 5750d2a09..4e5dd93da 100644
--- a/src/diff.h
+++ b/src/diff.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_diff_h__
#define INCLUDE_diff_h__
+#include "common.h"
+
#include "git2/diff.h"
#include "git2/patch.h"
#include "git2/sys/diff.h"
diff --git a/src/diff_driver.c b/src/diff_driver.c
index 14a898c4f..8cd57cdf6 100644
--- a/src/diff_driver.c
+++ b/src/diff_driver.c
@@ -4,20 +4,18 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+
+#include "diff_driver.h"
#include "git2/attr.h"
#include "diff.h"
-#include "diff_driver.h"
#include "strmap.h"
#include "map.h"
#include "buf_text.h"
#include "config.h"
#include "repository.h"
-GIT__USE_STRMAP
-
typedef enum {
DIFF_DRIVER_AUTO = 0,
DIFF_DRIVER_BINARY = 1,
@@ -114,7 +112,7 @@ static int diff_driver_add_patterns(
if (error < 0)
break;
- if ((error = regcomp(&pat->re, buf.ptr, regex_flags)) != 0) {
+ if ((error = p_regcomp(&pat->re, buf.ptr, regex_flags)) != 0) {
/*
* TODO: issue a warning
*/
@@ -151,7 +149,7 @@ static git_diff_driver_registry *git_repository_driver_registry(
}
if (!repo->diff_drivers)
- giterr_set(GITERR_REPOSITORY, "Unable to create diff driver registry");
+ giterr_set(GITERR_REPOSITORY, "unable to create diff driver registry");
return repo->diff_drivers;
}
@@ -210,14 +208,14 @@ static int git_diff_driver_builtin(
goto done;
if (ddef->words &&
- (error = regcomp(
+ (error = p_regcomp(
&drv->word_pattern, ddef->words, ddef->flags | REG_EXTENDED)))
{
error = giterr_set_regex(&drv->word_pattern, error);
goto done;
}
- git_strmap_insert(reg->drivers, drv->name, drv, error);
+ git_strmap_insert(reg->drivers, drv->name, drv, &error);
if (error > 0)
error = 0;
@@ -314,7 +312,7 @@ static int git_diff_driver_load(
goto done;
if (!ce || !ce->value)
/* no diff.<driver>.wordregex, so just continue */;
- else if (!(error = regcomp(&drv->word_pattern, ce->value, REG_EXTENDED)))
+ else if (!(error = p_regcomp(&drv->word_pattern, ce->value, REG_EXTENDED)))
found_driver = true;
else {
/* TODO: warn about bad regex instead of failure */
@@ -331,7 +329,7 @@ static int git_diff_driver_load(
goto done;
/* store driver in registry */
- git_strmap_insert(reg->drivers, drv->name, drv, error);
+ git_strmap_insert(reg->drivers, drv->name, drv, &error);
if (error < 0)
goto done;
error = 0;
@@ -519,4 +517,3 @@ void git_diff_find_context_clear(git_diff_find_context_payload *payload)
payload->driver = NULL;
}
}
-
diff --git a/src/diff_driver.h b/src/diff_driver.h
index 0706dcfc5..5691cac30 100644
--- a/src/diff_driver.h
+++ b/src/diff_driver.h
@@ -8,6 +8,7 @@
#define INCLUDE_diff_driver_h__
#include "common.h"
+
#include "buffer.h"
typedef struct git_diff_driver_registry git_diff_driver_registry;
diff --git a/src/diff_file.c b/src/diff_file.c
index cc1029038..270d59bbb 100644
--- a/src/diff_file.c
+++ b/src/diff_file.c
@@ -4,12 +4,13 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+
+#include "diff_file.h"
+
#include "git2/blob.h"
#include "git2/submodule.h"
#include "diff.h"
#include "diff_generate.h"
-#include "diff_file.h"
#include "odb.h"
#include "fileops.h"
#include "filter.h"
@@ -304,7 +305,7 @@ static int diff_file_content_load_workdir_symlink(
read_len = p_readlink(git_buf_cstr(path), fc->map.data, alloc_len);
if (read_len < 0) {
- giterr_set(GITERR_OS, "Failed to read symlink '%s'", fc->file->path);
+ giterr_set(GITERR_OS, "failed to read symlink '%s'", fc->file->path);
return -1;
}
diff --git a/src/diff_file.h b/src/diff_file.h
index 0d54b6d33..5da7a7bb8 100644
--- a/src/diff_file.h
+++ b/src/diff_file.h
@@ -8,6 +8,7 @@
#define INCLUDE_diff_file_h__
#include "common.h"
+
#include "diff.h"
#include "diff_driver.h"
#include "map.h"
diff --git a/src/diff_generate.c b/src/diff_generate.c
index 06f9b19c7..6436ab930 100644
--- a/src/diff_generate.c
+++ b/src/diff_generate.c
@@ -4,9 +4,10 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
-#include "diff.h"
+
#include "diff_generate.h"
+
+#include "diff.h"
#include "patch_generate.h"
#include "fileops.h"
#include "config.h"
@@ -624,7 +625,7 @@ int git_diff__oid_for_entry(
error = git_odb__hashlink(out, full_path.ptr);
diff->base.perf.oid_calculations++;
} else if (!git__is_sizet(entry.file_size)) {
- giterr_set(GITERR_OS, "File size overflow (for 32-bits) on '%s'",
+ giterr_set(GITERR_OS, "file size overflow (for 32-bits) on '%s'",
entry.path);
error = -1;
} else if (!(error = git_filter_list_load(&fl,
@@ -1587,7 +1588,7 @@ int git_diff__commit(
char commit_oidstr[GIT_OID_HEXSZ + 1];
error = -1;
- giterr_set(GITERR_INVALID, "Commit %s is a merge commit",
+ giterr_set(GITERR_INVALID, "commit %s is a merge commit",
git_oid_tostr(commit_oidstr, GIT_OID_HEXSZ + 1, git_commit_id(commit)));
goto on_error;
}
diff --git a/src/diff_generate.h b/src/diff_generate.h
index 63e7f0532..8de2a0644 100644
--- a/src/diff_generate.h
+++ b/src/diff_generate.h
@@ -7,6 +7,12 @@
#ifndef INCLUDE_diff_generate_h__
#define INCLUDE_diff_generate_h__
+#include "common.h"
+
+#include "diff.h"
+#include "pool.h"
+#include "index.h"
+
enum {
GIT_DIFFCAPS_HAS_SYMLINKS = (1 << 0), /* symlinks on platform? */
GIT_DIFFCAPS_IGNORE_STAT = (1 << 1), /* use stat? */
diff --git a/src/diff_parse.c b/src/diff_parse.c
index e640063af..78da3b675 100644
--- a/src/diff_parse.c
+++ b/src/diff_parse.c
@@ -4,9 +4,10 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
-#include "diff.h"
+
#include "diff_parse.h"
+
+#include "diff.h"
#include "patch.h"
#include "patch_parse.h"
@@ -37,7 +38,6 @@ static git_diff_parsed *diff_parsed_alloc(void)
GIT_REFCOUNT_INC(diff);
diff->base.type = GIT_DIFF_TYPE_PARSED;
- diff->base.opts.flags &= ~GIT_DIFF_IGNORE_CASE;
diff->base.strcomp = git__strcmp;
diff->base.strncomp = git__strncmp;
diff->base.pfxcomp = git__prefixcmp;
@@ -45,6 +45,13 @@ static git_diff_parsed *diff_parsed_alloc(void)
diff->base.patch_fn = git_patch_parsed_from_diff;
diff->base.free_fn = diff_parsed_free;
+ if (git_diff_init_options(&diff->base.opts, GIT_DIFF_OPTIONS_VERSION) < 0) {
+ git__free(diff);
+ return NULL;
+ }
+
+ diff->base.opts.flags &= ~GIT_DIFF_IGNORE_CASE;
+
git_pool_init(&diff->base.pool, 1);
if (git_vector_init(&diff->patches, 0, NULL) < 0 ||
diff --git a/src/diff_parse.h b/src/diff_parse.h
index c47d4cbc9..876782128 100644
--- a/src/diff_parse.h
+++ b/src/diff_parse.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_diff_parse_h__
#define INCLUDE_diff_parse_h__
+#include "common.h"
+
#include "diff.h"
typedef struct {
diff --git a/src/diff_print.c b/src/diff_print.c
index fd1a186c1..28ae38424 100644
--- a/src/diff_print.c
+++ b/src/diff_print.c
@@ -4,7 +4,9 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
+
#include "common.h"
+
#include "diff.h"
#include "diff_file.h"
#include "patch_generate.h"
@@ -222,7 +224,7 @@ static int diff_print_one_raw(
if (pi->id_strlen > id_abbrev) {
giterr_set(GITERR_PATCH,
- "The patch input contains %d id characters (cannot print %d)",
+ "the patch input contains %d id characters (cannot print %d)",
id_abbrev, pi->id_strlen);
return -1;
}
@@ -273,7 +275,7 @@ static int diff_print_oid_range(
if (delta->old_file.mode &&
id_strlen > delta->old_file.id_abbrev) {
giterr_set(GITERR_PATCH,
- "The patch input contains %d id characters (cannot print %d)",
+ "the patch input contains %d id characters (cannot print %d)",
delta->old_file.id_abbrev, id_strlen);
return -1;
}
@@ -281,7 +283,7 @@ static int diff_print_oid_range(
if ((delta->new_file.mode &&
id_strlen > delta->new_file.id_abbrev)) {
giterr_set(GITERR_PATCH,
- "The patch input contains %d id characters (cannot print %d)",
+ "the patch input contains %d id characters (cannot print %d)",
delta->new_file.id_abbrev, id_strlen);
return -1;
}
@@ -680,7 +682,7 @@ int git_diff_print(
print_file = diff_print_one_name_status;
break;
default:
- giterr_set(GITERR_INVALID, "Unknown diff output format (%d)", format);
+ giterr_set(GITERR_INVALID, "unknown diff output format (%d)", format);
return -1;
}
@@ -708,7 +710,7 @@ int git_diff_print_callback__to_buf(
GIT_UNUSED(delta); GIT_UNUSED(hunk);
if (!output) {
- giterr_set(GITERR_INVALID, "Buffer pointer must be provided");
+ giterr_set(GITERR_INVALID, "buffer pointer must be provided");
return -1;
}
diff --git a/src/diff_stats.c b/src/diff_stats.c
index 9c186d793..583c68459 100644
--- a/src/diff_stats.c
+++ b/src/diff_stats.c
@@ -4,7 +4,9 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
+
#include "common.h"
+
#include "vector.h"
#include "diff.h"
#include "patch_generate.h"
@@ -300,15 +302,24 @@ int git_diff_stats_to_buf(
}
if (format & GIT_DIFF_STATS_FULL || format & GIT_DIFF_STATS_SHORT) {
- error = git_buf_printf(
- out, " %" PRIuZ " file%s changed, %" PRIuZ
- " insertion%s(+), %" PRIuZ " deletion%s(-)\n",
- stats->files_changed, stats->files_changed != 1 ? "s" : "",
- stats->insertions, stats->insertions != 1 ? "s" : "",
- stats->deletions, stats->deletions != 1 ? "s" : "");
-
- if (error < 0)
- return error;
+ git_buf_printf(
+ out, " %" PRIuZ " file%s changed",
+ stats->files_changed, stats->files_changed != 1 ? "s" : "");
+
+ if (stats->insertions || stats->deletions == 0)
+ git_buf_printf(
+ out, ", %" PRIuZ " insertion%s(+)",
+ stats->insertions, stats->insertions != 1 ? "s" : "");
+
+ if (stats->deletions || stats->insertions == 0)
+ git_buf_printf(
+ out, ", %" PRIuZ " deletion%s(-)",
+ stats->deletions, stats->deletions != 1 ? "s" : "");
+
+ git_buf_putc(out, '\n');
+
+ if (git_buf_oom(out))
+ return -1;
}
if (format & GIT_DIFF_STATS_INCLUDE_SUMMARY) {
@@ -334,4 +345,3 @@ void git_diff_stats_free(git_diff_stats *stats)
git__free(stats->filestats);
git__free(stats);
}
-
diff --git a/src/diff_tform.c b/src/diff_tform.c
index e8848bd45..c0461a3a3 100644
--- a/src/diff_tform.c
+++ b/src/diff_tform.c
@@ -4,7 +4,8 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+
+#include "diff_tform.h"
#include "git2/config.h"
#include "git2/blob.h"
@@ -131,7 +132,7 @@ int git_diff__merge(
if (ignore_case != ((from->opts.flags & GIT_DIFF_IGNORE_CASE) != 0) ||
reversed != ((from->opts.flags & GIT_DIFF_REVERSE) != 0)) {
giterr_set(GITERR_INVALID,
- "Attempt to merge diffs created with conflicting options");
+ "attempt to merge diffs created with conflicting options");
return -1;
}
@@ -553,8 +554,8 @@ static int similarity_measure(
*score = -1;
- /* don't try to compare files of different types */
- if (GIT_MODE_TYPE(a_file->mode) != GIT_MODE_TYPE(b_file->mode))
+ /* don't try to compare things that aren't files */
+ if (!GIT_MODE_ISBLOB(a_file->mode) || !GIT_MODE_ISBLOB(b_file->mode))
return 0;
/* if exact match is requested, force calculation of missing OIDs now */
diff --git a/src/diff_tform.h b/src/diff_tform.h
index 5bd9712d9..a31c40f8e 100644
--- a/src/diff_tform.h
+++ b/src/diff_tform.h
@@ -7,6 +7,10 @@
#ifndef INCLUDE_diff_tform_h__
#define INCLUDE_diff_tform_h__
+#include "common.h"
+
+#include "diff_file.h"
+
extern int git_diff_find_similar__hashsig_for_file(
void **out, const git_diff_file *f, const char *path, void *p);
diff --git a/src/diff_xdiff.c b/src/diff_xdiff.c
index 5bd6381b5..5e10db13d 100644
--- a/src/diff_xdiff.c
+++ b/src/diff_xdiff.c
@@ -4,11 +4,12 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
+
+#include "diff_xdiff.h"
+
#include "git2/errors.h"
-#include "common.h"
#include "diff.h"
#include "diff_driver.h"
-#include "diff_xdiff.h"
#include "patch_generate.h"
static int git_xdiff_scan_int(const char **str, int *value)
@@ -50,7 +51,7 @@ static int git_xdiff_parse_hunk(git_diff_hunk *hunk, const char *header)
return 0;
fail:
- giterr_set(GITERR_INVALID, "Malformed hunk header from xdiff");
+ giterr_set(GITERR_INVALID, "malformed hunk header from xdiff");
return -1;
}
@@ -99,7 +100,7 @@ static int diff_update_lines(
info->new_lineno += (int)line->num_lines;
break;
default:
- giterr_set(GITERR_INVALID, "Unknown diff line origin %02x",
+ giterr_set(GITERR_INVALID, "unknown diff line origin %02x",
(unsigned int)line->origin);
return -1;
}
diff --git a/src/diff_xdiff.h b/src/diff_xdiff.h
index 88375986b..aca80b131 100644
--- a/src/diff_xdiff.h
+++ b/src/diff_xdiff.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_diff_xdiff_h__
#define INCLUDE_diff_xdiff_h__
+#include "common.h"
+
#include "diff.h"
#include "xdiff/xdiff.h"
#include "patch_generate.h"
diff --git a/src/errors.c b/src/errors.c
index 91acc3541..a874163b0 100644
--- a/src/errors.c
+++ b/src/errors.c
@@ -4,7 +4,9 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
+
#include "common.h"
+
#include "global.h"
#include "posix.h"
#include "buffer.h"
diff --git a/src/features.h.in b/src/features.h.in
new file mode 100644
index 000000000..e03b7a251
--- /dev/null
+++ b/src/features.h.in
@@ -0,0 +1,36 @@
+#ifndef INCLUDE_features_h__
+#define INCLUDE_features_h__
+
+#cmakedefine GIT_DEBUG_POOL 1
+#cmakedefine GIT_TRACE 1
+#cmakedefine GIT_THREADS 1
+#cmakedefine GIT_MSVC_CRTDBG 1
+
+#cmakedefine GIT_ARCH_64 1
+#cmakedefine GIT_ARCH_32 1
+
+#cmakedefine GIT_USE_ICONV 1
+#cmakedefine GIT_USE_NSEC 1
+#cmakedefine GIT_USE_STAT_MTIM 1
+#cmakedefine GIT_USE_STAT_MTIMESPEC 1
+#cmakedefine GIT_USE_STAT_MTIME_NSEC 1
+#cmakedefine GIT_USE_FUTIMENS 1
+#cmakedefine GIT_USE_REGCOMP_L 1
+
+#cmakedefine GIT_SSH 1
+#cmakedefine GIT_SSH_MEMORY_CREDENTIALS 1
+
+#cmakedefine GIT_GSSAPI 1
+#cmakedefine GIT_WINHTTP 1
+#cmakedefine GIT_CURL 1
+
+#cmakedefine GIT_HTTPS 1
+#cmakedefine GIT_OPENSSL 1
+#cmakedefine GIT_SECURE_TRANSPORT 1
+
+#cmakedefine GIT_SHA1_COLLISIONDETECT 1
+#cmakedefine GIT_SHA1_WIN32 1
+#cmakedefine GIT_SHA1_COMMON_CRYPTO 1
+#cmakedefine GIT_SHA1_OPENSSL 1
+
+#endif
diff --git a/src/fetch.c b/src/fetch.c
index 4d895752c..0b22b3673 100644
--- a/src/fetch.c
+++ b/src/fetch.c
@@ -5,16 +5,16 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "fetch.h"
+
#include "git2/oid.h"
#include "git2/refs.h"
#include "git2/revwalk.h"
#include "git2/transport.h"
-#include "common.h"
#include "remote.h"
#include "refspec.h"
#include "pack.h"
-#include "fetch.h"
#include "netops.h"
#include "repository.h"
#include "refs.h"
@@ -113,7 +113,7 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts)
remote->need_pack = 0;
if (filter_wants(remote, opts) < 0) {
- giterr_set(GITERR_NET, "Failed to filter the reference list for wants");
+ giterr_set(GITERR_NET, "failed to filter the reference list for wants");
return -1;
}
diff --git a/src/fetch.h b/src/fetch.h
index 0412d4e44..1c75af9c3 100644
--- a/src/fetch.h
+++ b/src/fetch.h
@@ -7,6 +7,10 @@
#ifndef INCLUDE_fetch_h__
#define INCLUDE_fetch_h__
+#include "common.h"
+
+#include "git2/remote.h"
+
#include "netops.h"
int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts);
diff --git a/src/fetchhead.c b/src/fetchhead.c
index a95ea4ca4..ac25723d3 100644
--- a/src/fetchhead.c
+++ b/src/fetchhead.c
@@ -5,11 +5,11 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "fetchhead.h"
+
#include "git2/types.h"
#include "git2/oid.h"
-#include "fetchhead.h"
-#include "common.h"
#include "buffer.h"
#include "fileops.h"
#include "filebuf.h"
@@ -115,7 +115,7 @@ int git_fetchhead_write(git_repository *repo, git_vector *fetchhead_refs)
assert(repo && fetchhead_refs);
- if (git_buf_joinpath(&path, repo->path_repository, GIT_FETCH_HEAD_FILE) < 0)
+ if (git_buf_joinpath(&path, repo->gitdir, GIT_FETCH_HEAD_FILE) < 0)
return -1;
if (git_filebuf_open(&file, path.ptr, GIT_FILEBUF_FORCE, GIT_REFS_FILE_MODE) < 0) {
@@ -149,7 +149,7 @@ static int fetchhead_ref_parse(
if (!*line) {
giterr_set(GITERR_FETCHHEAD,
- "Empty line in FETCH_HEAD line %d", line_num);
+ "empty line in FETCH_HEAD line %"PRIuZ, line_num);
return -1;
}
@@ -163,15 +163,15 @@ static int fetchhead_ref_parse(
if (strlen(oid_str) != GIT_OID_HEXSZ) {
giterr_set(GITERR_FETCHHEAD,
- "Invalid object ID in FETCH_HEAD line %d", line_num);
+ "invalid object ID in FETCH_HEAD line %"PRIuZ, line_num);
return -1;
}
if (git_oid_fromstr(oid, oid_str) < 0) {
const git_error *oid_err = giterr_last();
- const char *err_msg = oid_err ? oid_err->message : "Invalid object ID";
+ const char *err_msg = oid_err ? oid_err->message : "invalid object ID";
- giterr_set(GITERR_FETCHHEAD, "%s in FETCH_HEAD line %d",
+ giterr_set(GITERR_FETCHHEAD, "%s in FETCH_HEAD line %"PRIuZ,
err_msg, line_num);
return -1;
}
@@ -180,7 +180,7 @@ static int fetchhead_ref_parse(
if (*line) {
if ((is_merge_str = git__strsep(&line, "\t")) == NULL) {
giterr_set(GITERR_FETCHHEAD,
- "Invalid description data in FETCH_HEAD line %d", line_num);
+ "invalid description data in FETCH_HEAD line %"PRIuZ, line_num);
return -1;
}
@@ -190,13 +190,13 @@ static int fetchhead_ref_parse(
*is_merge = 0;
else {
giterr_set(GITERR_FETCHHEAD,
- "Invalid for-merge entry in FETCH_HEAD line %d", line_num);
+ "invalid for-merge entry in FETCH_HEAD line %"PRIuZ, line_num);
return -1;
}
if ((desc = line) == NULL) {
giterr_set(GITERR_FETCHHEAD,
- "Invalid description in FETCH_HEAD line %d", line_num);
+ "invalid description in FETCH_HEAD line %"PRIuZ, line_num);
return -1;
}
@@ -213,7 +213,7 @@ static int fetchhead_ref_parse(
if ((desc = strstr(name, "' ")) == NULL ||
git__prefixcmp(desc, "' of ") != 0) {
giterr_set(GITERR_FETCHHEAD,
- "Invalid description in FETCH_HEAD line %d", line_num);
+ "invalid description in FETCH_HEAD line %"PRIuZ, line_num);
return -1;
}
@@ -249,7 +249,7 @@ int git_repository_fetchhead_foreach(git_repository *repo,
assert(repo && cb);
- if (git_buf_joinpath(&path, repo->path_repository, GIT_FETCH_HEAD_FILE) < 0)
+ if (git_buf_joinpath(&path, repo->gitdir, GIT_FETCH_HEAD_FILE) < 0)
return -1;
if ((error = git_futils_readbuffer(&file, git_buf_cstr(&path))) < 0)
@@ -277,7 +277,7 @@ int git_repository_fetchhead_foreach(git_repository *repo,
}
if (*buffer) {
- giterr_set(GITERR_FETCHHEAD, "No EOL at line %d", line_num+1);
+ giterr_set(GITERR_FETCHHEAD, "no EOL at line %"PRIuZ, line_num+1);
error = -1;
goto done;
}
diff --git a/src/fetchhead.h b/src/fetchhead.h
index b03bd0f74..9e5171010 100644
--- a/src/fetchhead.h
+++ b/src/fetchhead.h
@@ -7,6 +7,9 @@
#ifndef INCLUDE_fetchhead_h__
#define INCLUDE_fetchhead_h__
+#include "common.h"
+
+#include "oid.h"
#include "vector.h"
typedef struct git_fetchhead_ref {
diff --git a/src/filebuf.c b/src/filebuf.c
index 582399470..8b7e489da 100644
--- a/src/filebuf.c
+++ b/src/filebuf.c
@@ -4,8 +4,9 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+
#include "filebuf.h"
+
#include "fileops.h"
static const size_t WRITE_BUFFER_SIZE = (4096 * 2);
@@ -23,7 +24,7 @@ static int verify_last_error(git_filebuf *file)
{
switch (file->last_error) {
case BUFERR_WRITE:
- giterr_set(GITERR_OS, "Failed to write out file");
+ giterr_set(GITERR_OS, "failed to write out file");
return -1;
case BUFERR_MEM:
@@ -48,7 +49,7 @@ static int lock_file(git_filebuf *file, int flags, mode_t mode)
else {
giterr_clear(); /* actual OS error code just confuses */
giterr_set(GITERR_OS,
- "Failed to lock file '%s' for writing", file->path_lock);
+ "failed to lock file '%s' for writing", file->path_lock);
return GIT_ELOCKED;
}
}
@@ -75,7 +76,7 @@ static int lock_file(git_filebuf *file, int flags, mode_t mode)
source = p_open(file->path_original, O_RDONLY);
if (source < 0) {
giterr_set(GITERR_OS,
- "Failed to open file '%s' for reading",
+ "failed to open file '%s' for reading",
file->path_original);
return -1;
}
@@ -90,10 +91,10 @@ static int lock_file(git_filebuf *file, int flags, mode_t mode)
p_close(source);
if (read_bytes < 0) {
- giterr_set(GITERR_OS, "Failed to read file '%s'", file->path_original);
+ giterr_set(GITERR_OS, "failed to read file '%s'", file->path_original);
return -1;
} else if (error < 0) {
- giterr_set(GITERR_OS, "Failed to write file '%s'", file->path_lock);
+ giterr_set(GITERR_OS, "failed to write file '%s'", file->path_lock);
return -1;
}
}
@@ -246,7 +247,7 @@ static int resolve_symlink(git_buf *out, const char *path)
root = git_path_root(target.ptr);
if (root >= 0) {
- if ((error = git_buf_puts(&curpath, target.ptr)) < 0)
+ if ((error = git_buf_sets(&curpath, target.ptr)) < 0)
goto cleanup;
} else {
git_buf dir = GIT_BUF_INIT;
@@ -291,6 +292,9 @@ int git_filebuf_open_withsize(git_filebuf *file, const char *path, int flags, mo
if (flags & GIT_FILEBUF_DO_NOT_BUFFER)
file->do_not_buffer = true;
+ if (flags & GIT_FILEBUF_FSYNC)
+ file->do_fsync = true;
+
file->buf_size = size;
file->buf_pos = 0;
file->fd = -1;
@@ -316,7 +320,7 @@ int git_filebuf_open_withsize(git_filebuf *file, const char *path, int flags, mo
if (compression != 0) {
/* Initialize the ZLib stream */
if (deflateInit(&file->zs, compression) != Z_OK) {
- giterr_set(GITERR_ZLIB, "Failed to initialize zlib");
+ giterr_set(GITERR_ZLIB, "failed to initialize zlib");
goto cleanup;
}
@@ -425,18 +429,26 @@ int git_filebuf_commit(git_filebuf *file)
file->fd_is_open = false;
+ if (file->do_fsync && p_fsync(file->fd) < 0) {
+ giterr_set(GITERR_OS, "failed to fsync '%s'", file->path_lock);
+ goto on_error;
+ }
+
if (p_close(file->fd) < 0) {
- giterr_set(GITERR_OS, "Failed to close file at '%s'", file->path_lock);
+ giterr_set(GITERR_OS, "failed to close file at '%s'", file->path_lock);
goto on_error;
}
file->fd = -1;
if (p_rename(file->path_lock, file->path_original) < 0) {
- giterr_set(GITERR_OS, "Failed to rename lockfile to '%s'", file->path_original);
+ giterr_set(GITERR_OS, "failed to rename lockfile to '%s'", file->path_original);
goto on_error;
}
+ if (file->do_fsync && git_futils_fsync_parent(file->path_original) < 0)
+ goto on_error;
+
file->did_rename = true;
git_filebuf_cleanup(file);
@@ -571,7 +583,7 @@ int git_filebuf_stats(time_t *mtime, size_t *size, git_filebuf *file)
res = p_stat(file->path_original, &st);
if (res < 0) {
- giterr_set(GITERR_OS, "Could not get stat info for '%s'",
+ giterr_set(GITERR_OS, "could not get stat info for '%s'",
file->path_original);
return res;
}
diff --git a/src/filebuf.h b/src/filebuf.h
index 467708d45..f51ff230f 100644
--- a/src/filebuf.h
+++ b/src/filebuf.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_filebuf_h__
#define INCLUDE_filebuf_h__
+#include "common.h"
+
#include "fileops.h"
#include "hash.h"
#include <zlib.h>
@@ -20,7 +22,8 @@
#define GIT_FILEBUF_FORCE (1 << 3)
#define GIT_FILEBUF_TEMPORARY (1 << 4)
#define GIT_FILEBUF_DO_NOT_BUFFER (1 << 5)
-#define GIT_FILEBUF_DEFLATE_SHIFT (6)
+#define GIT_FILEBUF_FSYNC (1 << 6)
+#define GIT_FILEBUF_DEFLATE_SHIFT (7)
#define GIT_FILELOCK_EXTENSION ".lock\0"
#define GIT_FILELOCK_EXTLENGTH 6
@@ -47,6 +50,7 @@ struct git_filebuf {
bool created_lock;
bool did_rename;
bool do_not_buffer;
+ bool do_fsync;
int last_error;
};
diff --git a/src/fileops.c b/src/fileops.c
index fcc0301f9..ad3f67e2b 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -4,8 +4,9 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+
#include "fileops.h"
+
#include "global.h"
#include "strmap.h"
#include <ctype.h>
@@ -13,8 +14,6 @@
#include "win32/findfile.h"
#endif
-GIT__USE_STRMAP
-
int git_futils_mkpath2file(const char *file_path, const mode_t mode)
{
return git_futils_mkdir(
@@ -37,13 +36,13 @@ int git_futils_mktmp(git_buf *path_out, const char *filename, mode_t mode)
if ((fd = p_mkstemp(path_out->ptr)) < 0) {
giterr_set(GITERR_OS,
- "Failed to create temporary file '%s'", path_out->ptr);
+ "failed to create temporary file '%s'", path_out->ptr);
return -1;
}
if (p_chmod(path_out->ptr, (mode & ~mask))) {
giterr_set(GITERR_OS,
- "Failed to set permissions on file '%s'", path_out->ptr);
+ "failed to set permissions on file '%s'", path_out->ptr);
return -1;
}
@@ -59,7 +58,7 @@ int git_futils_creat_withpath(const char *path, const mode_t dirmode, const mode
fd = p_creat(path, mode);
if (fd < 0) {
- giterr_set(GITERR_OS, "Failed to create file '%s'", path);
+ giterr_set(GITERR_OS, "failed to create file '%s'", path);
return -1;
}
@@ -68,12 +67,20 @@ int git_futils_creat_withpath(const char *path, const mode_t dirmode, const mode
int git_futils_creat_locked(const char *path, const mode_t mode)
{
- int fd = p_open(path, O_WRONLY | O_CREAT | O_TRUNC |
- O_EXCL | O_BINARY | O_CLOEXEC, mode);
+ int fd = p_open(path, O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC,
+ mode);
if (fd < 0) {
- giterr_set(GITERR_OS, "Failed to create locked file '%s'", path);
- return errno == EEXIST ? GIT_ELOCKED : -1;
+ int error = errno;
+ giterr_set(GITERR_OS, "failed to create locked file '%s'", path);
+ switch (error) {
+ case EEXIST:
+ return GIT_ELOCKED;
+ case ENOENT:
+ return GIT_ENOTFOUND;
+ default:
+ return -1;
+ }
}
return fd;
@@ -100,7 +107,7 @@ git_off_t git_futils_filesize(git_file fd)
struct stat sb;
if (p_fstat(fd, &sb)) {
- giterr_set(GITERR_OS, "Failed to stat file descriptor");
+ giterr_set(GITERR_OS, "failed to stat file descriptor");
return -1;
}
@@ -129,7 +136,7 @@ int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len)
git_buf_clear(buf);
if (!git__is_ssizet(len)) {
- giterr_set(GITERR_INVALID, "Read too large.");
+ giterr_set(GITERR_INVALID, "read too large");
return -1;
}
@@ -141,7 +148,7 @@ int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len)
read_size = p_read(fd, buf->ptr, len);
if (read_size != (ssize_t)len) {
- giterr_set(GITERR_OS, "Failed to read descriptor");
+ giterr_set(GITERR_OS, "failed to read descriptor");
git_buf_free(buf);
return -1;
}
@@ -176,7 +183,7 @@ int git_futils_readbuffer_updated(
}
if (!git__is_sizet(st.st_size+1)) {
- giterr_set(GITERR_OS, "Invalid regular file stat for '%s'", path);
+ giterr_set(GITERR_OS, "invalid regular file stat for '%s'", path);
return -1;
}
@@ -190,28 +197,29 @@ int git_futils_readbuffer_updated(
p_close(fd);
- if ((error = git_hash_buf(&checksum_new, buf.ptr, buf.size)) < 0) {
- git_buf_free(&buf);
- return error;
- }
+ if (checksum) {
+ if ((error = git_hash_buf(&checksum_new, buf.ptr, buf.size)) < 0) {
+ git_buf_free(&buf);
+ return error;
+ }
- /*
- * If we were given a checksum, we only want to use it if it's different
- */
- if (checksum && !git_oid__cmp(checksum, &checksum_new)) {
- git_buf_free(&buf);
- if (updated)
- *updated = 0;
+ /*
+ * If we were given a checksum, we only want to use it if it's different
+ */
+ if (!git_oid__cmp(checksum, &checksum_new)) {
+ git_buf_free(&buf);
+ if (updated)
+ *updated = 0;
- return 0;
+ return 0;
+ }
+
+ git_oid_cpy(checksum, &checksum_new);
}
/*
* If we're here, the file did change, or the user didn't have an old version
*/
- if (checksum)
- git_oid_cpy(checksum, &checksum_new);
-
if (updated != NULL)
*updated = 1;
@@ -229,26 +237,43 @@ int git_futils_readbuffer(git_buf *buf, const char *path)
int git_futils_writebuffer(
const git_buf *buf, const char *path, int flags, mode_t mode)
{
- int fd, error = 0;
+ int fd, do_fsync = 0, error = 0;
- if (flags <= 0)
+ if (!flags)
flags = O_CREAT | O_TRUNC | O_WRONLY;
+
+ if ((flags & O_FSYNC) != 0)
+ do_fsync = 1;
+
+ flags &= ~O_FSYNC;
+
if (!mode)
mode = GIT_FILEMODE_BLOB;
if ((fd = p_open(path, flags, mode)) < 0) {
- giterr_set(GITERR_OS, "Could not open '%s' for writing", path);
+ giterr_set(GITERR_OS, "could not open '%s' for writing", path);
return fd;
}
if ((error = p_write(fd, git_buf_cstr(buf), git_buf_len(buf))) < 0) {
- giterr_set(GITERR_OS, "Could not write to '%s'", path);
+ giterr_set(GITERR_OS, "could not write to '%s'", path);
(void)p_close(fd);
return error;
}
- if ((error = p_close(fd)) < 0)
- giterr_set(GITERR_OS, "Error while closing '%s'", path);
+ if (do_fsync && (error = p_fsync(fd)) < 0) {
+ giterr_set(GITERR_OS, "could not fsync '%s'", path);
+ p_close(fd);
+ return error;
+ }
+
+ if ((error = p_close(fd)) < 0) {
+ giterr_set(GITERR_OS, "error while closing '%s'", path);
+ return error;
+ }
+
+ if (do_fsync && (flags & O_CREAT))
+ error = git_futils_fsync_parent(path);
return error;
}
@@ -259,7 +284,7 @@ int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmod
return -1;
if (p_rename(from, to) < 0) {
- giterr_set(GITERR_OS, "Failed to rename '%s' to '%s'", from, to);
+ giterr_set(GITERR_OS, "failed to rename '%s' to '%s'", from, to);
return -1;
}
@@ -280,13 +305,19 @@ int git_futils_mmap_ro_file(git_map *out, const char *path)
if (fd < 0)
return fd;
- len = git_futils_filesize(fd);
+ if ((len = git_futils_filesize(fd)) < 0) {
+ result = -1;
+ goto out;
+ }
+
if (!git__is_sizet(len)) {
- giterr_set(GITERR_OS, "File `%s` too large to mmap", path);
- return -1;
+ giterr_set(GITERR_OS, "file `%s` too large to mmap", path);
+ result = -1;
+ goto out;
}
result = git_futils_mmap_ro(out, fd, 0, (size_t)len);
+out:
p_close(fd);
return result;
}
@@ -306,14 +337,14 @@ GIT_INLINE(int) mkdir_validate_dir(
/* with exclusive create, existing dir is an error */
if ((flags & GIT_MKDIR_EXCL) != 0) {
giterr_set(GITERR_FILESYSTEM,
- "Failed to make directory '%s': directory exists", path);
+ "failed to make directory '%s': directory exists", path);
return GIT_EEXISTS;
}
if ((S_ISREG(st->st_mode) && (flags & GIT_MKDIR_REMOVE_FILES)) ||
(S_ISLNK(st->st_mode) && (flags & GIT_MKDIR_REMOVE_SYMLINKS))) {
if (p_unlink(path) < 0) {
- giterr_set(GITERR_OS, "Failed to remove %s '%s'",
+ giterr_set(GITERR_OS, "failed to remove %s '%s'",
S_ISLNK(st->st_mode) ? "symlink" : "file", path);
return GIT_EEXISTS;
}
@@ -321,7 +352,7 @@ GIT_INLINE(int) mkdir_validate_dir(
opts->perfdata.mkdir_calls++;
if (p_mkdir(path, mode) < 0) {
- giterr_set(GITERR_OS, "Failed to make directory '%s'", path);
+ giterr_set(GITERR_OS, "failed to make directory '%s'", path);
return GIT_EEXISTS;
}
}
@@ -331,14 +362,14 @@ GIT_INLINE(int) mkdir_validate_dir(
opts->perfdata.stat_calls++;
if (p_stat(path, st) < 0) {
- giterr_set(GITERR_OS, "Failed to make directory '%s'", path);
+ giterr_set(GITERR_OS, "failed to make directory '%s'", path);
return GIT_EEXISTS;
}
}
else if (!S_ISDIR(st->st_mode)) {
giterr_set(GITERR_FILESYSTEM,
- "Failed to make directory '%s': directory exists", path);
+ "failed to make directory '%s': directory exists", path);
return GIT_EEXISTS;
}
@@ -561,7 +592,7 @@ int git_futils_mkdir_relative(
retry_lstat:
if (p_lstat(make_path.ptr, &st) < 0) {
if (mkdir_attempted || errno != ENOENT) {
- giterr_set(GITERR_OS, "Cannot access component in path '%s'", make_path.ptr);
+ giterr_set(GITERR_OS, "cannot access component in path '%s'", make_path.ptr);
error = -1;
goto done;
}
@@ -572,7 +603,7 @@ retry_lstat:
if (p_mkdir(make_path.ptr, mode) < 0) {
if (errno == EEXIST)
goto retry_lstat;
- giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr);
+ giterr_set(GITERR_OS, "failed to make directory '%s'", make_path.ptr);
error = -1;
goto done;
}
@@ -599,7 +630,7 @@ retry_lstat:
memcpy(cache_path, make_path.ptr, make_path.size + 1);
- git_strmap_insert(opts->dir_map, cache_path, cache_path, error);
+ git_strmap_insert(opts->dir_map, cache_path, cache_path, &error);
if (error < 0)
goto done;
}
@@ -613,7 +644,7 @@ retry_lstat:
opts->perfdata.stat_calls++;
if (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode)) {
- giterr_set(GITERR_OS, "Path is not a directory '%s'",
+ giterr_set(GITERR_OS, "path is not a directory '%s'",
make_path.ptr);
error = GIT_ENOTFOUND;
}
@@ -636,10 +667,10 @@ typedef struct {
static int futils__error_cannot_rmdir(const char *path, const char *filemsg)
{
if (filemsg)
- giterr_set(GITERR_OS, "Could not remove directory. File '%s' %s",
+ giterr_set(GITERR_OS, "could not remove directory '%s': %s",
path, filemsg);
else
- giterr_set(GITERR_OS, "Could not remove directory '%s'", path);
+ giterr_set(GITERR_OS, "could not remove directory '%s'", path);
return -1;
}
@@ -740,6 +771,9 @@ static int futils__rmdir_empty_parent(void *opaque, const char *path)
if (en == ENOENT || en == ENOTDIR) {
/* do nothing */
+ } else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0 &&
+ en == EBUSY) {
+ error = git_path_set_error(errno, path, "rmdir");
} else if (en == ENOTEMPTY || en == EEXIST || en == EBUSY) {
error = GIT_ITEROVER;
} else {
@@ -807,7 +841,7 @@ static int cp_by_fd(int ifd, int ofd, bool close_fd_when_done)
error = p_write(ofd, buffer, len);
if (len < 0) {
- giterr_set(GITERR_OS, "Read error while copying file");
+ giterr_set(GITERR_OS, "read error while copying file");
error = (int)len;
}
@@ -863,14 +897,14 @@ static int cp_link(const char *from, const char *to, size_t link_size)
read_len = p_readlink(from, link_data, link_size);
if (read_len != (ssize_t)link_size) {
- giterr_set(GITERR_OS, "Failed to read symlink data for '%s'", from);
+ giterr_set(GITERR_OS, "failed to read symlink data for '%s'", from);
error = -1;
}
else {
link_data[read_len] = '\0';
if (p_symlink(link_data, to) < 0) {
- giterr_set(GITERR_OS, "Could not symlink '%s' as '%s'",
+ giterr_set(GITERR_OS, "could not symlink '%s' as '%s'",
link_data, to);
error = -1;
}
@@ -966,7 +1000,7 @@ static int _cp_r_callback(void *ref, git_buf *from)
return 0;
if (p_unlink(info->to.ptr) < 0) {
- giterr_set(GITERR_OS, "Cannot overwrite existing file '%s'",
+ giterr_set(GITERR_OS, "cannot overwrite existing file '%s'",
info->to.ptr);
return GIT_EEXISTS;
}
@@ -1101,3 +1135,37 @@ void git_futils_filestamp_set_from_stat(
memset(stamp, 0, sizeof(*stamp));
}
}
+
+int git_futils_fsync_dir(const char *path)
+{
+#ifdef GIT_WIN32
+ GIT_UNUSED(path);
+ return 0;
+#else
+ int fd, error = -1;
+
+ if ((fd = p_open(path, O_RDONLY)) < 0) {
+ giterr_set(GITERR_OS, "failed to open directory '%s' for fsync", path);
+ return -1;
+ }
+
+ if ((error = p_fsync(fd)) < 0)
+ giterr_set(GITERR_OS, "failed to fsync directory '%s'", path);
+
+ p_close(fd);
+ return error;
+#endif
+}
+
+int git_futils_fsync_parent(const char *path)
+{
+ char *parent;
+ int error;
+
+ if ((parent = git_path_dirname(path)) == NULL)
+ return -1;
+
+ error = git_futils_fsync_dir(parent);
+ git__free(parent);
+ return error;
+}
diff --git a/src/fileops.h b/src/fileops.h
index 54e3bd4e4..fd5441243 100644
--- a/src/fileops.h
+++ b/src/fileops.h
@@ -8,6 +8,7 @@
#define INCLUDE_fileops_h__
#include "common.h"
+
#include "map.h"
#include "posix.h"
#include "path.h"
@@ -25,6 +26,13 @@ extern int git_futils_readbuffer_updated(
git_buf *obj, const char *path, git_oid *checksum, int *updated);
extern int git_futils_readbuffer_fd(git_buf *obj, git_file fd, size_t len);
+/* Additional constants for `git_futils_writebuffer`'s `open_flags`. We
+ * support these internally and they will be removed before the `open` call.
+ */
+#ifndef O_FSYNC
+# define O_FSYNC (1 << 31)
+#endif
+
extern int git_futils_writebuffer(
const git_buf *buf, const char *path, int open_flags, mode_t mode);
@@ -45,12 +53,12 @@ extern int git_futils_writebuffer(
extern int git_futils_creat_withpath(const char *path, const mode_t dirmode, const mode_t mode);
/**
- * Create an open a process-locked file
+ * Create and open a process-locked file
*/
extern int git_futils_creat_locked(const char *path, const mode_t mode);
/**
- * Create an open a process-locked file, while
+ * Create and open a process-locked file, while
* also creating all the folders in its path
*/
extern int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, const mode_t mode);
@@ -356,4 +364,22 @@ extern void git_futils_filestamp_set(
extern void git_futils_filestamp_set_from_stat(
git_futils_filestamp *stamp, struct stat *st);
+/**
+ * `fsync` the parent directory of the given path, if `fsync` is
+ * supported for directories on this platform.
+ *
+ * @param path Path of the directory to sync.
+ * @return 0 on success, -1 on error
+ */
+extern int git_futils_fsync_dir(const char *path);
+
+/**
+ * `fsync` the parent directory of the given path, if `fsync` is
+ * supported for directories on this platform.
+ *
+ * @param path Path of the file whose parent directory should be synced.
+ * @return 0 on success, -1 on error
+ */
+extern int git_futils_fsync_parent(const char *path);
+
#endif /* INCLUDE_fileops_h__ */
diff --git a/src/filter.c b/src/filter.c
index a0628d779..6ab09790b 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -5,10 +5,11 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "filter.h"
+
#include "common.h"
#include "fileops.h"
#include "hash.h"
-#include "filter.h"
#include "repository.h"
#include "global.h"
#include "git2/sys/filter.h"
@@ -296,7 +297,7 @@ int git_filter_unregister(const char *name)
/* cannot unregister default filters */
if (!strcmp(GIT_FILTER_CRLF, name) || !strcmp(GIT_FILTER_IDENT, name)) {
- giterr_set(GITERR_FILTER, "Cannot unregister filter '%s'", name);
+ giterr_set(GITERR_FILTER, "cannot unregister filter '%s'", name);
return -1;
}
@@ -306,7 +307,7 @@ int git_filter_unregister(const char *name)
}
if ((fdef = filter_registry_lookup(&pos, name)) == NULL) {
- giterr_set(GITERR_FILTER, "Cannot find filter '%s' to unregister", name);
+ giterr_set(GITERR_FILTER, "cannot find filter '%s' to unregister", name);
error = GIT_ENOTFOUND;
goto done;
}
@@ -645,7 +646,7 @@ int git_filter_list_push(
git_rwlock_rdunlock(&filter_registry.lock);
if (fdef == NULL) {
- giterr_set(GITERR_FILTER, "Cannot use an unregistered filter");
+ giterr_set(GITERR_FILTER, "cannot use an unregistered filter");
return -1;
}
@@ -758,7 +759,7 @@ static int buf_from_blob(git_buf *out, git_blob *blob)
git_off_t rawsize = git_blob_rawsize(blob);
if (!git__is_sizet(rawsize)) {
- giterr_set(GITERR_OS, "Blob is too large to filter");
+ giterr_set(GITERR_OS, "blob is too large to filter");
return -1;
}
@@ -895,7 +896,7 @@ static int stream_list_init(
git_array_size(filters->filters) - 1 - i : i;
git_filter_entry *fe = git_array_get(filters->filters, filter_idx);
git_writestream *filter_stream;
-
+
assert(fe->filter->stream || fe->filter->apply);
/* If necessary, create a stream that proxies the traditional
@@ -911,14 +912,19 @@ static int stream_list_init(
last_stream);
if (error < 0)
- return error;
+ goto out;
git_vector_insert(streams, filter_stream);
last_stream = filter_stream;
}
- *out = last_stream;
- return 0;
+out:
+ if (error)
+ last_stream->close(last_stream);
+ else
+ *out = last_stream;
+
+ return error;
}
void stream_list_free(git_vector *streams)
@@ -943,12 +949,13 @@ int git_filter_list_stream_file(
git_vector filter_streams = GIT_VECTOR_INIT;
git_writestream *stream_start;
ssize_t readlen;
- int fd = -1, error;
+ int fd = -1, error, initialized = 0;
if ((error = stream_list_init(
&stream_start, &filter_streams, filters, target)) < 0 ||
(error = git_path_join_unrooted(&abspath, path, base, NULL)) < 0)
goto done;
+ initialized = 1;
if ((fd = git_futils_open_ro(abspath.ptr)) < 0) {
error = fd;
@@ -960,13 +967,13 @@ int git_filter_list_stream_file(
goto done;
}
- if (!readlen)
- error = stream_start->close(stream_start);
- else if (readlen < 0)
+ if (readlen < 0)
error = readlen;
-
done:
+ if (initialized)
+ error |= stream_start->close(stream_start);
+
if (fd >= 0)
p_close(fd);
stream_list_free(&filter_streams);
@@ -981,20 +988,24 @@ int git_filter_list_stream_data(
{
git_vector filter_streams = GIT_VECTOR_INIT;
git_writestream *stream_start;
- int error = 0, close_error;
+ int error, initialized = 0;
git_buf_sanitize(data);
if ((error = stream_list_init(&stream_start, &filter_streams, filters, target)) < 0)
goto out;
+ initialized = 1;
- error = stream_start->write(stream_start, data->ptr, data->size);
+ if ((error = stream_start->write(
+ stream_start, data->ptr, data->size)) < 0)
+ goto out;
out:
- close_error = stream_start->close(stream_start);
+ if (initialized)
+ error |= stream_start->close(stream_start);
+
stream_list_free(&filter_streams);
- /* propagate the stream init or write error */
- return error < 0 ? error : close_error;
+ return error;
}
int git_filter_list_stream_blob(
@@ -1012,3 +1023,9 @@ int git_filter_list_stream_blob(
return git_filter_list_stream_data(filters, &in, target);
}
+
+int git_filter_init(git_filter *filter, unsigned int version)
+{
+ GIT_INIT_STRUCTURE_FROM_TEMPLATE(filter, version, git_filter, GIT_FILTER_INIT);
+ return 0;
+}
diff --git a/src/filter.h b/src/filter.h
index 9bd835f94..b1c403ba9 100644
--- a/src/filter.h
+++ b/src/filter.h
@@ -8,6 +8,7 @@
#define INCLUDE_filter_h__
#include "common.h"
+
#include "attr_file.h"
#include "git2/filter.h"
diff --git a/src/fnmatch.c b/src/fnmatch.c
index 33c8a2512..3cc2a27ba 100644
--- a/src/fnmatch.c
+++ b/src/fnmatch.c
@@ -44,12 +44,12 @@
* Compares a filename or pathname to a pattern.
*/
+#include "fnmatch.h"
+
#include <ctype.h>
#include <stdio.h>
#include <string.h>
-#include "fnmatch.h"
-
#define EOS '\0'
#define RANGE_MATCH 1
diff --git a/src/global.c b/src/global.c
index 45b1ab8f6..c6847a4d2 100644
--- a/src/global.c
+++ b/src/global.c
@@ -4,8 +4,9 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+
#include "global.h"
+
#include "hash.h"
#include "sysdir.h"
#include "filter.h"
@@ -22,7 +23,7 @@
git_mutex git__mwindow_mutex;
-#define MAX_SHUTDOWN_CB 8
+#define MAX_SHUTDOWN_CB 9
static git_global_shutdown_fn git__shutdown_callbacks[MAX_SHUTDOWN_CB];
static git_atomic git__n_shutdown_callbacks;
@@ -247,6 +248,7 @@ BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved)
#elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
static pthread_key_t _tls_key;
+static pthread_mutex_t _init_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_once_t _once_init = PTHREAD_ONCE_INIT;
int init_error = 0;
@@ -268,12 +270,19 @@ static void init_once(void)
int git_libgit2_init(void)
{
- int ret;
+ int ret, err;
ret = git_atomic_inc(&git__n_inits);
- pthread_once(&_once_init, init_once);
- return init_error ? init_error : ret;
+ if ((err = pthread_mutex_lock(&_init_mutex)) != 0)
+ return err;
+ err = pthread_once(&_once_init, init_once);
+ err |= pthread_mutex_unlock(&_init_mutex);
+
+ if (err || init_error)
+ return err | init_error;
+
+ return ret;
}
int git_libgit2_shutdown(void)
@@ -285,6 +294,9 @@ int git_libgit2_shutdown(void)
if ((ret = git_atomic_dec(&git__n_inits)) != 0)
return ret;
+ if ((ret = pthread_mutex_lock(&_init_mutex)) != 0)
+ return ret;
+
/* Shut down any subsystems that have global state */
shutdown_common();
@@ -298,6 +310,9 @@ int git_libgit2_shutdown(void)
git_mutex_free(&git__mwindow_mutex);
_once_init = new_once;
+ if ((ret = pthread_mutex_unlock(&_init_mutex)) != 0)
+ return ret;
+
return 0;
}
@@ -327,7 +342,7 @@ int git_libgit2_init(void)
{
int ret;
- /* Only init SSL the first time */
+ /* Only init subsystems the first time */
if ((ret = git_atomic_inc(&git__n_inits)) != 1)
return ret;
@@ -345,6 +360,7 @@ int git_libgit2_shutdown(void)
if ((ret = git_atomic_dec(&git__n_inits)) == 0) {
shutdown_common();
git__global_state_cleanup(&__state);
+ memset(&__state, 0, sizeof(__state));
}
return ret;
diff --git a/src/global.h b/src/global.h
index 219951525..b75ad6f56 100644
--- a/src/global.h
+++ b/src/global.h
@@ -8,6 +8,7 @@
#define INCLUDE_global_h__
#include "common.h"
+
#include "mwindow.h"
#include "hash.h"
@@ -16,6 +17,12 @@ typedef struct {
git_error error_t;
git_buf error_buf;
char oid_fmt[GIT_OID_HEXSZ+1];
+
+ /* On Windows, this is the current child thread that was started by
+ * `git_thread_create`. This is used to set the thread's exit code
+ * when terminated by `git_thread_exit`. It is unused on POSIX.
+ */
+ git_thread *current_thread;
} git_global_st;
#ifdef GIT_OPENSSL
diff --git a/src/graph.c b/src/graph.c
index 8accd808c..df82f0f71 100644
--- a/src/graph.c
+++ b/src/graph.c
@@ -5,6 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "common.h"
+
#include "revwalk.h"
#include "merge.h"
#include "git2/graph.h"
@@ -59,7 +61,7 @@ static int mark_parents(git_revwalk *walk, git_commit_list_node *one,
/* as long as there are non-STALE commits */
while (interesting(&list, roots)) {
git_commit_list_node *commit = git_pqueue_pop(&list);
- int flags;
+ unsigned int flags;
if (commit == NULL)
break;
diff --git a/src/hash.c b/src/hash.c
index f3645a913..cc6676d4d 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -5,7 +5,6 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
#include "hash.h"
int git_hash_buf(git_oid *out, const void *data, size_t len)
diff --git a/src/hash.h b/src/hash.h
index 0bc02a8a9..cce3a7f30 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_hash_h__
#define INCLUDE_hash_h__
+#include "common.h"
+
#include "git2/oid.h"
typedef struct git_hash_prov git_hash_prov;
@@ -16,11 +18,13 @@ int git_hash_global_init(void);
int git_hash_ctx_init(git_hash_ctx *ctx);
void git_hash_ctx_cleanup(git_hash_ctx *ctx);
-#if defined(GIT_COMMON_CRYPTO)
+#if defined(GIT_SHA1_COLLISIONDETECT)
+# include "hash/hash_collisiondetect.h"
+#elif defined(GIT_SHA1_COMMON_CRYPTO)
# include "hash/hash_common_crypto.h"
-#elif defined(OPENSSL_SHA1)
+#elif defined(GIT_SHA1_OPENSSL)
# include "hash/hash_openssl.h"
-#elif defined(WIN32_SHA1)
+#elif defined(GIT_SHA1_WIN32)
# include "hash/hash_win32.h"
#else
# include "hash/hash_generic.h"
diff --git a/src/hash/hash_collisiondetect.h b/src/hash/hash_collisiondetect.h
new file mode 100644
index 000000000..5fdae8df6
--- /dev/null
+++ b/src/hash/hash_collisiondetect.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_hash_collisiondetect_h__
+#define INCLUDE_hash_collisiondetect_h__
+
+#include "hash.h"
+#include "sha1dc/sha1.h"
+
+struct git_hash_ctx {
+ SHA1_CTX c;
+};
+
+#define git_hash_global_init() 0
+#define git_hash_ctx_init(ctx) git_hash_init(ctx)
+#define git_hash_ctx_cleanup(ctx)
+
+GIT_INLINE(int) git_hash_init(git_hash_ctx *ctx)
+{
+ assert(ctx);
+ SHA1DCInit(&ctx->c);
+ return 0;
+}
+
+GIT_INLINE(int) git_hash_update(git_hash_ctx *ctx, const void *data, size_t len)
+{
+ assert(ctx);
+ SHA1DCUpdate(&ctx->c, data, len);
+ return 0;
+}
+
+GIT_INLINE(int) git_hash_final(git_oid *out, git_hash_ctx *ctx)
+{
+ assert(ctx);
+ if (SHA1DCFinal(out->id, &ctx->c)) {
+ giterr_set(GITERR_SHA1, "SHA1 collision attack detected");
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif /* INCLUDE_hash_collisiondetect_h__ */
diff --git a/src/hash/hash_generic.c b/src/hash/hash_generic.c
index 472a7a696..7b33b6194 100644
--- a/src/hash/hash_generic.c
+++ b/src/hash/hash_generic.c
@@ -5,9 +5,9 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+#include "hash_generic.h"
+
#include "hash.h"
-#include "hash/hash_generic.h"
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
diff --git a/src/hash/hash_generic.h b/src/hash/hash_generic.h
index daeb1cda8..114b60781 100644
--- a/src/hash/hash_generic.h
+++ b/src/hash/hash_generic.h
@@ -8,6 +8,8 @@
#ifndef INCLUDE_hash_generic_h__
#define INCLUDE_hash_generic_h__
+#include "common.h"
+
#include "hash.h"
struct git_hash_ctx {
diff --git a/src/hash/hash_win32.c b/src/hash/hash_win32.c
index 6bae53e55..4d53a57bd 100644
--- a/src/hash/hash_win32.c
+++ b/src/hash/hash_win32.c
@@ -5,10 +5,10 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+#include "hash_win32.h"
+
#include "global.h"
#include "hash.h"
-#include "hash/hash_win32.h"
#include <wincrypt.h>
#include <strsafe.h>
diff --git a/src/hash/hash_win32.h b/src/hash/hash_win32.h
index 2eee5ca79..187c07267 100644
--- a/src/hash/hash_win32.h
+++ b/src/hash/hash_win32.h
@@ -9,6 +9,7 @@
#define INCLUDE_hash_win32_h__
#include "common.h"
+
#include "hash.h"
#include <wincrypt.h>
diff --git a/src/hash/sha1dc/sha1.c b/src/hash/sha1dc/sha1.c
new file mode 100644
index 000000000..facea1bb5
--- /dev/null
+++ b/src/hash/sha1dc/sha1.c
@@ -0,0 +1,1856 @@
+/***
+* Copyright 2017 Marc Stevens <marc@marc-stevens.nl>, Dan Shumow (danshu@microsoft.com)
+* Distributed under the MIT Software License.
+* See accompanying file LICENSE.txt or copy at
+* https://opensource.org/licenses/MIT
+***/
+
+#ifndef SHA1DC_NO_STANDARD_INCLUDES
+#include <string.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#endif
+
+#ifdef SHA1DC_CUSTOM_INCLUDE_SHA1_C
+#include SHA1DC_CUSTOM_INCLUDE_SHA1_C
+#endif
+
+#ifndef SHA1DC_INIT_SAFE_HASH_DEFAULT
+#define SHA1DC_INIT_SAFE_HASH_DEFAULT 1
+#endif
+
+#include "sha1.h"
+#include "ubc_check.h"
+
+
+/*
+ Because Little-Endian architectures are most common,
+ we only set SHA1DC_BIGENDIAN if one of these conditions is met.
+ Note that all MSFT platforms are little endian,
+ so none of these will be defined under the MSC compiler.
+ If you are compiling on a big endian platform and your compiler does not define one of these,
+ you will have to add whatever macros your tool chain defines to indicate Big-Endianness.
+ */
+#ifdef SHA1DC_BIGENDIAN
+#undef SHA1DC_BIGENDIAN
+#endif
+
+#if (defined(_BYTE_ORDER) || defined(__BYTE_ORDER) || defined(__BYTE_ORDER__))
+
+#if ((defined(_BYTE_ORDER) && (_BYTE_ORDER == _BIG_ENDIAN)) || \
+ (defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN)) || \
+ (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __BIG_ENDIAN__)) )
+#define SHA1DC_BIGENDIAN
+#endif
+
+#else
+
+#if (defined(_BIG_ENDIAN) || defined(__BIG_ENDIAN) || defined(__BIG_ENDIAN__) || \
+ defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \
+ defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || \
+ defined(__sparc))
+#define SHA1DC_BIGENDIAN
+#endif
+
+#endif
+
+#if (defined(SHA1DC_FORCE_LITTLEENDIAN) && defined(SHA1DC_BIGENDIAN))
+#undef SHA1DC_BIGENDIAN
+#endif
+#if (defined(SHA1DC_FORCE_BIGENDIAN) && !defined(SHA1DC_BIGENDIAN))
+#define SHA1DC_BIGENDIAN
+#endif
+/*ENDIANNESS SELECTION*/
+
+#if (defined SHA1DC_FORCE_UNALIGNED_ACCESS || \
+ defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || \
+ defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || \
+ defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || \
+ defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) || defined(__INTEL__) || \
+ defined(__386) || defined(_M_X64) || defined(_M_AMD64))
+
+#define SHA1DC_ALLOW_UNALIGNED_ACCESS
+
+#endif /*UNALIGNMENT DETECTION*/
+
+
+#define rotate_right(x,n) (((x)>>(n))|((x)<<(32-(n))))
+#define rotate_left(x,n) (((x)<<(n))|((x)>>(32-(n))))
+
+#define sha1_bswap32(x) \
+ {x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0xFF00FF); x = (x << 16) | (x >> 16);}
+
+#define sha1_mix(W, t) (rotate_left(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1))
+
+#ifdef SHA1DC_BIGENDIAN
+ #define sha1_load(m, t, temp) { temp = m[t]; }
+#else
+ #define sha1_load(m, t, temp) { temp = m[t]; sha1_bswap32(temp); }
+#endif
+
+#define sha1_store(W, t, x) *(volatile uint32_t *)&W[t] = x
+
+#define sha1_f1(b,c,d) ((d)^((b)&((c)^(d))))
+#define sha1_f2(b,c,d) ((b)^(c)^(d))
+#define sha1_f3(b,c,d) (((b)&(c))+((d)&((b)^(c))))
+#define sha1_f4(b,c,d) ((b)^(c)^(d))
+
+#define HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, m, t) \
+ { e += rotate_left(a, 5) + sha1_f1(b,c,d) + 0x5A827999 + m[t]; b = rotate_left(b, 30); }
+#define HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, m, t) \
+ { e += rotate_left(a, 5) + sha1_f2(b,c,d) + 0x6ED9EBA1 + m[t]; b = rotate_left(b, 30); }
+#define HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, m, t) \
+ { e += rotate_left(a, 5) + sha1_f3(b,c,d) + 0x8F1BBCDC + m[t]; b = rotate_left(b, 30); }
+#define HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, m, t) \
+ { e += rotate_left(a, 5) + sha1_f4(b,c,d) + 0xCA62C1D6 + m[t]; b = rotate_left(b, 30); }
+
+#define HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, m, t) \
+ { b = rotate_right(b, 30); e -= rotate_left(a, 5) + sha1_f1(b,c,d) + 0x5A827999 + m[t]; }
+#define HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, m, t) \
+ { b = rotate_right(b, 30); e -= rotate_left(a, 5) + sha1_f2(b,c,d) + 0x6ED9EBA1 + m[t]; }
+#define HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, m, t) \
+ { b = rotate_right(b, 30); e -= rotate_left(a, 5) + sha1_f3(b,c,d) + 0x8F1BBCDC + m[t]; }
+#define HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, m, t) \
+ { b = rotate_right(b, 30); e -= rotate_left(a, 5) + sha1_f4(b,c,d) + 0xCA62C1D6 + m[t]; }
+
+#define SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, t, temp) \
+ {sha1_load(m, t, temp); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f1(b,c,d) + 0x5A827999; b = rotate_left(b, 30);}
+
+#define SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(a, b, c, d, e, W, t, temp) \
+ {temp = sha1_mix(W, t); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f1(b,c,d) + 0x5A827999; b = rotate_left(b, 30); }
+
+#define SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, t, temp) \
+ {temp = sha1_mix(W, t); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f2(b,c,d) + 0x6ED9EBA1; b = rotate_left(b, 30); }
+
+#define SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, t, temp) \
+ {temp = sha1_mix(W, t); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f3(b,c,d) + 0x8F1BBCDC; b = rotate_left(b, 30); }
+
+#define SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, t, temp) \
+ {temp = sha1_mix(W, t); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f4(b,c,d) + 0xCA62C1D6; b = rotate_left(b, 30); }
+
+
+#define SHA1_STORE_STATE(i) states[i][0] = a; states[i][1] = b; states[i][2] = c; states[i][3] = d; states[i][4] = e;
+
+#ifdef BUILDNOCOLLDETECTSHA1COMPRESSION
+void sha1_compression(uint32_t ihv[5], const uint32_t m[16])
+{
+ uint32_t W[80];
+ uint32_t a,b,c,d,e;
+ unsigned i;
+
+ memcpy(W, m, 16 * 4);
+ for (i = 16; i < 80; ++i)
+ W[i] = sha1_mix(W, i);
+
+ a = ihv[0]; b = ihv[1]; c = ihv[2]; d = ihv[3]; e = ihv[4];
+
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 0);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 1);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 2);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 3);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 4);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 5);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 6);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 7);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 8);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 9);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 10);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 11);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 12);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 13);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 14);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 15);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 16);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 17);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 18);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 19);
+
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 20);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 21);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 22);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 23);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 24);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 25);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 26);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 27);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 28);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 29);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 30);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 31);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 32);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 33);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 34);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 35);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 36);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 37);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 38);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 39);
+
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 40);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 41);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 42);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 43);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 44);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 45);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 46);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 47);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 48);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 49);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 50);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 51);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 52);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 53);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 54);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 55);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 56);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 57);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 58);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 59);
+
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 60);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 61);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 62);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 63);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 64);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 65);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 66);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 67);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 68);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 69);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 70);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 71);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 72);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 73);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 74);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 75);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 76);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 77);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 78);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 79);
+
+ ihv[0] += a; ihv[1] += b; ihv[2] += c; ihv[3] += d; ihv[4] += e;
+}
+#endif /*BUILDNOCOLLDETECTSHA1COMPRESSION*/
+
+
+static void sha1_compression_W(uint32_t ihv[5], const uint32_t W[80])
+{
+ uint32_t a = ihv[0], b = ihv[1], c = ihv[2], d = ihv[3], e = ihv[4];
+
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 0);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 1);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 2);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 3);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 4);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 5);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 6);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 7);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 8);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 9);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 10);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 11);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 12);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 13);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 14);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 15);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 16);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 17);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 18);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 19);
+
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 20);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 21);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 22);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 23);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 24);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 25);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 26);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 27);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 28);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 29);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 30);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 31);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 32);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 33);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 34);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 35);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 36);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 37);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 38);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 39);
+
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 40);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 41);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 42);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 43);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 44);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 45);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 46);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 47);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 48);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 49);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 50);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 51);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 52);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 53);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 54);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 55);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 56);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 57);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 58);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 59);
+
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 60);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 61);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 62);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 63);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 64);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 65);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 66);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 67);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 68);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 69);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 70);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 71);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 72);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 73);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 74);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 75);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 76);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 77);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 78);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 79);
+
+ ihv[0] += a; ihv[1] += b; ihv[2] += c; ihv[3] += d; ihv[4] += e;
+}
+
+
+
+void sha1_compression_states(uint32_t ihv[5], const uint32_t m[16], uint32_t W[80], uint32_t states[80][5])
+{
+ uint32_t a = ihv[0], b = ihv[1], c = ihv[2], d = ihv[3], e = ihv[4];
+ uint32_t temp;
+
+#ifdef DOSTORESTATE00
+ SHA1_STORE_STATE(0)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 0, temp);
+
+#ifdef DOSTORESTATE01
+ SHA1_STORE_STATE(1)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 1, temp);
+
+#ifdef DOSTORESTATE02
+ SHA1_STORE_STATE(2)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 2, temp);
+
+#ifdef DOSTORESTATE03
+ SHA1_STORE_STATE(3)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 3, temp);
+
+#ifdef DOSTORESTATE04
+ SHA1_STORE_STATE(4)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 4, temp);
+
+#ifdef DOSTORESTATE05
+ SHA1_STORE_STATE(5)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 5, temp);
+
+#ifdef DOSTORESTATE06
+ SHA1_STORE_STATE(6)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 6, temp);
+
+#ifdef DOSTORESTATE07
+ SHA1_STORE_STATE(7)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 7, temp);
+
+#ifdef DOSTORESTATE08
+ SHA1_STORE_STATE(8)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 8, temp);
+
+#ifdef DOSTORESTATE09
+ SHA1_STORE_STATE(9)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 9, temp);
+
+#ifdef DOSTORESTATE10
+ SHA1_STORE_STATE(10)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 10, temp);
+
+#ifdef DOSTORESTATE11
+ SHA1_STORE_STATE(11)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 11, temp);
+
+#ifdef DOSTORESTATE12
+ SHA1_STORE_STATE(12)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 12, temp);
+
+#ifdef DOSTORESTATE13
+ SHA1_STORE_STATE(13)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 13, temp);
+
+#ifdef DOSTORESTATE14
+ SHA1_STORE_STATE(14)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 14, temp);
+
+#ifdef DOSTORESTATE15
+ SHA1_STORE_STATE(15)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 15, temp);
+
+#ifdef DOSTORESTATE16
+ SHA1_STORE_STATE(16)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(e, a, b, c, d, W, 16, temp);
+
+#ifdef DOSTORESTATE17
+ SHA1_STORE_STATE(17)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(d, e, a, b, c, W, 17, temp);
+
+#ifdef DOSTORESTATE18
+ SHA1_STORE_STATE(18)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(c, d, e, a, b, W, 18, temp);
+
+#ifdef DOSTORESTATE19
+ SHA1_STORE_STATE(19)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(b, c, d, e, a, W, 19, temp);
+
+
+
+#ifdef DOSTORESTATE20
+ SHA1_STORE_STATE(20)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 20, temp);
+
+#ifdef DOSTORESTATE21
+ SHA1_STORE_STATE(21)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 21, temp);
+
+#ifdef DOSTORESTATE22
+ SHA1_STORE_STATE(22)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 22, temp);
+
+#ifdef DOSTORESTATE23
+ SHA1_STORE_STATE(23)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 23, temp);
+
+#ifdef DOSTORESTATE24
+ SHA1_STORE_STATE(24)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 24, temp);
+
+#ifdef DOSTORESTATE25
+ SHA1_STORE_STATE(25)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 25, temp);
+
+#ifdef DOSTORESTATE26
+ SHA1_STORE_STATE(26)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 26, temp);
+
+#ifdef DOSTORESTATE27
+ SHA1_STORE_STATE(27)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 27, temp);
+
+#ifdef DOSTORESTATE28
+ SHA1_STORE_STATE(28)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 28, temp);
+
+#ifdef DOSTORESTATE29
+ SHA1_STORE_STATE(29)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 29, temp);
+
+#ifdef DOSTORESTATE30
+ SHA1_STORE_STATE(30)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 30, temp);
+
+#ifdef DOSTORESTATE31
+ SHA1_STORE_STATE(31)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 31, temp);
+
+#ifdef DOSTORESTATE32
+ SHA1_STORE_STATE(32)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 32, temp);
+
+#ifdef DOSTORESTATE33
+ SHA1_STORE_STATE(33)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 33, temp);
+
+#ifdef DOSTORESTATE34
+ SHA1_STORE_STATE(34)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 34, temp);
+
+#ifdef DOSTORESTATE35
+ SHA1_STORE_STATE(35)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 35, temp);
+
+#ifdef DOSTORESTATE36
+ SHA1_STORE_STATE(36)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 36, temp);
+
+#ifdef DOSTORESTATE37
+ SHA1_STORE_STATE(37)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 37, temp);
+
+#ifdef DOSTORESTATE38
+ SHA1_STORE_STATE(38)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 38, temp);
+
+#ifdef DOSTORESTATE39
+ SHA1_STORE_STATE(39)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 39, temp);
+
+
+
+#ifdef DOSTORESTATE40
+ SHA1_STORE_STATE(40)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 40, temp);
+
+#ifdef DOSTORESTATE41
+ SHA1_STORE_STATE(41)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 41, temp);
+
+#ifdef DOSTORESTATE42
+ SHA1_STORE_STATE(42)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 42, temp);
+
+#ifdef DOSTORESTATE43
+ SHA1_STORE_STATE(43)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 43, temp);
+
+#ifdef DOSTORESTATE44
+ SHA1_STORE_STATE(44)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 44, temp);
+
+#ifdef DOSTORESTATE45
+ SHA1_STORE_STATE(45)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 45, temp);
+
+#ifdef DOSTORESTATE46
+ SHA1_STORE_STATE(46)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 46, temp);
+
+#ifdef DOSTORESTATE47
+ SHA1_STORE_STATE(47)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 47, temp);
+
+#ifdef DOSTORESTATE48
+ SHA1_STORE_STATE(48)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 48, temp);
+
+#ifdef DOSTORESTATE49
+ SHA1_STORE_STATE(49)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 49, temp);
+
+#ifdef DOSTORESTATE50
+ SHA1_STORE_STATE(50)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 50, temp);
+
+#ifdef DOSTORESTATE51
+ SHA1_STORE_STATE(51)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 51, temp);
+
+#ifdef DOSTORESTATE52
+ SHA1_STORE_STATE(52)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 52, temp);
+
+#ifdef DOSTORESTATE53
+ SHA1_STORE_STATE(53)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 53, temp);
+
+#ifdef DOSTORESTATE54
+ SHA1_STORE_STATE(54)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 54, temp);
+
+#ifdef DOSTORESTATE55
+ SHA1_STORE_STATE(55)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 55, temp);
+
+#ifdef DOSTORESTATE56
+ SHA1_STORE_STATE(56)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 56, temp);
+
+#ifdef DOSTORESTATE57
+ SHA1_STORE_STATE(57)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 57, temp);
+
+#ifdef DOSTORESTATE58
+ SHA1_STORE_STATE(58)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 58, temp);
+
+#ifdef DOSTORESTATE59
+ SHA1_STORE_STATE(59)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 59, temp);
+
+
+
+
+#ifdef DOSTORESTATE60
+ SHA1_STORE_STATE(60)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 60, temp);
+
+#ifdef DOSTORESTATE61
+ SHA1_STORE_STATE(61)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 61, temp);
+
+#ifdef DOSTORESTATE62
+ SHA1_STORE_STATE(62)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 62, temp);
+
+#ifdef DOSTORESTATE63
+ SHA1_STORE_STATE(63)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 63, temp);
+
+#ifdef DOSTORESTATE64
+ SHA1_STORE_STATE(64)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 64, temp);
+
+#ifdef DOSTORESTATE65
+ SHA1_STORE_STATE(65)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 65, temp);
+
+#ifdef DOSTORESTATE66
+ SHA1_STORE_STATE(66)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 66, temp);
+
+#ifdef DOSTORESTATE67
+ SHA1_STORE_STATE(67)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 67, temp);
+
+#ifdef DOSTORESTATE68
+ SHA1_STORE_STATE(68)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 68, temp);
+
+#ifdef DOSTORESTATE69
+ SHA1_STORE_STATE(69)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 69, temp);
+
+#ifdef DOSTORESTATE70
+ SHA1_STORE_STATE(70)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 70, temp);
+
+#ifdef DOSTORESTATE71
+ SHA1_STORE_STATE(71)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 71, temp);
+
+#ifdef DOSTORESTATE72
+ SHA1_STORE_STATE(72)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 72, temp);
+
+#ifdef DOSTORESTATE73
+ SHA1_STORE_STATE(73)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 73, temp);
+
+#ifdef DOSTORESTATE74
+ SHA1_STORE_STATE(74)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 74, temp);
+
+#ifdef DOSTORESTATE75
+ SHA1_STORE_STATE(75)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 75, temp);
+
+#ifdef DOSTORESTATE76
+ SHA1_STORE_STATE(76)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 76, temp);
+
+#ifdef DOSTORESTATE77
+ SHA1_STORE_STATE(77)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 77, temp);
+
+#ifdef DOSTORESTATE78
+ SHA1_STORE_STATE(78)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 78, temp);
+
+#ifdef DOSTORESTATE79
+ SHA1_STORE_STATE(79)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 79, temp);
+
+
+
+ ihv[0] += a; ihv[1] += b; ihv[2] += c; ihv[3] += d; ihv[4] += e;
+}
+
+
+
+
+#define SHA1_RECOMPRESS(t) \
+static void sha1recompress_fast_ ## t (uint32_t ihvin[5], uint32_t ihvout[5], const uint32_t me2[80], const uint32_t state[5]) \
+{ \
+ uint32_t a = state[0], b = state[1], c = state[2], d = state[3], e = state[4]; \
+ if (t > 79) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 79); \
+ if (t > 78) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 78); \
+ if (t > 77) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 77); \
+ if (t > 76) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 76); \
+ if (t > 75) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 75); \
+ if (t > 74) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 74); \
+ if (t > 73) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 73); \
+ if (t > 72) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 72); \
+ if (t > 71) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 71); \
+ if (t > 70) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 70); \
+ if (t > 69) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 69); \
+ if (t > 68) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 68); \
+ if (t > 67) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 67); \
+ if (t > 66) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 66); \
+ if (t > 65) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 65); \
+ if (t > 64) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 64); \
+ if (t > 63) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 63); \
+ if (t > 62) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 62); \
+ if (t > 61) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 61); \
+ if (t > 60) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 60); \
+ if (t > 59) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 59); \
+ if (t > 58) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 58); \
+ if (t > 57) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 57); \
+ if (t > 56) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 56); \
+ if (t > 55) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 55); \
+ if (t > 54) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 54); \
+ if (t > 53) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 53); \
+ if (t > 52) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 52); \
+ if (t > 51) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 51); \
+ if (t > 50) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 50); \
+ if (t > 49) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 49); \
+ if (t > 48) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 48); \
+ if (t > 47) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 47); \
+ if (t > 46) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 46); \
+ if (t > 45) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 45); \
+ if (t > 44) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 44); \
+ if (t > 43) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 43); \
+ if (t > 42) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 42); \
+ if (t > 41) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 41); \
+ if (t > 40) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 40); \
+ if (t > 39) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 39); \
+ if (t > 38) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 38); \
+ if (t > 37) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 37); \
+ if (t > 36) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 36); \
+ if (t > 35) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 35); \
+ if (t > 34) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 34); \
+ if (t > 33) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 33); \
+ if (t > 32) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 32); \
+ if (t > 31) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 31); \
+ if (t > 30) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 30); \
+ if (t > 29) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 29); \
+ if (t > 28) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 28); \
+ if (t > 27) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 27); \
+ if (t > 26) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 26); \
+ if (t > 25) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 25); \
+ if (t > 24) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 24); \
+ if (t > 23) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 23); \
+ if (t > 22) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 22); \
+ if (t > 21) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 21); \
+ if (t > 20) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 20); \
+ if (t > 19) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 19); \
+ if (t > 18) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 18); \
+ if (t > 17) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 17); \
+ if (t > 16) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 16); \
+ if (t > 15) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 15); \
+ if (t > 14) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 14); \
+ if (t > 13) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 13); \
+ if (t > 12) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 12); \
+ if (t > 11) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 11); \
+ if (t > 10) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 10); \
+ if (t > 9) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 9); \
+ if (t > 8) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 8); \
+ if (t > 7) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 7); \
+ if (t > 6) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 6); \
+ if (t > 5) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 5); \
+ if (t > 4) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 4); \
+ if (t > 3) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 3); \
+ if (t > 2) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 2); \
+ if (t > 1) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 1); \
+ if (t > 0) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 0); \
+ ihvin[0] = a; ihvin[1] = b; ihvin[2] = c; ihvin[3] = d; ihvin[4] = e; \
+ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; \
+ if (t <= 0) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 0); \
+ if (t <= 1) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 1); \
+ if (t <= 2) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 2); \
+ if (t <= 3) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 3); \
+ if (t <= 4) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 4); \
+ if (t <= 5) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 5); \
+ if (t <= 6) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 6); \
+ if (t <= 7) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 7); \
+ if (t <= 8) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 8); \
+ if (t <= 9) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 9); \
+ if (t <= 10) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 10); \
+ if (t <= 11) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 11); \
+ if (t <= 12) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 12); \
+ if (t <= 13) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 13); \
+ if (t <= 14) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 14); \
+ if (t <= 15) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 15); \
+ if (t <= 16) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 16); \
+ if (t <= 17) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 17); \
+ if (t <= 18) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 18); \
+ if (t <= 19) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 19); \
+ if (t <= 20) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 20); \
+ if (t <= 21) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 21); \
+ if (t <= 22) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 22); \
+ if (t <= 23) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 23); \
+ if (t <= 24) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 24); \
+ if (t <= 25) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 25); \
+ if (t <= 26) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 26); \
+ if (t <= 27) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 27); \
+ if (t <= 28) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 28); \
+ if (t <= 29) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 29); \
+ if (t <= 30) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 30); \
+ if (t <= 31) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 31); \
+ if (t <= 32) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 32); \
+ if (t <= 33) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 33); \
+ if (t <= 34) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 34); \
+ if (t <= 35) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 35); \
+ if (t <= 36) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 36); \
+ if (t <= 37) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 37); \
+ if (t <= 38) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 38); \
+ if (t <= 39) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 39); \
+ if (t <= 40) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 40); \
+ if (t <= 41) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 41); \
+ if (t <= 42) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 42); \
+ if (t <= 43) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 43); \
+ if (t <= 44) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 44); \
+ if (t <= 45) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 45); \
+ if (t <= 46) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 46); \
+ if (t <= 47) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 47); \
+ if (t <= 48) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 48); \
+ if (t <= 49) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 49); \
+ if (t <= 50) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 50); \
+ if (t <= 51) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 51); \
+ if (t <= 52) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 52); \
+ if (t <= 53) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 53); \
+ if (t <= 54) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 54); \
+ if (t <= 55) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 55); \
+ if (t <= 56) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 56); \
+ if (t <= 57) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 57); \
+ if (t <= 58) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 58); \
+ if (t <= 59) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 59); \
+ if (t <= 60) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 60); \
+ if (t <= 61) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 61); \
+ if (t <= 62) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 62); \
+ if (t <= 63) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 63); \
+ if (t <= 64) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 64); \
+ if (t <= 65) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 65); \
+ if (t <= 66) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 66); \
+ if (t <= 67) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 67); \
+ if (t <= 68) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 68); \
+ if (t <= 69) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 69); \
+ if (t <= 70) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 70); \
+ if (t <= 71) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 71); \
+ if (t <= 72) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 72); \
+ if (t <= 73) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 73); \
+ if (t <= 74) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 74); \
+ if (t <= 75) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 75); \
+ if (t <= 76) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 76); \
+ if (t <= 77) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 77); \
+ if (t <= 78) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 78); \
+ if (t <= 79) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 79); \
+ ihvout[0] = ihvin[0] + a; ihvout[1] = ihvin[1] + b; ihvout[2] = ihvin[2] + c; ihvout[3] = ihvin[3] + d; ihvout[4] = ihvin[4] + e; \
+}
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4127) /* Complier complains about the checks in the above macro being constant. */
+#endif
+
+#ifdef DOSTORESTATE0
+SHA1_RECOMPRESS(0)
+#endif
+
+#ifdef DOSTORESTATE1
+SHA1_RECOMPRESS(1)
+#endif
+
+#ifdef DOSTORESTATE2
+SHA1_RECOMPRESS(2)
+#endif
+
+#ifdef DOSTORESTATE3
+SHA1_RECOMPRESS(3)
+#endif
+
+#ifdef DOSTORESTATE4
+SHA1_RECOMPRESS(4)
+#endif
+
+#ifdef DOSTORESTATE5
+SHA1_RECOMPRESS(5)
+#endif
+
+#ifdef DOSTORESTATE6
+SHA1_RECOMPRESS(6)
+#endif
+
+#ifdef DOSTORESTATE7
+SHA1_RECOMPRESS(7)
+#endif
+
+#ifdef DOSTORESTATE8
+SHA1_RECOMPRESS(8)
+#endif
+
+#ifdef DOSTORESTATE9
+SHA1_RECOMPRESS(9)
+#endif
+
+#ifdef DOSTORESTATE10
+SHA1_RECOMPRESS(10)
+#endif
+
+#ifdef DOSTORESTATE11
+SHA1_RECOMPRESS(11)
+#endif
+
+#ifdef DOSTORESTATE12
+SHA1_RECOMPRESS(12)
+#endif
+
+#ifdef DOSTORESTATE13
+SHA1_RECOMPRESS(13)
+#endif
+
+#ifdef DOSTORESTATE14
+SHA1_RECOMPRESS(14)
+#endif
+
+#ifdef DOSTORESTATE15
+SHA1_RECOMPRESS(15)
+#endif
+
+#ifdef DOSTORESTATE16
+SHA1_RECOMPRESS(16)
+#endif
+
+#ifdef DOSTORESTATE17
+SHA1_RECOMPRESS(17)
+#endif
+
+#ifdef DOSTORESTATE18
+SHA1_RECOMPRESS(18)
+#endif
+
+#ifdef DOSTORESTATE19
+SHA1_RECOMPRESS(19)
+#endif
+
+#ifdef DOSTORESTATE20
+SHA1_RECOMPRESS(20)
+#endif
+
+#ifdef DOSTORESTATE21
+SHA1_RECOMPRESS(21)
+#endif
+
+#ifdef DOSTORESTATE22
+SHA1_RECOMPRESS(22)
+#endif
+
+#ifdef DOSTORESTATE23
+SHA1_RECOMPRESS(23)
+#endif
+
+#ifdef DOSTORESTATE24
+SHA1_RECOMPRESS(24)
+#endif
+
+#ifdef DOSTORESTATE25
+SHA1_RECOMPRESS(25)
+#endif
+
+#ifdef DOSTORESTATE26
+SHA1_RECOMPRESS(26)
+#endif
+
+#ifdef DOSTORESTATE27
+SHA1_RECOMPRESS(27)
+#endif
+
+#ifdef DOSTORESTATE28
+SHA1_RECOMPRESS(28)
+#endif
+
+#ifdef DOSTORESTATE29
+SHA1_RECOMPRESS(29)
+#endif
+
+#ifdef DOSTORESTATE30
+SHA1_RECOMPRESS(30)
+#endif
+
+#ifdef DOSTORESTATE31
+SHA1_RECOMPRESS(31)
+#endif
+
+#ifdef DOSTORESTATE32
+SHA1_RECOMPRESS(32)
+#endif
+
+#ifdef DOSTORESTATE33
+SHA1_RECOMPRESS(33)
+#endif
+
+#ifdef DOSTORESTATE34
+SHA1_RECOMPRESS(34)
+#endif
+
+#ifdef DOSTORESTATE35
+SHA1_RECOMPRESS(35)
+#endif
+
+#ifdef DOSTORESTATE36
+SHA1_RECOMPRESS(36)
+#endif
+
+#ifdef DOSTORESTATE37
+SHA1_RECOMPRESS(37)
+#endif
+
+#ifdef DOSTORESTATE38
+SHA1_RECOMPRESS(38)
+#endif
+
+#ifdef DOSTORESTATE39
+SHA1_RECOMPRESS(39)
+#endif
+
+#ifdef DOSTORESTATE40
+SHA1_RECOMPRESS(40)
+#endif
+
+#ifdef DOSTORESTATE41
+SHA1_RECOMPRESS(41)
+#endif
+
+#ifdef DOSTORESTATE42
+SHA1_RECOMPRESS(42)
+#endif
+
+#ifdef DOSTORESTATE43
+SHA1_RECOMPRESS(43)
+#endif
+
+#ifdef DOSTORESTATE44
+SHA1_RECOMPRESS(44)
+#endif
+
+#ifdef DOSTORESTATE45
+SHA1_RECOMPRESS(45)
+#endif
+
+#ifdef DOSTORESTATE46
+SHA1_RECOMPRESS(46)
+#endif
+
+#ifdef DOSTORESTATE47
+SHA1_RECOMPRESS(47)
+#endif
+
+#ifdef DOSTORESTATE48
+SHA1_RECOMPRESS(48)
+#endif
+
+#ifdef DOSTORESTATE49
+SHA1_RECOMPRESS(49)
+#endif
+
+#ifdef DOSTORESTATE50
+SHA1_RECOMPRESS(50)
+#endif
+
+#ifdef DOSTORESTATE51
+SHA1_RECOMPRESS(51)
+#endif
+
+#ifdef DOSTORESTATE52
+SHA1_RECOMPRESS(52)
+#endif
+
+#ifdef DOSTORESTATE53
+SHA1_RECOMPRESS(53)
+#endif
+
+#ifdef DOSTORESTATE54
+SHA1_RECOMPRESS(54)
+#endif
+
+#ifdef DOSTORESTATE55
+SHA1_RECOMPRESS(55)
+#endif
+
+#ifdef DOSTORESTATE56
+SHA1_RECOMPRESS(56)
+#endif
+
+#ifdef DOSTORESTATE57
+SHA1_RECOMPRESS(57)
+#endif
+
+#ifdef DOSTORESTATE58
+SHA1_RECOMPRESS(58)
+#endif
+
+#ifdef DOSTORESTATE59
+SHA1_RECOMPRESS(59)
+#endif
+
+#ifdef DOSTORESTATE60
+SHA1_RECOMPRESS(60)
+#endif
+
+#ifdef DOSTORESTATE61
+SHA1_RECOMPRESS(61)
+#endif
+
+#ifdef DOSTORESTATE62
+SHA1_RECOMPRESS(62)
+#endif
+
+#ifdef DOSTORESTATE63
+SHA1_RECOMPRESS(63)
+#endif
+
+#ifdef DOSTORESTATE64
+SHA1_RECOMPRESS(64)
+#endif
+
+#ifdef DOSTORESTATE65
+SHA1_RECOMPRESS(65)
+#endif
+
+#ifdef DOSTORESTATE66
+SHA1_RECOMPRESS(66)
+#endif
+
+#ifdef DOSTORESTATE67
+SHA1_RECOMPRESS(67)
+#endif
+
+#ifdef DOSTORESTATE68
+SHA1_RECOMPRESS(68)
+#endif
+
+#ifdef DOSTORESTATE69
+SHA1_RECOMPRESS(69)
+#endif
+
+#ifdef DOSTORESTATE70
+SHA1_RECOMPRESS(70)
+#endif
+
+#ifdef DOSTORESTATE71
+SHA1_RECOMPRESS(71)
+#endif
+
+#ifdef DOSTORESTATE72
+SHA1_RECOMPRESS(72)
+#endif
+
+#ifdef DOSTORESTATE73
+SHA1_RECOMPRESS(73)
+#endif
+
+#ifdef DOSTORESTATE74
+SHA1_RECOMPRESS(74)
+#endif
+
+#ifdef DOSTORESTATE75
+SHA1_RECOMPRESS(75)
+#endif
+
+#ifdef DOSTORESTATE76
+SHA1_RECOMPRESS(76)
+#endif
+
+#ifdef DOSTORESTATE77
+SHA1_RECOMPRESS(77)
+#endif
+
+#ifdef DOSTORESTATE78
+SHA1_RECOMPRESS(78)
+#endif
+
+#ifdef DOSTORESTATE79
+SHA1_RECOMPRESS(79)
+#endif
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+static void sha1_recompression_step(uint32_t step, uint32_t ihvin[5], uint32_t ihvout[5], const uint32_t me2[80], const uint32_t state[5])
+{
+ switch (step)
+ {
+#ifdef DOSTORESTATE0
+ case 0:
+ sha1recompress_fast_0(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE1
+ case 1:
+ sha1recompress_fast_1(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE2
+ case 2:
+ sha1recompress_fast_2(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE3
+ case 3:
+ sha1recompress_fast_3(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE4
+ case 4:
+ sha1recompress_fast_4(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE5
+ case 5:
+ sha1recompress_fast_5(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE6
+ case 6:
+ sha1recompress_fast_6(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE7
+ case 7:
+ sha1recompress_fast_7(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE8
+ case 8:
+ sha1recompress_fast_8(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE9
+ case 9:
+ sha1recompress_fast_9(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE10
+ case 10:
+ sha1recompress_fast_10(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE11
+ case 11:
+ sha1recompress_fast_11(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE12
+ case 12:
+ sha1recompress_fast_12(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE13
+ case 13:
+ sha1recompress_fast_13(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE14
+ case 14:
+ sha1recompress_fast_14(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE15
+ case 15:
+ sha1recompress_fast_15(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE16
+ case 16:
+ sha1recompress_fast_16(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE17
+ case 17:
+ sha1recompress_fast_17(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE18
+ case 18:
+ sha1recompress_fast_18(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE19
+ case 19:
+ sha1recompress_fast_19(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE20
+ case 20:
+ sha1recompress_fast_20(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE21
+ case 21:
+ sha1recompress_fast_21(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE22
+ case 22:
+ sha1recompress_fast_22(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE23
+ case 23:
+ sha1recompress_fast_23(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE24
+ case 24:
+ sha1recompress_fast_24(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE25
+ case 25:
+ sha1recompress_fast_25(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE26
+ case 26:
+ sha1recompress_fast_26(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE27
+ case 27:
+ sha1recompress_fast_27(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE28
+ case 28:
+ sha1recompress_fast_28(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE29
+ case 29:
+ sha1recompress_fast_29(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE30
+ case 30:
+ sha1recompress_fast_30(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE31
+ case 31:
+ sha1recompress_fast_31(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE32
+ case 32:
+ sha1recompress_fast_32(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE33
+ case 33:
+ sha1recompress_fast_33(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE34
+ case 34:
+ sha1recompress_fast_34(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE35
+ case 35:
+ sha1recompress_fast_35(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE36
+ case 36:
+ sha1recompress_fast_36(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE37
+ case 37:
+ sha1recompress_fast_37(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE38
+ case 38:
+ sha1recompress_fast_38(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE39
+ case 39:
+ sha1recompress_fast_39(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE40
+ case 40:
+ sha1recompress_fast_40(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE41
+ case 41:
+ sha1recompress_fast_41(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE42
+ case 42:
+ sha1recompress_fast_42(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE43
+ case 43:
+ sha1recompress_fast_43(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE44
+ case 44:
+ sha1recompress_fast_44(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE45
+ case 45:
+ sha1recompress_fast_45(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE46
+ case 46:
+ sha1recompress_fast_46(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE47
+ case 47:
+ sha1recompress_fast_47(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE48
+ case 48:
+ sha1recompress_fast_48(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE49
+ case 49:
+ sha1recompress_fast_49(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE50
+ case 50:
+ sha1recompress_fast_50(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE51
+ case 51:
+ sha1recompress_fast_51(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE52
+ case 52:
+ sha1recompress_fast_52(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE53
+ case 53:
+ sha1recompress_fast_53(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE54
+ case 54:
+ sha1recompress_fast_54(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE55
+ case 55:
+ sha1recompress_fast_55(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE56
+ case 56:
+ sha1recompress_fast_56(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE57
+ case 57:
+ sha1recompress_fast_57(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE58
+ case 58:
+ sha1recompress_fast_58(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE59
+ case 59:
+ sha1recompress_fast_59(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE60
+ case 60:
+ sha1recompress_fast_60(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE61
+ case 61:
+ sha1recompress_fast_61(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE62
+ case 62:
+ sha1recompress_fast_62(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE63
+ case 63:
+ sha1recompress_fast_63(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE64
+ case 64:
+ sha1recompress_fast_64(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE65
+ case 65:
+ sha1recompress_fast_65(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE66
+ case 66:
+ sha1recompress_fast_66(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE67
+ case 67:
+ sha1recompress_fast_67(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE68
+ case 68:
+ sha1recompress_fast_68(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE69
+ case 69:
+ sha1recompress_fast_69(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE70
+ case 70:
+ sha1recompress_fast_70(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE71
+ case 71:
+ sha1recompress_fast_71(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE72
+ case 72:
+ sha1recompress_fast_72(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE73
+ case 73:
+ sha1recompress_fast_73(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE74
+ case 74:
+ sha1recompress_fast_74(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE75
+ case 75:
+ sha1recompress_fast_75(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE76
+ case 76:
+ sha1recompress_fast_76(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE77
+ case 77:
+ sha1recompress_fast_77(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE78
+ case 78:
+ sha1recompress_fast_78(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE79
+ case 79:
+ sha1recompress_fast_79(ihvin, ihvout, me2, state);
+ break;
+#endif
+ default:
+ abort();
+ }
+
+}
+
+
+
+static void sha1_process(SHA1_CTX* ctx, const uint32_t block[16])
+{
+ unsigned i, j;
+ uint32_t ubc_dv_mask[DVMASKSIZE] = { 0xFFFFFFFF };
+ uint32_t ihvtmp[5];
+
+ ctx->ihv1[0] = ctx->ihv[0];
+ ctx->ihv1[1] = ctx->ihv[1];
+ ctx->ihv1[2] = ctx->ihv[2];
+ ctx->ihv1[3] = ctx->ihv[3];
+ ctx->ihv1[4] = ctx->ihv[4];
+
+ sha1_compression_states(ctx->ihv, block, ctx->m1, ctx->states);
+
+ if (ctx->detect_coll)
+ {
+ if (ctx->ubc_check)
+ {
+ ubc_check(ctx->m1, ubc_dv_mask);
+ }
+
+ if (ubc_dv_mask[0] != 0)
+ {
+ for (i = 0; sha1_dvs[i].dvType != 0; ++i)
+ {
+ if (ubc_dv_mask[0] & ((uint32_t)(1) << sha1_dvs[i].maskb))
+ {
+ for (j = 0; j < 80; ++j)
+ ctx->m2[j] = ctx->m1[j] ^ sha1_dvs[i].dm[j];
+
+ sha1_recompression_step(sha1_dvs[i].testt, ctx->ihv2, ihvtmp, ctx->m2, ctx->states[sha1_dvs[i].testt]);
+
+ /* to verify SHA-1 collision detection code with collisions for reduced-step SHA-1 */
+ if ((0 == ((ihvtmp[0] ^ ctx->ihv[0]) | (ihvtmp[1] ^ ctx->ihv[1]) | (ihvtmp[2] ^ ctx->ihv[2]) | (ihvtmp[3] ^ ctx->ihv[3]) | (ihvtmp[4] ^ ctx->ihv[4])))
+ || (ctx->reduced_round_coll && 0==((ctx->ihv1[0] ^ ctx->ihv2[0]) | (ctx->ihv1[1] ^ ctx->ihv2[1]) | (ctx->ihv1[2] ^ ctx->ihv2[2]) | (ctx->ihv1[3] ^ ctx->ihv2[3]) | (ctx->ihv1[4] ^ ctx->ihv2[4]))))
+ {
+ ctx->found_collision = 1;
+
+ if (ctx->safe_hash)
+ {
+ sha1_compression_W(ctx->ihv, ctx->m1);
+ sha1_compression_W(ctx->ihv, ctx->m1);
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+void SHA1DCInit(SHA1_CTX* ctx)
+{
+ ctx->total = 0;
+ ctx->ihv[0] = 0x67452301;
+ ctx->ihv[1] = 0xEFCDAB89;
+ ctx->ihv[2] = 0x98BADCFE;
+ ctx->ihv[3] = 0x10325476;
+ ctx->ihv[4] = 0xC3D2E1F0;
+ ctx->found_collision = 0;
+ ctx->safe_hash = SHA1DC_INIT_SAFE_HASH_DEFAULT;
+ ctx->ubc_check = 1;
+ ctx->detect_coll = 1;
+ ctx->reduced_round_coll = 0;
+ ctx->callback = NULL;
+}
+
+void SHA1DCSetSafeHash(SHA1_CTX* ctx, int safehash)
+{
+ if (safehash)
+ ctx->safe_hash = 1;
+ else
+ ctx->safe_hash = 0;
+}
+
+
+void SHA1DCSetUseUBC(SHA1_CTX* ctx, int ubc_check)
+{
+ if (ubc_check)
+ ctx->ubc_check = 1;
+ else
+ ctx->ubc_check = 0;
+}
+
+void SHA1DCSetUseDetectColl(SHA1_CTX* ctx, int detect_coll)
+{
+ if (detect_coll)
+ ctx->detect_coll = 1;
+ else
+ ctx->detect_coll = 0;
+}
+
+void SHA1DCSetDetectReducedRoundCollision(SHA1_CTX* ctx, int reduced_round_coll)
+{
+ if (reduced_round_coll)
+ ctx->reduced_round_coll = 1;
+ else
+ ctx->reduced_round_coll = 0;
+}
+
+void SHA1DCSetCallback(SHA1_CTX* ctx, collision_block_callback callback)
+{
+ ctx->callback = callback;
+}
+
+void SHA1DCUpdate(SHA1_CTX* ctx, const char* buf, size_t len)
+{
+ unsigned left, fill;
+
+ if (len == 0)
+ return;
+
+ left = ctx->total & 63;
+ fill = 64 - left;
+
+ if (left && len >= fill)
+ {
+ ctx->total += fill;
+ memcpy(ctx->buffer + left, buf, fill);
+ sha1_process(ctx, (uint32_t*)(ctx->buffer));
+ buf += fill;
+ len -= fill;
+ left = 0;
+ }
+ while (len >= 64)
+ {
+ ctx->total += 64;
+
+#if defined(SHA1DC_ALLOW_UNALIGNED_ACCESS)
+ sha1_process(ctx, (uint32_t*)(buf));
+#else
+ memcpy(ctx->buffer, buf, 64);
+ sha1_process(ctx, (uint32_t*)(ctx->buffer));
+#endif /* defined(SHA1DC_ALLOW_UNALIGNED_ACCESS) */
+ buf += 64;
+ len -= 64;
+ }
+ if (len > 0)
+ {
+ ctx->total += len;
+ memcpy(ctx->buffer + left, buf, len);
+ }
+}
+
+static const unsigned char sha1_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+int SHA1DCFinal(unsigned char output[20], SHA1_CTX *ctx)
+{
+ uint32_t last = ctx->total & 63;
+ uint32_t padn = (last < 56) ? (56 - last) : (120 - last);
+ uint64_t total;
+ SHA1DCUpdate(ctx, (const char*)(sha1_padding), padn);
+
+ total = ctx->total - padn;
+ total <<= 3;
+ ctx->buffer[56] = (unsigned char)(total >> 56);
+ ctx->buffer[57] = (unsigned char)(total >> 48);
+ ctx->buffer[58] = (unsigned char)(total >> 40);
+ ctx->buffer[59] = (unsigned char)(total >> 32);
+ ctx->buffer[60] = (unsigned char)(total >> 24);
+ ctx->buffer[61] = (unsigned char)(total >> 16);
+ ctx->buffer[62] = (unsigned char)(total >> 8);
+ ctx->buffer[63] = (unsigned char)(total);
+ sha1_process(ctx, (uint32_t*)(ctx->buffer));
+ output[0] = (unsigned char)(ctx->ihv[0] >> 24);
+ output[1] = (unsigned char)(ctx->ihv[0] >> 16);
+ output[2] = (unsigned char)(ctx->ihv[0] >> 8);
+ output[3] = (unsigned char)(ctx->ihv[0]);
+ output[4] = (unsigned char)(ctx->ihv[1] >> 24);
+ output[5] = (unsigned char)(ctx->ihv[1] >> 16);
+ output[6] = (unsigned char)(ctx->ihv[1] >> 8);
+ output[7] = (unsigned char)(ctx->ihv[1]);
+ output[8] = (unsigned char)(ctx->ihv[2] >> 24);
+ output[9] = (unsigned char)(ctx->ihv[2] >> 16);
+ output[10] = (unsigned char)(ctx->ihv[2] >> 8);
+ output[11] = (unsigned char)(ctx->ihv[2]);
+ output[12] = (unsigned char)(ctx->ihv[3] >> 24);
+ output[13] = (unsigned char)(ctx->ihv[3] >> 16);
+ output[14] = (unsigned char)(ctx->ihv[3] >> 8);
+ output[15] = (unsigned char)(ctx->ihv[3]);
+ output[16] = (unsigned char)(ctx->ihv[4] >> 24);
+ output[17] = (unsigned char)(ctx->ihv[4] >> 16);
+ output[18] = (unsigned char)(ctx->ihv[4] >> 8);
+ output[19] = (unsigned char)(ctx->ihv[4]);
+ return ctx->found_collision;
+}
+
+#ifdef SHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_C
+#include SHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_C
+#endif
diff --git a/src/hash/sha1dc/sha1.h b/src/hash/sha1dc/sha1.h
new file mode 100644
index 000000000..1e4e94be5
--- /dev/null
+++ b/src/hash/sha1dc/sha1.h
@@ -0,0 +1,110 @@
+/***
+* Copyright 2017 Marc Stevens <marc@marc-stevens.nl>, Dan Shumow <danshu@microsoft.com>
+* Distributed under the MIT Software License.
+* See accompanying file LICENSE.txt or copy at
+* https://opensource.org/licenses/MIT
+***/
+
+#ifndef SHA1DC_SHA1_H
+#define SHA1DC_SHA1_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#ifndef SHA1DC_NO_STANDARD_INCLUDES
+#include <stdint.h>
+#endif
+
+/* sha-1 compression function that takes an already expanded message, and additionally store intermediate states */
+/* only stores states ii (the state between step ii-1 and step ii) when DOSTORESTATEii is defined in ubc_check.h */
+void sha1_compression_states(uint32_t[5], const uint32_t[16], uint32_t[80], uint32_t[80][5]);
+
+/*
+// Function type for sha1_recompression_step_T (uint32_t ihvin[5], uint32_t ihvout[5], const uint32_t me2[80], const uint32_t state[5]).
+// Where 0 <= T < 80
+// me2 is an expanded message (the expansion of an original message block XOR'ed with a disturbance vector's message block difference.)
+// state is the internal state (a,b,c,d,e) before step T of the SHA-1 compression function while processing the original message block.
+// The function will return:
+// ihvin: The reconstructed input chaining value.
+// ihvout: The reconstructed output chaining value.
+*/
+typedef void(*sha1_recompression_type)(uint32_t*, uint32_t*, const uint32_t*, const uint32_t*);
+
+/* A callback function type that can be set to be called when a collision block has been found: */
+/* void collision_block_callback(uint64_t byteoffset, const uint32_t ihvin1[5], const uint32_t ihvin2[5], const uint32_t m1[80], const uint32_t m2[80]) */
+typedef void(*collision_block_callback)(uint64_t, const uint32_t*, const uint32_t*, const uint32_t*, const uint32_t*);
+
+/* The SHA-1 context. */
+typedef struct {
+ uint64_t total;
+ uint32_t ihv[5];
+ unsigned char buffer[64];
+ int found_collision;
+ int safe_hash;
+ int detect_coll;
+ int ubc_check;
+ int reduced_round_coll;
+ collision_block_callback callback;
+
+ uint32_t ihv1[5];
+ uint32_t ihv2[5];
+ uint32_t m1[80];
+ uint32_t m2[80];
+ uint32_t states[80][5];
+} SHA1_CTX;
+
+/* Initialize SHA-1 context. */
+void SHA1DCInit(SHA1_CTX*);
+
+/*
+ Function to enable safe SHA-1 hashing:
+ Collision attacks are thwarted by hashing a detected near-collision block 3 times.
+ Think of it as extending SHA-1 from 80-steps to 240-steps for such blocks:
+ The best collision attacks against SHA-1 have complexity about 2^60,
+ thus for 240-steps an immediate lower-bound for the best cryptanalytic attacks would be 2^180.
+ An attacker would be better off using a generic birthday search of complexity 2^80.
+
+ Enabling safe SHA-1 hashing will result in the correct SHA-1 hash for messages where no collision attack was detected,
+ but it will result in a different SHA-1 hash for messages where a collision attack was detected.
+ This will automatically invalidate SHA-1 based digital signature forgeries.
+ Enabled by default.
+*/
+void SHA1DCSetSafeHash(SHA1_CTX*, int);
+
+/*
+ Function to disable or enable the use of Unavoidable Bitconditions (provides a significant speed up).
+ Enabled by default
+ */
+void SHA1DCSetUseUBC(SHA1_CTX*, int);
+
+/*
+ Function to disable or enable the use of Collision Detection.
+ Enabled by default.
+ */
+void SHA1DCSetUseDetectColl(SHA1_CTX*, int);
+
+/* function to disable or enable the detection of reduced-round SHA-1 collisions */
+/* disabled by default */
+void SHA1DCSetDetectReducedRoundCollision(SHA1_CTX*, int);
+
+/* function to set a callback function, pass NULL to disable */
+/* by default no callback set */
+void SHA1DCSetCallback(SHA1_CTX*, collision_block_callback);
+
+/* update SHA-1 context with buffer contents */
+void SHA1DCUpdate(SHA1_CTX*, const char*, size_t);
+
+/* obtain SHA-1 hash from SHA-1 context */
+/* returns: 0 = no collision detected, otherwise = collision found => warn user for active attack */
+int SHA1DCFinal(unsigned char[20], SHA1_CTX*);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#ifdef SHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_H
+#include SHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_H
+#endif
+
+#endif
diff --git a/src/hash/sha1dc/ubc_check.c b/src/hash/sha1dc/ubc_check.c
new file mode 100644
index 000000000..b3beff2af
--- /dev/null
+++ b/src/hash/sha1dc/ubc_check.c
@@ -0,0 +1,372 @@
+/***
+* Copyright 2017 Marc Stevens <marc@marc-stevens.nl>, Dan Shumow <danshu@microsoft.com>
+* Distributed under the MIT Software License.
+* See accompanying file LICENSE.txt or copy at
+* https://opensource.org/licenses/MIT
+***/
+
+/*
+// this file was generated by the 'parse_bitrel' program in the tools section
+// using the data files from directory 'tools/data/3565'
+//
+// sha1_dvs contains a list of SHA-1 Disturbance Vectors (DV) to check
+// dvType, dvK and dvB define the DV: I(K,B) or II(K,B) (see the paper)
+// dm[80] is the expanded message block XOR-difference defined by the DV
+// testt is the step to do the recompression from for collision detection
+// maski and maskb define the bit to check for each DV in the dvmask returned by ubc_check
+//
+// ubc_check takes as input an expanded message block and verifies the unavoidable bitconditions for all listed DVs
+// it returns a dvmask where each bit belonging to a DV is set if all unavoidable bitconditions for that DV have been met
+// thus one needs to do the recompression check for each DV that has its bit set
+//
+// ubc_check is programmatically generated and the unavoidable bitconditions have been hardcoded
+// a directly verifiable version named ubc_check_verify can be found in ubc_check_verify.c
+// ubc_check has been verified against ubc_check_verify using the 'ubc_check_test' program in the tools section
+*/
+
+#ifndef SHA1DC_NO_STANDARD_INCLUDES
+#include <stdint.h>
+#endif
+#ifdef SHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C
+#include SHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C
+#endif
+#include "ubc_check.h"
+
+static const uint32_t DV_I_43_0_bit = (uint32_t)(1) << 0;
+static const uint32_t DV_I_44_0_bit = (uint32_t)(1) << 1;
+static const uint32_t DV_I_45_0_bit = (uint32_t)(1) << 2;
+static const uint32_t DV_I_46_0_bit = (uint32_t)(1) << 3;
+static const uint32_t DV_I_46_2_bit = (uint32_t)(1) << 4;
+static const uint32_t DV_I_47_0_bit = (uint32_t)(1) << 5;
+static const uint32_t DV_I_47_2_bit = (uint32_t)(1) << 6;
+static const uint32_t DV_I_48_0_bit = (uint32_t)(1) << 7;
+static const uint32_t DV_I_48_2_bit = (uint32_t)(1) << 8;
+static const uint32_t DV_I_49_0_bit = (uint32_t)(1) << 9;
+static const uint32_t DV_I_49_2_bit = (uint32_t)(1) << 10;
+static const uint32_t DV_I_50_0_bit = (uint32_t)(1) << 11;
+static const uint32_t DV_I_50_2_bit = (uint32_t)(1) << 12;
+static const uint32_t DV_I_51_0_bit = (uint32_t)(1) << 13;
+static const uint32_t DV_I_51_2_bit = (uint32_t)(1) << 14;
+static const uint32_t DV_I_52_0_bit = (uint32_t)(1) << 15;
+static const uint32_t DV_II_45_0_bit = (uint32_t)(1) << 16;
+static const uint32_t DV_II_46_0_bit = (uint32_t)(1) << 17;
+static const uint32_t DV_II_46_2_bit = (uint32_t)(1) << 18;
+static const uint32_t DV_II_47_0_bit = (uint32_t)(1) << 19;
+static const uint32_t DV_II_48_0_bit = (uint32_t)(1) << 20;
+static const uint32_t DV_II_49_0_bit = (uint32_t)(1) << 21;
+static const uint32_t DV_II_49_2_bit = (uint32_t)(1) << 22;
+static const uint32_t DV_II_50_0_bit = (uint32_t)(1) << 23;
+static const uint32_t DV_II_50_2_bit = (uint32_t)(1) << 24;
+static const uint32_t DV_II_51_0_bit = (uint32_t)(1) << 25;
+static const uint32_t DV_II_51_2_bit = (uint32_t)(1) << 26;
+static const uint32_t DV_II_52_0_bit = (uint32_t)(1) << 27;
+static const uint32_t DV_II_53_0_bit = (uint32_t)(1) << 28;
+static const uint32_t DV_II_54_0_bit = (uint32_t)(1) << 29;
+static const uint32_t DV_II_55_0_bit = (uint32_t)(1) << 30;
+static const uint32_t DV_II_56_0_bit = (uint32_t)(1) << 31;
+
+dv_info_t sha1_dvs[] =
+{
+ {1,43,0,58,0,0, { 0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6,0x8000004c,0x00000803,0x80000161,0x80000599 } }
+, {1,44,0,58,0,1, { 0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6,0x8000004c,0x00000803,0x80000161 } }
+, {1,45,0,58,0,2, { 0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6,0x8000004c,0x00000803 } }
+, {1,46,0,58,0,3, { 0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6,0x8000004c } }
+, {1,46,2,58,0,4, { 0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060,0x00000590,0x00001020,0x0000039a,0x00000132 } }
+, {1,47,0,58,0,5, { 0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6 } }
+, {1,47,2,58,0,6, { 0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060,0x00000590,0x00001020,0x0000039a } }
+, {1,48,0,58,0,7, { 0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408 } }
+, {1,48,2,58,0,8, { 0xe000002a,0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060,0x00000590,0x00001020 } }
+, {1,49,0,58,0,9, { 0x18000000,0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164 } }
+, {1,49,2,58,0,10, { 0x60000000,0xe000002a,0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060,0x00000590 } }
+, {1,50,0,65,0,11, { 0x0800000c,0x18000000,0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018 } }
+, {1,50,2,65,0,12, { 0x20000030,0x60000000,0xe000002a,0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060 } }
+, {1,51,0,65,0,13, { 0xe8000000,0x0800000c,0x18000000,0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202 } }
+, {1,51,2,65,0,14, { 0xa0000003,0x20000030,0x60000000,0xe000002a,0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a } }
+, {1,52,0,65,0,15, { 0x04000010,0xe8000000,0x0800000c,0x18000000,0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012 } }
+, {2,45,0,58,0,16, { 0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d,0x8000041a,0x000002e4,0x80000054,0x00000967 } }
+, {2,46,0,58,0,17, { 0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d,0x8000041a,0x000002e4,0x80000054 } }
+, {2,46,2,58,0,18, { 0x90000070,0xb0000053,0x30000008,0x00000043,0xd0000072,0xb0000010,0xf0000062,0xc0000042,0x00000030,0xe0000042,0x20000060,0xe0000041,0x20000050,0xc0000041,0xe0000072,0xa0000003,0xc0000012,0x60000041,0xc0000032,0x20000001,0xc0000002,0xe0000042,0x60000042,0x80000002,0x00000000,0x00000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000001,0x00000060,0x80000003,0x40000002,0xc0000040,0xc0000002,0x80000000,0x80000000,0x80000002,0x00000040,0x00000002,0x80000000,0x80000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000105,0x00000089,0x00000016,0x0000020b,0x0000011b,0x0000012d,0x0000041e,0x00000224,0x00000050,0x0000092e,0x0000046c,0x000005b6,0x0000106a,0x00000b90,0x00000152 } }
+, {2,47,0,58,0,19, { 0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d,0x8000041a,0x000002e4 } }
+, {2,48,0,58,0,20, { 0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d,0x8000041a } }
+, {2,49,0,58,0,21, { 0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d } }
+, {2,49,2,58,0,22, { 0xf0000010,0xf000006a,0x80000040,0x90000070,0xb0000053,0x30000008,0x00000043,0xd0000072,0xb0000010,0xf0000062,0xc0000042,0x00000030,0xe0000042,0x20000060,0xe0000041,0x20000050,0xc0000041,0xe0000072,0xa0000003,0xc0000012,0x60000041,0xc0000032,0x20000001,0xc0000002,0xe0000042,0x60000042,0x80000002,0x00000000,0x00000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000001,0x00000060,0x80000003,0x40000002,0xc0000040,0xc0000002,0x80000000,0x80000000,0x80000002,0x00000040,0x00000002,0x80000000,0x80000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000105,0x00000089,0x00000016,0x0000020b,0x0000011b,0x0000012d,0x0000041e,0x00000224,0x00000050,0x0000092e,0x0000046c,0x000005b6 } }
+, {2,50,0,65,0,23, { 0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b } }
+, {2,50,2,65,0,24, { 0xd0000072,0xf0000010,0xf000006a,0x80000040,0x90000070,0xb0000053,0x30000008,0x00000043,0xd0000072,0xb0000010,0xf0000062,0xc0000042,0x00000030,0xe0000042,0x20000060,0xe0000041,0x20000050,0xc0000041,0xe0000072,0xa0000003,0xc0000012,0x60000041,0xc0000032,0x20000001,0xc0000002,0xe0000042,0x60000042,0x80000002,0x00000000,0x00000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000001,0x00000060,0x80000003,0x40000002,0xc0000040,0xc0000002,0x80000000,0x80000000,0x80000002,0x00000040,0x00000002,0x80000000,0x80000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000105,0x00000089,0x00000016,0x0000020b,0x0000011b,0x0000012d,0x0000041e,0x00000224,0x00000050,0x0000092e,0x0000046c } }
+, {2,51,0,65,0,25, { 0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b } }
+, {2,51,2,65,0,26, { 0x00000043,0xd0000072,0xf0000010,0xf000006a,0x80000040,0x90000070,0xb0000053,0x30000008,0x00000043,0xd0000072,0xb0000010,0xf0000062,0xc0000042,0x00000030,0xe0000042,0x20000060,0xe0000041,0x20000050,0xc0000041,0xe0000072,0xa0000003,0xc0000012,0x60000041,0xc0000032,0x20000001,0xc0000002,0xe0000042,0x60000042,0x80000002,0x00000000,0x00000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000001,0x00000060,0x80000003,0x40000002,0xc0000040,0xc0000002,0x80000000,0x80000000,0x80000002,0x00000040,0x00000002,0x80000000,0x80000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000105,0x00000089,0x00000016,0x0000020b,0x0000011b,0x0000012d,0x0000041e,0x00000224,0x00000050,0x0000092e } }
+, {2,52,0,65,0,27, { 0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014 } }
+, {2,53,0,65,0,28, { 0xcc000014,0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089 } }
+, {2,54,0,65,0,29, { 0x0400001c,0xcc000014,0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107 } }
+, {2,55,0,65,0,30, { 0x00000010,0x0400001c,0xcc000014,0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b } }
+, {2,56,0,65,0,31, { 0x2600001a,0x00000010,0x0400001c,0xcc000014,0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046 } }
+, {0,0,0,0,0,0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}
+};
+void ubc_check(const uint32_t W[80], uint32_t dvmask[1])
+{
+ uint32_t mask = ~((uint32_t)(0));
+ mask &= (((((W[44]^W[45])>>29)&1)-1) | ~(DV_I_48_0_bit|DV_I_51_0_bit|DV_I_52_0_bit|DV_II_45_0_bit|DV_II_46_0_bit|DV_II_50_0_bit|DV_II_51_0_bit));
+ mask &= (((((W[49]^W[50])>>29)&1)-1) | ~(DV_I_46_0_bit|DV_II_45_0_bit|DV_II_50_0_bit|DV_II_51_0_bit|DV_II_55_0_bit|DV_II_56_0_bit));
+ mask &= (((((W[48]^W[49])>>29)&1)-1) | ~(DV_I_45_0_bit|DV_I_52_0_bit|DV_II_49_0_bit|DV_II_50_0_bit|DV_II_54_0_bit|DV_II_55_0_bit));
+ mask &= ((((W[47]^(W[50]>>25))&(1<<4))-(1<<4)) | ~(DV_I_47_0_bit|DV_I_49_0_bit|DV_I_51_0_bit|DV_II_45_0_bit|DV_II_51_0_bit|DV_II_56_0_bit));
+ mask &= (((((W[47]^W[48])>>29)&1)-1) | ~(DV_I_44_0_bit|DV_I_51_0_bit|DV_II_48_0_bit|DV_II_49_0_bit|DV_II_53_0_bit|DV_II_54_0_bit));
+ mask &= (((((W[46]>>4)^(W[49]>>29))&1)-1) | ~(DV_I_46_0_bit|DV_I_48_0_bit|DV_I_50_0_bit|DV_I_52_0_bit|DV_II_50_0_bit|DV_II_55_0_bit));
+ mask &= (((((W[46]^W[47])>>29)&1)-1) | ~(DV_I_43_0_bit|DV_I_50_0_bit|DV_II_47_0_bit|DV_II_48_0_bit|DV_II_52_0_bit|DV_II_53_0_bit));
+ mask &= (((((W[45]>>4)^(W[48]>>29))&1)-1) | ~(DV_I_45_0_bit|DV_I_47_0_bit|DV_I_49_0_bit|DV_I_51_0_bit|DV_II_49_0_bit|DV_II_54_0_bit));
+ mask &= (((((W[45]^W[46])>>29)&1)-1) | ~(DV_I_49_0_bit|DV_I_52_0_bit|DV_II_46_0_bit|DV_II_47_0_bit|DV_II_51_0_bit|DV_II_52_0_bit));
+ mask &= (((((W[44]>>4)^(W[47]>>29))&1)-1) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_I_48_0_bit|DV_I_50_0_bit|DV_II_48_0_bit|DV_II_53_0_bit));
+ mask &= (((((W[43]>>4)^(W[46]>>29))&1)-1) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_I_47_0_bit|DV_I_49_0_bit|DV_II_47_0_bit|DV_II_52_0_bit));
+ mask &= (((((W[43]^W[44])>>29)&1)-1) | ~(DV_I_47_0_bit|DV_I_50_0_bit|DV_I_51_0_bit|DV_II_45_0_bit|DV_II_49_0_bit|DV_II_50_0_bit));
+ mask &= (((((W[42]>>4)^(W[45]>>29))&1)-1) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_I_48_0_bit|DV_I_52_0_bit|DV_II_46_0_bit|DV_II_51_0_bit));
+ mask &= (((((W[41]>>4)^(W[44]>>29))&1)-1) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_I_47_0_bit|DV_I_51_0_bit|DV_II_45_0_bit|DV_II_50_0_bit));
+ mask &= (((((W[40]^W[41])>>29)&1)-1) | ~(DV_I_44_0_bit|DV_I_47_0_bit|DV_I_48_0_bit|DV_II_46_0_bit|DV_II_47_0_bit|DV_II_56_0_bit));
+ mask &= (((((W[54]^W[55])>>29)&1)-1) | ~(DV_I_51_0_bit|DV_II_47_0_bit|DV_II_50_0_bit|DV_II_55_0_bit|DV_II_56_0_bit));
+ mask &= (((((W[53]^W[54])>>29)&1)-1) | ~(DV_I_50_0_bit|DV_II_46_0_bit|DV_II_49_0_bit|DV_II_54_0_bit|DV_II_55_0_bit));
+ mask &= (((((W[52]^W[53])>>29)&1)-1) | ~(DV_I_49_0_bit|DV_II_45_0_bit|DV_II_48_0_bit|DV_II_53_0_bit|DV_II_54_0_bit));
+ mask &= ((((W[50]^(W[53]>>25))&(1<<4))-(1<<4)) | ~(DV_I_50_0_bit|DV_I_52_0_bit|DV_II_46_0_bit|DV_II_48_0_bit|DV_II_54_0_bit));
+ mask &= (((((W[50]^W[51])>>29)&1)-1) | ~(DV_I_47_0_bit|DV_II_46_0_bit|DV_II_51_0_bit|DV_II_52_0_bit|DV_II_56_0_bit));
+ mask &= ((((W[49]^(W[52]>>25))&(1<<4))-(1<<4)) | ~(DV_I_49_0_bit|DV_I_51_0_bit|DV_II_45_0_bit|DV_II_47_0_bit|DV_II_53_0_bit));
+ mask &= ((((W[48]^(W[51]>>25))&(1<<4))-(1<<4)) | ~(DV_I_48_0_bit|DV_I_50_0_bit|DV_I_52_0_bit|DV_II_46_0_bit|DV_II_52_0_bit));
+ mask &= (((((W[42]^W[43])>>29)&1)-1) | ~(DV_I_46_0_bit|DV_I_49_0_bit|DV_I_50_0_bit|DV_II_48_0_bit|DV_II_49_0_bit));
+ mask &= (((((W[41]^W[42])>>29)&1)-1) | ~(DV_I_45_0_bit|DV_I_48_0_bit|DV_I_49_0_bit|DV_II_47_0_bit|DV_II_48_0_bit));
+ mask &= (((((W[40]>>4)^(W[43]>>29))&1)-1) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_I_50_0_bit|DV_II_49_0_bit|DV_II_56_0_bit));
+ mask &= (((((W[39]>>4)^(W[42]>>29))&1)-1) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_I_49_0_bit|DV_II_48_0_bit|DV_II_55_0_bit));
+ if (mask & (DV_I_44_0_bit|DV_I_48_0_bit|DV_II_47_0_bit|DV_II_54_0_bit|DV_II_56_0_bit))
+ mask &= (((((W[38]>>4)^(W[41]>>29))&1)-1) | ~(DV_I_44_0_bit|DV_I_48_0_bit|DV_II_47_0_bit|DV_II_54_0_bit|DV_II_56_0_bit));
+ mask &= (((((W[37]>>4)^(W[40]>>29))&1)-1) | ~(DV_I_43_0_bit|DV_I_47_0_bit|DV_II_46_0_bit|DV_II_53_0_bit|DV_II_55_0_bit));
+ if (mask & (DV_I_52_0_bit|DV_II_48_0_bit|DV_II_51_0_bit|DV_II_56_0_bit))
+ mask &= (((((W[55]^W[56])>>29)&1)-1) | ~(DV_I_52_0_bit|DV_II_48_0_bit|DV_II_51_0_bit|DV_II_56_0_bit));
+ if (mask & (DV_I_52_0_bit|DV_II_48_0_bit|DV_II_50_0_bit|DV_II_56_0_bit))
+ mask &= ((((W[52]^(W[55]>>25))&(1<<4))-(1<<4)) | ~(DV_I_52_0_bit|DV_II_48_0_bit|DV_II_50_0_bit|DV_II_56_0_bit));
+ if (mask & (DV_I_51_0_bit|DV_II_47_0_bit|DV_II_49_0_bit|DV_II_55_0_bit))
+ mask &= ((((W[51]^(W[54]>>25))&(1<<4))-(1<<4)) | ~(DV_I_51_0_bit|DV_II_47_0_bit|DV_II_49_0_bit|DV_II_55_0_bit));
+ if (mask & (DV_I_48_0_bit|DV_II_47_0_bit|DV_II_52_0_bit|DV_II_53_0_bit))
+ mask &= (((((W[51]^W[52])>>29)&1)-1) | ~(DV_I_48_0_bit|DV_II_47_0_bit|DV_II_52_0_bit|DV_II_53_0_bit));
+ if (mask & (DV_I_46_0_bit|DV_I_49_0_bit|DV_II_45_0_bit|DV_II_48_0_bit))
+ mask &= (((((W[36]>>4)^(W[40]>>29))&1)-1) | ~(DV_I_46_0_bit|DV_I_49_0_bit|DV_II_45_0_bit|DV_II_48_0_bit));
+ if (mask & (DV_I_52_0_bit|DV_II_48_0_bit|DV_II_49_0_bit))
+ mask &= ((0-(((W[53]^W[56])>>29)&1)) | ~(DV_I_52_0_bit|DV_II_48_0_bit|DV_II_49_0_bit));
+ if (mask & (DV_I_50_0_bit|DV_II_46_0_bit|DV_II_47_0_bit))
+ mask &= ((0-(((W[51]^W[54])>>29)&1)) | ~(DV_I_50_0_bit|DV_II_46_0_bit|DV_II_47_0_bit));
+ if (mask & (DV_I_49_0_bit|DV_I_51_0_bit|DV_II_45_0_bit))
+ mask &= ((0-(((W[50]^W[52])>>29)&1)) | ~(DV_I_49_0_bit|DV_I_51_0_bit|DV_II_45_0_bit));
+ if (mask & (DV_I_48_0_bit|DV_I_50_0_bit|DV_I_52_0_bit))
+ mask &= ((0-(((W[49]^W[51])>>29)&1)) | ~(DV_I_48_0_bit|DV_I_50_0_bit|DV_I_52_0_bit));
+ if (mask & (DV_I_47_0_bit|DV_I_49_0_bit|DV_I_51_0_bit))
+ mask &= ((0-(((W[48]^W[50])>>29)&1)) | ~(DV_I_47_0_bit|DV_I_49_0_bit|DV_I_51_0_bit));
+ if (mask & (DV_I_46_0_bit|DV_I_48_0_bit|DV_I_50_0_bit))
+ mask &= ((0-(((W[47]^W[49])>>29)&1)) | ~(DV_I_46_0_bit|DV_I_48_0_bit|DV_I_50_0_bit));
+ if (mask & (DV_I_45_0_bit|DV_I_47_0_bit|DV_I_49_0_bit))
+ mask &= ((0-(((W[46]^W[48])>>29)&1)) | ~(DV_I_45_0_bit|DV_I_47_0_bit|DV_I_49_0_bit));
+ mask &= ((((W[45]^W[47])&(1<<6))-(1<<6)) | ~(DV_I_47_2_bit|DV_I_49_2_bit|DV_I_51_2_bit));
+ if (mask & (DV_I_44_0_bit|DV_I_46_0_bit|DV_I_48_0_bit))
+ mask &= ((0-(((W[45]^W[47])>>29)&1)) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_I_48_0_bit));
+ mask &= (((((W[44]^W[46])>>6)&1)-1) | ~(DV_I_46_2_bit|DV_I_48_2_bit|DV_I_50_2_bit));
+ if (mask & (DV_I_43_0_bit|DV_I_45_0_bit|DV_I_47_0_bit))
+ mask &= ((0-(((W[44]^W[46])>>29)&1)) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_I_47_0_bit));
+ mask &= ((0-((W[41]^(W[42]>>5))&(1<<1))) | ~(DV_I_48_2_bit|DV_II_46_2_bit|DV_II_51_2_bit));
+ mask &= ((0-((W[40]^(W[41]>>5))&(1<<1))) | ~(DV_I_47_2_bit|DV_I_51_2_bit|DV_II_50_2_bit));
+ if (mask & (DV_I_44_0_bit|DV_I_46_0_bit|DV_II_56_0_bit))
+ mask &= ((0-(((W[40]^W[42])>>4)&1)) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_II_56_0_bit));
+ mask &= ((0-((W[39]^(W[40]>>5))&(1<<1))) | ~(DV_I_46_2_bit|DV_I_50_2_bit|DV_II_49_2_bit));
+ if (mask & (DV_I_43_0_bit|DV_I_45_0_bit|DV_II_55_0_bit))
+ mask &= ((0-(((W[39]^W[41])>>4)&1)) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_II_55_0_bit));
+ if (mask & (DV_I_44_0_bit|DV_II_54_0_bit|DV_II_56_0_bit))
+ mask &= ((0-(((W[38]^W[40])>>4)&1)) | ~(DV_I_44_0_bit|DV_II_54_0_bit|DV_II_56_0_bit));
+ if (mask & (DV_I_43_0_bit|DV_II_53_0_bit|DV_II_55_0_bit))
+ mask &= ((0-(((W[37]^W[39])>>4)&1)) | ~(DV_I_43_0_bit|DV_II_53_0_bit|DV_II_55_0_bit));
+ mask &= ((0-((W[36]^(W[37]>>5))&(1<<1))) | ~(DV_I_47_2_bit|DV_I_50_2_bit|DV_II_46_2_bit));
+ if (mask & (DV_I_45_0_bit|DV_I_48_0_bit|DV_II_47_0_bit))
+ mask &= (((((W[35]>>4)^(W[39]>>29))&1)-1) | ~(DV_I_45_0_bit|DV_I_48_0_bit|DV_II_47_0_bit));
+ if (mask & (DV_I_48_0_bit|DV_II_48_0_bit))
+ mask &= ((0-((W[63]^(W[64]>>5))&(1<<0))) | ~(DV_I_48_0_bit|DV_II_48_0_bit));
+ if (mask & (DV_I_45_0_bit|DV_II_45_0_bit))
+ mask &= ((0-((W[63]^(W[64]>>5))&(1<<1))) | ~(DV_I_45_0_bit|DV_II_45_0_bit));
+ if (mask & (DV_I_47_0_bit|DV_II_47_0_bit))
+ mask &= ((0-((W[62]^(W[63]>>5))&(1<<0))) | ~(DV_I_47_0_bit|DV_II_47_0_bit));
+ if (mask & (DV_I_46_0_bit|DV_II_46_0_bit))
+ mask &= ((0-((W[61]^(W[62]>>5))&(1<<0))) | ~(DV_I_46_0_bit|DV_II_46_0_bit));
+ mask &= ((0-((W[61]^(W[62]>>5))&(1<<2))) | ~(DV_I_46_2_bit|DV_II_46_2_bit));
+ if (mask & (DV_I_45_0_bit|DV_II_45_0_bit))
+ mask &= ((0-((W[60]^(W[61]>>5))&(1<<0))) | ~(DV_I_45_0_bit|DV_II_45_0_bit));
+ if (mask & (DV_II_51_0_bit|DV_II_54_0_bit))
+ mask &= (((((W[58]^W[59])>>29)&1)-1) | ~(DV_II_51_0_bit|DV_II_54_0_bit));
+ if (mask & (DV_II_50_0_bit|DV_II_53_0_bit))
+ mask &= (((((W[57]^W[58])>>29)&1)-1) | ~(DV_II_50_0_bit|DV_II_53_0_bit));
+ if (mask & (DV_II_52_0_bit|DV_II_54_0_bit))
+ mask &= ((((W[56]^(W[59]>>25))&(1<<4))-(1<<4)) | ~(DV_II_52_0_bit|DV_II_54_0_bit));
+ if (mask & (DV_II_51_0_bit|DV_II_52_0_bit))
+ mask &= ((0-(((W[56]^W[59])>>29)&1)) | ~(DV_II_51_0_bit|DV_II_52_0_bit));
+ if (mask & (DV_II_49_0_bit|DV_II_52_0_bit))
+ mask &= (((((W[56]^W[57])>>29)&1)-1) | ~(DV_II_49_0_bit|DV_II_52_0_bit));
+ if (mask & (DV_II_51_0_bit|DV_II_53_0_bit))
+ mask &= ((((W[55]^(W[58]>>25))&(1<<4))-(1<<4)) | ~(DV_II_51_0_bit|DV_II_53_0_bit));
+ if (mask & (DV_II_50_0_bit|DV_II_52_0_bit))
+ mask &= ((((W[54]^(W[57]>>25))&(1<<4))-(1<<4)) | ~(DV_II_50_0_bit|DV_II_52_0_bit));
+ if (mask & (DV_II_49_0_bit|DV_II_51_0_bit))
+ mask &= ((((W[53]^(W[56]>>25))&(1<<4))-(1<<4)) | ~(DV_II_49_0_bit|DV_II_51_0_bit));
+ mask &= ((((W[51]^(W[50]>>5))&(1<<1))-(1<<1)) | ~(DV_I_50_2_bit|DV_II_46_2_bit));
+ mask &= ((((W[48]^W[50])&(1<<6))-(1<<6)) | ~(DV_I_50_2_bit|DV_II_46_2_bit));
+ if (mask & (DV_I_51_0_bit|DV_I_52_0_bit))
+ mask &= ((0-(((W[48]^W[55])>>29)&1)) | ~(DV_I_51_0_bit|DV_I_52_0_bit));
+ mask &= ((((W[47]^W[49])&(1<<6))-(1<<6)) | ~(DV_I_49_2_bit|DV_I_51_2_bit));
+ mask &= ((((W[48]^(W[47]>>5))&(1<<1))-(1<<1)) | ~(DV_I_47_2_bit|DV_II_51_2_bit));
+ mask &= ((((W[46]^W[48])&(1<<6))-(1<<6)) | ~(DV_I_48_2_bit|DV_I_50_2_bit));
+ mask &= ((((W[47]^(W[46]>>5))&(1<<1))-(1<<1)) | ~(DV_I_46_2_bit|DV_II_50_2_bit));
+ mask &= ((0-((W[44]^(W[45]>>5))&(1<<1))) | ~(DV_I_51_2_bit|DV_II_49_2_bit));
+ mask &= ((((W[43]^W[45])&(1<<6))-(1<<6)) | ~(DV_I_47_2_bit|DV_I_49_2_bit));
+ mask &= (((((W[42]^W[44])>>6)&1)-1) | ~(DV_I_46_2_bit|DV_I_48_2_bit));
+ mask &= ((((W[43]^(W[42]>>5))&(1<<1))-(1<<1)) | ~(DV_II_46_2_bit|DV_II_51_2_bit));
+ mask &= ((((W[42]^(W[41]>>5))&(1<<1))-(1<<1)) | ~(DV_I_51_2_bit|DV_II_50_2_bit));
+ mask &= ((((W[41]^(W[40]>>5))&(1<<1))-(1<<1)) | ~(DV_I_50_2_bit|DV_II_49_2_bit));
+ if (mask & (DV_I_52_0_bit|DV_II_51_0_bit))
+ mask &= ((((W[39]^(W[43]>>25))&(1<<4))-(1<<4)) | ~(DV_I_52_0_bit|DV_II_51_0_bit));
+ if (mask & (DV_I_51_0_bit|DV_II_50_0_bit))
+ mask &= ((((W[38]^(W[42]>>25))&(1<<4))-(1<<4)) | ~(DV_I_51_0_bit|DV_II_50_0_bit));
+ if (mask & (DV_I_48_2_bit|DV_I_51_2_bit))
+ mask &= ((0-((W[37]^(W[38]>>5))&(1<<1))) | ~(DV_I_48_2_bit|DV_I_51_2_bit));
+ if (mask & (DV_I_50_0_bit|DV_II_49_0_bit))
+ mask &= ((((W[37]^(W[41]>>25))&(1<<4))-(1<<4)) | ~(DV_I_50_0_bit|DV_II_49_0_bit));
+ if (mask & (DV_II_52_0_bit|DV_II_54_0_bit))
+ mask &= ((0-((W[36]^W[38])&(1<<4))) | ~(DV_II_52_0_bit|DV_II_54_0_bit));
+ mask &= ((0-((W[35]^(W[36]>>5))&(1<<1))) | ~(DV_I_46_2_bit|DV_I_49_2_bit));
+ if (mask & (DV_I_51_0_bit|DV_II_47_0_bit))
+ mask &= ((((W[35]^(W[39]>>25))&(1<<3))-(1<<3)) | ~(DV_I_51_0_bit|DV_II_47_0_bit));
+if (mask) {
+
+ if (mask & DV_I_43_0_bit)
+ if (
+ !((W[61]^(W[62]>>5)) & (1<<1))
+ || !(!((W[59]^(W[63]>>25)) & (1<<5)))
+ || !((W[58]^(W[63]>>30)) & (1<<0))
+ ) mask &= ~DV_I_43_0_bit;
+ if (mask & DV_I_44_0_bit)
+ if (
+ !((W[62]^(W[63]>>5)) & (1<<1))
+ || !(!((W[60]^(W[64]>>25)) & (1<<5)))
+ || !((W[59]^(W[64]>>30)) & (1<<0))
+ ) mask &= ~DV_I_44_0_bit;
+ if (mask & DV_I_46_2_bit)
+ mask &= ((~((W[40]^W[42])>>2)) | ~DV_I_46_2_bit);
+ if (mask & DV_I_47_2_bit)
+ if (
+ !((W[62]^(W[63]>>5)) & (1<<2))
+ || !(!((W[41]^W[43]) & (1<<6)))
+ ) mask &= ~DV_I_47_2_bit;
+ if (mask & DV_I_48_2_bit)
+ if (
+ !((W[63]^(W[64]>>5)) & (1<<2))
+ || !(!((W[48]^(W[49]<<5)) & (1<<6)))
+ ) mask &= ~DV_I_48_2_bit;
+ if (mask & DV_I_49_2_bit)
+ if (
+ !(!((W[49]^(W[50]<<5)) & (1<<6)))
+ || !((W[42]^W[50]) & (1<<1))
+ || !(!((W[39]^(W[40]<<5)) & (1<<6)))
+ || !((W[38]^W[40]) & (1<<1))
+ ) mask &= ~DV_I_49_2_bit;
+ if (mask & DV_I_50_0_bit)
+ mask &= ((((W[36]^W[37])<<7)) | ~DV_I_50_0_bit);
+ if (mask & DV_I_50_2_bit)
+ mask &= ((((W[43]^W[51])<<11)) | ~DV_I_50_2_bit);
+ if (mask & DV_I_51_0_bit)
+ mask &= ((((W[37]^W[38])<<9)) | ~DV_I_51_0_bit);
+ if (mask & DV_I_51_2_bit)
+ if (
+ !(!((W[51]^(W[52]<<5)) & (1<<6)))
+ || !(!((W[49]^W[51]) & (1<<6)))
+ || !(!((W[37]^(W[37]>>5)) & (1<<1)))
+ || !(!((W[35]^(W[39]>>25)) & (1<<5)))
+ ) mask &= ~DV_I_51_2_bit;
+ if (mask & DV_I_52_0_bit)
+ mask &= ((((W[38]^W[39])<<11)) | ~DV_I_52_0_bit);
+ if (mask & DV_II_46_2_bit)
+ mask &= ((((W[47]^W[51])<<17)) | ~DV_II_46_2_bit);
+ if (mask & DV_II_48_0_bit)
+ if (
+ !(!((W[36]^(W[40]>>25)) & (1<<3)))
+ || !((W[35]^(W[40]<<2)) & (1<<30))
+ ) mask &= ~DV_II_48_0_bit;
+ if (mask & DV_II_49_0_bit)
+ if (
+ !(!((W[37]^(W[41]>>25)) & (1<<3)))
+ || !((W[36]^(W[41]<<2)) & (1<<30))
+ ) mask &= ~DV_II_49_0_bit;
+ if (mask & DV_II_49_2_bit)
+ if (
+ !(!((W[53]^(W[54]<<5)) & (1<<6)))
+ || !(!((W[51]^W[53]) & (1<<6)))
+ || !((W[50]^W[54]) & (1<<1))
+ || !(!((W[45]^(W[46]<<5)) & (1<<6)))
+ || !(!((W[37]^(W[41]>>25)) & (1<<5)))
+ || !((W[36]^(W[41]>>30)) & (1<<0))
+ ) mask &= ~DV_II_49_2_bit;
+ if (mask & DV_II_50_0_bit)
+ if (
+ !((W[55]^W[58]) & (1<<29))
+ || !(!((W[38]^(W[42]>>25)) & (1<<3)))
+ || !((W[37]^(W[42]<<2)) & (1<<30))
+ ) mask &= ~DV_II_50_0_bit;
+ if (mask & DV_II_50_2_bit)
+ if (
+ !(!((W[54]^(W[55]<<5)) & (1<<6)))
+ || !(!((W[52]^W[54]) & (1<<6)))
+ || !((W[51]^W[55]) & (1<<1))
+ || !((W[45]^W[47]) & (1<<1))
+ || !(!((W[38]^(W[42]>>25)) & (1<<5)))
+ || !((W[37]^(W[42]>>30)) & (1<<0))
+ ) mask &= ~DV_II_50_2_bit;
+ if (mask & DV_II_51_0_bit)
+ if (
+ !(!((W[39]^(W[43]>>25)) & (1<<3)))
+ || !((W[38]^(W[43]<<2)) & (1<<30))
+ ) mask &= ~DV_II_51_0_bit;
+ if (mask & DV_II_51_2_bit)
+ if (
+ !(!((W[55]^(W[56]<<5)) & (1<<6)))
+ || !(!((W[53]^W[55]) & (1<<6)))
+ || !((W[52]^W[56]) & (1<<1))
+ || !((W[46]^W[48]) & (1<<1))
+ || !(!((W[39]^(W[43]>>25)) & (1<<5)))
+ || !((W[38]^(W[43]>>30)) & (1<<0))
+ ) mask &= ~DV_II_51_2_bit;
+ if (mask & DV_II_52_0_bit)
+ if (
+ !(!((W[59]^W[60]) & (1<<29)))
+ || !(!((W[40]^(W[44]>>25)) & (1<<3)))
+ || !(!((W[40]^(W[44]>>25)) & (1<<4)))
+ || !((W[39]^(W[44]<<2)) & (1<<30))
+ ) mask &= ~DV_II_52_0_bit;
+ if (mask & DV_II_53_0_bit)
+ if (
+ !((W[58]^W[61]) & (1<<29))
+ || !(!((W[57]^(W[61]>>25)) & (1<<4)))
+ || !(!((W[41]^(W[45]>>25)) & (1<<3)))
+ || !(!((W[41]^(W[45]>>25)) & (1<<4)))
+ ) mask &= ~DV_II_53_0_bit;
+ if (mask & DV_II_54_0_bit)
+ if (
+ !(!((W[58]^(W[62]>>25)) & (1<<4)))
+ || !(!((W[42]^(W[46]>>25)) & (1<<3)))
+ || !(!((W[42]^(W[46]>>25)) & (1<<4)))
+ ) mask &= ~DV_II_54_0_bit;
+ if (mask & DV_II_55_0_bit)
+ if (
+ !(!((W[59]^(W[63]>>25)) & (1<<4)))
+ || !(!((W[57]^(W[59]>>25)) & (1<<4)))
+ || !(!((W[43]^(W[47]>>25)) & (1<<3)))
+ || !(!((W[43]^(W[47]>>25)) & (1<<4)))
+ ) mask &= ~DV_II_55_0_bit;
+ if (mask & DV_II_56_0_bit)
+ if (
+ !(!((W[60]^(W[64]>>25)) & (1<<4)))
+ || !(!((W[44]^(W[48]>>25)) & (1<<3)))
+ || !(!((W[44]^(W[48]>>25)) & (1<<4)))
+ ) mask &= ~DV_II_56_0_bit;
+}
+
+ dvmask[0]=mask;
+}
+
+#ifdef SHA1DC_CUSTOM_TRAILING_INCLUDE_UBC_CHECK_C
+#include SHA1DC_CUSTOM_TRAILING_INCLUDE_UBC_CHECK_C
+#endif
diff --git a/src/hash/sha1dc/ubc_check.h b/src/hash/sha1dc/ubc_check.h
new file mode 100644
index 000000000..d7e17dc73
--- /dev/null
+++ b/src/hash/sha1dc/ubc_check.h
@@ -0,0 +1,52 @@
+/***
+* Copyright 2017 Marc Stevens <marc@marc-stevens.nl>, Dan Shumow <danshu@microsoft.com>
+* Distributed under the MIT Software License.
+* See accompanying file LICENSE.txt or copy at
+* https://opensource.org/licenses/MIT
+***/
+
+/*
+// this file was generated by the 'parse_bitrel' program in the tools section
+// using the data files from directory 'tools/data/3565'
+//
+// sha1_dvs contains a list of SHA-1 Disturbance Vectors (DV) to check
+// dvType, dvK and dvB define the DV: I(K,B) or II(K,B) (see the paper)
+// dm[80] is the expanded message block XOR-difference defined by the DV
+// testt is the step to do the recompression from for collision detection
+// maski and maskb define the bit to check for each DV in the dvmask returned by ubc_check
+//
+// ubc_check takes as input an expanded message block and verifies the unavoidable bitconditions for all listed DVs
+// it returns a dvmask where each bit belonging to a DV is set if all unavoidable bitconditions for that DV have been met
+// thus one needs to do the recompression check for each DV that has its bit set
+*/
+
+#ifndef SHA1DC_UBC_CHECK_H
+#define SHA1DC_UBC_CHECK_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#ifndef SHA1DC_NO_STANDARD_INCLUDES
+#include <stdint.h>
+#endif
+
+#define DVMASKSIZE 1
+typedef struct { int dvType; int dvK; int dvB; int testt; int maski; int maskb; uint32_t dm[80]; } dv_info_t;
+extern dv_info_t sha1_dvs[];
+void ubc_check(const uint32_t W[80], uint32_t dvmask[DVMASKSIZE]);
+
+#define DOSTORESTATE58
+#define DOSTORESTATE65
+
+#define CHECK_DVMASK(_DVMASK) (0 != _DVMASK[0])
+
+#if defined(__cplusplus)
+}
+#endif
+
+#ifdef SHA1DC_CUSTOM_TRAILING_INCLUDE_UBC_CHECK_H
+#include SHA1DC_CUSTOM_TRAILING_INCLUDE_UBC_CHECK_H
+#endif
+
+#endif
diff --git a/src/hashsig.c b/src/hashsig.c
index e99637d8b..30d059463 100644
--- a/src/hashsig.c
+++ b/src/hashsig.c
@@ -4,6 +4,9 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
+
+#include "common.h"
+
#include "git2/sys/hashsig.h"
#include "fileops.h"
#include "util.h"
@@ -214,7 +217,7 @@ static int hashsig_finalize_hashes(git_hashsig *sig)
if (sig->mins.size < HASHSIG_HEAP_MIN_SIZE &&
!(sig->opt & GIT_HASHSIG_ALLOW_SMALL_FILES)) {
giterr_set(GITERR_INVALID,
- "File too small for similarity signature calculation");
+ "file too small for similarity signature calculation");
return GIT_EBUFS;
}
@@ -286,7 +289,7 @@ int git_hashsig_create_fromfile(
if ((buflen = p_read(fd, buf, sizeof(buf))) <= 0) {
if ((error = (int)buflen) < 0)
giterr_set(GITERR_OS,
- "Read error on '%s' calculating similarity hashes", path);
+ "read error on '%s' calculating similarity hashes", path);
break;
}
diff --git a/src/ident.c b/src/ident.c
index 4718ed664..7eccf9a43 100644
--- a/src/ident.c
+++ b/src/ident.c
@@ -5,6 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "common.h"
+
#include "git2/sys/filter.h"
#include "filter.h"
#include "buffer.h"
diff --git a/src/idxmap.c b/src/idxmap.c
new file mode 100644
index 000000000..45f0c2204
--- /dev/null
+++ b/src/idxmap.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "idxmap.h"
+
+/* This is __ac_X31_hash_string but with tolower and it takes the entry's stage into account */
+static kh_inline khint_t idxentry_hash(const git_index_entry *e)
+{
+ const char *s = e->path;
+ khint_t h = (khint_t)git__tolower(*s);
+ if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)git__tolower(*s);
+ return h + GIT_IDXENTRY_STAGE(e);
+}
+
+#define idxentry_equal(a, b) (GIT_IDXENTRY_STAGE(a) == GIT_IDXENTRY_STAGE(b) && strcmp(a->path, b->path) == 0)
+#define idxentry_icase_equal(a, b) (GIT_IDXENTRY_STAGE(a) == GIT_IDXENTRY_STAGE(b) && strcasecmp(a->path, b->path) == 0)
+
+__KHASH_IMPL(idx, static kh_inline, const git_index_entry *, git_index_entry *, 1, idxentry_hash, idxentry_equal)
+__KHASH_IMPL(idxicase, static kh_inline, const git_index_entry *, git_index_entry *, 1, idxentry_hash, idxentry_icase_equal)
+
+int git_idxmap_alloc(git_idxmap **map)
+{
+ if ((*map = kh_init(idx)) == NULL) {
+ giterr_set_oom();
+ return -1;
+ }
+
+ return 0;
+}
+
+int git_idxmap_icase_alloc(git_idxmap_icase **map)
+{
+ if ((*map = kh_init(idxicase)) == NULL) {
+ giterr_set_oom();
+ return -1;
+ }
+
+ return 0;
+}
+
+void git_idxmap_insert(git_idxmap *map, const git_index_entry *key, void *value, int *rval)
+{
+ khiter_t idx = kh_put(idx, map, key, rval);
+
+ if ((*rval) >= 0) {
+ if ((*rval) == 0)
+ kh_key(map, idx) = key;
+ kh_val(map, idx) = value;
+ }
+}
+
+void git_idxmap_icase_insert(git_idxmap_icase *map, const git_index_entry *key, void *value, int *rval)
+{
+ khiter_t idx = kh_put(idxicase, map, key, rval);
+
+ if ((*rval) >= 0) {
+ if ((*rval) == 0)
+ kh_key(map, idx) = key;
+ kh_val(map, idx) = value;
+ }
+}
+
+size_t git_idxmap_lookup_index(git_idxmap *map, const git_index_entry *key)
+{
+ return kh_get(idx, map, key);
+}
+
+size_t git_idxmap_icase_lookup_index(git_idxmap_icase *map, const git_index_entry *key)
+{
+ return kh_get(idxicase, map, key);
+}
+
+void *git_idxmap_value_at(git_idxmap *map, size_t idx)
+{
+ return kh_val(map, idx);
+}
+
+int git_idxmap_valid_index(git_idxmap *map, size_t idx)
+{
+ return idx != kh_end(map);
+}
+
+int git_idxmap_has_data(git_idxmap *map, size_t idx)
+{
+ return kh_exist(map, idx);
+}
+
+void git_idxmap_resize(git_idxmap *map, size_t size)
+{
+ kh_resize(idx, map, size);
+}
+
+void git_idxmap_icase_resize(git_idxmap_icase *map, size_t size)
+{
+ kh_resize(idxicase, map, size);
+}
+
+void git_idxmap_free(git_idxmap *map)
+{
+ kh_destroy(idx, map);
+}
+
+void git_idxmap_clear(git_idxmap *map)
+{
+ kh_clear(idx, map);
+}
+
+void git_idxmap_delete_at(git_idxmap *map, size_t idx)
+{
+ kh_del(idx, map, idx);
+}
+
+void git_idxmap_icase_delete_at(git_idxmap_icase *map, size_t idx)
+{
+ kh_del(idxicase, map, idx);
+}
+
+void git_idxmap_delete(git_idxmap *map, const git_index_entry *key)
+{
+ khiter_t idx = git_idxmap_lookup_index(map, key);
+ if (git_idxmap_valid_index(map, idx))
+ git_idxmap_delete_at(map, idx);
+}
+void git_idxmap_icase_delete(git_idxmap_icase *map, const git_index_entry *key)
+{
+ khiter_t idx = git_idxmap_icase_lookup_index(map, key);
+ if (git_idxmap_valid_index((git_idxmap *)map, idx))
+ git_idxmap_icase_delete_at(map, idx);
+}
diff --git a/src/idxmap.h b/src/idxmap.h
index 4122a89fe..f7e903a61 100644
--- a/src/idxmap.h
+++ b/src/idxmap.h
@@ -7,8 +7,9 @@
#ifndef INCLUDE_idxmap_h__
#define INCLUDE_idxmap_h__
-#include <ctype.h>
#include "common.h"
+
+#include <ctype.h>
#include "git2/index.h"
#define kmalloc git__malloc
@@ -26,66 +27,27 @@ typedef khash_t(idxicase) git_idxmap_icase;
typedef khiter_t git_idxmap_iter;
-/* This is __ac_X31_hash_string but with tolower and it takes the entry's stage into account */
-static kh_inline khint_t idxentry_hash(const git_index_entry *e)
-{
- const char *s = e->path;
- khint_t h = (khint_t)git__tolower(*s);
- if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)git__tolower(*s);
- return h + GIT_IDXENTRY_STAGE(e);
-}
-
-#define idxentry_equal(a, b) (GIT_IDXENTRY_STAGE(a) == GIT_IDXENTRY_STAGE(b) && strcmp(a->path, b->path) == 0)
-#define idxentry_icase_equal(a, b) (GIT_IDXENTRY_STAGE(a) == GIT_IDXENTRY_STAGE(b) && strcasecmp(a->path, b->path) == 0)
-
-#define GIT__USE_IDXMAP \
- __KHASH_IMPL(idx, static kh_inline, const git_index_entry *, git_index_entry *, 1, idxentry_hash, idxentry_equal)
-
-#define GIT__USE_IDXMAP_ICASE \
- __KHASH_IMPL(idxicase, static kh_inline, const git_index_entry *, git_index_entry *, 1, idxentry_hash, idxentry_icase_equal)
-
-#define git_idxmap_alloc(hp) \
- ((*(hp) = kh_init(idx)) == NULL) ? giterr_set_oom(), -1 : 0
-
-#define git_idxmap_icase_alloc(hp) \
- ((*(hp) = kh_init(idxicase)) == NULL) ? giterr_set_oom(), -1 : 0
-
-#define git_idxmap_insert(h, key, val, rval) do { \
- khiter_t __pos = kh_put(idx, h, key, &rval); \
- if (rval >= 0) { \
- if (rval == 0) kh_key(h, __pos) = key; \
- kh_val(h, __pos) = val; \
- } } while (0)
-
-#define git_idxmap_icase_insert(h, key, val, rval) do { \
- khiter_t __pos = kh_put(idxicase, h, key, &rval); \
- if (rval >= 0) { \
- if (rval == 0) kh_key(h, __pos) = key; \
- kh_val(h, __pos) = val; \
- } } while (0)
-
-#define git_idxmap_lookup_index(h, k) kh_get(idx, h, k)
-#define git_idxmap_icase_lookup_index(h, k) kh_get(idxicase, h, k)
-#define git_idxmap_value_at(h, idx) kh_val(h, idx)
-#define git_idxmap_valid_index(h, idx) (idx != kh_end(h))
-#define git_idxmap_has_data(h, idx) kh_exist(h, idx)
+int git_idxmap_alloc(git_idxmap **map);
+int git_idxmap_icase_alloc(git_idxmap_icase **map);
+void git_idxmap_insert(git_idxmap *map, const git_index_entry *key, void *value, int *rval);
+void git_idxmap_icase_insert(git_idxmap_icase *map, const git_index_entry *key, void *value, int *rval);
-#define git_idxmap_resize(h,s) kh_resize(idx, h, s)
-#define git_idxmap_free(h) kh_destroy(idx, h), h = NULL
-#define git_idxmap_clear(h) kh_clear(idx, h)
+size_t git_idxmap_lookup_index(git_idxmap *map, const git_index_entry *key);
+size_t git_idxmap_icase_lookup_index(git_idxmap_icase *map, const git_index_entry *key);
+void *git_idxmap_value_at(git_idxmap *map, size_t idx);
+int git_idxmap_valid_index(git_idxmap *map, size_t idx);
+int git_idxmap_has_data(git_idxmap *map, size_t idx);
-#define git_idxmap_delete_at(h, id) kh_del(idx, h, id)
-#define git_idxmap_icase_delete_at(h, id) kh_del(idxicase, h, id)
+void git_idxmap_resize(git_idxmap *map, size_t size);
+void git_idxmap_icase_resize(git_idxmap_icase *map, size_t size);
+void git_idxmap_free(git_idxmap *map);
+void git_idxmap_clear(git_idxmap *map);
-#define git_idxmap_delete(h, key) do { \
- khiter_t __pos = git_idxmap_lookup_index(h, key); \
- if (git_idxmap_valid_index(h, __pos)) \
- git_idxmap_delete_at(h, __pos); } while (0)
+void git_idxmap_delete_at(git_idxmap *map, size_t idx);
+void git_idxmap_icase_delete_at(git_idxmap_icase *map, size_t idx);
-#define git_idxmap_icase_delete(h, key) do { \
- khiter_t __pos = git_idxmap_icase_lookup_index(h, key); \
- if (git_idxmap_valid_index(h, __pos)) \
- git_idxmap_icase_delete_at(h, __pos); } while (0)
+void git_idxmap_delete(git_idxmap *map, const git_index_entry *key);
+void git_idxmap_icase_delete(git_idxmap_icase *map, const git_index_entry *key);
#define git_idxmap_begin kh_begin
#define git_idxmap_end kh_end
diff --git a/src/ignore.c b/src/ignore.c
index dcbd5c1ca..f089dbeb5 100644
--- a/src/ignore.c
+++ b/src/ignore.c
@@ -1,6 +1,14 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "ignore.h"
+
#include "git2/ignore.h"
#include "common.h"
-#include "ignore.h"
#include "attrcache.h"
#include "path.h"
#include "config.h"
@@ -40,38 +48,42 @@
*/
static int does_negate_pattern(git_attr_fnmatch *rule, git_attr_fnmatch *neg)
{
+ int (*cmp)(const char *, const char *, size_t);
git_attr_fnmatch *longer, *shorter;
char *p;
- if ((rule->flags & GIT_ATTR_FNMATCH_NEGATIVE) == 0
- && (neg->flags & GIT_ATTR_FNMATCH_NEGATIVE) != 0) {
-
- /* If lengths match we need to have an exact match */
- if (rule->length == neg->length) {
- return strcmp(rule->pattern, neg->pattern) == 0;
- } else if (rule->length < neg->length) {
- shorter = rule;
- longer = neg;
- } else {
- shorter = neg;
- longer = rule;
- }
-
- /* Otherwise, we need to check if the shorter
- * rule is a basename only (that is, it contains
- * no path separator) and, if so, if it
- * matches the tail of the longer rule */
- p = longer->pattern + longer->length - shorter->length;
+ if ((rule->flags & GIT_ATTR_FNMATCH_NEGATIVE) != 0
+ || (neg->flags & GIT_ATTR_FNMATCH_NEGATIVE) == 0)
+ return false;
+
+ if (neg->flags & GIT_ATTR_FNMATCH_ICASE)
+ cmp = git__strncasecmp;
+ else
+ cmp = strncmp;
+
+ /* If lengths match we need to have an exact match */
+ if (rule->length == neg->length) {
+ return cmp(rule->pattern, neg->pattern, rule->length) == 0;
+ } else if (rule->length < neg->length) {
+ shorter = rule;
+ longer = neg;
+ } else {
+ shorter = neg;
+ longer = rule;
+ }
- if (p[-1] != '/')
- return false;
- if (memchr(shorter->pattern, '/', shorter->length) != NULL)
- return false;
+ /* Otherwise, we need to check if the shorter
+ * rule is a basename only (that is, it contains
+ * no path separator) and, if so, if it
+ * matches the tail of the longer rule */
+ p = longer->pattern + longer->length - shorter->length;
- return memcmp(p, shorter->pattern, shorter->length) == 0;
- }
+ if (p[-1] != '/')
+ return false;
+ if (memchr(shorter->pattern, '/', shorter->length) != NULL)
+ return false;
- return false;
+ return cmp(p, shorter->pattern, shorter->length) == 0;
}
/**
@@ -89,7 +101,7 @@ static int does_negate_pattern(git_attr_fnmatch *rule, git_attr_fnmatch *neg)
*/
static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match)
{
- int error = 0;
+ int error = 0, fnflags;
size_t i;
git_attr_fnmatch *rule;
char *path;
@@ -97,6 +109,10 @@ static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match
*out = 0;
+ fnflags = FNM_PATHNAME;
+ if (match->flags & GIT_ATTR_FNMATCH_ICASE)
+ fnflags |= FNM_IGNORECASE;
+
/* path of the file relative to the workdir, so we match the rules in subdirs */
if (match->containing_dir) {
git_buf_puts(&buf, match->containing_dir);
@@ -117,12 +133,12 @@ static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match
continue;
}
- /*
- * When dealing with a directory, we add '/<star>' so
- * p_fnmatch() honours FNM_PATHNAME. Checking for LEADINGDIR
- * alone isn't enough as that's also set for nagations, so we
- * need to check that NEGATIVE is off.
- */
+ /*
+ * When dealing with a directory, we add '/<star>' so
+ * p_fnmatch() honours FNM_PATHNAME. Checking for LEADINGDIR
+ * alone isn't enough as that's also set for nagations, so we
+ * need to check that NEGATIVE is off.
+ */
git_buf_clear(&buf);
if (rule->containing_dir) {
git_buf_puts(&buf, rule->containing_dir);
@@ -136,7 +152,7 @@ static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match
if (error < 0)
goto out;
- if ((error = p_fnmatch(git_buf_cstr(&buf), path, FNM_PATHNAME)) < 0) {
+ if ((error = p_fnmatch(git_buf_cstr(&buf), path, fnflags)) < 0) {
giterr_set(GITERR_INVALID, "error matching pattern");
goto out;
}
@@ -175,7 +191,7 @@ static int parse_ignore_file(
context = attrs->entry->path;
if (git_mutex_lock(&attrs->lock) < 0) {
- giterr_set(GITERR_OS, "Failed to lock ignore file");
+ giterr_set(GITERR_OS, "failed to lock ignore file");
return -1;
}
@@ -199,8 +215,14 @@ static int parse_ignore_file(
scan = git__next_line(scan);
- /* if a negative match doesn't actually do anything, throw it away */
- if (match->flags & GIT_ATTR_FNMATCH_NEGATIVE)
+ /*
+ * If a negative match doesn't actually do anything,
+ * throw it away. As we cannot always verify whether a
+ * rule containing wildcards negates another rule, we
+ * do not optimize away these rules, though.
+ * */
+ if (match->flags & GIT_ATTR_FNMATCH_NEGATIVE
+ && !(match->flags & GIT_ATTR_FNMATCH_HASWILD))
error = does_negate_rule(&valid_rule, &attrs->rules, match);
if (!error && valid_rule)
@@ -277,8 +299,9 @@ int git_ignore__for_path(
{
int error = 0;
const char *workdir = git_repository_workdir(repo);
+ git_buf infopath = GIT_BUF_INIT;
- assert(ignores && path);
+ assert(repo && ignores && path);
memset(ignores, 0, sizeof(*ignores));
ignores->repo = repo;
@@ -322,10 +345,14 @@ int git_ignore__for_path(
goto cleanup;
}
+ if ((error = git_repository_item_path(&infopath,
+ repo, GIT_REPOSITORY_ITEM_INFO)) < 0)
+ goto cleanup;
+
/* load .git/info/exclude */
error = push_ignore_file(
ignores, &ignores->ign_global,
- git_repository_path(repo), GIT_IGNORE_FILE_INREPO);
+ infopath.ptr, GIT_IGNORE_FILE_INREPO);
if (error < 0)
goto cleanup;
@@ -336,6 +363,7 @@ int git_ignore__for_path(
git_repository_attr_cache(repo)->cfg_excl_file);
cleanup:
+ git_buf_free(&infopath);
if (error < 0)
git_ignore__free(ignores);
@@ -503,9 +531,9 @@ int git_ignore_path_is_ignored(
unsigned int i;
git_attr_file *file;
- assert(ignored && pathname);
+ assert(repo && ignored && pathname);
- workdir = repo ? git_repository_workdir(repo) : NULL;
+ workdir = git_repository_workdir(repo);
memset(&path, 0, sizeof(path));
memset(&ignores, 0, sizeof(ignores));
diff --git a/src/ignore.h b/src/ignore.h
index d40bd60f9..5895d3faa 100644
--- a/src/ignore.h
+++ b/src/ignore.h
@@ -7,12 +7,14 @@
#ifndef INCLUDE_ignore_h__
#define INCLUDE_ignore_h__
+#include "common.h"
+
#include "repository.h"
#include "vector.h"
#include "attr_file.h"
#define GIT_IGNORE_FILE ".gitignore"
-#define GIT_IGNORE_FILE_INREPO "info/exclude"
+#define GIT_IGNORE_FILE_INREPO "exclude"
#define GIT_IGNORE_FILE_XDG "ignore"
/* The git_ignores structure maintains three sets of ignores:
diff --git a/src/index.c b/src/index.c
index bc15959a8..b7602fb44 100644
--- a/src/index.c
+++ b/src/index.c
@@ -5,11 +5,11 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "index.h"
+
#include <stddef.h>
-#include "common.h"
#include "repository.h"
-#include "index.h"
#include "tree.h"
#include "tree-cache.h"
#include "hash.h"
@@ -27,9 +27,6 @@
#include "git2/config.h"
#include "git2/sys/index.h"
-GIT__USE_IDXMAP
-GIT__USE_IDXMAP_ICASE
-
#define INSERT_IN_MAP_EX(idx, map, e, err) do { \
if ((idx)->ignore_case) \
git_idxmap_icase_insert((khash_t(idxicase) *) (map), (e), (e), (err)); \
@@ -57,10 +54,6 @@ static int index_apply_to_wd_diff(git_index *index, int action, const git_strarr
unsigned int flags,
git_index_matched_path_cb cb, void *payload);
-#define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7)
-#define short_entry_size(len) entry_size(struct entry_short, len)
-#define long_entry_size(len) entry_size(struct entry_long, len)
-
#define minimal_entry_size (offsetof(struct entry_short, path))
static const size_t INDEX_FOOTER_SIZE = GIT_OID_RAWSZ;
@@ -552,7 +545,7 @@ int git_index_clear(git_index *index)
static int create_index_error(int error, const char *msg)
{
- giterr_set(GITERR_INDEX, msg);
+ giterr_set_str(GITERR_INDEX, msg);
return error;
}
@@ -570,7 +563,7 @@ int git_index_set_caps(git_index *index, int caps)
if (!repo)
return create_index_error(
- -1, "Cannot access repository to set index caps");
+ -1, "cannot access repository to set index caps");
if (!git_repository__cvar(&val, repo, GIT_CVAR_IGNORECASE))
index->ignore_case = (val != 0);
@@ -639,7 +632,7 @@ int git_index_read(git_index *index, int force)
if (!index->index_file_path)
return create_index_error(-1,
- "Failed to read index: The index is in-memory only");
+ "failed to read index: The index is in-memory only");
index->on_disk = git_path_exists(index->index_file_path);
@@ -653,7 +646,7 @@ int git_index_read(git_index *index, int force)
((updated = compare_checksum(index)) < 0)) {
giterr_set(
GITERR_INDEX,
- "Failed to read index: '%s' no longer exists",
+ "failed to read index: '%s' no longer exists",
index->index_file_path);
return updated;
}
@@ -765,7 +758,7 @@ int git_index_set_version(git_index *index, unsigned int version)
if (version < INDEX_VERSION_NUMBER_LB ||
version > INDEX_VERSION_NUMBER_UB) {
- giterr_set(GITERR_INDEX, "Invalid version number");
+ giterr_set(GITERR_INDEX, "invalid version number");
return -1;
}
@@ -805,7 +798,7 @@ int git_index_write_tree(git_oid *oid, git_index *index)
if (repo == NULL)
return create_index_error(-1, "Failed to write tree. "
- "The index file is not backed up by an existing repository");
+ "the index file is not backed up by an existing repository");
return git_tree__write_index(oid, index, repo);
}
@@ -847,7 +840,7 @@ const git_index_entry *git_index_get_bypath(
if (git_idxmap_valid_index(index->entries_map, pos))
return git_idxmap_value_at(index->entries_map, pos);
- giterr_set(GITERR_INDEX, "Index does not contain %s", path);
+ giterr_set(GITERR_INDEX, "index does not contain '%s'", path);
return NULL;
}
@@ -934,7 +927,7 @@ static int index_entry_init(
if (INDEX_OWNER(index) == NULL)
return create_index_error(-1,
- "Could not initialize index entry. "
+ "could not initialize index entry. "
"Index is not backed up by an existing repository.");
if (index_entry_create(&entry, INDEX_OWNER(index), rel_path, true) < 0)
@@ -1365,7 +1358,7 @@ static int index_insert(
error = git_vector_insert_sorted(&index->entries, entry, index_no_dups);
if (error == 0) {
- INSERT_IN_MAP(index, entry, error);
+ INSERT_IN_MAP(index, entry, &error);
}
}
@@ -1423,7 +1416,7 @@ int git_index_add_frombuffer(
if (INDEX_OWNER(index) == NULL)
return create_index_error(-1,
- "Could not initialize index entry. "
+ "could not initialize index entry. "
"Index is not backed up by an existing repository.");
if (!valid_filemode(source_entry->mode)) {
@@ -1592,7 +1585,7 @@ int git_index__fill(git_index *index, const git_vector *source_entries)
if ((ret = git_vector_insert(&index->entries, entry)) < 0)
break;
- INSERT_IN_MAP(index, entry, ret);
+ INSERT_IN_MAP(index, entry, &ret);
if (ret < 0)
break;
}
@@ -1637,7 +1630,7 @@ int git_index_remove(git_index *index, const char *path, int stage)
if (index_find(&position, index, path, 0, stage) < 0) {
giterr_set(
- GITERR_INDEX, "Index does not contain %s at stage %d", path, stage);
+ GITERR_INDEX, "index does not contain %s at stage %d", path, stage);
error = GIT_ENOTFOUND;
} else {
error = index_remove_entry(index, position);
@@ -1709,7 +1702,7 @@ int git_index_find(size_t *at_pos, git_index *index, const char *path)
if (git_vector_bsearch2(
&pos, &index->entries, index->entries_search_path, path) < 0) {
- giterr_set(GITERR_INDEX, "Index does not contain %s", path);
+ giterr_set(GITERR_INDEX, "index does not contain %s", path);
return GIT_ENOTFOUND;
}
@@ -2153,7 +2146,7 @@ void git_index_reuc_clear(git_index *index)
static int index_error_invalid(const char *message)
{
- giterr_set(GITERR_INDEX, "Invalid data in index - %s", message);
+ giterr_set(GITERR_INDEX, "invalid data in index - %s", message);
return -1;
}
@@ -2285,12 +2278,29 @@ out_err:
return 0;
}
+static size_t index_entry_size(size_t path_len, size_t varint_len, uint32_t flags)
+{
+ if (varint_len) {
+ if (flags & GIT_IDXENTRY_EXTENDED)
+ return offsetof(struct entry_long, path) + path_len + 1 + varint_len;
+ else
+ return offsetof(struct entry_short, path) + path_len + 1 + varint_len;
+ } else {
+#define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7)
+ if (flags & GIT_IDXENTRY_EXTENDED)
+ return entry_size(struct entry_long, path_len);
+ else
+ return entry_size(struct entry_short, path_len);
+#undef entry_size
+ }
+}
+
static size_t read_entry(
git_index_entry **out,
git_index *index,
const void *buffer,
size_t buffer_size,
- const char **last)
+ const char *last)
{
size_t path_length, entry_size;
const char *path_ptr;
@@ -2347,35 +2357,34 @@ static size_t read_entry(
path_length = path_end - path_ptr;
}
- if (entry.flags & GIT_IDXENTRY_EXTENDED)
- entry_size = long_entry_size(path_length);
- else
- entry_size = short_entry_size(path_length);
-
- if (INDEX_FOOTER_SIZE + entry_size > buffer_size)
- return 0;
-
+ entry_size = index_entry_size(path_length, 0, entry.flags);
entry.path = (char *)path_ptr;
} else {
size_t varint_len;
- size_t shared = git_decode_varint((const unsigned char *)path_ptr,
- &varint_len);
- size_t len = strlen(path_ptr + varint_len);
- size_t last_len = strlen(*last);
- size_t tmp_path_len;
+ size_t strip_len = git_decode_varint((const unsigned char *)path_ptr,
+ &varint_len);
+ size_t last_len = strlen(last);
+ size_t prefix_len = last_len - strip_len;
+ size_t suffix_len = strlen(path_ptr + varint_len);
+ size_t path_len;
if (varint_len == 0)
return index_error_invalid("incorrect prefix length");
- GITERR_CHECK_ALLOC_ADD(&tmp_path_len, shared, len + 1);
- tmp_path = git__malloc(tmp_path_len);
+ GITERR_CHECK_ALLOC_ADD(&path_len, prefix_len, suffix_len);
+ GITERR_CHECK_ALLOC_ADD(&path_len, path_len, 1);
+ tmp_path = git__malloc(path_len);
GITERR_CHECK_ALLOC(tmp_path);
- memcpy(tmp_path, last, last_len);
- memcpy(tmp_path + last_len, path_ptr + varint_len, len);
- entry_size = long_entry_size(shared + len);
+
+ memcpy(tmp_path, last, prefix_len);
+ memcpy(tmp_path + prefix_len, path_ptr + varint_len, suffix_len + 1);
+ entry_size = index_entry_size(suffix_len, varint_len, entry.flags);
entry.path = tmp_path;
}
+ if (INDEX_FOOTER_SIZE + entry_size > buffer_size)
+ return 0;
+
if (index_entry_dup(out, index, &entry) < 0) {
git__free(tmp_path);
return 0;
@@ -2448,7 +2457,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
unsigned int i;
struct index_header header = { 0 };
git_oid checksum_calculated, checksum_expected;
- const char **last = NULL;
+ const char *last = NULL;
const char *empty = "";
#define seek_forward(_increase) { \
@@ -2472,16 +2481,16 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
index->version = header.version;
if (index->version >= INDEX_VERSION_NUMBER_COMP)
- last = &empty;
+ last = empty;
seek_forward(INDEX_HEADER_SIZE);
assert(!index->entries.length);
if (index->ignore_case)
- kh_resize(idxicase, (khash_t(idxicase) *) index->entries_map, header.entry_count);
+ git_idxmap_icase_resize((khash_t(idxicase) *) index->entries_map, header.entry_count);
else
- kh_resize(idx, index->entries_map, header.entry_count);
+ git_idxmap_resize(index->entries_map, header.entry_count);
/* Parse all the entries */
for (i = 0; i < header.entry_count && buffer_size > INDEX_FOOTER_SIZE; ++i) {
@@ -2499,7 +2508,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
goto done;
}
- INSERT_IN_MAP(index, entry, error);
+ INSERT_IN_MAP(index, entry, &error);
if (error < 0) {
index_entry_free(entry);
@@ -2507,6 +2516,9 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
}
error = 0;
+ if (index->version >= INDEX_VERSION_NUMBER_COMP)
+ last = entry->path;
+
seek_forward(entry_size);
}
@@ -2577,11 +2589,12 @@ static bool is_index_extended(git_index *index)
return (extended > 0);
}
-static int write_disk_entry(git_filebuf *file, git_index_entry *entry, const char **last)
+static int write_disk_entry(git_filebuf *file, git_index_entry *entry, const char *last)
{
void *mem = NULL;
struct entry_short *ondisk;
size_t path_len, disk_size;
+ int varint_len = 0;
char *path;
const char *path_start = entry->path;
size_t same_len = 0;
@@ -2589,7 +2602,7 @@ static int write_disk_entry(git_filebuf *file, git_index_entry *entry, const cha
path_len = ((struct entry_internal *)entry)->pathlen;
if (last) {
- const char *last_c = *last;
+ const char *last_c = last;
while (*path_start == *last_c) {
if (!*path_start || !*last_c)
@@ -2599,13 +2612,10 @@ static int write_disk_entry(git_filebuf *file, git_index_entry *entry, const cha
++same_len;
}
path_len -= same_len;
- *last = entry->path;
+ varint_len = git_encode_varint(NULL, 0, same_len);
}
- if (entry->flags & GIT_IDXENTRY_EXTENDED)
- disk_size = long_entry_size(path_len);
- else
- disk_size = short_entry_size(path_len);
+ disk_size = index_entry_size(path_len, varint_len, entry->flags);
if (git_filebuf_reserve(file, &mem, disk_size) < 0)
return -1;
@@ -2645,16 +2655,34 @@ static int write_disk_entry(git_filebuf *file, git_index_entry *entry, const cha
ondisk_ext->flags_extended = htons(entry->flags_extended &
GIT_IDXENTRY_EXTENDED_FLAGS);
path = ondisk_ext->path;
- }
- else
+ disk_size -= offsetof(struct entry_long, path);
+ } else {
path = ondisk->path;
+ disk_size -= offsetof(struct entry_short, path);
+ }
if (last) {
- path += git_encode_varint((unsigned char *) path,
- disk_size,
- path_len - same_len);
+ varint_len = git_encode_varint((unsigned char *) path,
+ disk_size, same_len);
+ assert(varint_len > 0);
+ path += varint_len;
+ disk_size -= varint_len;
+
+ /*
+ * If using path compression, we are not allowed
+ * to have additional trailing NULs.
+ */
+ assert(disk_size == path_len + 1);
+ } else {
+ /*
+ * If no path compression is used, we do have
+ * NULs as padding. As such, simply assert that
+ * we have enough space left to write the path.
+ */
+ assert(disk_size > path_len);
}
- memcpy(path, path_start, path_len);
+
+ memcpy(path, path_start, path_len + 1);
return 0;
}
@@ -2665,8 +2693,7 @@ static int write_entries(git_index *index, git_filebuf *file)
size_t i;
git_vector case_sorted, *entries;
git_index_entry *entry;
- const char **last = NULL;
- const char *empty = "";
+ const char *last = NULL;
/* If index->entries is sorted case-insensitively, then we need
* to re-sort it case-sensitively before writing */
@@ -2679,11 +2706,14 @@ static int write_entries(git_index *index, git_filebuf *file)
}
if (index->version >= INDEX_VERSION_NUMBER_COMP)
- last = &empty;
+ last = "";
- git_vector_foreach(entries, i, entry)
+ git_vector_foreach(entries, i, entry) {
if ((error = write_disk_entry(file, entry, last)) < 0)
break;
+ if (index->version >= INDEX_VERSION_NUMBER_COMP)
+ last = entry->path;
+ }
if (index->ignore_case)
git_vector_free(&case_sorted);
@@ -2979,12 +3009,12 @@ int git_index_read_tree(git_index *index, const git_tree *tree)
goto cleanup;
if (index->ignore_case)
- kh_resize(idxicase, (khash_t(idxicase) *) entries_map, entries.length);
+ git_idxmap_icase_resize((khash_t(idxicase) *) entries_map, entries.length);
else
- kh_resize(idx, entries_map, entries.length);
+ git_idxmap_resize(entries_map, entries.length);
git_vector_foreach(&entries, i, e) {
- INSERT_IN_MAP_EX(index, entries_map, e, error);
+ INSERT_IN_MAP_EX(index, entries_map, e, &error);
if (error < 0) {
giterr_set(GITERR_INDEX, "failed to insert entry into map");
@@ -3037,9 +3067,9 @@ static int git_index_read_iterator(
goto done;
if (index->ignore_case && new_length_hint)
- kh_resize(idxicase, (khash_t(idxicase) *) new_entries_map, new_length_hint);
+ git_idxmap_icase_resize((khash_t(idxicase) *) new_entries_map, new_length_hint);
else if (new_length_hint)
- kh_resize(idx, new_entries_map, new_length_hint);
+ git_idxmap_resize(new_entries_map, new_length_hint);
opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE |
GIT_ITERATOR_INCLUDE_CONFLICTS;
@@ -3103,7 +3133,7 @@ static int git_index_read_iterator(
if (add_entry) {
if ((error = git_vector_insert(&new_entries, add_entry)) == 0)
- INSERT_IN_MAP_EX(index, new_entries_map, add_entry, error);
+ INSERT_IN_MAP_EX(index, new_entries_map, add_entry, &error);
}
if (remove_entry && error >= 0)
@@ -3390,7 +3420,7 @@ static int index_apply_to_all(
i--; /* back up foreach if we removed this */
break;
default:
- giterr_set(GITERR_INVALID, "Unknown index action %d", action);
+ giterr_set(GITERR_INVALID, "unknown index action %d", action);
error = -1;
break;
}
@@ -3475,13 +3505,13 @@ int git_indexwriter_init(
if (!index->index_file_path)
return create_index_error(-1,
- "Failed to write index: The index is in-memory only");
+ "failed to write index: The index is in-memory only");
if ((error = git_filebuf_open(
&writer->file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS, GIT_INDEX_FILE_MODE)) < 0) {
if (error == GIT_ELOCKED)
- giterr_set(GITERR_INDEX, "The index is locked. This might be due to a concurrent or crashed process");
+ giterr_set(GITERR_INDEX, "the index is locked; this might be due to a concurrent or crashed process");
return error;
}
@@ -3530,7 +3560,7 @@ int git_indexwriter_commit(git_indexwriter *writer)
if ((error = git_futils_filestamp_check(
&writer->index->stamp, writer->index->index_file_path)) < 0) {
- giterr_set(GITERR_OS, "Could not read index timestamp");
+ giterr_set(GITERR_OS, "could not read index timestamp");
return -1;
}
diff --git a/src/index.h b/src/index.h
index 9918f140d..0f1c0956c 100644
--- a/src/index.h
+++ b/src/index.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_index_h__
#define INCLUDE_index_h__
+#include "common.h"
+
#include "fileops.h"
#include "filebuf.h"
#include "vector.h"
diff --git a/src/indexer.c b/src/indexer.c
index a3a866989..766bbc3c3 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -5,10 +5,11 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "indexer.h"
+
#include "git2/indexer.h"
#include "git2/object.h"
-#include "common.h"
#include "pack.h"
#include "mwindow.h"
#include "posix.h"
@@ -17,8 +18,7 @@
#include "oid.h"
#include "oidmap.h"
#include "zstream.h"
-
-GIT__USE_OIDMAP
+#include "object.h"
extern git_mutex git__mwindow_mutex;
@@ -33,9 +33,10 @@ struct entry {
struct git_indexer {
unsigned int parsed_header :1,
- opened_pack :1,
+ pack_committed :1,
have_stream :1,
- have_delta :1;
+ have_delta :1,
+ do_fsync :1;
struct git_pack_header hdr;
struct git_pack_file *pack;
unsigned int mode;
@@ -83,12 +84,12 @@ static int parse_header(struct git_pack_header *hdr, struct git_pack_file *pack)
/* Verify we recognize this pack file format. */
if (hdr->hdr_signature != ntohl(PACK_SIGNATURE)) {
- giterr_set(GITERR_INDEXER, "Wrong pack signature");
+ giterr_set(GITERR_INDEXER, "wrong pack signature");
return -1;
}
if (!pack_version_ok(hdr->hdr_version)) {
- giterr_set(GITERR_INDEXER, "Wrong pack version");
+ giterr_set(GITERR_INDEXER, "wrong pack version");
return -1;
}
@@ -125,6 +126,9 @@ int git_indexer_new(
git_hash_ctx_init(&idx->hash_ctx);
git_hash_ctx_init(&idx->trailer);
+ if (git_repository__fsync_gitdir)
+ idx->do_fsync = 1;
+
error = git_buf_joinpath(&path, prefix, suff);
if (error < 0)
goto cleanup;
@@ -151,12 +155,23 @@ cleanup:
if (fd != -1)
p_close(fd);
+ if (git_buf_len(&tmp_path) > 0)
+ p_unlink(git_buf_cstr(&tmp_path));
+
+ if (idx->pack != NULL)
+ p_unlink(idx->pack->pack_name);
+
git_buf_free(&path);
git_buf_free(&tmp_path);
git__free(idx);
return -1;
}
+void git_indexer__set_fsync(git_indexer *idx, int do_fsync)
+{
+ idx->do_fsync = !!do_fsync;
+}
+
/* Try to store the delta so we can try to resolve it later */
static int store_delta(git_indexer *idx)
{
@@ -288,7 +303,7 @@ static int store_object(git_indexer *idx)
git_oid_cpy(&pentry->sha1, &oid);
pentry->offset = entry_start;
- k = kh_put(oid, idx->pack->idx_cache, &pentry->sha1, &error);
+ k = git_oidmap_put(idx->pack->idx_cache, &pentry->sha1, &error);
if (error == -1) {
git__free(pentry);
giterr_set_oom();
@@ -302,7 +317,7 @@ static int store_object(git_indexer *idx)
}
- kh_value(idx->pack->idx_cache, k) = pentry;
+ git_oidmap_set_value_at(idx->pack->idx_cache, k, pentry);
git_oid_cpy(&entry->oid, &oid);
@@ -327,9 +342,7 @@ on_error:
GIT_INLINE(bool) has_entry(git_indexer *idx, git_oid *id)
{
- khiter_t k;
- k = kh_get(oid, idx->pack->idx_cache, id);
- return (k != kh_end(idx->pack->idx_cache));
+ return git_oidmap_exists(idx->pack->idx_cache, id);
}
static int save_entry(git_indexer *idx, struct entry *entry, struct git_pack_entry *pentry, git_off_t entry_start)
@@ -345,14 +358,14 @@ static int save_entry(git_indexer *idx, struct entry *entry, struct git_pack_ent
}
pentry->offset = entry_start;
- k = kh_put(oid, idx->pack->idx_cache, &pentry->sha1, &error);
+ k = git_oidmap_put(idx->pack->idx_cache, &pentry->sha1, &error);
if (error <= 0) {
giterr_set(GITERR_INDEXER, "cannot insert object into pack");
return -1;
}
- kh_value(idx->pack->idx_cache, k) = pentry;
+ git_oidmap_set_value_at(idx->pack->idx_cache, k, pentry);
/* Add the object to the list */
if (git_vector_insert(&idx->objects, entry) < 0)
@@ -376,7 +389,7 @@ static int hash_and_save(git_indexer *idx, git_rawobj *obj, git_off_t entry_star
GITERR_CHECK_ALLOC(entry);
if (git_odb__hashobj(&oid, obj) < 0) {
- giterr_set(GITERR_INDEXER, "Failed to hash object");
+ giterr_set(GITERR_INDEXER, "failed to hash object");
goto on_error;
}
@@ -477,13 +490,29 @@ static int write_at(git_indexer *idx, const void *data, git_off_t offset, size_t
static int append_to_pack(git_indexer *idx, const void *data, size_t size)
{
+ git_off_t new_size;
+ size_t mmap_alignment;
+ size_t page_offset;
+ git_off_t page_start;
git_off_t current_size = idx->pack->mwf.size;
int fd = idx->pack->mwf.fd;
+ int error;
if (!size)
return 0;
- if (p_lseek(fd, current_size + size - 1, SEEK_SET) < 0 ||
+ if ((error = git__mmap_alignment(&mmap_alignment)) < 0)
+ return error;
+
+ /* Write a single byte to force the file system to allocate space now or
+ * report an error, since we can't report errors when writing using mmap.
+ * Round the size up to the nearest page so that we only need to perform file
+ * I/O when we add a page, instead of whenever we write even a single byte. */
+ new_size = current_size + size;
+ page_offset = new_size % mmap_alignment;
+ page_start = new_size - page_offset;
+
+ if (p_lseek(fd, page_start + mmap_alignment - 1, SEEK_SET) < 0 ||
p_write(idx->pack->mwf.fd, data, 1) < 0) {
giterr_set(GITERR_OS, "cannot extend packfile '%s'", idx->pack->pack_name);
return -1;
@@ -909,7 +938,6 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats)
git_buf filename = GIT_BUF_INIT;
struct entry *entry;
git_oid trailer_hash, file_hash;
- git_hash_ctx ctx;
git_filebuf index_file = {0};
void *packfile_trailer;
@@ -918,9 +946,6 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats)
return -1;
}
- if (git_hash_ctx_init(&ctx) < 0)
- return -1;
-
/* Test for this before resolve_deltas(), as it plays with idx->off */
if (idx->off + 20 < idx->pack->mwf.size) {
giterr_set(GITERR_INDEXER, "unexpected data at the end of the pack");
@@ -964,6 +989,10 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats)
git_vector_sort(&idx->objects);
+ /* Use the trailer hash as the pack file name to ensure
+ * files with different contents have different names */
+ git_oid_cpy(&idx->hash, &trailer_hash);
+
git_buf_sets(&filename, idx->pack->pack_name);
git_buf_shorten(&filename, strlen("pack"));
git_buf_puts(&filename, "idx");
@@ -971,7 +1000,9 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats)
return -1;
if (git_filebuf_open(&index_file, filename.ptr,
- GIT_FILEBUF_HASH_CONTENTS, idx->mode) < 0)
+ GIT_FILEBUF_HASH_CONTENTS |
+ (idx->do_fsync ? GIT_FILEBUF_FSYNC : 0),
+ idx->mode) < 0)
goto on_error;
/* Write out the header */
@@ -988,9 +1019,7 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats)
/* Write out the object names (SHA-1 hashes) */
git_vector_foreach(&idx->objects, i, entry) {
git_filebuf_write(&index_file, &entry->oid, sizeof(git_oid));
- git_hash_update(&ctx, &entry->oid, GIT_OID_RAWSZ);
}
- git_hash_final(&idx->hash, &ctx);
/* Write out the CRC32 values */
git_vector_foreach(&idx->objects, i, entry) {
@@ -1041,6 +1070,18 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats)
goto on_error;
git_mwindow_free_all(&idx->pack->mwf);
+
+ /* Truncate file to undo rounding up to next page_size in append_to_pack */
+ if (p_ftruncate(idx->pack->mwf.fd, idx->pack->mwf.size) < 0) {
+ giterr_set(GITERR_OS, "failed to truncate pack file '%s'", idx->pack->pack_name);
+ return -1;
+ }
+
+ if (idx->do_fsync && p_fsync(idx->pack->mwf.fd) < 0) {
+ giterr_set(GITERR_OS, "failed to fsync packfile");
+ goto on_error;
+ }
+
/* We need to close the descriptor here so Windows doesn't choke on commit_at */
if (p_close(idx->pack->mwf.fd) < 0) {
giterr_set(GITERR_OS, "failed to close packfile");
@@ -1053,17 +1094,23 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats)
goto on_error;
/* And don't forget to rename the packfile to its new place. */
- p_rename(idx->pack->pack_name, git_buf_cstr(&filename));
+ if (p_rename(idx->pack->pack_name, git_buf_cstr(&filename)) < 0)
+ goto on_error;
+
+ /* And fsync the parent directory if we're asked to. */
+ if (idx->do_fsync &&
+ git_futils_fsync_parent(git_buf_cstr(&filename)) < 0)
+ goto on_error;
+
+ idx->pack_committed = 1;
git_buf_free(&filename);
- git_hash_ctx_cleanup(&ctx);
return 0;
on_error:
git_mwindow_free_all(&idx->pack->mwf);
git_filebuf_cleanup(&index_file);
git_buf_free(&filename);
- git_hash_ctx_cleanup(&ctx);
return -1;
}
@@ -1074,10 +1121,11 @@ void git_indexer_free(git_indexer *idx)
git_vector_free_deep(&idx->objects);
- if (idx->pack && idx->pack->idx_cache) {
+ if (idx->pack->idx_cache) {
struct git_pack_entry *pentry;
- kh_foreach_value(
- idx->pack->idx_cache, pentry, { git__free(pentry); });
+ git_oidmap_foreach_value(idx->pack->idx_cache, pentry, {
+ git__free(pentry);
+ });
git_oidmap_free(idx->pack->idx_cache);
}
@@ -1085,6 +1133,9 @@ void git_indexer_free(git_indexer *idx)
git_vector_free_deep(&idx->deltas);
if (!git_mutex_lock(&git__mwindow_mutex)) {
+ if (!idx->pack_committed)
+ git_packfile_close(idx->pack, true);
+
git_packfile_free(idx->pack);
git_mutex_unlock(&git__mwindow_mutex);
}
diff --git a/include/git2/sys/remote.h b/src/indexer.h
index 3037b411c..8ee6115a6 100644
--- a/include/git2/sys/remote.h
+++ b/src/indexer.h
@@ -4,13 +4,13 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
+#ifndef INCLUDE_indexer_h__
+#define INCLUDE_indexer_h__
-#ifndef INCLUDE_sys_git_transport_h
-#define INCLUDE_sys_git_transport_h
+#include "common.h"
-#include "git2/net.h"
-#include "git2/types.h"
+#include "git2/indexer.h"
-GIT_BEGIN_DECL
+extern void git_indexer__set_fsync(git_indexer *idx, int do_fsync);
-GIT_END_DECL
+#endif
diff --git a/src/integer.h b/src/integer.h
index b08094c2f..61712cebf 100644
--- a/src/integer.h
+++ b/src/integer.h
@@ -55,16 +55,16 @@ GIT_INLINE(bool) git__add_uint64_overflow(uint64_t *out, uint64_t one, uint64_t
}
/* Use clang/gcc compiler intrinsics whenever possible */
-#if (SIZE_MAX == UINT_MAX) && __has_builtin(__builtin_uadd_overflow)
-# define git__add_sizet_overflow(out, one, two) \
- __builtin_uadd_overflow(one, two, out)
-# define git__multiply_sizet_overflow(out, one, two) \
- __builtin_umul_overflow(one, two, out)
-#elif (SIZE_MAX == ULONG_MAX) && __has_builtin(__builtin_uaddl_overflow)
+#if (SIZE_MAX == ULONG_MAX) && __has_builtin(__builtin_uaddl_overflow)
# define git__add_sizet_overflow(out, one, two) \
__builtin_uaddl_overflow(one, two, out)
# define git__multiply_sizet_overflow(out, one, two) \
__builtin_umull_overflow(one, two, out)
+#elif (SIZE_MAX == UINT_MAX) && __has_builtin(__builtin_uadd_overflow)
+# define git__add_sizet_overflow(out, one, two) \
+ __builtin_uadd_overflow(one, two, out)
+# define git__multiply_sizet_overflow(out, one, two) \
+ __builtin_umul_overflow(one, two, out)
#else
/**
diff --git a/src/iterator.c b/src/iterator.c
index 598c69c83..960031233 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -6,6 +6,7 @@
*/
#include "iterator.h"
+
#include "tree.h"
#include "index.h"
@@ -1311,7 +1312,7 @@ static int filesystem_iterator_frame_push(
if (iter->frames.size == FILESYSTEM_MAX_DEPTH) {
giterr_set(GITERR_REPOSITORY,
- "directory nesting too deep (%d)", iter->frames.size);
+ "directory nesting too deep (%"PRIuZ")", iter->frames.size);
return -1;
}
diff --git a/src/iterator.h b/src/iterator.h
index 0b239a5bd..0bcb128d9 100644
--- a/src/iterator.h
+++ b/src/iterator.h
@@ -8,6 +8,7 @@
#define INCLUDE_iterator_h__
#include "common.h"
+
#include "git2/index.h"
#include "vector.h"
#include "buffer.h"
diff --git a/src/merge.c b/src/merge.c
index 6934aa731..72cfa464d 100644
--- a/src/merge.c
+++ b/src/merge.c
@@ -5,13 +5,13 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+#include "merge.h"
+
#include "posix.h"
#include "buffer.h"
#include "repository.h"
#include "revwalk.h"
#include "commit_list.h"
-#include "merge.h"
#include "path.h"
#include "refs.h"
#include "object.h"
@@ -32,6 +32,8 @@
#include "commit.h"
#include "oidarray.h"
#include "merge_driver.h"
+#include "oidmap.h"
+#include "array.h"
#include "git2/types.h"
#include "git2/repository.h"
@@ -78,7 +80,7 @@ int merge_bases_many(git_commit_list **out, git_revwalk **walk_out, git_reposito
unsigned int i;
if (length < 2) {
- giterr_set(GITERR_INVALID, "At least two commits are required to find an ancestor. Provided 'length' was %" PRIuZ ".", length);
+ giterr_set(GITERR_INVALID, "at least two commits are required to find an ancestor");
return -1;
}
@@ -104,7 +106,7 @@ int merge_bases_many(git_commit_list **out, git_revwalk **walk_out, git_reposito
goto on_error;
if (!result) {
- giterr_set(GITERR_MERGE, "No merge base found");
+ giterr_set(GITERR_MERGE, "no merge base found");
error = GIT_ENOTFOUND;
goto on_error;
}
@@ -184,7 +186,7 @@ int git_merge_base_octopus(git_oid *out, git_repository *repo, size_t length, co
assert(out && repo && input_array);
if (length < 2) {
- giterr_set(GITERR_INVALID, "At least two commits are required to find an ancestor. Provided 'length' was %" PRIuZ ".", length);
+ giterr_set(GITERR_INVALID, "at least two commits are required to find an ancestor");
return -1;
}
@@ -230,7 +232,7 @@ static int merge_bases(git_commit_list **out, git_revwalk **walk_out, git_reposi
if (!result) {
git_revwalk_free(walk);
- giterr_set(GITERR_MERGE, "No merge base found");
+ giterr_set(GITERR_MERGE, "no merge base found");
return GIT_ENOTFOUND;
}
@@ -562,7 +564,7 @@ int git_repository_mergehead_foreach(
assert(repo && cb);
- if ((error = git_buf_joinpath(&merge_head_path, repo->path_repository,
+ if ((error = git_buf_joinpath(&merge_head_path, repo->gitdir,
GIT_MERGE_HEAD_FILE)) < 0)
return error;
@@ -574,7 +576,7 @@ int git_repository_mergehead_foreach(
while ((line = git__strsep(&buffer, "\n")) != NULL) {
if (strlen(line) != GIT_OID_HEXSZ) {
- giterr_set(GITERR_INVALID, "Unable to parse OID - invalid length");
+ giterr_set(GITERR_INVALID, "unable to parse OID - invalid length");
error = -1;
goto cleanup;
}
@@ -591,7 +593,7 @@ int git_repository_mergehead_foreach(
}
if (*buffer) {
- giterr_set(GITERR_MERGE, "No EOL at line %d", line_num);
+ giterr_set(GITERR_MERGE, "no EOL at line %"PRIuZ, line_num);
error = -1;
goto cleanup;
}
@@ -1005,27 +1007,6 @@ struct merge_diff_similarity {
size_t other_idx;
};
-static int index_entry_similarity_exact(
- git_repository *repo,
- git_index_entry *a,
- size_t a_idx,
- git_index_entry *b,
- size_t b_idx,
- void **cache,
- const git_merge_options *opts)
-{
- GIT_UNUSED(repo);
- GIT_UNUSED(a_idx);
- GIT_UNUSED(b_idx);
- GIT_UNUSED(cache);
- GIT_UNUSED(opts);
-
- if (git_oid__cmp(&a->id, &b->id) == 0)
- return 100;
-
- return 0;
-}
-
static int index_entry_similarity_calc(
void **out,
git_repository *repo,
@@ -1075,7 +1056,7 @@ static int index_entry_similarity_inexact(
int score = 0;
int error = 0;
- if (GIT_MODE_TYPE(a->mode) != GIT_MODE_TYPE(b->mode))
+ if (!GIT_MODE_ISBLOB(a->mode) || !GIT_MODE_ISBLOB(b->mode))
return 0;
/* update signature cache if needed */
@@ -1102,12 +1083,154 @@ static int index_entry_similarity_inexact(
return score;
}
-static int merge_diff_mark_similarity(
+/* Tracks deletes by oid for merge_diff_mark_similarity_exact(). This is a
+* non-shrinking queue where next_pos is the next position to dequeue.
+*/
+typedef struct {
+ git_array_t(size_t) arr;
+ size_t next_pos;
+ size_t first_entry;
+} deletes_by_oid_queue;
+
+static void deletes_by_oid_free(git_oidmap *map) {
+ deletes_by_oid_queue *queue;
+
+ if (!map)
+ return;
+
+ git_oidmap_foreach_value(map, queue, {
+ git_array_clear(queue->arr);
+ });
+ git_oidmap_free(map);
+}
+
+static int deletes_by_oid_enqueue(git_oidmap *map, git_pool* pool, const git_oid *id, size_t idx) {
+ khint_t pos;
+ deletes_by_oid_queue *queue;
+ size_t *array_entry;
+ int error;
+
+ pos = git_oidmap_lookup_index(map, id);
+ if (!git_oidmap_valid_index(map, pos)) {
+ queue = git_pool_malloc(pool, sizeof(deletes_by_oid_queue));
+ GITERR_CHECK_ALLOC(queue);
+
+ git_array_init(queue->arr);
+ queue->next_pos = 0;
+ queue->first_entry = idx;
+
+ git_oidmap_insert(map, id, queue, &error);
+ if (error < 0)
+ return -1;
+ } else {
+ queue = git_oidmap_value_at(map, pos);
+ array_entry = git_array_alloc(queue->arr);
+ GITERR_CHECK_ALLOC(array_entry);
+ *array_entry = idx;
+ }
+
+ return 0;
+}
+
+static int deletes_by_oid_dequeue(size_t *idx, git_oidmap *map, const git_oid *id) {
+ khint_t pos;
+ deletes_by_oid_queue *queue;
+ size_t *array_entry;
+
+ pos = git_oidmap_lookup_index(map, id);
+
+ if (!git_oidmap_valid_index(map, pos))
+ return GIT_ENOTFOUND;
+
+ queue = git_oidmap_value_at(map, pos);
+
+ if (queue->next_pos == 0) {
+ *idx = queue->first_entry;
+ } else {
+ array_entry = git_array_get(queue->arr, queue->next_pos - 1);
+ if (array_entry == NULL)
+ return GIT_ENOTFOUND;
+
+ *idx = *array_entry;
+ }
+
+ queue->next_pos++;
+ return 0;
+}
+
+static int merge_diff_mark_similarity_exact(
+ git_merge_diff_list *diff_list,
+ struct merge_diff_similarity *similarity_ours,
+ struct merge_diff_similarity *similarity_theirs)
+{
+ size_t i, j;
+ git_merge_diff *conflict_src, *conflict_tgt;
+ git_oidmap *ours_deletes_by_oid = NULL, *theirs_deletes_by_oid = NULL;
+ int error = 0;
+
+ if (!(ours_deletes_by_oid = git_oidmap_alloc()) ||
+ !(theirs_deletes_by_oid = git_oidmap_alloc())) {
+ error = -1;
+ goto done;
+ }
+
+ /* Build a map of object ids to conflicts */
+ git_vector_foreach(&diff_list->conflicts, i, conflict_src) {
+ /* Items can be the source of a rename iff they have an item in the
+ * ancestor slot and lack an item in the ours or theirs slot. */
+ if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->ancestor_entry))
+ continue;
+
+ if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->our_entry)) {
+ error = deletes_by_oid_enqueue(ours_deletes_by_oid, &diff_list->pool, &conflict_src->ancestor_entry.id, i);
+ if (error < 0)
+ goto done;
+ }
+
+ if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->their_entry)) {
+ error = deletes_by_oid_enqueue(theirs_deletes_by_oid, &diff_list->pool, &conflict_src->ancestor_entry.id, i);
+ if (error < 0)
+ goto done;
+ }
+ }
+
+ git_vector_foreach(&diff_list->conflicts, j, conflict_tgt) {
+ if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->ancestor_entry))
+ continue;
+
+ if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->our_entry)) {
+ if (deletes_by_oid_dequeue(&i, ours_deletes_by_oid, &conflict_tgt->our_entry.id) == 0) {
+ similarity_ours[i].similarity = 100;
+ similarity_ours[i].other_idx = j;
+
+ similarity_ours[j].similarity = 100;
+ similarity_ours[j].other_idx = i;
+ }
+ }
+
+ if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->their_entry)) {
+ if (deletes_by_oid_dequeue(&i, theirs_deletes_by_oid, &conflict_tgt->their_entry.id) == 0) {
+ similarity_theirs[i].similarity = 100;
+ similarity_theirs[i].other_idx = j;
+
+ similarity_theirs[j].similarity = 100;
+ similarity_theirs[j].other_idx = i;
+ }
+ }
+ }
+
+done:
+ deletes_by_oid_free(ours_deletes_by_oid);
+ deletes_by_oid_free(theirs_deletes_by_oid);
+
+ return error;
+}
+
+static int merge_diff_mark_similarity_inexact(
git_repository *repo,
git_merge_diff_list *diff_list,
struct merge_diff_similarity *similarity_ours,
struct merge_diff_similarity *similarity_theirs,
- int (*similarity_fn)(git_repository *, git_index_entry *, size_t, git_index_entry *, size_t, void **, const git_merge_options *),
void **cache,
const git_merge_options *opts)
{
@@ -1132,7 +1255,7 @@ static int merge_diff_mark_similarity(
if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->our_entry) &&
!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->our_entry)) {
- similarity = similarity_fn(repo, &conflict_src->ancestor_entry, i, &conflict_tgt->our_entry, our_idx, cache, opts);
+ similarity = index_entry_similarity_inexact(repo, &conflict_src->ancestor_entry, i, &conflict_tgt->our_entry, our_idx, cache, opts);
if (similarity == GIT_EBUFS)
continue;
@@ -1158,7 +1281,7 @@ static int merge_diff_mark_similarity(
if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->their_entry) &&
!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->their_entry)) {
- similarity = similarity_fn(repo, &conflict_src->ancestor_entry, i, &conflict_tgt->their_entry, their_idx, cache, opts);
+ similarity = index_entry_similarity_inexact(repo, &conflict_src->ancestor_entry, i, &conflict_tgt->their_entry, their_idx, cache, opts);
if (similarity > similarity_theirs[i].similarity &&
similarity > similarity_theirs[j].similarity) {
@@ -1396,11 +1519,10 @@ int git_merge_diff_list__find_renames(
/* Calculate similarity between items that were deleted from the ancestor
* and added in the other branch.
*/
- if ((error = merge_diff_mark_similarity(repo, diff_list, similarity_ours,
- similarity_theirs, index_entry_similarity_exact, NULL, opts)) < 0)
+ if ((error = merge_diff_mark_similarity_exact(diff_list, similarity_ours, similarity_theirs)) < 0)
goto done;
- if (diff_list->conflicts.length <= opts->target_limit) {
+ if (opts->rename_threshold < 100 && diff_list->conflicts.length <= opts->target_limit) {
GITERR_CHECK_ALLOC_MULTIPLY(&cache_size, diff_list->conflicts.length, 3);
cache = git__calloc(cache_size, sizeof(void *));
GITERR_CHECK_ALLOC(cache);
@@ -1410,9 +1532,8 @@ int git_merge_diff_list__find_renames(
if (src_count > opts->target_limit || tgt_count > opts->target_limit) {
/* TODO: report! */
} else {
- if ((error = merge_diff_mark_similarity(
- repo, diff_list, similarity_ours, similarity_theirs,
- index_entry_similarity_inexact, cache, opts)) < 0)
+ if ((error = merge_diff_mark_similarity_inexact(
+ repo, diff_list, similarity_ours, similarity_theirs, cache, opts)) < 0)
goto done;
}
}
@@ -1713,15 +1834,15 @@ static int merge_normalize_opts(
if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
return error;
- if (given != NULL)
+ if (given != NULL) {
memcpy(opts, given, sizeof(git_merge_options));
- else {
+ } else {
git_merge_options init = GIT_MERGE_OPTIONS_INIT;
memcpy(opts, &init, sizeof(init));
+ }
- opts->flags = GIT_MERGE_FIND_RENAMES;
+ if ((opts->flags & GIT_MERGE_FIND_RENAMES) && !opts->rename_threshold)
opts->rename_threshold = GIT_MERGE_DEFAULT_RENAME_THRESHOLD;
- }
if (given && given->default_driver) {
opts->default_driver = git__strdup(given->default_driver);
@@ -2018,6 +2139,26 @@ int git_merge_trees(
git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT;
int error;
+ assert(out && repo);
+
+ /* if one side is treesame to the ancestor, take the other side */
+ if (ancestor_tree && merge_opts && (merge_opts->flags & GIT_MERGE_SKIP_REUC)) {
+ const git_tree *result = NULL;
+ const git_oid *ancestor_tree_id = git_tree_id(ancestor_tree);
+
+ if (our_tree && !git_oid_cmp(ancestor_tree_id, git_tree_id(our_tree)))
+ result = their_tree;
+ else if (their_tree && !git_oid_cmp(ancestor_tree_id, git_tree_id(their_tree)))
+ result = our_tree;
+
+ if (result) {
+ if ((error = git_index_new(out)) == 0)
+ error = git_index_read_tree(*out, result);
+
+ return error;
+ }
+ }
+
iter_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE;
if ((error = git_iterator_for_tree(
@@ -2277,7 +2418,7 @@ static int write_merge_head(
assert(repo && heads);
- if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_HEAD_FILE)) < 0 ||
+ if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_HEAD_FILE)) < 0 ||
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0)
goto cleanup;
@@ -2305,7 +2446,7 @@ static int write_merge_mode(git_repository *repo)
assert(repo);
- if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_MODE_FILE)) < 0 ||
+ if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MODE_FILE)) < 0 ||
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0)
goto cleanup;
@@ -2536,7 +2677,7 @@ static int write_merge_msg(
for (i = 0; i < heads_len; i++)
entries[i].merge_head = heads[i];
- if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_MSG_FILE)) < 0 ||
+ if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MSG_FILE)) < 0 ||
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0 ||
(error = git_filebuf_write(&file, "Merge ", 6)) < 0)
goto cleanup;
@@ -2914,7 +3055,7 @@ int git_merge__append_conflicts_to_merge_msg(
if (!git_index_has_conflicts(index))
return 0;
- if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_MSG_FILE)) < 0 ||
+ if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MSG_FILE)) < 0 ||
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_APPEND, GIT_MERGE_FILE_MODE)) < 0)
goto cleanup;
@@ -3043,7 +3184,7 @@ int git_merge_analysis(
assert(analysis_out && preference_out && repo && their_heads);
if (their_heads_len != 1) {
- giterr_set(GITERR_MERGE, "Can only merge a single branch");
+ giterr_set(GITERR_MERGE, "can only merge a single branch");
error = -1;
goto done;
}
@@ -3099,7 +3240,7 @@ int git_merge(
assert(repo && their_heads);
if (their_heads_len != 1) {
- giterr_set(GITERR_MERGE, "Can only merge a single branch");
+ giterr_set(GITERR_MERGE, "can only merge a single branch");
return -1;
}
diff --git a/src/merge.h b/src/merge.h
index f8cac161f..173a1b435 100644
--- a/src/merge.h
+++ b/src/merge.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_merge_h__
#define INCLUDE_merge_h__
+#include "common.h"
+
#include "vector.h"
#include "commit_list.h"
#include "pool.h"
diff --git a/src/merge_driver.c b/src/merge_driver.c
index 88a53ecdb..ea4bd2787 100644
--- a/src/merge_driver.c
+++ b/src/merge_driver.c
@@ -5,11 +5,11 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+#include "merge_driver.h"
+
#include "vector.h"
#include "global.h"
#include "merge.h"
-#include "merge_driver.h"
#include "git2/merge.h"
#include "git2/sys/merge.h"
@@ -32,6 +32,35 @@ static struct merge_driver_registry merge_driver_registry;
static void git_merge_driver_global_shutdown(void);
+const git_repository* git_merge_driver_source_repo(const git_merge_driver_source *src)
+{
+ assert(src);
+ return src->repo;
+}
+
+const git_index_entry* git_merge_driver_source_ancestor(const git_merge_driver_source *src)
+{
+ assert(src);
+ return src->ancestor;
+}
+
+const git_index_entry* git_merge_driver_source_ours(const git_merge_driver_source *src)
+{
+ assert(src);
+ return src->ours;
+}
+
+const git_index_entry* git_merge_driver_source_theirs(const git_merge_driver_source *src)
+{
+ assert(src);
+ return src->theirs;
+}
+
+const git_merge_file_options* git_merge_driver_source_file_options(const git_merge_driver_source *src)
+{
+ assert(src);
+ return src->file_opts;
+}
int git_merge_driver__builtin_apply(
git_merge_driver *self,
diff --git a/src/merge_driver.h b/src/merge_driver.h
index bde27502c..6b7da5287 100644
--- a/src/merge_driver.h
+++ b/src/merge_driver.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_merge_driver_h__
#define INCLUDE_merge_driver_h__
+#include "common.h"
+
#include "git2/merge.h"
#include "git2/index.h"
#include "git2/sys/merge.h"
diff --git a/src/merge_file.c b/src/merge_file.c
index 3f14a4f63..a54d6bd57 100644
--- a/src/merge_file.c
+++ b/src/merge_file.c
@@ -6,6 +6,7 @@
*/
#include "common.h"
+
#include "repository.h"
#include "posix.h"
#include "fileops.h"
@@ -127,7 +128,7 @@ static int merge_file__xdiff(
if ((xdl_result = xdl_merge(&ancestor_mmfile, &our_mmfile,
&their_mmfile, &xmparam, &mmbuffer)) < 0) {
- giterr_set(GITERR_MERGE, "Failed to merge files.");
+ giterr_set(GITERR_MERGE, "failed to merge files");
error = -1;
goto done;
}
diff --git a/src/message.h b/src/message.h
index 3c4b8dc45..88fc7884c 100644
--- a/src/message.h
+++ b/src/message.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_message_h__
#define INCLUDE_message_h__
+#include "common.h"
+
#include "git2/message.h"
#include "buffer.h"
diff --git a/src/mwindow.c b/src/mwindow.c
index 8a5b5caee..38d0352b4 100644
--- a/src/mwindow.c
+++ b/src/mwindow.c
@@ -5,8 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
#include "mwindow.h"
+
#include "vector.h"
#include "fileops.h"
#include "map.h"
@@ -14,8 +14,6 @@
#include "strmap.h"
#include "pack.h"
-GIT__USE_STRMAP
-
#define DEFAULT_WINDOW_SIZE \
(sizeof(void*) >= 8 \
? 1 * 1024 * 1024 * 1024 \
@@ -84,7 +82,7 @@ int git_mwindow_get_pack(struct git_pack_file **out, const char *path)
git_atomic_inc(&pack->refcount);
- git_strmap_insert(git__pack_cache, pack->pack_name, pack, error);
+ git_strmap_insert(git__pack_cache, pack->pack_name, pack, &error);
git_mutex_unlock(&git__mwindow_mutex);
if (error < 0) {
@@ -231,7 +229,7 @@ static int git_mwindow_close_lru(git_mwindow_file *mwf)
}
if (!lru_w) {
- giterr_set(GITERR_OS, "Failed to close memory window. Couldn't find LRU");
+ giterr_set(GITERR_OS, "failed to close memory window; couldn't find LRU");
return -1;
}
diff --git a/src/mwindow.h b/src/mwindow.h
index bdde9e0a4..ea962d1b6 100644
--- a/src/mwindow.h
+++ b/src/mwindow.h
@@ -8,6 +8,8 @@
#ifndef INCLUDE_mwindow__
#define INCLUDE_mwindow__
+#include "common.h"
+
#include "map.h"
#include "vector.h"
diff --git a/src/netops.c b/src/netops.c
index 90326ea59..68f404d2c 100644
--- a/src/netops.c
+++ b/src/netops.c
@@ -5,11 +5,11 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "netops.h"
+
#include <ctype.h>
#include "git2/errors.h"
-#include "common.h"
-#include "netops.h"
#include "posix.h"
#include "buffer.h"
#include "http_parser.h"
@@ -144,7 +144,7 @@ int gitno_connection_data_from_url(
default_port = "80";
if (data->use_ssl) {
- giterr_set(GITERR_NET, "Redirect from HTTPS to HTTP is not allowed");
+ giterr_set(GITERR_NET, "redirect from HTTPS to HTTP is not allowed");
goto cleanup;
}
} else if (!git__prefixcmp(url, prefix_https)) {
@@ -155,7 +155,7 @@ int gitno_connection_data_from_url(
default_port = data->use_ssl ? "443" : "80";
if (!default_port) {
- giterr_set(GITERR_NET, "Unrecognized URL prefix");
+ giterr_set(GITERR_NET, "unrecognized URL prefix");
goto cleanup;
}
@@ -187,7 +187,7 @@ int gitno_connection_data_from_url(
/* Check for errors in the resulting data */
if (original_host && url[0] != '/' && strcmp(original_host, data->host)) {
- giterr_set(GITERR_NET, "Cross host redirect not allowed");
+ giterr_set(GITERR_NET, "cross host redirect not allowed");
error = -1;
}
}
@@ -237,7 +237,7 @@ int gitno_extract_url_parts(
const char *_host, *_port, *_path, *_userinfo;
if (http_parser_parse_url(url, strlen(url), false, &u)) {
- giterr_set(GITERR_NET, "Malformed URL '%s'", url);
+ giterr_set(GITERR_NET, "malformed URL '%s'", url);
return GIT_EINVALIDSPEC;
}
diff --git a/src/netops.h b/src/netops.h
index b7170a0f2..75fd9a512 100644
--- a/src/netops.h
+++ b/src/netops.h
@@ -7,8 +7,9 @@
#ifndef INCLUDE_netops_h__
#define INCLUDE_netops_h__
-#include "posix.h"
#include "common.h"
+
+#include "posix.h"
#include "stream.h"
#ifdef GIT_OPENSSL
diff --git a/src/notes.c b/src/notes.c
index fe8d2164f..75108b9c9 100644
--- a/src/notes.c
+++ b/src/notes.c
@@ -15,7 +15,7 @@
static int note_error_notfound(void)
{
- giterr_set(GITERR_INVALID, "Note could not be found");
+ giterr_set(GITERR_INVALID, "note could not be found");
return GIT_ENOTFOUND;
}
@@ -226,7 +226,7 @@ static int remove_note_in_tree_enotfound_cb(
GIT_UNUSED(note_oid);
GIT_UNUSED(fanout);
- giterr_set(GITERR_REPOSITORY, "Object '%s' has no note", annotated_object_sha);
+ giterr_set(GITERR_REPOSITORY, "object '%s' has no note", annotated_object_sha);
return current_error;
}
@@ -244,7 +244,7 @@ static int insert_note_in_tree_eexists_cb(git_tree **out,
GIT_UNUSED(note_oid);
GIT_UNUSED(fanout);
- giterr_set(GITERR_REPOSITORY, "Note for '%s' exists already", annotated_object_sha);
+ giterr_set(GITERR_REPOSITORY, "note for '%s' exists already", annotated_object_sha);
return current_error;
}
diff --git a/src/object.c b/src/object.c
index 1d45f9f1b..4d069a34c 100644
--- a/src/object.c
+++ b/src/object.c
@@ -4,9 +4,11 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
+
+#include "object.h"
+
#include "git2/object.h"
-#include "common.h"
#include "repository.h"
#include "commit.h"
@@ -66,12 +68,12 @@ int git_object__from_odb_object(
/* Validate type match */
if (type != GIT_OBJ_ANY && type != odb_obj->cached.type) {
giterr_set(GITERR_INVALID,
- "The requested type does not match the type in the ODB");
+ "the requested type does not match the type in the ODB");
return GIT_ENOTFOUND;
}
if ((object_size = git_object__size(odb_obj->cached.type)) == 0) {
- giterr_set(GITERR_INVALID, "The requested type is invalid");
+ giterr_set(GITERR_INVALID, "the requested type is invalid");
return GIT_ENOTFOUND;
}
@@ -122,7 +124,7 @@ int git_object_lookup_prefix(
assert(repo && object_out && id);
if (len < GIT_OID_MINPREFIXLEN) {
- giterr_set(GITERR_OBJECT, "Ambiguous lookup - OID prefix is too short");
+ giterr_set(GITERR_OBJECT, "ambiguous lookup - OID prefix is too short");
return GIT_EAMBIGUOUS;
}
@@ -147,7 +149,7 @@ int git_object_lookup_prefix(
if (type != GIT_OBJ_ANY && type != object->cached.type) {
git_object_free(object);
giterr_set(GITERR_INVALID,
- "The requested type does not match the type in ODB");
+ "the requested type does not match the type in ODB");
return GIT_ENOTFOUND;
}
@@ -292,7 +294,7 @@ static int peel_error(int error, const git_oid *oid, git_otype type)
git_oid_fmt(hex_oid, oid);
hex_oid[GIT_OID_HEXSZ] = '\0';
- giterr_set(GITERR_OBJECT, "The git_object of id '%s' can not be "
+ giterr_set(GITERR_OBJECT, "the git_object of id '%s' can not be "
"successfully peeled into a %s (git_otype=%i).", hex_oid, type_name, type);
return error;
diff --git a/src/object.h b/src/object.h
index dd227d16d..ff61c1d33 100644
--- a/src/object.h
+++ b/src/object.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_object_h__
#define INCLUDE_object_h__
+#include "common.h"
+
#include "repository.h"
extern bool git_object__strict_input_validation;
diff --git a/src/object_api.c b/src/object_api.c
index e0d8760e7..75efa4d10 100644
--- a/src/object_api.c
+++ b/src/object_api.c
@@ -4,11 +4,12 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "git2/object.h"
#include "common.h"
-#include "repository.h"
+#include "git2/object.h"
+
+#include "repository.h"
#include "commit.h"
#include "tree.h"
#include "blob.h"
diff --git a/src/odb.c b/src/odb.c
index acf4dea71..7da391bff 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -5,13 +5,13 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+#include "odb.h"
+
#include <zlib.h>
#include "git2/object.h"
#include "git2/sys/odb_backend.h"
#include "fileops.h"
#include "hash.h"
-#include "odb.h"
#include "delta.h"
#include "filter.h"
#include "repository.h"
@@ -31,6 +31,8 @@
#define GIT_ALTERNATES_MAX_DEPTH 5
+bool git_odb__strict_hash_verification = true;
+
typedef struct
{
git_odb_backend *backend;
@@ -176,7 +178,7 @@ int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_otype type)
int error = 0;
if (!git_object_typeisloose(type)) {
- giterr_set(GITERR_INVALID, "Invalid object type for hash");
+ giterr_set(GITERR_INVALID, "invalid object type for hash");
return -1;
}
@@ -199,7 +201,7 @@ int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_otype type)
* If size is not zero, the file was truncated after we originally
* stat'd it, so we consider this a read failure too */
if (read_len < 0 || size > 0) {
- giterr_set(GITERR_OS, "Error reading file for hashing");
+ giterr_set(GITERR_OS, "error reading file for hashing");
error = -1;
goto done;
@@ -251,7 +253,7 @@ int git_odb__hashlink(git_oid *out, const char *path)
return -1;
if (!git__is_int(st.st_size) || (int)st.st_size < 0) {
- giterr_set(GITERR_FILESYSTEM, "File size overflow for 32-bit systems");
+ giterr_set(GITERR_FILESYSTEM, "file size overflow for 32-bit systems");
return -1;
}
@@ -269,7 +271,7 @@ int git_odb__hashlink(git_oid *out, const char *path)
read_len = p_readlink(path, link_data, size);
link_data[size] = '\0';
if (read_len != size) {
- giterr_set(GITERR_OS, "Failed to read symlink data for '%s'", path);
+ giterr_set(GITERR_OS, "failed to read symlink data for '%s'", path);
git__free(link_data);
return -1;
}
@@ -295,7 +297,7 @@ int git_odb_hashfile(git_oid *out, const char *path, git_otype type)
return fd;
if ((size = git_futils_filesize(fd)) < 0 || !git__is_sizet(size)) {
- giterr_set(GITERR_OS, "File size overflow for 32-bit systems");
+ giterr_set(GITERR_OS, "file size overflow for 32-bit systems");
p_close(fd);
return -1;
}
@@ -475,7 +477,7 @@ size_t git_odb_num_backends(git_odb *odb)
static int git_odb__error_unsupported_in_backend(const char *action)
{
giterr_set(GITERR_ODB,
- "Cannot %s - unsupported in the loaded odb backends", action);
+ "cannot %s - unsupported in the loaded odb backends", action);
return -1;
}
@@ -492,11 +494,11 @@ int git_odb_get_backend(git_odb_backend **out, git_odb *odb, size_t pos)
return 0;
}
- giterr_set(GITERR_ODB, "No ODB backend loaded at index %" PRIuZ, pos);
+ giterr_set(GITERR_ODB, "no ODB backend loaded at index %" PRIuZ, pos);
return GIT_ENOTFOUND;
}
-static int add_default_backends(
+int git_odb__add_default_backends(
git_odb *db, const char *objects_dir,
bool as_alternates, int alternate_depth)
{
@@ -517,7 +519,7 @@ static int add_default_backends(
if (as_alternates)
return 0;
- giterr_set(GITERR_ODB, "Failed to load object database in '%s'", objects_dir);
+ giterr_set(GITERR_ODB, "failed to load object database in '%s'", objects_dir);
return -1;
}
@@ -531,7 +533,7 @@ static int add_default_backends(
#endif
/* add the loose object backend */
- if (git_odb_backend_loose(&loose, objects_dir, -1, 0, 0, 0) < 0 ||
+ if (git_odb_backend_loose(&loose, objects_dir, -1, db->do_fsync, 0, 0) < 0 ||
add_backend_internal(db, loose, GIT_LOOSE_PRIORITY, as_alternates, inode) < 0)
return -1;
@@ -586,7 +588,7 @@ static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_
alternate = git_buf_cstr(&alternates_path);
}
- if ((result = add_default_backends(odb, alternate, true, alternate_depth + 1)) < 0)
+ if ((result = git_odb__add_default_backends(odb, alternate, true, alternate_depth + 1)) < 0)
break;
}
@@ -598,7 +600,7 @@ static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_
int git_odb_add_disk_alternate(git_odb *odb, const char *path)
{
- return add_default_backends(odb, path, true, 0);
+ return git_odb__add_default_backends(odb, path, true, 0);
}
int git_odb_open(git_odb **out, const char *objects_dir)
@@ -612,7 +614,7 @@ int git_odb_open(git_odb **out, const char *objects_dir)
if (git_odb_new(&db) < 0)
return -1;
- if (add_default_backends(db, objects_dir, 0, 0) < 0) {
+ if (git_odb__add_default_backends(db, objects_dir, 0, 0) < 0) {
git_odb_free(db);
return -1;
}
@@ -621,6 +623,24 @@ int git_odb_open(git_odb **out, const char *objects_dir)
return 0;
}
+int git_odb__set_caps(git_odb *odb, int caps)
+{
+ if (caps == GIT_ODB_CAP_FROM_OWNER) {
+ git_repository *repo = odb->rc.owner;
+ int val;
+
+ if (!repo) {
+ giterr_set(GITERR_ODB, "cannot access repository to set odb caps");
+ return -1;
+ }
+
+ if (!git_repository__cvar(&val, repo, GIT_CVAR_FSYNCOBJECTFILES))
+ odb->do_fsync = !!val;
+ }
+
+ return 0;
+}
+
static void odb_free(git_odb *db)
{
size_t i;
@@ -695,7 +715,7 @@ static int odb_freshen_1(
return (int)found;
}
-static int odb_freshen(git_odb *db, const git_oid *id)
+int git_odb__freshen(git_odb *db, const git_oid *id)
{
assert(db && id);
@@ -980,7 +1000,9 @@ static int odb_read_1(git_odb_object **out, git_odb *db, const git_oid *id,
size_t i;
git_rawobj raw;
git_odb_object *object;
+ git_oid hashed;
bool found = false;
+ int error = 0;
if (!only_refreshed && odb_read_hardcoded(&raw, id) == 0)
found = true;
@@ -993,7 +1015,7 @@ static int odb_read_1(git_odb_object **out, git_odb *db, const git_oid *id,
continue;
if (b->read != NULL) {
- int error = b->read(&raw.data, &raw.len, &raw.type, b, id);
+ error = b->read(&raw.data, &raw.len, &raw.type, b, id);
if (error == GIT_PASSTHROUGH || error == GIT_ENOTFOUND)
continue;
@@ -1007,12 +1029,26 @@ static int odb_read_1(git_odb_object **out, git_odb *db, const git_oid *id,
if (!found)
return GIT_ENOTFOUND;
+ if (git_odb__strict_hash_verification) {
+ if ((error = git_odb_hash(&hashed, raw.data, raw.len, raw.type)) < 0)
+ goto out;
+
+ if (!git_oid_equal(id, &hashed)) {
+ error = git_odb__error_mismatch(id, &hashed);
+ goto out;
+ }
+ }
+
giterr_clear();
if ((object = odb_object__alloc(id, &raw)) == NULL)
- return -1;
+ goto out;
*out = git_cache_store_raw(odb_cache(db), object);
- return 0;
+
+out:
+ if (error)
+ git__free(raw.data);
+ return error;
}
int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
@@ -1063,9 +1099,9 @@ static int read_prefix_1(git_odb_object **out, git_odb *db,
const git_oid *key, size_t len, bool only_refreshed)
{
size_t i;
- int error = GIT_ENOTFOUND;
+ int error = 0;
git_oid found_full_oid = {{0}};
- git_rawobj raw;
+ git_rawobj raw = {0};
void *data = NULL;
bool found = false;
git_odb_object *object;
@@ -1080,18 +1116,29 @@ static int read_prefix_1(git_odb_object **out, git_odb *db,
if (b->read_prefix != NULL) {
git_oid full_oid;
error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, key, len);
- if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH)
+
+ if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH) {
+ error = 0;
continue;
+ }
if (error)
- return error;
+ goto out;
git__free(data);
data = raw.data;
if (found && git_oid__cmp(&full_oid, &found_full_oid)) {
- git__free(raw.data);
- return git_odb__error_ambiguous("multiple matches for prefix");
+ git_buf buf = GIT_BUF_INIT;
+
+ git_buf_printf(&buf, "multiple matches for prefix: %s",
+ git_oid_tostr_s(&full_oid));
+ git_buf_printf(&buf, " %s",
+ git_oid_tostr_s(&found_full_oid));
+
+ error = git_odb__error_ambiguous(buf.ptr);
+ git_buf_free(&buf);
+ goto out;
}
found_full_oid = full_oid;
@@ -1102,11 +1149,28 @@ static int read_prefix_1(git_odb_object **out, git_odb *db,
if (!found)
return GIT_ENOTFOUND;
+ if (git_odb__strict_hash_verification) {
+ git_oid hash;
+
+ if ((error = git_odb_hash(&hash, raw.data, raw.len, raw.type)) < 0)
+ goto out;
+
+ if (!git_oid_equal(&found_full_oid, &hash)) {
+ error = git_odb__error_mismatch(&found_full_oid, &hash);
+ goto out;
+ }
+ }
+
if ((object = odb_object__alloc(&found_full_oid, &raw)) == NULL)
- return -1;
+ goto out;
*out = git_cache_store_raw(odb_cache(db), object);
- return 0;
+
+out:
+ if (error)
+ git__free(raw.data);
+
+ return error;
}
int git_odb_read_prefix(
@@ -1167,7 +1231,7 @@ int git_odb_write(
assert(oid && db);
git_odb_hash(oid, data, len, type);
- if (odb_freshen(db, oid))
+ if (git_odb__freshen(db, oid))
return 0;
for (i = 0; i < db->backends.length && error < 0; ++i) {
@@ -1264,10 +1328,10 @@ static int git_odb_stream__invalid_length(
const char *action)
{
giterr_set(GITERR_ODB,
- "Cannot %s - "
- "Invalid length. %"PRIuZ" was expected. The "
- "total size of the received chunks amounts to %"PRIuZ".",
- action, stream->declared_size, stream->received_bytes);
+ "cannot %s - "
+ "Invalid length. %"PRIdZ" was expected. The "
+ "total size of the received chunks amounts to %"PRIdZ".",
+ action, stream->declared_size, stream->received_bytes);
return -1;
}
@@ -1293,7 +1357,7 @@ int git_odb_stream_finalize_write(git_oid *out, git_odb_stream *stream)
git_hash_final(out, stream->hash_ctx);
- if (odb_freshen(stream->backend->odb, out))
+ if (git_odb__freshen(stream->backend->odb, out))
return 0;
return stream->finalize_write(stream, out);
@@ -1393,23 +1457,36 @@ int git_odb_refresh(struct git_odb *db)
return 0;
}
+int git_odb__error_mismatch(const git_oid *expected, const git_oid *actual)
+{
+ char expected_oid[GIT_OID_HEXSZ + 1], actual_oid[GIT_OID_HEXSZ + 1];
+
+ git_oid_tostr(expected_oid, sizeof(expected_oid), expected);
+ git_oid_tostr(actual_oid, sizeof(actual_oid), actual);
+
+ giterr_set(GITERR_ODB, "object hash mismatch - expected %s but got %s",
+ expected_oid, actual_oid);
+
+ return GIT_EMISMATCH;
+}
+
int git_odb__error_notfound(
const char *message, const git_oid *oid, size_t oid_len)
{
if (oid != NULL) {
char oid_str[GIT_OID_HEXSZ + 1];
git_oid_tostr(oid_str, oid_len+1, oid);
- giterr_set(GITERR_ODB, "Object not found - %s (%.*s)",
- message, oid_len, oid_str);
+ giterr_set(GITERR_ODB, "object not found - %s (%.*s)",
+ message, (int) oid_len, oid_str);
} else
- giterr_set(GITERR_ODB, "Object not found - %s", message);
+ giterr_set(GITERR_ODB, "object not found - %s", message);
return GIT_ENOTFOUND;
}
int git_odb__error_ambiguous(const char *message)
{
- giterr_set(GITERR_ODB, "Ambiguous SHA1 prefix - %s", message);
+ giterr_set(GITERR_ODB, "ambiguous SHA1 prefix - %s", message);
return GIT_EAMBIGUOUS;
}
diff --git a/src/odb.h b/src/odb.h
index 31a9fd1b9..6845b22f1 100644
--- a/src/odb.h
+++ b/src/odb.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_odb_h__
#define INCLUDE_odb_h__
+#include "common.h"
+
#include "git2/odb.h"
#include "git2/oid.h"
#include "git2/types.h"
@@ -20,6 +22,8 @@
#define GIT_OBJECT_DIR_MODE 0777
#define GIT_OBJECT_FILE_MODE 0444
+extern bool git_odb__strict_hash_verification;
+
/* DO NOT EXPORT */
typedef struct {
void *data; /**< Raw, decompressed object data. */
@@ -38,8 +42,25 @@ struct git_odb {
git_refcount rc;
git_vector backends;
git_cache own_cache;
+ unsigned int do_fsync :1;
};
+typedef enum {
+ GIT_ODB_CAP_FROM_OWNER = -1,
+} git_odb_cap_t;
+
+/*
+ * Set the capabilities for the object database.
+ */
+int git_odb__set_caps(git_odb *odb, int caps);
+
+/*
+ * Add the default loose and packed backends for a database.
+ */
+int git_odb__add_default_backends(
+ git_odb *db, const char *objects_dir,
+ bool as_alternates, int alternate_depth);
+
/*
* Hash a git_rawobj internally.
* The `git_rawobj` is supposed to be previously initialized
@@ -79,6 +100,12 @@ int git_odb__hashfd_filtered(
*/
int git_odb__hashlink(git_oid *out, const char *path);
+/**
+ * Generate a GIT_EMISMATCH error for the ODB.
+ */
+int git_odb__error_mismatch(
+ const git_oid *expected, const git_oid *actual);
+
/*
* Generate a GIT_ENOTFOUND error for the ODB.
*/
@@ -98,6 +125,9 @@ int git_odb__read_header_or_object(
git_odb_object **out, size_t *len_p, git_otype *type_p,
git_odb *db, const git_oid *id);
+/* freshen an entry in the object database */
+int git_odb__freshen(git_odb *db, const git_oid *id);
+
/* fully free the object; internal method, DO NOT EXPORT */
void git_odb_object__free(void *object);
diff --git a/src/odb_loose.c b/src/odb_loose.c
index f312b9c9c..72b47f091 100644
--- a/src/odb_loose.c
+++ b/src/odb_loose.c
@@ -6,6 +6,7 @@
*/
#include "common.h"
+
#include <zlib.h>
#include "git2/object.h"
#include "git2/sys/odb_backend.h"
@@ -14,6 +15,7 @@
#include "odb.h"
#include "delta.h"
#include "filebuf.h"
+#include "object.h"
#include "git2/odb_backend.h"
#include "git2/types.h"
@@ -204,6 +206,11 @@ static int start_inflate(z_stream *s, git_buf *obj, void *out, size_t len)
return inflate(s, 0);
}
+static void abort_inflate(z_stream *s)
+{
+ inflateEnd(s);
+}
+
static int finish_inflate(z_stream *s)
{
int status = Z_OK;
@@ -214,7 +221,7 @@ static int finish_inflate(z_stream *s)
inflateEnd(s);
if ((status != Z_STREAM_END) || (s->avail_in != 0)) {
- giterr_set(GITERR_ZLIB, "Failed to finish ZLib inflation. Stream aborted prematurely");
+ giterr_set(GITERR_ZLIB, "failed to finish zlib inflation; stream aborted prematurely");
return -1;
}
@@ -243,7 +250,7 @@ static int inflate_buffer(void *in, size_t inlen, void *out, size_t outlen)
zs.avail_in = (uInt)inlen;
if (inflateInit(&zs) < Z_OK) {
- giterr_set(GITERR_ZLIB, "Failed to inflate buffer");
+ giterr_set(GITERR_ZLIB, "failed to inflate buffer");
return -1;
}
@@ -255,7 +262,7 @@ static int inflate_buffer(void *in, size_t inlen, void *out, size_t outlen)
if (status != Z_STREAM_END /* || zs.avail_in != 0 */ ||
zs.total_out != outlen)
{
- giterr_set(GITERR_ZLIB, "Failed to inflate buffer. Stream aborted prematurely");
+ giterr_set(GITERR_ZLIB, "failed to inflate buffer; stream aborted prematurely");
return -1;
}
@@ -319,7 +326,7 @@ static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_buf *obj)
*/
if ((used = get_binary_object_header(&hdr, obj)) == 0 ||
!git_object_typeisloose(hdr.type)) {
- giterr_set(GITERR_ODB, "Failed to inflate loose object.");
+ giterr_set(GITERR_ODB, "failed to inflate loose object");
return -1;
}
@@ -366,7 +373,8 @@ static int inflate_disk_obj(git_rawobj *out, git_buf *obj)
(used = get_object_header(&hdr, head)) == 0 ||
!git_object_typeisloose(hdr.type))
{
- giterr_set(GITERR_ODB, "Failed to inflate disk object.");
+ abort_inflate(&zs);
+ giterr_set(GITERR_ODB, "failed to inflate disk object");
return -1;
}
@@ -455,7 +463,7 @@ static int read_header_loose(git_rawobj *out, git_buf *loc)
|| get_object_header(&header_obj, inflated_buffer) == 0
|| git_object_typeisloose(header_obj.type) == 0)
{
- giterr_set(GITERR_ZLIB, "Failed to read loose object header");
+ giterr_set(GITERR_ZLIB, "failed to read loose object header");
error = -1;
} else {
out->len = header_obj.size;
@@ -838,6 +846,17 @@ static void loose_backend__stream_free(git_odb_stream *_stream)
git__free(stream);
}
+static int filebuf_flags(loose_backend *backend)
+{
+ int flags = GIT_FILEBUF_TEMPORARY |
+ (backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT);
+
+ if (backend->fsync_object_files || git_repository__fsync_gitdir)
+ flags |= GIT_FILEBUF_FSYNC;
+
+ return flags;
+}
+
static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_backend, git_off_t length, git_otype type)
{
loose_backend *backend;
@@ -864,9 +883,7 @@ static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_
stream->stream.mode = GIT_STREAM_WRONLY;
if (git_buf_joinpath(&tmp_path, backend->objects_dir, "tmp_object") < 0 ||
- git_filebuf_open(&stream->fbuf, tmp_path.ptr,
- GIT_FILEBUF_TEMPORARY |
- (backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT),
+ git_filebuf_open(&stream->fbuf, tmp_path.ptr, filebuf_flags(backend),
backend->object_file_mode) < 0 ||
stream->stream.write((git_odb_stream *)stream, hdr, hdrlen) < 0)
{
@@ -894,9 +911,7 @@ static int loose_backend__write(git_odb_backend *_backend, const git_oid *oid, c
header_len = git_odb__format_object_header(header, sizeof(header), len, type);
if (git_buf_joinpath(&final_path, backend->objects_dir, "tmp_object") < 0 ||
- git_filebuf_open(&fbuf, final_path.ptr,
- GIT_FILEBUF_TEMPORARY |
- (backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT),
+ git_filebuf_open(&fbuf, final_path.ptr, filebuf_flags(backend),
backend->object_file_mode) < 0)
{
error = -1;
diff --git a/src/odb_mempack.c b/src/odb_mempack.c
index 594a2784c..0c05f0566 100644
--- a/src/odb_mempack.c
+++ b/src/odb_mempack.c
@@ -6,6 +6,7 @@
*/
#include "common.h"
+
#include "git2/object.h"
#include "git2/sys/odb_backend.h"
#include "fileops.h"
@@ -18,13 +19,11 @@
#include "git2/types.h"
#include "git2/pack.h"
-GIT__USE_OIDMAP
-
struct memobject {
git_oid oid;
size_t len;
git_otype type;
- char data[];
+ char data[GIT_FLEX_ARRAY];
};
struct memory_packer_db {
@@ -41,7 +40,7 @@ static int impl__write(git_odb_backend *_backend, const git_oid *oid, const void
size_t alloc_len;
int rval;
- pos = kh_put(oid, db->objects, oid, &rval);
+ pos = git_oidmap_put(db->objects, oid, &rval);
if (rval < 0)
return -1;
@@ -57,8 +56,8 @@ static int impl__write(git_odb_backend *_backend, const git_oid *oid, const void
obj->len = len;
obj->type = type;
- kh_key(db->objects, pos) = &obj->oid;
- kh_val(db->objects, pos) = obj;
+ git_oidmap_set_key_at(db->objects, pos, &obj->oid);
+ git_oidmap_set_value_at(db->objects, pos, obj);
if (type == GIT_OBJ_COMMIT) {
struct memobject **store = git_array_alloc(db->commits);
@@ -72,13 +71,8 @@ static int impl__write(git_odb_backend *_backend, const git_oid *oid, const void
static int impl__exists(git_odb_backend *backend, const git_oid *oid)
{
struct memory_packer_db *db = (struct memory_packer_db *)backend;
- khiter_t pos;
- pos = kh_get(oid, db->objects, oid);
- if (pos != kh_end(db->objects))
- return 1;
-
- return 0;
+ return git_oidmap_exists(db->objects, oid);
}
static int impl__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
@@ -87,11 +81,11 @@ static int impl__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb
struct memobject *obj = NULL;
khiter_t pos;
- pos = kh_get(oid, db->objects, oid);
- if (pos == kh_end(db->objects))
+ pos = git_oidmap_lookup_index(db->objects, oid);
+ if (!git_oidmap_valid_index(db->objects, pos))
return GIT_ENOTFOUND;
- obj = kh_val(db->objects, pos);
+ obj = git_oidmap_value_at(db->objects, pos);
*len_p = obj->len;
*type_p = obj->type;
@@ -108,11 +102,11 @@ static int impl__read_header(size_t *len_p, git_otype *type_p, git_odb_backend *
struct memobject *obj = NULL;
khiter_t pos;
- pos = kh_get(oid, db->objects, oid);
- if (pos == kh_end(db->objects))
+ pos = git_oidmap_lookup_index(db->objects, oid);
+ if (!git_oidmap_valid_index(db->objects, pos))
return GIT_ENOTFOUND;
- obj = kh_val(db->objects, pos);
+ obj = git_oidmap_value_at(db->objects, pos);
*len_p = obj->len;
*type_p = obj->type;
@@ -149,7 +143,7 @@ void git_mempack_reset(git_odb_backend *_backend)
struct memory_packer_db *db = (struct memory_packer_db *)_backend;
struct memobject *object = NULL;
- kh_foreach_value(db->objects, object, {
+ git_oidmap_foreach_value(db->objects, object, {
git__free(object);
});
@@ -177,6 +171,7 @@ int git_mempack_new(git_odb_backend **out)
db->objects = git_oidmap_alloc();
+ db->parent.version = GIT_ODB_BACKEND_VERSION;
db->parent.read = &impl__read;
db->parent.write = &impl__write;
db->parent.read_header = &impl__read_header;
diff --git a/src/odb_pack.c b/src/odb_pack.c
index b80d0337a..20aff5386 100644
--- a/src/odb_pack.c
+++ b/src/odb_pack.c
@@ -6,6 +6,7 @@
*/
#include "common.h"
+
#include <zlib.h>
#include "git2/repository.h"
#include "git2/indexer.h"
@@ -428,7 +429,7 @@ static int pack_backend__read_prefix(
git_oid_cpy(out_oid, short_oid);
} else {
struct git_pack_entry e;
- git_rawobj raw;
+ git_rawobj raw = {NULL};
if ((error = pack_entry_find_prefix(
&e, (struct pack_backend *)backend, short_oid, len)) == 0 &&
diff --git a/src/offmap.c b/src/offmap.c
new file mode 100644
index 000000000..ab6649697
--- /dev/null
+++ b/src/offmap.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "offmap.h"
+
+__KHASH_IMPL(off, static kh_inline, git_off_t, void *, 1, kh_int64_hash_func, kh_int64_hash_equal)
+
+git_offmap *git_offmap_alloc(void)
+{
+ return kh_init(off);
+}
+
+void git_offmap_free(git_offmap *map)
+{
+ kh_destroy(off, map);
+}
+
+void git_offmap_clear(git_offmap *map)
+{
+ kh_clear(off, map);
+}
+
+size_t git_offmap_num_entries(git_offmap *map)
+{
+ return kh_size(map);
+}
+
+size_t git_offmap_lookup_index(git_offmap *map, const git_off_t key)
+{
+ return kh_get(off, map, key);
+}
+
+int git_offmap_valid_index(git_offmap *map, size_t idx)
+{
+ return idx != kh_end(map);
+}
+
+int git_offmap_exists(git_offmap *map, const git_off_t key)
+{
+ return kh_get(off, map, key) != kh_end(map);
+}
+
+void *git_offmap_value_at(git_offmap *map, size_t idx)
+{
+ return kh_val(map, idx);
+}
+
+void git_offmap_set_value_at(git_offmap *map, size_t idx, void *value)
+{
+ kh_val(map, idx) = value;
+}
+
+void git_offmap_delete_at(git_offmap *map, size_t idx)
+{
+ kh_del(off, map, idx);
+}
+
+int git_offmap_put(git_offmap *map, const git_off_t key, int *err)
+{
+ return kh_put(off, map, key, err);
+}
+
+void git_offmap_insert(git_offmap *map, const git_off_t key, void *value, int *rval)
+{
+ khiter_t idx = kh_put(off, map, key, rval);
+
+ if ((*rval) >= 0) {
+ if ((*rval) == 0)
+ kh_key(map, idx) = key;
+ kh_val(map, idx) = value;
+ }
+}
+
+void git_offmap_delete(git_offmap *map, const git_off_t key)
+{
+ khiter_t idx = git_offmap_lookup_index(map, key);
+ if (git_offmap_valid_index(map, idx))
+ git_offmap_delete_at(map, idx);
+}
diff --git a/src/offmap.h b/src/offmap.h
index 0d0e51272..0b0896b8f 100644
--- a/src/offmap.h
+++ b/src/offmap.h
@@ -8,6 +8,7 @@
#define INCLUDE_offmap_h__
#include "common.h"
+
#include "git2/types.h"
#define kmalloc git__malloc
@@ -20,45 +21,24 @@
__KHASH_TYPE(off, git_off_t, void *)
typedef khash_t(off) git_offmap;
-#define GIT__USE_OFFMAP \
- __KHASH_IMPL(off, static kh_inline, git_off_t, void *, 1, kh_int64_hash_func, kh_int64_hash_equal)
-
-#define git_offmap_alloc() kh_init(off)
-#define git_offmap_free(h) kh_destroy(off, h), h = NULL
-#define git_offmap_clear(h) kh_clear(off, h)
-
-#define git_offmap_num_entries(h) kh_size(h)
-
-#define git_offmap_lookup_index(h, k) kh_get(off, h, k)
-#define git_offmap_valid_index(h, idx) (idx != kh_end(h))
+git_offmap *git_offmap_alloc(void);
+void git_offmap_free(git_offmap *map);
+void git_offmap_clear(git_offmap *map);
-#define git_offmap_exists(h, k) (kh_get(off, h, k) != kh_end(h))
+size_t git_offmap_num_entries(git_offmap *map);
-#define git_offmap_value_at(h, idx) kh_val(h, idx)
-#define git_offmap_set_value_at(h, idx, v) kh_val(h, idx) = v
-#define git_offmap_delete_at(h, idx) kh_del(off, h, idx)
+size_t git_offmap_lookup_index(git_offmap *map, const git_off_t key);
+int git_offmap_valid_index(git_offmap *map, size_t idx);
-#define git_offmap_insert(h, key, val, rval) do { \
- khiter_t __pos = kh_put(off, h, key, &rval); \
- if (rval >= 0) { \
- if (rval == 0) kh_key(h, __pos) = key; \
- kh_val(h, __pos) = val; \
- } } while (0)
+int git_offmap_exists(git_offmap *map, const git_off_t key);
-#define git_offmap_insert2(h, key, val, oldv, rval) do { \
- khiter_t __pos = kh_put(off, h, key, &rval); \
- if (rval >= 0) { \
- if (rval == 0) { \
- oldv = kh_val(h, __pos); \
- kh_key(h, __pos) = key; \
- } else { oldv = NULL; } \
- kh_val(h, __pos) = val; \
- } } while (0)
+void *git_offmap_value_at(git_offmap *map, size_t idx);
+void git_offmap_set_value_at(git_offmap *map, size_t idx, void *value);
+void git_offmap_delete_at(git_offmap *map, size_t idx);
-#define git_offmap_delete(h, key) do { \
- khiter_t __pos = git_offmap_lookup_index(h, key); \
- if (git_offmap_valid_index(h, __pos)) \
- git_offmap_delete_at(h, __pos); } while (0)
+int git_offmap_put(git_offmap *map, const git_off_t key, int *err);
+void git_offmap_insert(git_offmap *map, const git_off_t key, void *value, int *rval);
+void git_offmap_delete(git_offmap *map, const git_off_t key);
#define git_offmap_foreach kh_foreach
#define git_offmap_foreach_value kh_foreach_value
diff --git a/src/oid.c b/src/oid.c
index 9fe2ebb65..0c63abb2e 100644
--- a/src/oid.c
+++ b/src/oid.c
@@ -5,7 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+#include "oid.h"
+
#include "git2/oid.h"
#include "repository.h"
#include "global.h"
@@ -16,7 +17,7 @@ static char to_hex[] = "0123456789abcdef";
static int oid_error_invalid(const char *msg)
{
- giterr_set(GITERR_INVALID, "Unable to parse OID - %s", msg);
+ giterr_set(GITERR_INVALID, "unable to parse OID - %s", msg);
return -1;
}
@@ -380,7 +381,7 @@ int git_oid_shorten_add(git_oid_shorten *os, const char *text_oid)
node_index idx;
if (os->full) {
- giterr_set(GITERR_INVALID, "Unable to shorten OID - OID set full");
+ giterr_set(GITERR_INVALID, "unable to shorten OID - OID set full");
return -1;
}
@@ -395,7 +396,7 @@ int git_oid_shorten_add(git_oid_shorten *os, const char *text_oid)
trie_node *node;
if (c == -1) {
- giterr_set(GITERR_INVALID, "Unable to shorten OID - invalid hex value");
+ giterr_set(GITERR_INVALID, "unable to shorten OID - invalid hex value");
return -1;
}
@@ -410,7 +411,7 @@ int git_oid_shorten_add(git_oid_shorten *os, const char *text_oid)
node = push_leaf(os, idx, git__fromhex(tail[0]), &tail[1]);
if (node == NULL) {
if (os->full)
- giterr_set(GITERR_INVALID, "Unable to shorten OID - OID set full");
+ giterr_set(GITERR_INVALID, "unable to shorten OID - OID set full");
return -1;
}
}
@@ -418,7 +419,7 @@ int git_oid_shorten_add(git_oid_shorten *os, const char *text_oid)
if (node->children[c] == 0) {
if (push_leaf(os, idx, c, &text_oid[i + 1]) == NULL) {
if (os->full)
- giterr_set(GITERR_INVALID, "Unable to shorten OID - OID set full");
+ giterr_set(GITERR_INVALID, "unable to shorten OID - OID set full");
return -1;
}
break;
diff --git a/src/oid.h b/src/oid.h
index 922a2a347..84231ffca 100644
--- a/src/oid.h
+++ b/src/oid.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_oid_h__
#define INCLUDE_oid_h__
+#include "common.h"
+
#include "git2/oid.h"
/**
@@ -22,14 +24,7 @@ char *git_oid_allocfmt(const git_oid *id);
GIT_INLINE(int) git_oid__hashcmp(const unsigned char *sha1, const unsigned char *sha2)
{
- int i;
-
- for (i = 0; i < GIT_OID_RAWSZ; i++, sha1++, sha2++) {
- if (*sha1 != *sha2)
- return *sha1 - *sha2;
- }
-
- return 0;
+ return memcmp(sha1, sha2, GIT_OID_RAWSZ);
}
/*
diff --git a/src/oidarray.c b/src/oidarray.c
index 1d51a2958..fda3b638d 100644
--- a/src/oidarray.c
+++ b/src/oidarray.c
@@ -5,8 +5,9 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "git2/oidarray.h"
#include "oidarray.h"
+
+#include "git2/oidarray.h"
#include "array.h"
void git_oidarray_free(git_oidarray *arr)
diff --git a/src/oidarray.h b/src/oidarray.h
index a7215ae6c..f051a0ec4 100644
--- a/src/oidarray.h
+++ b/src/oidarray.h
@@ -8,6 +8,7 @@
#define INCLUDE_oidarray_h__
#include "common.h"
+
#include "git2/oidarray.h"
#include "array.h"
diff --git a/src/oidmap.c b/src/oidmap.c
new file mode 100644
index 000000000..5f156a18e
--- /dev/null
+++ b/src/oidmap.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "oidmap.h"
+
+GIT_INLINE(khint_t) git_oidmap_hash(const git_oid *oid)
+{
+ khint_t h;
+ memcpy(&h, oid, sizeof(khint_t));
+ return h;
+}
+
+__KHASH_IMPL(oid, static kh_inline, const git_oid *, void *, 1, git_oidmap_hash, git_oid_equal)
+
+git_oidmap *git_oidmap_alloc()
+{
+ return kh_init(oid);
+}
+
+void git_oidmap_free(git_oidmap *map)
+{
+ kh_destroy(oid, map);
+}
+
+void git_oidmap_clear(git_oidmap *map)
+{
+ kh_clear(oid, map);
+}
+
+size_t git_oidmap_size(git_oidmap *map)
+{
+ return kh_size(map);
+}
+
+size_t git_oidmap_lookup_index(git_oidmap *map, const git_oid *key)
+{
+ return kh_get(oid, map, key);
+}
+
+int git_oidmap_valid_index(git_oidmap *map, size_t idx)
+{
+ return idx != kh_end(map);
+}
+
+int git_oidmap_exists(git_oidmap *map, const git_oid *key)
+{
+ return kh_get(oid, map, key) != kh_end(map);
+}
+
+int git_oidmap_has_data(git_oidmap *map, size_t idx)
+{
+ return kh_exist(map, idx);
+}
+
+const git_oid *git_oidmap_key(git_oidmap *map, size_t idx)
+{
+ return kh_key(map, idx);
+}
+
+void git_oidmap_set_key_at(git_oidmap *map, size_t idx, git_oid *key)
+{
+ kh_key(map, idx) = key;
+}
+
+void *git_oidmap_value_at(git_oidmap *map, size_t idx)
+{
+ return kh_val(map, idx);
+}
+
+void git_oidmap_set_value_at(git_oidmap *map, size_t idx, void *value)
+{
+ kh_val(map, idx) = value;
+}
+
+void git_oidmap_delete_at(git_oidmap *map, size_t idx)
+{
+ kh_del(oid, map, idx);
+}
+
+int git_oidmap_put(git_oidmap *map, const git_oid *key, int *err)
+{
+ return kh_put(oid, map, key, err);
+}
+
+void git_oidmap_insert(git_oidmap *map, const git_oid *key, void *value, int *rval)
+{
+ khiter_t idx = kh_put(oid, map, key, rval);
+
+ if ((*rval) >= 0) {
+ if ((*rval) == 0)
+ kh_key(map, idx) = key;
+ kh_val(map, idx) = value;
+ }
+}
+
+void git_oidmap_delete(git_oidmap *map, const git_oid *key)
+{
+ khiter_t idx = git_oidmap_lookup_index(map, key);
+ if (git_oidmap_valid_index(map, idx))
+ git_oidmap_delete_at(map, idx);
+}
diff --git a/src/oidmap.h b/src/oidmap.h
index 2cf208f53..49f129e93 100644
--- a/src/oidmap.h
+++ b/src/oidmap.h
@@ -8,6 +8,7 @@
#define INCLUDE_oidmap_h__
#include "common.h"
+
#include "git2/oid.h"
#define kmalloc git__malloc
@@ -20,35 +21,31 @@
__KHASH_TYPE(oid, const git_oid *, void *)
typedef khash_t(oid) git_oidmap;
-GIT_INLINE(khint_t) git_oidmap_hash(const git_oid *oid)
-{
- khint_t h;
- memcpy(&h, oid, sizeof(khint_t));
- return h;
-}
+git_oidmap *git_oidmap_alloc(void);
+void git_oidmap_free(git_oidmap *map);
+void git_oidmap_clear(git_oidmap *map);
-#define GIT__USE_OIDMAP \
- __KHASH_IMPL(oid, static kh_inline, const git_oid *, void *, 1, git_oidmap_hash, git_oid_equal)
+size_t git_oidmap_size(git_oidmap *map);
-#define git_oidmap_alloc() kh_init(oid)
-#define git_oidmap_free(h) kh_destroy(oid,h), h = NULL
+size_t git_oidmap_lookup_index(git_oidmap *map, const git_oid *key);
+int git_oidmap_valid_index(git_oidmap *map, size_t idx);
-#define git_oidmap_lookup_index(h, k) kh_get(oid, h, k)
-#define git_oidmap_valid_index(h, idx) (idx != kh_end(h))
+int git_oidmap_exists(git_oidmap *map, const git_oid *key);
+int git_oidmap_has_data(git_oidmap *map, size_t idx);
-#define git_oidmap_value_at(h, idx) kh_val(h, idx)
+const git_oid *git_oidmap_key(git_oidmap *map, size_t idx);
+void git_oidmap_set_key_at(git_oidmap *map, size_t idx, git_oid *key);
+void *git_oidmap_value_at(git_oidmap *map, size_t idx);
+void git_oidmap_set_value_at(git_oidmap *map, size_t idx, void *value);
+void git_oidmap_delete_at(git_oidmap *map, size_t idx);
-#define git_oidmap_insert(h, key, val, rval) do { \
- khiter_t __pos = kh_put(oid, h, key, &rval); \
- if (rval >= 0) { \
- if (rval == 0) kh_key(h, __pos) = key; \
- kh_val(h, __pos) = val; \
- } } while (0)
+int git_oidmap_put(git_oidmap *map, const git_oid *key, int *err);
+void git_oidmap_insert(git_oidmap *map, const git_oid *key, void *value, int *rval);
+void git_oidmap_delete(git_oidmap *map, const git_oid *key);
#define git_oidmap_foreach_value kh_foreach_value
-#define git_oidmap_size(h) kh_size(h)
-
-#define git_oidmap_clear(h) kh_clear(oid, h)
+#define git_oidmap_begin kh_begin
+#define git_oidmap_end kh_end
#endif
diff --git a/src/openssl_stream.c b/src/openssl_stream.c
index b8ab21fef..3860c4f3c 100644
--- a/src/openssl_stream.c
+++ b/src/openssl_stream.c
@@ -5,6 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "openssl_stream.h"
+
#ifdef GIT_OPENSSL
#include <ctype.h>
@@ -36,7 +38,7 @@ SSL_CTX *git__ssl_ctx;
#define GIT_SSL_DEFAULT_CIPHERS "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES128-SHA256:DHE-DSS-AES256-SHA256:DHE-DSS-AES128-SHA:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA"
-#ifdef GIT_THREADS
+#if defined(GIT_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L
static git_mutex *openssl_locks;
@@ -65,11 +67,14 @@ static void shutdown_ssl_locking(void)
CRYPTO_set_locking_callback(NULL);
for (i = 0; i < num_locks; ++i)
- git_mutex_free(openssl_locks);
+ git_mutex_free(&openssl_locks[i]);
git__free(openssl_locks);
}
-#endif /* GIT_THREADS */
+#endif /* GIT_THREADS && OPENSSL_VERSION_NUMBER < 0x10100000L */
+
+static BIO_METHOD *git_stream_bio_method;
+static int init_bio_method(void);
/**
* This function aims to clean-up the SSL context which
@@ -77,6 +82,11 @@ static void shutdown_ssl_locking(void)
*/
static void shutdown_ssl(void)
{
+ if (git_stream_bio_method) {
+ BIO_meth_free(git_stream_bio_method);
+ git_stream_bio_method = NULL;
+ }
+
if (git__ssl_ctx) {
SSL_CTX_free(git__ssl_ctx);
git__ssl_ctx = NULL;
@@ -94,8 +104,13 @@ int git_openssl_stream_global_init(void)
ssl_opts |= SSL_OP_NO_COMPRESSION;
#endif
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
+#else
+ OPENSSL_init_ssl(0, NULL);
+#endif
+
/*
* Load SSLv{2,3} and TLSv1 so that we can talk with servers
* which use the SSL hellos, which are often used for
@@ -121,6 +136,13 @@ int git_openssl_stream_global_init(void)
git__ssl_ctx = NULL;
return -1;
}
+
+ if (init_bio_method() < 0) {
+ SSL_CTX_free(git__ssl_ctx);
+ git__ssl_ctx = NULL;
+ return -1;
+ }
+
#endif
git__on_shutdown(shutdown_ssl);
@@ -130,7 +152,7 @@ int git_openssl_stream_global_init(void)
int git_openssl_set_locking(void)
{
-#ifdef GIT_THREADS
+#if defined(GIT_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L
int num_locks, i;
num_locks = CRYPTO_num_locks();
@@ -147,8 +169,10 @@ int git_openssl_set_locking(void)
CRYPTO_set_locking_callback(openssl_locking_function);
git__on_shutdown(shutdown_ssl_locking);
return 0;
+#elif OPENSSL_VERSION_NUMBER >= 0x10100000L
+ return 0;
#else
- giterr_set(GITERR_THREAD, "libgit2 as not built with threads");
+ giterr_set(GITERR_THREAD, "libgit2 was not built with threads");
return -1;
#endif
}
@@ -156,10 +180,8 @@ int git_openssl_set_locking(void)
static int bio_create(BIO *b)
{
- b->init = 1;
- b->num = 0;
- b->ptr = NULL;
- b->flags = 0;
+ BIO_set_init(b, 1);
+ BIO_set_data(b, NULL);
return 1;
}
@@ -169,23 +191,22 @@ static int bio_destroy(BIO *b)
if (!b)
return 0;
- b->init = 0;
- b->num = 0;
- b->ptr = NULL;
- b->flags = 0;
+ BIO_set_data(b, NULL);
return 1;
}
static int bio_read(BIO *b, char *buf, int len)
{
- git_stream *io = (git_stream *) b->ptr;
+ git_stream *io = (git_stream *) BIO_get_data(b);
+
return (int) git_stream_read(io, buf, len);
}
static int bio_write(BIO *b, const char *buf, int len)
{
- git_stream *io = (git_stream *) b->ptr;
+ git_stream *io = (git_stream *) BIO_get_data(b);
+
return (int) git_stream_write(io, buf, len, 0);
}
@@ -214,17 +235,22 @@ static int bio_puts(BIO *b, const char *str)
return bio_write(b, str, strlen(str));
}
-static BIO_METHOD git_stream_bio_method = {
- BIO_TYPE_SOURCE_SINK,
- "git_stream",
- bio_write,
- bio_read,
- bio_puts,
- bio_gets,
- bio_ctrl,
- bio_create,
- bio_destroy
-};
+static int init_bio_method(void)
+{
+ /* Set up the BIO_METHOD we use for wrapping our own stream implementations */
+ git_stream_bio_method = BIO_meth_new(BIO_TYPE_SOURCE_SINK | BIO_get_new_index(), "git_stream");
+ GITERR_CHECK_ALLOC(git_stream_bio_method);
+
+ BIO_meth_set_write(git_stream_bio_method, bio_write);
+ BIO_meth_set_read(git_stream_bio_method, bio_read);
+ BIO_meth_set_puts(git_stream_bio_method, bio_puts);
+ BIO_meth_set_gets(git_stream_bio_method, bio_gets);
+ BIO_meth_set_ctrl(git_stream_bio_method, bio_ctrl);
+ BIO_meth_set_create(git_stream_bio_method, bio_create);
+ BIO_meth_set_destroy(git_stream_bio_method, bio_destroy);
+
+ return 0;
+}
static int ssl_set_error(SSL *ssl, int error)
{
@@ -239,10 +265,10 @@ static int ssl_set_error(SSL *ssl, int error)
switch (err) {
case SSL_ERROR_WANT_CONNECT:
case SSL_ERROR_WANT_ACCEPT:
- giterr_set(GITERR_NET, "SSL error: connection failure\n");
+ giterr_set(GITERR_NET, "SSL error: connection failure");
break;
case SSL_ERROR_WANT_X509_LOOKUP:
- giterr_set(GITERR_NET, "SSL error: x509 error\n");
+ giterr_set(GITERR_NET, "SSL error: x509 error");
break;
case SSL_ERROR_SYSCALL:
e = ERR_get_error();
@@ -309,7 +335,7 @@ static int verify_server_cert(SSL *ssl, const char *host)
int i = -1,j;
if (SSL_get_verify_result(ssl) != X509_V_OK) {
- giterr_set(GITERR_SSL, "The SSL certificate is invalid");
+ giterr_set(GITERR_SSL, "the SSL certificate is invalid");
return GIT_ECERTIFICATE;
}
@@ -339,7 +365,7 @@ static int verify_server_cert(SSL *ssl, const char *host)
num = sk_GENERAL_NAME_num(alts);
for (i = 0; i < num && matched != 1; i++) {
const GENERAL_NAME *gn = sk_GENERAL_NAME_value(alts, i);
- const char *name = (char *) ASN1_STRING_data(gn->d.ia5);
+ const char *name = (char *) ASN1_STRING_get0_data(gn->d.ia5);
size_t namelen = (size_t) ASN1_STRING_length(gn->d.ia5);
/* Skip any names of a type we're not looking for */
@@ -394,7 +420,7 @@ static int verify_server_cert(SSL *ssl, const char *host)
if (size > 0) {
peer_cn = OPENSSL_malloc(size + 1);
GITERR_CHECK_ALLOC(peer_cn);
- memcpy(peer_cn, ASN1_STRING_data(str), size);
+ memcpy(peer_cn, ASN1_STRING_get0_data(str), size);
peer_cn[size] = '\0';
} else {
goto cert_fail_name;
@@ -445,11 +471,12 @@ int openssl_connect(git_stream *stream)
st->connected = true;
- bio = BIO_new(&git_stream_bio_method);
+ bio = BIO_new(git_stream_bio_method);
GITERR_CHECK_ALLOC(bio);
- bio->ptr = st->io;
+ BIO_set_data(bio, st->io);
SSL_set_bio(st->ssl, bio, bio);
+
/* specify the host in case SNI is needed */
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
SSL_set_tlsext_host_name(st->ssl, st->host);
diff --git a/src/openssl_stream.h b/src/openssl_stream.h
index 82b5110c4..2dcfcc929 100644
--- a/src/openssl_stream.h
+++ b/src/openssl_stream.h
@@ -7,10 +7,118 @@
#ifndef INCLUDE_openssl_stream_h__
#define INCLUDE_openssl_stream_h__
+#include "common.h"
+
#include "git2/sys/stream.h"
extern int git_openssl_stream_global_init(void);
extern int git_openssl_stream_new(git_stream **out, const char *host, const char *port);
+/*
+ * OpenSSL 1.1 made BIO opaque so we have to use functions to interact with it
+ * which do not exist in previous versions. We define these inline functions so
+ * we can program against the interface instead of littering the implementation
+ * with ifdefs.
+ */
+#ifdef GIT_OPENSSL
+# include <openssl/ssl.h>
+# include <openssl/err.h>
+# include <openssl/x509v3.h>
+# include <openssl/bio.h>
+
+
+
+# if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+
+GIT_INLINE(BIO_METHOD*) BIO_meth_new(int type, const char *name)
+{
+ BIO_METHOD *meth = git__calloc(1, sizeof(BIO_METHOD));
+ if (!meth) {
+ return NULL;
+ }
+
+ meth->type = type;
+ meth->name = name;
+
+ return meth;
+}
+
+GIT_INLINE(void) BIO_meth_free(BIO_METHOD *biom)
+{
+ git__free(biom);
+}
+
+GIT_INLINE(int) BIO_meth_set_write(BIO_METHOD *biom, int (*write) (BIO *, const char *, int))
+{
+ biom->bwrite = write;
+ return 1;
+}
+
+GIT_INLINE(int) BIO_meth_set_read(BIO_METHOD *biom, int (*read) (BIO *, char *, int))
+{
+ biom->bread = read;
+ return 1;
+}
+
+GIT_INLINE(int) BIO_meth_set_puts(BIO_METHOD *biom, int (*puts) (BIO *, const char *))
+{
+ biom->bputs = puts;
+ return 1;
+}
+
+GIT_INLINE(int) BIO_meth_set_gets(BIO_METHOD *biom, int (*gets) (BIO *, char *, int))
+
+{
+ biom->bgets = gets;
+ return 1;
+}
+
+GIT_INLINE(int) BIO_meth_set_ctrl(BIO_METHOD *biom, long (*ctrl) (BIO *, int, long, void *))
+{
+ biom->ctrl = ctrl;
+ return 1;
+}
+
+GIT_INLINE(int) BIO_meth_set_create(BIO_METHOD *biom, int (*create) (BIO *))
+{
+ biom->create = create;
+ return 1;
+}
+
+GIT_INLINE(int) BIO_meth_set_destroy(BIO_METHOD *biom, int (*destroy) (BIO *))
+{
+ biom->destroy = destroy;
+ return 1;
+}
+
+GIT_INLINE(int) BIO_get_new_index(void)
+{
+ /* This exists as of 1.1 so before we'd just have 0 */
+ return 0;
+}
+
+GIT_INLINE(void) BIO_set_init(BIO *b, int init)
+{
+ b->init = init;
+}
+
+GIT_INLINE(void) BIO_set_data(BIO *a, void *ptr)
+{
+ a->ptr = ptr;
+}
+
+GIT_INLINE(void*) BIO_get_data(BIO *a)
+{
+ return a->ptr;
+}
+
+GIT_INLINE(const unsigned char *) ASN1_STRING_get0_data(const ASN1_STRING *x)
+{
+ return ASN1_STRING_data((ASN1_STRING *)x);
+}
+
+# endif // OpenSSL < 1.1
+#endif // GIT_OPENSSL
+
#endif
diff --git a/src/pack-objects.c b/src/pack-objects.c
index 9f62322f7..ef272e8f5 100644
--- a/src/pack-objects.c
+++ b/src/pack-objects.c
@@ -41,8 +41,6 @@ struct pack_write_context {
git_transfer_progress *stats;
};
-GIT__USE_OIDMAP
-
#ifdef GIT_THREADS
#define GIT_PACKBUILDER__MUTEX_OP(pb, mtx, op) do { \
@@ -162,7 +160,7 @@ int git_packbuilder_new(git_packbuilder **out, git_repository *repo)
git_mutex_init(&pb->progress_mutex) ||
git_cond_init(&pb->progress_cond))
{
- giterr_set(GITERR_OS, "Failed to initialize packbuilder mutex");
+ giterr_set(GITERR_OS, "failed to initialize packbuilder mutex");
goto on_error;
}
@@ -197,10 +195,10 @@ static void rehash(git_packbuilder *pb)
size_t i;
int ret;
- kh_clear(oid, pb->object_ix);
+ git_oidmap_clear(pb->object_ix);
for (i = 0, po = pb->object_list; i < pb->nr_objects; i++, po++) {
- pos = kh_put(oid, pb->object_ix, &po->id, &ret);
- kh_value(pb->object_ix, pos) = po;
+ pos = git_oidmap_put(pb->object_ix, &po->id, &ret);
+ git_oidmap_set_value_at(pb->object_ix, pos, po);
}
}
@@ -216,8 +214,7 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid,
/* If the object already exists in the hash table, then we don't
* have any work to do */
- pos = kh_get(oid, pb->object_ix, oid);
- if (pos != kh_end(pb->object_ix))
+ if (git_oidmap_exists(pb->object_ix, oid))
return 0;
if (pb->nr_objects >= pb->nr_alloc) {
@@ -225,7 +222,7 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid,
GITERR_CHECK_ALLOC_MULTIPLY(&newsize, newsize, 3 / 2);
if (!git__is_uint32(newsize)) {
- giterr_set(GITERR_NOMEMORY, "Packfile too large to fit in memory.");
+ giterr_set(GITERR_NOMEMORY, "packfile too large to fit in memory.");
return -1;
}
@@ -247,13 +244,13 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid,
git_oid_cpy(&po->id, oid);
po->hash = name_hash(name);
- pos = kh_put(oid, pb->object_ix, &po->id, &ret);
+ pos = git_oidmap_put(pb->object_ix, &po->id, &ret);
if (ret < 0) {
giterr_set_oom();
return ret;
}
assert(ret != 0);
- kh_value(pb->object_ix, pos) = po;
+ git_oidmap_set_value_at(pb->object_ix, pos, po);
pb->done = false;
@@ -298,7 +295,7 @@ static int get_delta(void **out, git_odb *odb, git_pobject *po)
goto on_error;
if (error == GIT_EBUFS || delta_size != po->delta_size) {
- giterr_set(GITERR_INVALID, "Delta size changed");
+ giterr_set(GITERR_INVALID, "delta size changed");
goto on_error;
}
@@ -517,11 +514,11 @@ static int cb_tag_foreach(const char *name, git_oid *oid, void *data)
GIT_UNUSED(name);
- pos = kh_get(oid, pb->object_ix, oid);
- if (pos == kh_end(pb->object_ix))
+ pos = git_oidmap_lookup_index(pb->object_ix, oid);
+ if (!git_oidmap_valid_index(pb->object_ix, pos))
return 0;
- po = kh_value(pb->object_ix, pos);
+ po = git_oidmap_value_at(pb->object_ix, pos);
po->tagged = 1;
/* TODO: peel objects */
@@ -808,7 +805,7 @@ static int try_delta(git_packbuilder *pb, struct unpacked *trg,
if (sz != trg_size) {
giterr_set(GITERR_INVALID,
- "Inconsistent target object length");
+ "inconsistent target object length");
return -1;
}
@@ -830,7 +827,7 @@ static int try_delta(git_packbuilder *pb, struct unpacked *trg,
if (sz != src_size) {
giterr_set(GITERR_INVALID,
- "Inconsistent source object length");
+ "inconsistent source object length");
return -1;
}
@@ -1388,6 +1385,7 @@ int git_packbuilder_write(
git_indexer *indexer;
git_transfer_progress stats;
struct pack_write_context ctx;
+ int t;
PREPARE_PACK;
@@ -1395,6 +1393,9 @@ int git_packbuilder_write(
&indexer, path, mode, pb->odb, progress_cb, progress_cb_payload) < 0)
return -1;
+ if (!git_repository__cvar(&t, pb->repo, GIT_CVAR_FSYNCOBJECTFILES) && t)
+ git_indexer__set_fsync(indexer, 1);
+
ctx.indexer = indexer;
ctx.stats = &stats;
@@ -1541,7 +1542,7 @@ static int retrieve_object(git_walk_object **out, git_packbuilder *pb, const git
if ((error = lookup_walk_object(&obj, pb, id)) < 0)
return error;
- git_oidmap_insert(pb->walk_objects, &obj->id, obj, error);
+ git_oidmap_insert(pb->walk_objects, &obj->id, obj, &error);
}
*out = obj;
@@ -1738,7 +1739,7 @@ int git_packbuilder_insert_walk(git_packbuilder *pb, git_revwalk *walk)
if (error == GIT_ITEROVER)
error = 0;
- return 0;
+ return error;
}
int git_packbuilder_set_callbacks(git_packbuilder *pb, git_packbuilder_progress progress_cb, void *progress_cb_payload)
diff --git a/src/pack-objects.h b/src/pack-objects.h
index 5a84f4158..e1e0ee3c8 100644
--- a/src/pack-objects.h
+++ b/src/pack-objects.h
@@ -16,6 +16,7 @@
#include "netops.h"
#include "zstream.h"
#include "pool.h"
+#include "indexer.h"
#include "git2/oid.h"
#include "git2/pack.h"
diff --git a/src/pack.c b/src/pack.c
index 310f00fa3..7fd95c905 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -5,9 +5,9 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
-#include "odb.h"
#include "pack.h"
+
+#include "odb.h"
#include "delta.h"
#include "sha1_lookup.h"
#include "mwindow.h"
@@ -16,9 +16,6 @@
#include <zlib.h>
-GIT__USE_OFFMAP
-GIT__USE_OIDMAP
-
static int packfile_open(struct git_pack_file *p);
static git_off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n);
static int packfile_unpack_compressed(
@@ -45,7 +42,7 @@ static int pack_entry_find_offset(
static int packfile_error(const char *message)
{
- giterr_set(GITERR_ODB, "Invalid pack file - %s", message);
+ giterr_set(GITERR_ODB, "invalid pack file - %s", message);
return -1;
}
@@ -78,13 +75,12 @@ static void free_cache_object(void *o)
static void cache_free(git_pack_cache *cache)
{
- khiter_t k;
+ git_pack_cache_entry *entry;
if (cache->entries) {
- for (k = kh_begin(cache->entries); k != kh_end(cache->entries); k++) {
- if (kh_exist(cache->entries, k))
- free_cache_object(kh_value(cache->entries, k));
- }
+ git_offmap_foreach_value(cache->entries, entry, {
+ free_cache_object(entry);
+ });
git_offmap_free(cache->entries);
cache->entries = NULL;
@@ -99,7 +95,7 @@ static int cache_init(git_pack_cache *cache)
cache->memory_limit = GIT_PACK_CACHE_MEMORY_LIMIT;
if (git_mutex_init(&cache->lock)) {
- giterr_set(GITERR_OS, "Failed to initialize pack cache mutex");
+ giterr_set(GITERR_OS, "failed to initialize pack cache mutex");
git__free(cache->entries);
cache->entries = NULL;
@@ -118,9 +114,9 @@ static git_pack_cache_entry *cache_get(git_pack_cache *cache, git_off_t offset)
if (git_mutex_lock(&cache->lock) < 0)
return NULL;
- k = kh_get(off, cache->entries, offset);
- if (k != kh_end(cache->entries)) { /* found it */
- entry = kh_value(cache->entries, k);
+ k = git_offmap_lookup_index(cache->entries, offset);
+ if (git_offmap_valid_index(cache->entries, k)) { /* found it */
+ entry = git_offmap_value_at(cache->entries, k);
git_atomic_inc(&entry->refcount);
entry->last_usage = cache->use_ctr++;
}
@@ -132,21 +128,16 @@ static git_pack_cache_entry *cache_get(git_pack_cache *cache, git_off_t offset)
/* Run with the cache lock held */
static void free_lowest_entry(git_pack_cache *cache)
{
+ git_off_t offset;
git_pack_cache_entry *entry;
- khiter_t k;
-
- for (k = kh_begin(cache->entries); k != kh_end(cache->entries); k++) {
- if (!kh_exist(cache->entries, k))
- continue;
-
- entry = kh_value(cache->entries, k);
+ git_offmap_foreach(cache->entries, offset, entry, {
if (entry && entry->refcount.val == 0) {
cache->memory_used -= entry->raw.len;
- kh_del(off, cache->entries, k);
+ git_offmap_delete(cache->entries, offset);
free_cache_object(entry);
}
- }
+ });
}
static int cache_add(
@@ -170,14 +161,14 @@ static int cache_add(
return -1;
}
/* Add it to the cache if nobody else has */
- exists = kh_get(off, cache->entries, offset) != kh_end(cache->entries);
+ exists = git_offmap_exists(cache->entries, offset);
if (!exists) {
while (cache->memory_used + base->len > cache->memory_limit)
free_lowest_entry(cache);
- k = kh_put(off, cache->entries, offset, &error);
+ k = git_offmap_put(cache->entries, offset, &error);
assert(error != 0);
- kh_value(cache->entries, k) = entry;
+ git_offmap_set_value_at(cache->entries, k, entry);
cache->memory_used += entry->raw.len;
*cached_out = entry;
@@ -226,7 +217,7 @@ static int pack_index_check(const char *path, struct git_pack_file *p)
if (p_fstat(fd, &st) < 0) {
p_close(fd);
- giterr_set(GITERR_OS, "Unable to stat pack index '%s'", path);
+ giterr_set(GITERR_OS, "unable to stat pack index '%s'", path);
return -1;
}
@@ -235,7 +226,7 @@ static int pack_index_check(const char *path, struct git_pack_file *p)
(idx_size = (size_t)st.st_size) < 4 * 256 + 20 + 20)
{
p_close(fd);
- giterr_set(GITERR_ODB, "Invalid pack index '%s'", path);
+ giterr_set(GITERR_ODB, "invalid pack index '%s'", path);
return -1;
}
@@ -321,7 +312,7 @@ static int pack_index_open(struct git_pack_file *p)
{
int error = 0;
size_t name_len;
- git_buf idx_name = GIT_BUF_INIT;
+ git_buf idx_name;
if (p->index_version > -1)
return 0;
@@ -329,11 +320,13 @@ static int pack_index_open(struct git_pack_file *p)
name_len = strlen(p->pack_name);
assert(name_len > strlen(".pack")); /* checked by git_pack_file alloc */
- git_buf_grow(&idx_name, name_len);
+ if (git_buf_init(&idx_name, name_len) < 0)
+ return -1;
+
git_buf_put(&idx_name, p->pack_name, name_len - strlen(".pack"));
git_buf_puts(&idx_name, ".idx");
if (git_buf_oom(&idx_name)) {
- giterr_set_oom();
+ git_buf_free(&idx_name);
return -1;
}
@@ -509,8 +502,10 @@ int git_packfile_resolve_header(
git_packfile_stream_free(&stream);
if (error < 0)
return error;
- } else
+ } else {
*size_p = size;
+ base_offset = 0;
+ }
while (type == GIT_OBJ_OFS_DELTA || type == GIT_OBJ_REF_DELTA) {
curpos = base_offset;
@@ -757,8 +752,11 @@ int git_packfile_unpack(
}
cleanup:
- if (error < 0)
+ if (error < 0) {
git__free(obj->data);
+ if (cached)
+ git_atomic_dec(&cached->refcount);
+ }
if (elem)
*obj_offset = curpos;
@@ -957,10 +955,10 @@ git_off_t get_delta_base(
git_oid oid;
git_oid_fromraw(&oid, base_info);
- k = kh_get(oid, p->idx_cache, &oid);
- if (k != kh_end(p->idx_cache)) {
+ k = git_oidmap_lookup_index(p->idx_cache, &oid);
+ if (git_oidmap_valid_index(p->idx_cache, k)) {
*curpos += 20;
- return ((struct git_pack_entry *)kh_value(p->idx_cache, k))->offset;
+ return ((struct git_pack_entry *)git_oidmap_value_at(p->idx_cache, k))->offset;
} else {
/* If we're building an index, don't try to find the pack
* entry; we just haven't seen it yet. We'll make
@@ -986,6 +984,18 @@ git_off_t get_delta_base(
*
***********************************************************/
+void git_packfile_close(struct git_pack_file *p, bool unlink_packfile)
+{
+ if (p->mwf.fd >= 0) {
+ git_mwindow_free_all_locked(&p->mwf);
+ p_close(p->mwf.fd);
+ p->mwf.fd = -1;
+ }
+
+ if (unlink_packfile)
+ p_unlink(p->pack_name);
+}
+
void git_packfile_free(struct git_pack_file *p)
{
if (!p)
@@ -993,10 +1003,7 @@ void git_packfile_free(struct git_pack_file *p)
cache_free(&p->bases);
- if (p->mwf.fd >= 0) {
- git_mwindow_free_all_locked(&p->mwf);
- p_close(p->mwf.fd);
- }
+ git_packfile_close(p, false);
pack_index_free(p);
@@ -1077,7 +1084,7 @@ static int packfile_open(struct git_pack_file *p)
return 0;
cleanup:
- giterr_set(GITERR_OS, "Invalid packfile '%s'", p->pack_name);
+ giterr_set(GITERR_OS, "invalid packfile '%s'", p->pack_name);
if (p->mwf.fd >= 0)
p_close(p->mwf.fd);
@@ -1153,7 +1160,7 @@ int git_packfile_alloc(struct git_pack_file **pack_out, const char *path)
p->index_version = -1;
if (git_mutex_init(&p->lock)) {
- giterr_set(GITERR_OS, "Failed to initialize packfile mutex");
+ giterr_set(GITERR_OS, "failed to initialize packfile mutex");
git__free(p);
return -1;
}
@@ -1268,8 +1275,8 @@ static int pack_entry_find_offset(
const git_oid *short_oid,
size_t len)
{
- const uint32_t *level1_ofs = p->index_map.data;
- const unsigned char *index = p->index_map.data;
+ const uint32_t *level1_ofs;
+ const unsigned char *index;
unsigned hi, lo, stride;
int pos, found = 0;
git_off_t offset;
@@ -1283,11 +1290,11 @@ static int pack_entry_find_offset(
if ((error = pack_index_open(p)) < 0)
return error;
assert(p->index_map.data);
-
- index = p->index_map.data;
- level1_ofs = p->index_map.data;
}
+ index = p->index_map.data;
+ level1_ofs = p->index_map.data;
+
if (p->index_version > 1) {
level1_ofs += 2;
index += 8;
@@ -1309,11 +1316,7 @@ static int pack_entry_find_offset(
short_oid->id[0], short_oid->id[1], short_oid->id[2], lo, hi, p->num_objects);
#endif
-#ifdef GIT_USE_LOOKUP
- pos = sha1_entry_pos(index, stride, 0, lo, hi, p->num_objects, short_oid->id);
-#else
pos = sha1_position(index, stride, lo, hi, short_oid->id);
-#endif
if (pos >= 0) {
/* An object matching exactly the oid was found */
diff --git a/src/pack.h b/src/pack.h
index 5302db5b7..c0ca74f14 100644
--- a/src/pack.h
+++ b/src/pack.h
@@ -8,11 +8,12 @@
#ifndef INCLUDE_pack_h__
#define INCLUDE_pack_h__
+#include "common.h"
+
#include <zlib.h>
#include "git2/oid.h"
-#include "common.h"
#include "map.h"
#include "mwindow.h"
#include "odb.h"
@@ -149,6 +150,7 @@ git_off_t get_delta_base(struct git_pack_file *p, git_mwindow **w_curs,
git_off_t *curpos, git_otype type,
git_off_t delta_obj_offset);
+void git_packfile_close(struct git_pack_file *p, bool unlink_packfile);
void git_packfile_free(struct git_pack_file *p);
int git_packfile_alloc(struct git_pack_file **pack_out, const char *path);
diff --git a/src/patch.c b/src/patch.c
index 9b7c9c64c..5e329518d 100644
--- a/src/patch.c
+++ b/src/patch.c
@@ -1,7 +1,14 @@
-#include "git2/patch.h"
-#include "diff.h"
+/*
+* Copyright (C) the libgit2 contributors. All rights reserved.
+*
+* This file is part of libgit2, distributed under the GNU GPL v2 with
+* a Linking Exception. For full terms see the included COPYING file.
+*/
+
#include "patch.h"
+#include "git2/patch.h"
+#include "diff.h"
int git_patch__invoke_callbacks(
git_patch *patch,
diff --git a/src/patch.h b/src/patch.h
index 525ae7007..156d1310e 100644
--- a/src/patch.h
+++ b/src/patch.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_patch_h__
#define INCLUDE_patch_h__
+#include "common.h"
+
#include "git2/patch.h"
#include "array.h"
diff --git a/src/patch_generate.c b/src/patch_generate.c
index a13f2ff5d..3995c56be 100644
--- a/src/patch_generate.c
+++ b/src/patch_generate.c
@@ -4,13 +4,14 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+
+#include "patch_generate.h"
+
#include "git2/blob.h"
#include "diff.h"
#include "diff_generate.h"
#include "diff_file.h"
#include "diff_driver.h"
-#include "patch_generate.h"
#include "diff_xdiff.h"
#include "delta.h"
#include "zstream.h"
@@ -206,35 +207,14 @@ static int patch_generated_load(git_patch_generated *patch, git_patch_generated_
((patch->nfile.flags & GIT_DIFF_FLAG__NO_DATA) != 0 ||
(patch->nfile.file->flags & GIT_DIFF_FLAG_VALID_ID) != 0));
- /* always try to load workdir content first because filtering may
- * need 2x data size and this minimizes peak memory footprint
- */
- if (patch->ofile.src == GIT_ITERATOR_TYPE_WORKDIR) {
- if ((error = git_diff_file_content__load(
- &patch->ofile, &patch->base.diff_opts)) < 0 ||
- should_skip_binary(patch, patch->ofile.file))
- goto cleanup;
- }
- if (patch->nfile.src == GIT_ITERATOR_TYPE_WORKDIR) {
- if ((error = git_diff_file_content__load(
- &patch->nfile, &patch->base.diff_opts)) < 0 ||
- should_skip_binary(patch, patch->nfile.file))
- goto cleanup;
- }
-
- /* once workdir has been tried, load other data as needed */
- if (patch->ofile.src != GIT_ITERATOR_TYPE_WORKDIR) {
- if ((error = git_diff_file_content__load(
- &patch->ofile, &patch->base.diff_opts)) < 0 ||
- should_skip_binary(patch, patch->ofile.file))
- goto cleanup;
- }
- if (patch->nfile.src != GIT_ITERATOR_TYPE_WORKDIR) {
- if ((error = git_diff_file_content__load(
- &patch->nfile, &patch->base.diff_opts)) < 0 ||
- should_skip_binary(patch, patch->nfile.file))
- goto cleanup;
- }
+ if ((error = git_diff_file_content__load(
+ &patch->ofile, &patch->base.diff_opts)) < 0 ||
+ should_skip_binary(patch, patch->ofile.file))
+ goto cleanup;
+ if ((error = git_diff_file_content__load(
+ &patch->nfile, &patch->base.diff_opts)) < 0 ||
+ should_skip_binary(patch, patch->nfile.file))
+ goto cleanup;
/* if previously missing an oid, and now that we have it the two sides
* are the same (and not submodules), update MODIFIED -> UNMODIFIED
@@ -284,7 +264,7 @@ static int create_binary(
size_t b_datalen)
{
git_buf deflate = GIT_BUF_INIT, delta = GIT_BUF_INIT;
- size_t delta_data_len;
+ size_t delta_data_len = 0;
int error;
/* The git_delta function accepts unsigned long only */
@@ -417,58 +397,10 @@ static int diff_required(git_diff *diff, const char *action)
{
if (diff)
return 0;
- giterr_set(GITERR_INVALID, "Must provide valid diff to %s", action);
+ giterr_set(GITERR_INVALID, "must provide valid diff to %s", action);
return -1;
}
-int git_diff_foreach(
- git_diff *diff,
- git_diff_file_cb file_cb,
- git_diff_binary_cb binary_cb,
- git_diff_hunk_cb hunk_cb,
- git_diff_line_cb data_cb,
- void *payload)
-{
- int error = 0;
- git_xdiff_output xo;
- size_t idx;
- git_patch_generated patch;
-
- if ((error = diff_required(diff, "git_diff_foreach")) < 0)
- return error;
-
- memset(&xo, 0, sizeof(xo));
- memset(&patch, 0, sizeof(patch));
- diff_output_init(
- &xo.output, &diff->opts, file_cb, binary_cb, hunk_cb, data_cb, payload);
- git_xdiff_init(&xo, &diff->opts);
-
- git_vector_foreach(&diff->deltas, idx, patch.base.delta) {
-
- /* check flags against patch status */
- if (git_diff_delta__should_skip(&diff->opts, patch.base.delta))
- continue;
-
- if (binary_cb || hunk_cb || data_cb) {
- if ((error = patch_generated_init(&patch, diff, idx)) != 0 ||
- (error = patch_generated_load(&patch, &xo.output)) != 0)
- return error;
- }
-
- if ((error = patch_generated_invoke_file_callback(&patch, &xo.output)) == 0) {
- if (binary_cb || hunk_cb || data_cb)
- error = patch_generated_create(&patch, &xo.output);
- }
-
- git_patch_free(&patch.base);
-
- if (error)
- break;
- }
-
- return error;
-}
-
typedef struct {
git_patch_generated patch;
git_diff_delta delta;
@@ -710,7 +642,7 @@ int git_patch_from_blob_and_buffer(
git_patch **out,
const git_blob *old_blob,
const char *old_path,
- const char *buf,
+ const void *buf,
size_t buflen,
const char *buf_path,
const git_diff_options *opts)
@@ -749,7 +681,7 @@ int git_patch_from_buffers(
const void *old_buf,
size_t old_len,
const char *old_path,
- const char *new_buf,
+ const void *new_buf,
size_t new_len,
const char *new_path,
const git_diff_options *opts)
@@ -776,7 +708,7 @@ int git_patch_generated_from_diff(
delta = git_vector_get(&diff->deltas, idx);
if (!delta) {
- giterr_set(GITERR_INVALID, "Index out of range for delta in diff");
+ giterr_set(GITERR_INVALID, "index out of range for delta in diff");
return GIT_ENOTFOUND;
}
diff --git a/src/patch_generate.h b/src/patch_generate.h
index 2e89b5c4d..20f78cbfa 100644
--- a/src/patch_generate.h
+++ b/src/patch_generate.h
@@ -8,6 +8,7 @@
#define INCLUDE_patch_generate_h__
#include "common.h"
+
#include "diff.h"
#include "diff_file.h"
#include "patch.h"
diff --git a/src/patch_parse.c b/src/patch_parse.c
index 5ee09ee27..a531eec4d 100644
--- a/src/patch_parse.c
+++ b/src/patch_parse.c
@@ -4,9 +4,11 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
+
+#include "patch_parse.h"
+
#include "git2/patch.h"
#include "patch.h"
-#include "patch_parse.h"
#include "diff_parse.h"
#include "path.h"
@@ -176,7 +178,7 @@ static int parse_header_mode(uint16_t *mode, git_patch_parse_ctx *ctx)
int ret;
if (ctx->line_len < 1 || !git__isdigit(ctx->line[0]))
- return parse_err("invalid file mode at line %d", ctx->line_num);
+ return parse_err("invalid file mode at line %"PRIuZ, ctx->line_num);
if ((ret = git__strntol32(&m, ctx->line, ctx->line_len, &end, 8)) < 0)
return ret;
@@ -205,7 +207,7 @@ static int parse_header_oid(
if (len < GIT_OID_MINPREFIXLEN || len > GIT_OID_HEXSZ ||
git_oid_fromstrn(oid, ctx->line, len) < 0)
- return parse_err("invalid hex formatted object id at line %d",
+ return parse_err("invalid hex formatted object id at line %"PRIuZ,
ctx->line_num);
parse_advance_chars(ctx, len);
@@ -350,7 +352,7 @@ static int parse_header_similarity(
git_patch_parsed *patch, git_patch_parse_ctx *ctx)
{
if (parse_header_percent(&patch->base.delta->similarity, ctx) < 0)
- return parse_err("invalid similarity percentage at line %d",
+ return parse_err("invalid similarity percentage at line %"PRIuZ,
ctx->line_num);
return 0;
@@ -362,7 +364,7 @@ static int parse_header_dissimilarity(
uint16_t dissimilarity;
if (parse_header_percent(&dissimilarity, ctx) < 0)
- return parse_err("invalid similarity percentage at line %d",
+ return parse_err("invalid similarity percentage at line %"PRIuZ,
ctx->line_num);
patch->base.delta->similarity = 100 - dissimilarity;
@@ -406,15 +408,15 @@ static int parse_header_git(
/* Parse the diff --git line */
if (parse_advance_expected_str(ctx, "diff --git ") < 0)
- return parse_err("corrupt git diff header at line %d", ctx->line_num);
+ return parse_err("corrupt git diff header at line %"PRIuZ, ctx->line_num);
if (parse_header_path(&patch->header_old_path, ctx) < 0)
- return parse_err("corrupt old path in git diff header at line %d",
+ return parse_err("corrupt old path in git diff header at line %"PRIuZ,
ctx->line_num);
if (parse_advance_ws(ctx) < 0 ||
parse_header_path(&patch->header_new_path, ctx) < 0)
- return parse_err("corrupt new path in git diff header at line %d",
+ return parse_err("corrupt new path in git diff header at line %"PRIuZ,
ctx->line_num);
/* Parse remaining header lines */
@@ -444,10 +446,10 @@ static int parse_header_git(
goto done;
parse_advance_ws(ctx);
- parse_advance_expected_str(ctx, "\n");
- if (ctx->line_len > 0) {
- error = parse_err("trailing data at line %d", ctx->line_num);
+ if (parse_advance_expected_str(ctx, "\n") < 0 ||
+ ctx->line_len > 0) {
+ error = parse_err("trailing data at line %"PRIuZ, ctx->line_num);
goto done;
}
@@ -456,7 +458,7 @@ static int parse_header_git(
}
if (!found) {
- error = parse_err("invalid patch header at line %d",
+ error = parse_err("invalid patch header at line %"PRIuZ,
ctx->line_num);
goto done;
}
@@ -536,7 +538,7 @@ static int parse_hunk_header(
hunk->hunk.header_len = ctx->line - header_start;
if (hunk->hunk.header_len > (GIT_DIFF_HUNK_HEADER_SIZE - 1))
- return parse_err("oversized patch hunk header at line %d",
+ return parse_err("oversized patch hunk header at line %"PRIuZ,
ctx->line_num);
memcpy(hunk->hunk.header, header_start, hunk->hunk.header_len);
@@ -545,7 +547,7 @@ static int parse_hunk_header(
return 0;
fail:
- giterr_set(GITERR_PATCH, "invalid patch hunk header at line %d",
+ giterr_set(GITERR_PATCH, "invalid patch hunk header at line %"PRIuZ,
ctx->line_num);
return -1;
}
@@ -562,15 +564,16 @@ static int parse_hunk_body(
int newlines = hunk->hunk.new_lines;
for (;
- ctx->remain_len > 4 && (oldlines || newlines) &&
- memcmp(ctx->line, "@@ -", 4) != 0;
+ ctx->remain_len > 1 &&
+ (oldlines || newlines) &&
+ (ctx->remain_len <= 4 || memcmp(ctx->line, "@@ -", 4) != 0);
parse_advance_line(ctx)) {
int origin;
int prefix = 1;
if (ctx->line_len == 0 || ctx->line[ctx->line_len - 1] != '\n') {
- error = parse_err("invalid patch instruction at line %d",
+ error = parse_err("invalid patch instruction at line %"PRIuZ,
ctx->line_num);
goto done;
}
@@ -596,7 +599,7 @@ static int parse_hunk_body(
break;
default:
- error = parse_err("invalid patch hunk at line %d", ctx->line_num);
+ error = parse_err("invalid patch hunk at line %"PRIuZ, ctx->line_num);
goto done;
}
@@ -672,7 +675,7 @@ static int parse_patch_header(
continue;
}
- error = parse_err("invalid hunk header outside patch at line %d",
+ error = parse_err("invalid hunk header outside patch at line %"PRIuZ,
line_num);
goto done;
}
@@ -715,12 +718,12 @@ static int parse_patch_binary_side(
parse_advance_chars(ctx, 6);
} else {
error = parse_err(
- "unknown binary delta type at line %d", ctx->line_num);
+ "unknown binary delta type at line %"PRIuZ, ctx->line_num);
goto done;
}
if (parse_number(&len, ctx) < 0 || parse_advance_nl(ctx) < 0 || len < 0) {
- error = parse_err("invalid binary size at line %d", ctx->line_num);
+ error = parse_err("invalid binary size at line %"PRIuZ, ctx->line_num);
goto done;
}
@@ -736,7 +739,7 @@ static int parse_patch_binary_side(
decoded_len = c - 'a' + (('z' - 'a') + 1) + 1;
if (!decoded_len) {
- error = parse_err("invalid binary length at line %d", ctx->line_num);
+ error = parse_err("invalid binary length at line %"PRIuZ, ctx->line_num);
goto done;
}
@@ -745,7 +748,7 @@ static int parse_patch_binary_side(
encoded_len = ((decoded_len / 4) + !!(decoded_len % 4)) * 5;
if (encoded_len > ctx->line_len - 1) {
- error = parse_err("truncated binary data at line %d", ctx->line_num);
+ error = parse_err("truncated binary data at line %"PRIuZ, ctx->line_num);
goto done;
}
@@ -754,14 +757,14 @@ static int parse_patch_binary_side(
goto done;
if (decoded.size - decoded_orig != decoded_len) {
- error = parse_err("truncated binary data at line %d", ctx->line_num);
+ error = parse_err("truncated binary data at line %"PRIuZ, ctx->line_num);
goto done;
}
parse_advance_chars(ctx, encoded_len);
if (parse_advance_nl(ctx) < 0) {
- error = parse_err("trailing data at line %d", ctx->line_num);
+ error = parse_err("trailing data at line %"PRIuZ, ctx->line_num);
goto done;
}
}
@@ -785,7 +788,7 @@ static int parse_patch_binary(
if (parse_advance_expected_str(ctx, "GIT binary patch") < 0 ||
parse_advance_nl(ctx) < 0)
- return parse_err("corrupt git binary header at line %d", ctx->line_num);
+ return parse_err("corrupt git binary header at line %"PRIuZ, ctx->line_num);
/* parse old->new binary diff */
if ((error = parse_patch_binary_side(
@@ -793,7 +796,7 @@ static int parse_patch_binary(
return error;
if (parse_advance_nl(ctx) < 0)
- return parse_err("corrupt git binary separator at line %d",
+ return parse_err("corrupt git binary separator at line %"PRIuZ,
ctx->line_num);
/* parse new->old binary diff */
@@ -802,7 +805,7 @@ static int parse_patch_binary(
return error;
if (parse_advance_nl(ctx) < 0)
- return parse_err("corrupt git binary patch separator at line %d",
+ return parse_err("corrupt git binary patch separator at line %"PRIuZ,
ctx->line_num);
patch->base.binary.contains_data = 1;
@@ -820,7 +823,7 @@ static int parse_patch_binary_nodata(
parse_advance_expected_str(ctx, patch->header_new_path) < 0 ||
parse_advance_expected_str(ctx, " differ") < 0 ||
parse_advance_nl(ctx) < 0)
- return parse_err("corrupt git binary header at line %d", ctx->line_num);
+ return parse_err("corrupt git binary header at line %"PRIuZ, ctx->line_num);
patch->base.binary.contains_data = 0;
patch->base.delta->flags |= GIT_DIFF_FLAG_BINARY;
@@ -912,7 +915,7 @@ static int check_prefix(
if (remain_len || !*path)
return parse_err(
- "header filename does not contain %d path components",
+ "header filename does not contain %"PRIuZ" path components",
prefix_len);
done:
@@ -1014,8 +1017,10 @@ git_patch_parse_ctx *git_patch_parse_ctx_init(
return NULL;
if (content_len) {
- if ((ctx->content = git__malloc(content_len)) == NULL)
+ if ((ctx->content = git__malloc(content_len)) == NULL) {
+ git__free(ctx);
return NULL;
+ }
memcpy((char *)ctx->content, content, content_len);
}
diff --git a/src/patch_parse.h b/src/patch_parse.h
index 99eb4587b..f27651e39 100644
--- a/src/patch_parse.h
+++ b/src/patch_parse.h
@@ -7,6 +7,10 @@
#ifndef INCLUDE_patch_parse_h__
#define INCLUDE_patch_parse_h__
+#include "common.h"
+
+#include "patch.h"
+
typedef struct {
git_refcount rc;
diff --git a/src/path.c b/src/path.c
index e5f04a56a..ea0a3c3f6 100644
--- a/src/path.c
+++ b/src/path.c
@@ -4,8 +4,9 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+
#include "path.h"
+
#include "posix.h"
#include "repository.h"
#ifdef GIT_WIN32
@@ -111,13 +112,41 @@ Exit:
}
/*
+ * Determine if the path is a Windows prefix and, if so, returns
+ * its actual lentgh. If it is not a prefix, returns -1.
+ */
+static int win32_prefix_length(const char *path, int len)
+{
+#ifndef GIT_WIN32
+ GIT_UNUSED(path);
+ GIT_UNUSED(len);
+#else
+ /*
+ * Mimic unix behavior where '/.git' returns '/': 'C:/.git' will return
+ * 'C:/' here
+ */
+ if (len == 2 && LOOKS_LIKE_DRIVE_PREFIX(path))
+ return 2;
+
+ /*
+ * Similarly checks if we're dealing with a network computer name
+ * '//computername/.git' will return '//computername/'
+ */
+ if (looks_like_network_computer_name(path, len))
+ return len;
+#endif
+
+ return -1;
+}
+
+/*
* Based on the Android implementation, BSD licensed.
* Check http://android.git.kernel.org/
*/
int git_path_dirname_r(git_buf *buffer, const char *path)
{
const char *endp;
- int result, len;
+ int is_prefix = 0, len;
/* Empty or NULL string gets treated as "." */
if (path == NULL || *path == '\0') {
@@ -131,6 +160,11 @@ int git_path_dirname_r(git_buf *buffer, const char *path)
while (endp > path && *endp == '/')
endp--;
+ if ((len = win32_prefix_length(path, endp - path + 1)) > 0) {
+ is_prefix = 1;
+ goto Exit;
+ }
+
/* Find the start of the dir */
while (endp > path && *endp != '/')
endp--;
@@ -146,35 +180,23 @@ int git_path_dirname_r(git_buf *buffer, const char *path)
endp--;
} while (endp > path && *endp == '/');
- /* Cast is safe because max path < max int */
- len = (int)(endp - path + 1);
-
-#ifdef GIT_WIN32
- /* Mimic unix behavior where '/.git' returns '/': 'C:/.git' will return
- 'C:/' here */
-
- if (len == 2 && LOOKS_LIKE_DRIVE_PREFIX(path)) {
- len = 3;
- goto Exit;
- }
-
- /* Similarly checks if we're dealing with a network computer name
- '//computername/.git' will return '//computername/' */
-
- if (looks_like_network_computer_name(path, len)) {
- len++;
+ if ((len = win32_prefix_length(path, endp - path + 1)) > 0) {
+ is_prefix = 1;
goto Exit;
}
-#endif
+ /* Cast is safe because max path < max int */
+ len = (int)(endp - path + 1);
Exit:
- result = len;
-
- if (buffer != NULL && git_buf_set(buffer, path, len) < 0)
- return -1;
+ if (buffer) {
+ if (git_buf_set(buffer, path, len) < 0)
+ return -1;
+ if (is_prefix && git_buf_putc(buffer, '/') < 0)
+ return -1;
+ }
- return result;
+ return len;
}
@@ -341,7 +363,7 @@ int git_path_prettify(git_buf *path_out, const char *path, const char *base)
if (p_realpath(path, buf) == NULL) {
/* giterr_set resets the errno when dealing with a GITERR_OS kind of error */
int error = (errno == ENOENT || errno == ENOTDIR) ? GIT_ENOTFOUND : -1;
- giterr_set(GITERR_OS, "Failed to resolve path '%s'", path);
+ giterr_set(GITERR_OS, "failed to resolve path '%s'", path);
git_buf_clear(path_out);
@@ -632,20 +654,24 @@ int git_path_set_error(int errno_value, const char *path, const char *action)
switch (errno_value) {
case ENOENT:
case ENOTDIR:
- giterr_set(GITERR_OS, "Could not find '%s' to %s", path, action);
+ giterr_set(GITERR_OS, "could not find '%s' to %s", path, action);
return GIT_ENOTFOUND;
case EINVAL:
case ENAMETOOLONG:
- giterr_set(GITERR_OS, "Invalid path for filesystem '%s'", path);
+ giterr_set(GITERR_OS, "invalid path for filesystem '%s'", path);
return GIT_EINVALIDSPEC;
case EEXIST:
- giterr_set(GITERR_OS, "Failed %s - '%s' already exists", action, path);
+ giterr_set(GITERR_OS, "failed %s - '%s' already exists", action, path);
return GIT_EEXISTS;
+ case EACCES:
+ giterr_set(GITERR_OS, "failed %s - '%s' is locked", action, path);
+ return GIT_ELOCKED;
+
default:
- giterr_set(GITERR_OS, "Could not %s '%s'", action, path);
+ giterr_set(GITERR_OS, "could not %s '%s'", action, path);
return -1;
}
}
@@ -675,7 +701,8 @@ static bool _check_dir_contents(
return false;
/* save excursion */
- git_buf_joinpath(dir, dir->ptr, sub);
+ if (git_buf_joinpath(dir, dir->ptr, sub) < 0)
+ return false;
result = predicate(dir->ptr);
@@ -754,7 +781,7 @@ int git_path_resolve_relative(git_buf *path, size_t ceiling)
/* error out if trying to up one from a hard base */
if (to == base && ceiling != 0) {
giterr_set(GITERR_INVALID,
- "Cannot strip root component off url");
+ "cannot strip root component off url");
return -1;
}
@@ -800,8 +827,8 @@ int git_path_resolve_relative(git_buf *path, size_t ceiling)
int git_path_apply_relative(git_buf *target, const char *relpath)
{
- git_buf_joinpath(target, git_buf_cstr(target), relpath);
- return git_path_resolve_relative(target, 0);
+ return git_buf_joinpath(target, git_buf_cstr(target), relpath) ||
+ git_path_resolve_relative(target, 0);
}
int git_path_cmp(
@@ -983,7 +1010,7 @@ int git_path_iconv(git_path_iconv_t *ic, const char **in, size_t *inlen)
return 0;
fail:
- giterr_set(GITERR_OS, "Unable to convert unicode path data");
+ giterr_set(GITERR_OS, "unable to convert unicode path data");
return -1;
}
@@ -1076,7 +1103,7 @@ int git_path_direach(
wd_len = git_buf_len(path);
if ((dir = opendir(path->ptr)) == NULL) {
- giterr_set(GITERR_OS, "Failed to open directory '%s'", path->ptr);
+ giterr_set(GITERR_OS, "failed to open directory '%s'", path->ptr);
if (errno == ENOENT)
return GIT_ENOTFOUND;
@@ -1141,7 +1168,6 @@ int git_path_diriter_init(
unsigned int flags)
{
git_win32_path path_filter;
- git_buf hack = {0};
static int is_win7_or_later = -1;
if (is_win7_or_later < 0)
@@ -1158,13 +1184,13 @@ int git_path_diriter_init(
git_path_trim_slashes(&diriter->path_utf8);
if (diriter->path_utf8.size == 0) {
- giterr_set(GITERR_FILESYSTEM, "Could not open directory '%s'", path);
+ giterr_set(GITERR_FILESYSTEM, "could not open directory '%s'", path);
return -1;
}
if ((diriter->parent_len = git_win32_path_from_utf8(diriter->path, diriter->path_utf8.ptr)) < 0 ||
!git_win32__findfirstfile_filter(path_filter, diriter->path_utf8.ptr)) {
- giterr_set(GITERR_OS, "Could not parse the directory path '%s'", path);
+ giterr_set(GITERR_OS, "could not parse the directory path '%s'", path);
return -1;
}
@@ -1177,7 +1203,7 @@ int git_path_diriter_init(
is_win7_or_later ? FIND_FIRST_EX_LARGE_FETCH : 0);
if (diriter->handle == INVALID_HANDLE_VALUE) {
- giterr_set(GITERR_OS, "Could not open directory '%s'", path);
+ giterr_set(GITERR_OS, "could not open directory '%s'", path);
return -1;
}
@@ -1307,14 +1333,14 @@ int git_path_diriter_init(
git_path_trim_slashes(&diriter->path);
if (diriter->path.size == 0) {
- giterr_set(GITERR_FILESYSTEM, "Could not open directory '%s'", path);
+ giterr_set(GITERR_FILESYSTEM, "could not open directory '%s'", path);
return -1;
}
if ((diriter->dir = opendir(diriter->path.ptr)) == NULL) {
git_buf_free(&diriter->path);
- giterr_set(GITERR_OS, "Failed to open directory '%s'", path);
+ giterr_set(GITERR_OS, "failed to open directory '%s'", path);
return -1;
}
@@ -1347,7 +1373,7 @@ int git_path_diriter_next(git_path_diriter *diriter)
return GIT_ITEROVER;
giterr_set(GITERR_OS,
- "Could not read directory '%s'", diriter->path);
+ "could not read directory '%s'", diriter->path.ptr);
return -1;
}
} while (skip_dot && git_path_is_dot_or_dotdot(de->d_name));
@@ -1683,6 +1709,7 @@ GIT_INLINE(unsigned int) dotgit_flags(
unsigned int flags)
{
int protectHFS = 0, protectNTFS = 0;
+ int error = 0;
flags |= GIT_PATH_REJECT_DOT_GIT_LITERAL;
@@ -1695,13 +1722,13 @@ GIT_INLINE(unsigned int) dotgit_flags(
#endif
if (repo && !protectHFS)
- git_repository__cvar(&protectHFS, repo, GIT_CVAR_PROTECTHFS);
- if (protectHFS)
+ error = git_repository__cvar(&protectHFS, repo, GIT_CVAR_PROTECTHFS);
+ if (!error && protectHFS)
flags |= GIT_PATH_REJECT_DOT_GIT_HFS;
if (repo && !protectNTFS)
- git_repository__cvar(&protectNTFS, repo, GIT_CVAR_PROTECTNTFS);
- if (protectNTFS)
+ error = git_repository__cvar(&protectNTFS, repo, GIT_CVAR_PROTECTNTFS);
+ if (!error && protectNTFS)
flags |= GIT_PATH_REJECT_DOT_GIT_NTFS;
return flags;
diff --git a/src/path.h b/src/path.h
index fb45a6534..360372cfb 100644
--- a/src/path.h
+++ b/src/path.h
@@ -8,6 +8,7 @@
#define INCLUDE_path_h__
#include "common.h"
+
#include "posix.h"
#include "buffer.h"
#include "vector.h"
diff --git a/src/pathspec.c b/src/pathspec.c
index 361b398b8..998b6fb36 100644
--- a/src/pathspec.c
+++ b/src/pathspec.c
@@ -5,9 +5,10 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "pathspec.h"
+
#include "git2/pathspec.h"
#include "git2/diff.h"
-#include "pathspec.h"
#include "buf_text.h"
#include "attr_file.h"
#include "iterator.h"
@@ -487,7 +488,7 @@ static int pathspec_match_from_iterator(
/* if every pattern failed to match, then we have failed */
if ((flags & GIT_PATHSPEC_NO_MATCH_ERROR) != 0 && !found_files) {
- giterr_set(GITERR_INVALID, "No matching files were found");
+ giterr_set(GITERR_INVALID, "no matching files were found");
error = GIT_ENOTFOUND;
}
@@ -658,7 +659,7 @@ int git_pathspec_match_diff(
/* if every pattern failed to match, then we have failed */
if ((flags & GIT_PATHSPEC_NO_MATCH_ERROR) != 0 && !found_deltas) {
- giterr_set(GITERR_INVALID, "No matching deltas were found");
+ giterr_set(GITERR_INVALID, "no matching deltas were found");
error = GIT_ENOTFOUND;
}
diff --git a/src/pathspec.h b/src/pathspec.h
index 40cd21c3f..c4d1a83d3 100644
--- a/src/pathspec.h
+++ b/src/pathspec.h
@@ -8,7 +8,8 @@
#define INCLUDE_pathspec_h__
#include "common.h"
-#include <git2/pathspec.h>
+
+#include "git2/pathspec.h"
#include "buffer.h"
#include "vector.h"
#include "pool.h"
diff --git a/src/pool.c b/src/pool.c
index b4fc50fca..c0efe9c9d 100644
--- a/src/pool.c
+++ b/src/pool.c
@@ -1,4 +1,12 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
#include "pool.h"
+
#include "posix.h"
#ifndef GIT_WIN32
#include <unistd.h>
diff --git a/src/pool.h b/src/pool.h
index f61f16944..92ddf994a 100644
--- a/src/pool.h
+++ b/src/pool.h
@@ -8,6 +8,7 @@
#define INCLUDE_pool_h__
#include "common.h"
+
#include "vector.h"
typedef struct git_pool_page git_pool_page;
diff --git a/src/posix.c b/src/posix.c
index b3f1a1cd3..6e7985ece 100644
--- a/src/posix.c
+++ b/src/posix.c
@@ -4,12 +4,15 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+
#include "posix.h"
+
#include "path.h"
#include <stdio.h>
#include <ctype.h>
+size_t p_fsync__cnt = 0;
+
#ifndef GIT_WIN32
#ifdef NO_ADDRINFO
@@ -38,7 +41,7 @@ int p_getaddrinfo(
if (ainfo->ai_servent)
ainfo->ai_port = ainfo->ai_servent->s_port;
else
- ainfo->ai_port = atol(port);
+ ainfo->ai_port = htons(atol(port));
memcpy(&ainfo->ai_addr_in.sin_addr,
ainfo->ai_hostent->h_addr_list[0],
@@ -240,7 +243,7 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs
out->len = 0;
if ((prot & GIT_PROT_WRITE) && ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED)) {
- giterr_set(GITERR_OS, "Trying to map shared-writeable");
+ giterr_set(GITERR_OS, "trying to map shared-writeable");
return -1;
}
diff --git a/src/posix.h b/src/posix.h
index f204751cf..3e3bcb287 100644
--- a/src/posix.h
+++ b/src/posix.h
@@ -8,6 +8,7 @@
#define INCLUDE_posix_h__
#include "common.h"
+
#include <fcntl.h>
#include <time.h>
#include "fnmatch.h"
@@ -24,6 +25,10 @@
#define _S_IFLNK S_IFLNK
#endif
+#ifndef S_IWUSR
+#define S_IWUSR 00200
+#endif
+
#ifndef S_IXUSR
#define S_IXUSR 00100
#endif
@@ -111,6 +116,12 @@ extern int p_rename(const char *from, const char *to);
extern int git__page_size(size_t *page_size);
extern int git__mmap_alignment(size_t *page_size);
+/* The number of times `p_fsync` has been called. Note that this is for
+ * test code only; it it not necessarily thread-safe and should not be
+ * relied upon in production.
+ */
+extern size_t p_fsync__cnt;
+
/**
* Platform-dependent methods
*/
diff --git a/src/pqueue.c b/src/pqueue.c
index 54a60ca04..3820e999c 100644
--- a/src/pqueue.c
+++ b/src/pqueue.c
@@ -6,6 +6,7 @@
*/
#include "pqueue.h"
+
#include "util.h"
#define PQUEUE_LCHILD_OF(I) (((I)<<1)+1)
@@ -86,14 +87,15 @@ int git_pqueue_insert(git_pqueue *pq, void *item)
if ((pq->flags & GIT_PQUEUE_FIXED_SIZE) != 0 &&
pq->length >= pq->_alloc_size)
{
- /* skip this item if below min item in heap */
- if (pq->_cmp(item, git_vector_get(pq, 0)) <= 0)
+ /* skip this item if below min item in heap or if
+ * we do not have a comparison function */
+ if (!pq->_cmp || pq->_cmp(item, git_vector_get(pq, 0)) <= 0)
return 0;
/* otherwise remove the min item before inserting new */
(void)git_pqueue_pop(pq);
}
- if (!(error = git_vector_insert(pq, item)))
+ if (!(error = git_vector_insert(pq, item)) && pq->_cmp)
pqueue_up(pq, pq->length - 1);
return error;
@@ -101,9 +103,15 @@ int git_pqueue_insert(git_pqueue *pq, void *item)
void *git_pqueue_pop(git_pqueue *pq)
{
- void *rval = git_pqueue_get(pq, 0);
+ void *rval;
+
+ if (!pq->_cmp) {
+ rval = git_vector_last(pq);
+ } else {
+ rval = git_pqueue_get(pq, 0);
+ }
- if (git_pqueue_size(pq) > 1) {
+ if (git_pqueue_size(pq) > 1 && pq->_cmp) {
/* move last item to top of heap, shrink, and push item down */
pq->contents[0] = git_vector_last(pq);
git_vector_pop(pq);
diff --git a/src/pqueue.h b/src/pqueue.h
index da7b74edf..c0a6cd49e 100644
--- a/src/pqueue.h
+++ b/src/pqueue.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_pqueue_h__
#define INCLUDE_pqueue_h__
+#include "common.h"
+
#include "vector.h"
typedef git_vector git_pqueue;
@@ -35,6 +37,7 @@ extern int git_pqueue_init(
#define git_pqueue_clear git_vector_clear
#define git_pqueue_size git_vector_length
#define git_pqueue_get git_vector_get
+#define git_pqueue_reverse git_vector_reverse
/**
* Insert a new item into the queue
diff --git a/src/proxy.c b/src/proxy.c
index f53ac1151..b07371d48 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -5,7 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+#include "proxy.h"
+
#include "git2/proxy.h"
int git_proxy_init_options(git_proxy_options *opts, unsigned int version)
diff --git a/src/proxy.h b/src/proxy.h
index bf9382737..7582301c9 100644
--- a/src/proxy.h
+++ b/src/proxy.h
@@ -7,8 +7,10 @@
#ifndef INCLUDE_proxy_h__
#define INCLUDE_proxy_h__
+#include "common.h"
+
#include "git2/proxy.h"
extern int git_proxy_options_dup(git_proxy_options *tgt, const git_proxy_options *src);
-#endif \ No newline at end of file
+#endif
diff --git a/src/push.c b/src/push.c
index b4901388b..41b66df06 100644
--- a/src/push.c
+++ b/src/push.c
@@ -5,14 +5,14 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "push.h"
+
#include "git2.h"
-#include "common.h"
#include "pack.h"
#include "pack-objects.h"
#include "remote.h"
#include "vector.h"
-#include "push.h"
#include "tree.h"
static int push_spec_rref_cmp(const void *a, const void *b)
@@ -90,7 +90,7 @@ static void free_refspec(push_spec *spec)
static int check_rref(char *ref)
{
if (git__prefixcmp(ref, "refs/")) {
- giterr_set(GITERR_INVALID, "Not a valid reference '%s'", ref);
+ giterr_set(GITERR_INVALID, "not a valid reference '%s'", ref);
return -1;
}
@@ -111,7 +111,7 @@ static int check_lref(git_push *push, char *ref)
giterr_set(GITERR_REFERENCE,
"src refspec '%s' does not match any existing object", ref);
else
- giterr_set(GITERR_INVALID, "Not a valid reference '%s'", ref);
+ giterr_set(GITERR_INVALID, "not a valid reference '%s'", ref);
return -1;
}
@@ -178,6 +178,9 @@ int git_push_update_tips(git_push *push, const git_remote_callbacks *callbacks)
if (!fetch_spec)
continue;
+ /* Clear the buffer which can be dirty from previous iteration */
+ git_buf_clear(&remote_ref_name);
+
if ((error = git_refspec_transform(&remote_ref_name, fetch_spec, status->ref)) < 0)
goto on_error;
@@ -321,7 +324,7 @@ static int revwalk(git_vector *commits, git_push *push)
if (!git_odb_exists(push->repo->_odb, &spec->roid)) {
giterr_set(GITERR_REFERENCE,
- "Cannot push because a reference that you are trying to update on the remote contains commits that are not present locally.");
+ "cannot push because a reference that you are trying to update on the remote contains commits that are not present locally.");
error = GIT_ENONFASTFORWARD;
goto on_error;
}
@@ -332,7 +335,7 @@ static int revwalk(git_vector *commits, git_push *push)
if (error == GIT_ENOTFOUND ||
(!error && !git_oid_equal(&base, &spec->roid))) {
giterr_set(GITERR_REFERENCE,
- "Cannot push non-fastforwardable reference");
+ "cannot push non-fastforwardable reference");
error = GIT_ENONFASTFORWARD;
goto on_error;
}
@@ -553,7 +556,7 @@ static int calculate_work(git_push *push)
/* This is a create or update. Local ref must exist. */
if (git_reference_name_to_id(
&spec->loid, push->repo, spec->refspec.src) < 0) {
- giterr_set(GITERR_REFERENCE, "No such reference '%s'", spec->refspec.src);
+ giterr_set(GITERR_REFERENCE, "no such reference '%s'", spec->refspec.src);
return -1;
}
}
@@ -579,7 +582,7 @@ static int do_push(git_push *push, const git_remote_callbacks *callbacks)
git_transport *transport = push->remote->transport;
if (!transport->push) {
- giterr_set(GITERR_NET, "Remote transport doesn't support push");
+ giterr_set(GITERR_NET, "remote transport doesn't support push");
error = -1;
goto on_error;
}
diff --git a/src/push.h b/src/push.h
index e32ad2f4d..31ac43609 100644
--- a/src/push.h
+++ b/src/push.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_push_h__
#define INCLUDE_push_h__
+#include "common.h"
+
#include "git2.h"
#include "refspec.h"
diff --git a/src/rebase.c b/src/rebase.c
index 470e62a23..3be751254 100644
--- a/src/rebase.c
+++ b/src/rebase.c
@@ -6,6 +6,7 @@
*/
#include "common.h"
+
#include "buffer.h"
#include "repository.h"
#include "posix.h"
@@ -92,7 +93,7 @@ static int rebase_state_type(
git_buf path = GIT_BUF_INIT;
git_rebase_type_t type = GIT_REBASE_TYPE_NONE;
- if (git_buf_joinpath(&path, repo->path_repository, REBASE_APPLY_DIR) < 0)
+ if (git_buf_joinpath(&path, repo->gitdir, REBASE_APPLY_DIR) < 0)
return -1;
if (git_path_isdir(git_buf_cstr(&path))) {
@@ -101,7 +102,7 @@ static int rebase_state_type(
}
git_buf_clear(&path);
- if (git_buf_joinpath(&path, repo->path_repository, REBASE_MERGE_DIR) < 0)
+ if (git_buf_joinpath(&path, repo->gitdir, REBASE_MERGE_DIR) < 0)
return -1;
if (git_path_isdir(git_buf_cstr(&path))) {
@@ -152,7 +153,7 @@ GIT_INLINE(int) rebase_readint(
return error;
if (git__strtol32(&num, asc_out->ptr, &eol, 10) < 0 || num < 0 || *eol) {
- giterr_set(GITERR_REBASE, "The file '%s' contains an invalid numeric value", filename);
+ giterr_set(GITERR_REBASE, "the file '%s' contains an invalid numeric value", filename);
return -1;
}
@@ -170,7 +171,7 @@ GIT_INLINE(int) rebase_readoid(
return error;
if (str_out->size != GIT_OID_HEXSZ || git_oid_fromstr(out, str_out->ptr) < 0) {
- giterr_set(GITERR_REBASE, "The file '%s' contains an invalid object ID", filename);
+ giterr_set(GITERR_REBASE, "the file '%s' contains an invalid object ID", filename);
return -1;
}
@@ -316,7 +317,7 @@ int git_rebase_open(
goto done;
if (rebase->type == GIT_REBASE_TYPE_NONE) {
- giterr_set(GITERR_REBASE, "There is no rebase in progress");
+ giterr_set(GITERR_REBASE, "there is no rebase in progress");
error = GIT_ENOTFOUND;
goto done;
}
@@ -372,14 +373,14 @@ int git_rebase_open(
switch (rebase->type) {
case GIT_REBASE_TYPE_INTERACTIVE:
- giterr_set(GITERR_REBASE, "Interactive rebase is not supported");
+ giterr_set(GITERR_REBASE, "interactive rebase is not supported");
error = -1;
break;
case GIT_REBASE_TYPE_MERGE:
error = rebase_open_merge(rebase);
break;
case GIT_REBASE_TYPE_APPLY:
- giterr_set(GITERR_REBASE, "Patch application rebase is not supported");
+ giterr_set(GITERR_REBASE, "patch application rebase is not supported");
error = -1;
break;
default:
@@ -447,8 +448,8 @@ static int rebase_setupfiles_merge(git_rebase *rebase)
size_t i;
int error = 0;
- if ((error = rebase_setupfile(rebase, END_FILE, -1, "%" PRIuZ "\n", git_array_size(rebase->operations))) < 0 ||
- (error = rebase_setupfile(rebase, ONTO_NAME_FILE, -1, "%s\n", rebase->onto_name)) < 0)
+ if ((error = rebase_setupfile(rebase, END_FILE, 0, "%" PRIuZ "\n", git_array_size(rebase->operations))) < 0 ||
+ (error = rebase_setupfile(rebase, ONTO_NAME_FILE, 0, "%s\n", rebase->onto_name)) < 0)
goto done;
for (i = 0; i < git_array_size(rebase->operations); i++) {
@@ -459,7 +460,7 @@ static int rebase_setupfiles_merge(git_rebase *rebase)
git_oid_fmt(id_str, &operation->id);
- if ((error = rebase_setupfile(rebase, commit_filename.ptr, -1,
+ if ((error = rebase_setupfile(rebase, commit_filename.ptr, 0,
"%.*s\n", GIT_OID_HEXSZ, id_str)) < 0)
goto done;
}
@@ -478,7 +479,7 @@ static int rebase_setupfiles(git_rebase *rebase)
git_oid_fmt(orig_head, &rebase->orig_head_id);
if (p_mkdir(rebase->state_path, REBASE_DIR_MODE) < 0) {
- giterr_set(GITERR_OS, "Failed to create rebase directory '%s'", rebase->state_path);
+ giterr_set(GITERR_OS, "failed to create rebase directory '%s'", rebase->state_path);
return -1;
}
@@ -486,10 +487,10 @@ static int rebase_setupfiles(git_rebase *rebase)
rebase->orig_head_name;
if (git_repository__set_orig_head(rebase->repo, &rebase->orig_head_id) < 0 ||
- rebase_setupfile(rebase, HEAD_NAME_FILE, -1, "%s\n", orig_head_name) < 0 ||
- rebase_setupfile(rebase, ONTO_FILE, -1, "%.*s\n", GIT_OID_HEXSZ, onto) < 0 ||
- rebase_setupfile(rebase, ORIG_HEAD_FILE, -1, "%.*s\n", GIT_OID_HEXSZ, orig_head) < 0 ||
- rebase_setupfile(rebase, QUIET_FILE, -1, rebase->quiet ? "t\n" : "\n") < 0)
+ rebase_setupfile(rebase, HEAD_NAME_FILE, 0, "%s\n", orig_head_name) < 0 ||
+ rebase_setupfile(rebase, ONTO_FILE, 0, "%.*s\n", GIT_OID_HEXSZ, onto) < 0 ||
+ rebase_setupfile(rebase, ORIG_HEAD_FILE, 0, "%.*s\n", GIT_OID_HEXSZ, orig_head) < 0 ||
+ rebase_setupfile(rebase, QUIET_FILE, 0, rebase->quiet ? "t\n" : "\n") < 0)
return -1;
return rebase_setupfiles_merge(rebase);
@@ -511,7 +512,7 @@ static int rebase_ensure_not_in_progress(git_repository *repo)
return error;
if (type != GIT_REBASE_TYPE_NONE) {
- giterr_set(GITERR_REBASE, "There is an existing rebase in progress");
+ giterr_set(GITERR_REBASE, "there is an existing rebase in progress");
return -1;
}
@@ -536,7 +537,7 @@ static int rebase_ensure_not_dirty(
goto done;
if (git_diff_num_deltas(diff) > 0) {
- giterr_set(GITERR_REBASE, "Uncommitted changes exist in index");
+ giterr_set(GITERR_REBASE, "uncommitted changes exist in index");
error = fail_with;
goto done;
}
@@ -546,11 +547,13 @@ static int rebase_ensure_not_dirty(
}
if (check_workdir) {
- if ((error = git_diff_index_to_workdir(&diff, repo, index, NULL)) < 0)
+ git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
+ diff_opts.ignore_submodules = GIT_SUBMODULE_IGNORE_UNTRACKED;
+ if ((error = git_diff_index_to_workdir(&diff, repo, index, &diff_opts)) < 0)
goto done;
if (git_diff_num_deltas(diff) > 0) {
- giterr_set(GITERR_REBASE, "Unstaged changes exist in workdir");
+ giterr_set(GITERR_REBASE, "unstaged changes exist in workdir");
error = fail_with;
goto done;
}
@@ -586,7 +589,7 @@ static int rebase_init_operations(
(error = git_revwalk_hide(revwalk, git_annotated_commit_id(upstream))) < 0)
goto done;
- git_revwalk_sorting(revwalk, GIT_SORT_REVERSE | GIT_SORT_TIME);
+ git_revwalk_sorting(revwalk, GIT_SORT_REVERSE);
while ((error = git_revwalk_next(&id, revwalk)) == 0) {
if ((error = git_commit_lookup(&commit, repo, &id)) < 0)
@@ -624,13 +627,13 @@ static int rebase_init_merge(
GIT_UNUSED(upstream);
- if ((error = git_buf_joinpath(&state_path, repo->path_repository, REBASE_MERGE_DIR)) < 0)
+ if ((error = git_buf_joinpath(&state_path, repo->gitdir, REBASE_MERGE_DIR)) < 0)
goto done;
rebase->state_path = git_buf_detach(&state_path);
GITERR_CHECK_ALLOC(rebase->state_path);
- if (branch->ref_name) {
+ if (branch->ref_name && strcmp(branch->ref_name, "HEAD")) {
rebase->orig_head_name = git__strdup(branch->ref_name);
GITERR_CHECK_ALLOC(rebase->orig_head_name);
} else {
@@ -731,7 +734,7 @@ int git_rebase_init(
if (inmemory)
error = rebase_init_inmemory(rebase, repo, branch, upstream, onto);
else
- rebase_init_merge(rebase, repo, branch ,upstream, onto);
+ error = rebase_init_merge(rebase, repo, branch ,upstream, onto);
if (error == 0)
*out = rebase;
@@ -807,7 +810,7 @@ static int rebase_next_merge(
goto done;
if ((parent_count = git_commit_parentcount(current_commit)) > 1) {
- giterr_set(GITERR_REBASE, "Cannot rebase a merge commit");
+ giterr_set(GITERR_REBASE, "cannot rebase a merge commit");
error = -1;
goto done;
} else if (parent_count) {
@@ -821,8 +824,8 @@ static int rebase_next_merge(
normalize_checkout_options_for_apply(&checkout_opts, rebase, current_commit);
if ((error = git_indexwriter_init_for_operation(&indexwriter, rebase->repo, &checkout_opts.checkout_strategy)) < 0 ||
- (error = rebase_setupfile(rebase, MSGNUM_FILE, -1, "%" PRIuZ "\n", rebase->current+1)) < 0 ||
- (error = rebase_setupfile(rebase, CURRENT_FILE, -1, "%.*s\n", GIT_OID_HEXSZ, current_idstr)) < 0 ||
+ (error = rebase_setupfile(rebase, MSGNUM_FILE, 0, "%" PRIuZ "\n", rebase->current+1)) < 0 ||
+ (error = rebase_setupfile(rebase, CURRENT_FILE, 0, "%.*s\n", GIT_OID_HEXSZ, current_idstr)) < 0 ||
(error = git_merge_trees(&index, rebase->repo, parent_tree, head_tree, current_tree, &rebase->options.merge_options)) < 0 ||
(error = git_merge__check_result(rebase->repo, index)) < 0 ||
(error = git_checkout_index(rebase->repo, index, &checkout_opts)) < 0 ||
@@ -864,7 +867,7 @@ static int rebase_next_inmemory(
goto done;
if ((parent_count = git_commit_parentcount(current_commit)) > 1) {
- giterr_set(GITERR_REBASE, "Cannot rebase a merge commit");
+ giterr_set(GITERR_REBASE, "cannot rebase a merge commit");
error = -1;
goto done;
} else if (parent_count) {
@@ -1259,7 +1262,7 @@ static int rebase_copy_notes(
goto done;
on_error:
- giterr_set(GITERR_REBASE, "Invalid rewritten file at line %d", linenum);
+ giterr_set(GITERR_REBASE, "invalid rewritten file at line %d", linenum);
error = -1;
done:
diff --git a/src/refdb.c b/src/refdb.c
index debba1276..c162a153f 100644
--- a/src/refdb.c
+++ b/src/refdb.c
@@ -5,8 +5,7 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
-#include "posix.h"
+#include "refdb.h"
#include "git2/object.h"
#include "git2/refs.h"
@@ -14,9 +13,9 @@
#include "git2/sys/refdb_backend.h"
#include "hash.h"
-#include "refdb.h"
#include "refs.h"
#include "reflog.h"
+#include "posix.h"
int git_refdb_new(git_refdb **out, git_repository *repo)
{
@@ -125,13 +124,15 @@ int git_refdb_lookup(git_reference **out, git_refdb *db, const char *ref_name)
int git_refdb_iterator(git_reference_iterator **out, git_refdb *db, const char *glob)
{
+ int error;
+
if (!db->backend || !db->backend->iterator) {
- giterr_set(GITERR_REFERENCE, "This backend doesn't support iterators");
+ giterr_set(GITERR_REFERENCE, "this backend doesn't support iterators");
return -1;
}
- if (db->backend->iterator(out, db->backend, glob) < 0)
- return -1;
+ if ((error = db->backend->iterator(out, db->backend, glob)) < 0)
+ return error;
GIT_REFCOUNT_INC(db);
(*out)->db = db;
diff --git a/src/refdb.h b/src/refdb.h
index 4ee3b8065..2d4ec753a 100644
--- a/src/refdb.h
+++ b/src/refdb.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_refdb_h__
#define INCLUDE_refdb_h__
+#include "common.h"
+
#include "git2/refdb.h"
#include "repository.h"
diff --git a/src/refdb_fs.c b/src/refdb_fs.c
index f978038e6..ade734c6a 100644
--- a/src/refdb_fs.c
+++ b/src/refdb_fs.c
@@ -5,6 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "refdb_fs.h"
+
#include "refs.h"
#include "hash.h"
#include "repository.h"
@@ -13,7 +15,6 @@
#include "pack.h"
#include "reflog.h"
#include "refdb.h"
-#include "refdb_fs.h"
#include "iterator.h"
#include "sortedcache.h"
#include "signature.h"
@@ -26,8 +27,6 @@
#include <git2/sys/refs.h>
#include <git2/sys/reflog.h>
-GIT__USE_STRMAP
-
#define DEFAULT_NESTING_LEVEL 5
#define MAX_NESTING_LEVEL 10
@@ -55,12 +54,16 @@ typedef struct refdb_fs_backend {
git_refdb_backend parent;
git_repository *repo;
- char *path;
+ /* path to git directory */
+ char *gitpath;
+ /* path to common objects' directory */
+ char *commonpath;
git_sortedcache *refcache;
int peeling_mode;
git_iterator_flag_t iterator_flags;
uint32_t direach_flags;
+ int fsync;
} refdb_fs_backend;
static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name);
@@ -77,7 +80,7 @@ static int packed_reload(refdb_fs_backend *backend)
git_buf packedrefs = GIT_BUF_INIT;
char *scan, *eof, *eol;
- if (!backend->path)
+ if (!backend->gitpath)
return 0;
error = git_sortedcache_lockandload(backend->refcache, &packedrefs);
@@ -185,7 +188,7 @@ static int packed_reload(refdb_fs_backend *backend)
return 0;
parse_failed:
- giterr_set(GITERR_REFERENCE, "Corrupted packed references file");
+ giterr_set(GITERR_REFERENCE, "corrupted packed references file");
git_sortedcache_clear(backend->refcache, false);
git_sortedcache_wunlock(backend->refcache);
@@ -212,7 +215,7 @@ static int loose_parse_oid(
return 0;
corrupted:
- giterr_set(GITERR_REFERENCE, "Corrupted loose reference file: %s", filename);
+ giterr_set(GITERR_REFERENCE, "corrupted loose reference file: %s", filename);
return -1;
}
@@ -238,7 +241,7 @@ static int loose_lookup_to_packfile(refdb_fs_backend *backend, const char *name)
/* if we fail to load the loose reference, assume someone changed
* the filesystem under us and skip it...
*/
- if (loose_readbuffer(&ref_file, backend->path, name) < 0) {
+ if (loose_readbuffer(&ref_file, backend->gitpath, name) < 0) {
giterr_clear();
goto done;
}
@@ -287,7 +290,7 @@ static int _dirent_loose_load(void *payload, git_buf *full_path)
return error;
}
- file_path = full_path->ptr + strlen(backend->path);
+ file_path = full_path->ptr + strlen(backend->gitpath);
return loose_lookup_to_packfile(backend, file_path);
}
@@ -303,7 +306,7 @@ static int packed_loadloose(refdb_fs_backend *backend)
int error;
git_buf refs_path = GIT_BUF_INIT;
- if (git_buf_joinpath(&refs_path, backend->path, GIT_REFS_DIR) < 0)
+ if (git_buf_joinpath(&refs_path, backend->gitpath, GIT_REFS_DIR) < 0)
return -1;
/*
@@ -326,12 +329,13 @@ static int refdb_fs_backend__exists(
{
refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
git_buf ref_path = GIT_BUF_INIT;
+ int error;
assert(backend);
- if (packed_reload(backend) < 0 ||
- git_buf_joinpath(&ref_path, backend->path, ref_name) < 0)
- return -1;
+ if ((error = packed_reload(backend)) < 0 ||
+ (error = git_buf_joinpath(&ref_path, backend->gitpath, ref_name)) < 0)
+ return error;
*exists = git_path_isfile(ref_path.ptr) ||
(git_sortedcache_lookup(backend->refcache, ref_name) != NULL);
@@ -348,7 +352,7 @@ static const char *loose_parse_symbolic(git_buf *file_content)
refname_start = (const char *)file_content->ptr;
if (git_buf_len(file_content) < header_len + 1) {
- giterr_set(GITERR_REFERENCE, "Corrupted loose reference file");
+ giterr_set(GITERR_REFERENCE, "corrupted loose reference file");
return NULL;
}
@@ -361,6 +365,19 @@ static const char *loose_parse_symbolic(git_buf *file_content)
return refname_start;
}
+/*
+ * Returns whether a reference is stored per worktree or not.
+ * Per-worktree references are:
+ *
+ * - all pseudorefs, e.g. HEAD and MERGE_HEAD
+ * - all references stored inside of "refs/bisect/"
+ */
+static bool is_per_worktree_ref(const char *ref_name)
+{
+ return git__prefixcmp(ref_name, "refs/") != 0 ||
+ git__prefixcmp(ref_name, "refs/bisect/") == 0;
+}
+
static int loose_lookup(
git_reference **out,
refdb_fs_backend *backend,
@@ -368,11 +385,17 @@ static int loose_lookup(
{
git_buf ref_file = GIT_BUF_INIT;
int error = 0;
+ const char *ref_dir;
if (out)
*out = NULL;
- if ((error = loose_readbuffer(&ref_file, backend->path, ref_name)) < 0)
+ if (is_per_worktree_ref(ref_name))
+ ref_dir = backend->gitpath;
+ else
+ ref_dir = backend->commonpath;
+
+ if ((error = loose_readbuffer(&ref_file, ref_dir, ref_name)) < 0)
/* cannot read loose ref file - gah */;
else if (git__prefixcmp(git_buf_cstr(&ref_file), GIT_SYMREF) == 0) {
const char *target;
@@ -397,7 +420,7 @@ static int loose_lookup(
static int ref_error_notfound(const char *name)
{
- giterr_set(GITERR_REFERENCE, "Reference '%s' not found", name);
+ giterr_set(GITERR_REFERENCE, "reference '%s' not found", name);
return GIT_ENOTFOUND;
}
@@ -409,8 +432,8 @@ static int packed_lookup(
int error = 0;
struct packref *entry;
- if (packed_reload(backend) < 0)
- return -1;
+ if ((error = packed_reload(backend)) < 0)
+ return error;
if (git_sortedcache_rlock(backend->refcache) < 0)
return -1;
@@ -483,12 +506,12 @@ static int iter_load_loose_paths(refdb_fs_backend *backend, refdb_fs_iter *iter)
git_iterator_options fsit_opts = GIT_ITERATOR_OPTIONS_INIT;
const git_index_entry *entry = NULL;
- if (!backend->path) /* do nothing if no path for loose refs */
+ if (!backend->commonpath) /* do nothing if no commonpath for loose refs */
return 0;
fsit_opts.flags = backend->iterator_flags;
- if ((error = git_buf_printf(&path, "%s/refs", backend->path)) < 0 ||
+ if ((error = git_buf_printf(&path, "%s/refs", backend->commonpath)) < 0 ||
(error = git_iterator_for_filesystem(&fsit, path.ptr, &fsit_opts)) < 0) {
git_buf_free(&path);
return error;
@@ -615,13 +638,14 @@ static int refdb_fs_backend__iterator_next_name(
static int refdb_fs_backend__iterator(
git_reference_iterator **out, git_refdb_backend *_backend, const char *glob)
{
+ int error;
refdb_fs_iter *iter;
refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
assert(backend);
- if (packed_reload(backend) < 0)
- return -1;
+ if ((error = packed_reload(backend)) < 0)
+ return error;
iter = git__calloc(1, sizeof(refdb_fs_iter));
GITERR_CHECK_ALLOC(iter);
@@ -674,20 +698,22 @@ static int reference_path_available(
int force)
{
size_t i;
+ int error;
- if (packed_reload(backend) < 0)
- return -1;
+ if ((error = packed_reload(backend)) < 0)
+ return error;
if (!force) {
int exists;
- if (refdb_fs_backend__exists(
- &exists, (git_refdb_backend *)backend, new_ref) < 0)
- return -1;
+ if ((error = refdb_fs_backend__exists(
+ &exists, (git_refdb_backend *)backend, new_ref)) < 0) {
+ return error;
+ }
if (exists) {
giterr_set(GITERR_REFERENCE,
- "Failed to write reference '%s': a reference with "
+ "failed to write reference '%s': a reference with "
"that name already exists.", new_ref);
return GIT_EEXISTS;
}
@@ -701,7 +727,7 @@ static int reference_path_available(
if (ref && !ref_is_available(old_ref, new_ref, ref->name)) {
git_sortedcache_runlock(backend->refcache);
giterr_set(GITERR_REFERENCE,
- "Path to reference '%s' collides with existing one", new_ref);
+ "path to reference '%s' collides with existing one", new_ref);
return -1;
}
}
@@ -712,26 +738,36 @@ static int reference_path_available(
static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *name)
{
- int error;
+ int error, filebuf_flags;
git_buf ref_path = GIT_BUF_INIT;
+ const char *basedir;
assert(file && backend && name);
if (!git_path_isvalid(backend->repo, name, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) {
- giterr_set(GITERR_INVALID, "Invalid reference name '%s'.", name);
+ giterr_set(GITERR_INVALID, "invalid reference name '%s'", name);
return GIT_EINVALIDSPEC;
}
+ if (is_per_worktree_ref(name))
+ basedir = backend->gitpath;
+ else
+ basedir = backend->commonpath;
+
/* Remove a possibly existing empty directory hierarchy
* which name would collide with the reference name
*/
- if (git_futils_rmdir_r(name, backend->path, GIT_RMDIR_SKIP_NONEMPTY) < 0)
- return -1;
+ if ((error = git_futils_rmdir_r(name, basedir, GIT_RMDIR_SKIP_NONEMPTY)) < 0)
+ return error;
- if (git_buf_joinpath(&ref_path, backend->path, name) < 0)
+ if (git_buf_joinpath(&ref_path, basedir, name) < 0)
return -1;
- error = git_filebuf_open(file, ref_path.ptr, GIT_FILEBUF_FORCE, GIT_REFS_FILE_MODE);
+ filebuf_flags = GIT_FILEBUF_FORCE;
+ if (backend->fsync)
+ filebuf_flags |= GIT_FILEBUF_FSYNC;
+
+ error = git_filebuf_open(file, ref_path.ptr, filebuf_flags, GIT_REFS_FILE_MODE);
if (error == GIT_EDIRECTORY)
giterr_set(GITERR_REFERENCE, "cannot lock ref '%s', there are refs beneath that folder", name);
@@ -901,40 +937,62 @@ static int packed_write_ref(struct packref *ref, git_filebuf *file)
static int packed_remove_loose(refdb_fs_backend *backend)
{
size_t i;
- git_buf full_path = GIT_BUF_INIT;
- int failed = 0;
+ git_filebuf lock = GIT_FILEBUF_INIT;
+ git_buf ref_content = GIT_BUF_INIT;
+ int error = 0;
/* backend->refcache is already locked when this is called */
for (i = 0; i < git_sortedcache_entrycount(backend->refcache); ++i) {
struct packref *ref = git_sortedcache_entry(backend->refcache, i);
+ git_oid current_id;
if (!ref || !(ref->flags & PACKREF_WAS_LOOSE))
continue;
- if (git_buf_joinpath(&full_path, backend->path, ref->name) < 0)
- return -1; /* critical; do not try to recover on oom */
+ git_filebuf_cleanup(&lock);
- if (git_path_exists(full_path.ptr) && p_unlink(full_path.ptr) < 0) {
- if (failed)
- continue;
+ /* We need to stop anybody from updating the ref while we try to do a safe delete */
+ error = loose_lock(&lock, backend, ref->name);
+ /* If someone else is updating it, let them do it */
+ if (error == GIT_EEXISTS || error == GIT_ENOTFOUND)
+ continue;
- giterr_set(GITERR_REFERENCE,
- "Failed to remove loose reference '%s' after packing: %s",
- full_path.ptr, strerror(errno));
- failed = 1;
+ if (error < 0) {
+ git_buf_free(&ref_content);
+ giterr_set(GITERR_REFERENCE, "failed to lock loose reference '%s'", ref->name);
+ return error;
}
+ error = git_futils_readbuffer(&ref_content, lock.path_original);
+ /* Someone else beat us to cleaning up the ref, let's simply continue */
+ if (error == GIT_ENOTFOUND)
+ continue;
+
+ /* This became a symref between us packing and trying to delete it, so ignore it */
+ if (!git__prefixcmp(ref_content.ptr, GIT_SYMREF))
+ continue;
+
+ /* Figure out the current id; if we find a bad ref file, skip it so we can do the rest */
+ if (loose_parse_oid(&current_id, lock.path_original, &ref_content) < 0)
+ continue;
+
+ /* If the ref moved since we packed it, we must not delete it */
+ if (!git_oid_equal(&current_id, &ref->oid))
+ continue;
+
/*
* if we fail to remove a single file, this is *not* good,
* but we should keep going and remove as many as possible.
- * After we've removed as many files as possible, we return
- * the error code anyway.
+ * If we fail to remove, the ref is still in the old state, so
+ * we haven't lost information.
*/
+ p_unlink(lock.path_original);
}
- git_buf_free(&full_path);
- return failed ? -1 : 0;
+ git_buf_free(&ref_content);
+ git_filebuf_cleanup(&lock);
+ return 0;
}
/*
@@ -944,41 +1002,45 @@ static int packed_write(refdb_fs_backend *backend)
{
git_sortedcache *refcache = backend->refcache;
git_filebuf pack_file = GIT_FILEBUF_INIT;
+ int error, open_flags = 0;
size_t i;
/* lock the cache to updates while we do this */
- if (git_sortedcache_wlock(refcache) < 0)
- return -1;
+ if ((error = git_sortedcache_wlock(refcache)) < 0)
+ return error;
+
+ if (backend->fsync)
+ open_flags = GIT_FILEBUF_FSYNC;
/* Open the file! */
- if (git_filebuf_open(&pack_file, git_sortedcache_path(refcache), 0, GIT_PACKEDREFS_FILE_MODE) < 0)
+ if ((error = git_filebuf_open(&pack_file, git_sortedcache_path(refcache), open_flags, GIT_PACKEDREFS_FILE_MODE)) < 0)
goto fail;
/* Packfiles have a header... apparently
* This is in fact not required, but we might as well print it
* just for kicks */
- if (git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER) < 0)
+ if ((error = git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER)) < 0)
goto fail;
for (i = 0; i < git_sortedcache_entrycount(refcache); ++i) {
struct packref *ref = git_sortedcache_entry(refcache, i);
assert(ref);
- if (packed_find_peel(backend, ref) < 0)
+ if ((error = packed_find_peel(backend, ref)) < 0)
goto fail;
- if (packed_write_ref(ref, &pack_file) < 0)
+ if ((error = packed_write_ref(ref, &pack_file)) < 0)
goto fail;
}
/* if we've written all the references properly, we can commit
* the packfile to make the changes effective */
- if (git_filebuf_commit(&pack_file) < 0)
+ if ((error = git_filebuf_commit(&pack_file)) < 0)
goto fail;
/* when and only when the packfile has been properly written,
* we can go ahead and remove the loose refs */
- if (packed_remove_loose(backend) < 0)
+ if ((error = packed_remove_loose(backend)) < 0)
goto fail;
git_sortedcache_updated(refcache);
@@ -991,7 +1053,7 @@ fail:
git_filebuf_cleanup(&pack_file);
git_sortedcache_wunlock(refcache);
- return -1;
+ return error;
}
static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, const git_oid *old, const git_oid *new, const git_signature *author, const char *message);
@@ -1079,7 +1141,7 @@ out:
static int maybe_append_head(refdb_fs_backend *backend, const git_reference *ref, const git_signature *who, const char *message)
{
int error;
- git_oid old_id = {{0}};
+ git_oid old_id;
git_reference *tmp = NULL, *head = NULL, *peeled = NULL;
const char *name;
@@ -1087,7 +1149,8 @@ static int maybe_append_head(refdb_fs_backend *backend, const git_reference *ref
return 0;
/* if we can't resolve, we use {0}*40 as old id */
- git_reference_name_to_id(&old_id, backend->repo, ref->name);
+ if (git_reference_name_to_id(&old_id, backend->repo, ref->name) < 0)
+ memset(&old_id, 0, sizeof(old_id));
if ((error = git_reference_lookup(&head, backend->repo, GIT_HEAD_FILE)) < 0)
return error;
@@ -1143,8 +1206,7 @@ static int refdb_fs_backend__write(
assert(backend);
- error = reference_path_available(backend, ref->name, NULL, force);
- if (error < 0)
+ if ((error = reference_path_available(backend, ref->name, NULL, force)) < 0)
return error;
/* We need to perform the reflog append and old value check under the ref's lock */
@@ -1257,18 +1319,17 @@ static int refdb_fs_backend__delete_tail(
}
/* If a loose reference exists, remove it from the filesystem */
- if (git_buf_joinpath(&loose_path, backend->path, ref_name) < 0)
+ if (git_buf_joinpath(&loose_path, backend->gitpath, ref_name) < 0)
return -1;
- if (git_path_isfile(loose_path.ptr)) {
- error = p_unlink(loose_path.ptr);
- loose_deleted = 1;
- }
-
- git_buf_free(&loose_path);
- if (error != 0)
+ error = p_unlink(loose_path.ptr);
+ if (error < 0 && errno == ENOENT)
+ error = 0;
+ else if (error < 0)
goto cleanup;
+ else if (error == 0)
+ loose_deleted = 1;
if ((error = packed_reload(backend)) < 0)
goto cleanup;
@@ -1291,6 +1352,7 @@ static int refdb_fs_backend__delete_tail(
error = packed_write(backend);
cleanup:
+ git_buf_free(&loose_path);
git_filebuf_cleanup(file);
return error;
@@ -1362,14 +1424,15 @@ static int refdb_fs_backend__rename(
static int refdb_fs_backend__compress(git_refdb_backend *_backend)
{
+ int error;
refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
assert(backend);
- if (packed_reload(backend) < 0 || /* load the existing packfile */
- packed_loadloose(backend) < 0 || /* add all the loose refs */
- packed_write(backend) < 0) /* write back to disk */
- return -1;
+ if ((error = packed_reload(backend)) < 0 || /* load the existing packfile */
+ (error = packed_loadloose(backend)) < 0 || /* add all the loose refs */
+ (error = packed_write(backend)) < 0) /* write back to disk */
+ return error;
return 0;
}
@@ -1381,28 +1444,30 @@ static void refdb_fs_backend__free(git_refdb_backend *_backend)
assert(backend);
git_sortedcache_free(backend->refcache);
- git__free(backend->path);
+ git__free(backend->gitpath);
+ git__free(backend->commonpath);
git__free(backend);
}
-static int setup_namespace(git_buf *path, git_repository *repo)
+static char *setup_namespace(git_repository *repo, const char *in)
{
- char *parts, *start, *end;
+ git_buf path = GIT_BUF_INIT;
+ char *parts, *start, *end, *out = NULL;
- /* Not all repositories have a path */
- if (repo->path_repository == NULL)
- return 0;
+ if (!in)
+ goto done;
- /* Load the path to the repo first */
- git_buf_puts(path, repo->path_repository);
+ git_buf_puts(&path, in);
/* if the repo is not namespaced, nothing else to do */
- if (repo->namespace == NULL)
- return 0;
+ if (repo->namespace == NULL) {
+ out = git_buf_detach(&path);
+ goto done;
+ }
parts = end = git__strdup(repo->namespace);
if (parts == NULL)
- return -1;
+ goto done;
/*
* From `man gitnamespaces`:
@@ -1410,21 +1475,24 @@ static int setup_namespace(git_buf *path, git_repository *repo)
* of namespaces; for example, GIT_NAMESPACE=foo/bar will store
* refs under refs/namespaces/foo/refs/namespaces/bar/
*/
- while ((start = git__strsep(&end, "/")) != NULL) {
- git_buf_printf(path, "refs/namespaces/%s/", start);
- }
+ while ((start = git__strsep(&end, "/")) != NULL)
+ git_buf_printf(&path, "refs/namespaces/%s/", start);
- git_buf_printf(path, "refs/namespaces/%s/refs", end);
+ git_buf_printf(&path, "refs/namespaces/%s/refs", end);
git__free(parts);
/* Make sure that the folder with the namespace exists */
- if (git_futils_mkdir_relative(git_buf_cstr(path), repo->path_repository,
- 0777, GIT_MKDIR_PATH, NULL) < 0)
- return -1;
+ if (git_futils_mkdir_relative(git_buf_cstr(&path), in, 0777,
+ GIT_MKDIR_PATH, NULL) < 0)
+ goto done;
- /* Return root of the namespaced path, i.e. without the trailing '/refs' */
- git_buf_rtruncate_at_char(path, '/');
- return 0;
+ /* Return root of the namespaced gitpath, i.e. without the trailing '/refs' */
+ git_buf_rtruncate_at_char(&path, '/');
+ out = git_buf_detach(&path);
+
+done:
+ git_buf_free(&path);
+ return out;
}
static int reflog_alloc(git_reflog **reflog, const char *name)
@@ -1457,7 +1525,7 @@ static int reflog_parse(git_reflog *log, const char *buf, size_t buf_size)
#define seek_forward(_increase) do { \
if (_increase >= buf_size) { \
- giterr_set(GITERR_INVALID, "Ran out of data while parsing reflog"); \
+ giterr_set(GITERR_INVALID, "ran out of data while parsing reflog"); \
goto fail; \
} \
buf += _increase; \
@@ -1535,7 +1603,7 @@ static int create_new_reflog_file(const char *filepath)
GIT_INLINE(int) retrieve_reflog_path(git_buf *path, git_repository *repo, const char *name)
{
- return git_buf_join3(path, '/', repo->path_repository, GIT_REFLOG_DIR, name);
+ return git_buf_join3(path, '/', repo->commondir, GIT_REFLOG_DIR, name);
}
static int refdb_reflog_fs__ensure_log(git_refdb_backend *_backend, const char *name)
@@ -1673,7 +1741,7 @@ static int lock_reflog(git_filebuf *file, refdb_fs_backend *backend, const char
repo = backend->repo;
if (!git_path_isvalid(backend->repo, refname, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) {
- giterr_set(GITERR_INVALID, "Invalid reference name '%s'.", refname);
+ giterr_set(GITERR_INVALID, "invalid reference name '%s'", refname);
return GIT_EINVALIDSPEC;
}
@@ -1682,7 +1750,7 @@ static int lock_reflog(git_filebuf *file, refdb_fs_backend *backend, const char
if (!git_path_isfile(git_buf_cstr(&log_path))) {
giterr_set(GITERR_INVALID,
- "Log file for reference '%s' doesn't exist.", refname);
+ "log file for reference '%s' doesn't exist", refname);
error = -1;
goto cleanup;
}
@@ -1734,7 +1802,7 @@ success:
/* Append to the reflog, must be called under reference lock */
static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, const git_oid *old, const git_oid *new, const git_signature *who, const char *message)
{
- int error, is_symbolic;
+ int error, is_symbolic, open_flags;
git_oid old_id = {{0}}, new_id = {{0}};
git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT;
git_repository *repo = backend->repo;
@@ -1789,9 +1857,10 @@ static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, co
* there maybe an obsolete/unused directory (or directory hierarchy) in the way.
*/
if (git_path_isdir(git_buf_cstr(&path))) {
- if ((git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_SKIP_NONEMPTY) < 0))
- error = -1;
- else if (git_path_isdir(git_buf_cstr(&path))) {
+ if ((error = git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_SKIP_NONEMPTY)) < 0) {
+ if (error == GIT_ENOTFOUND)
+ error = 0;
+ } else if (git_path_isdir(git_buf_cstr(&path))) {
giterr_set(GITERR_REFERENCE, "cannot create reflog at '%s', there are reflogs beneath that folder",
ref->name);
error = GIT_EDIRECTORY;
@@ -1801,7 +1870,12 @@ static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, co
goto cleanup;
}
- error = git_futils_writebuffer(&buf, git_buf_cstr(&path), O_WRONLY|O_CREAT|O_APPEND, GIT_REFLOG_FILE_MODE);
+ open_flags = O_WRONLY | O_CREAT | O_APPEND;
+
+ if (backend->fsync)
+ open_flags |= O_FSYNC;
+
+ error = git_futils_writebuffer(&buf, git_buf_cstr(&path), open_flags, GIT_REFLOG_FILE_MODE);
cleanup:
git_buf_free(&buf);
@@ -1829,7 +1903,7 @@ static int refdb_reflog_fs__rename(git_refdb_backend *_backend, const char *old_
&normalized, new_name, GIT_REF_FORMAT_ALLOW_ONELEVEL)) < 0)
return error;
- if (git_buf_joinpath(&temp_path, repo->path_repository, GIT_REFLOG_DIR) < 0)
+ if (git_buf_joinpath(&temp_path, repo->gitdir, GIT_REFLOG_DIR) < 0)
return -1;
if (git_buf_joinpath(&old_path, git_buf_cstr(&temp_path), old_name) < 0)
@@ -1861,7 +1935,7 @@ static int refdb_reflog_fs__rename(git_refdb_backend *_backend, const char *old_
p_close(fd);
if (p_rename(git_buf_cstr(&old_path), git_buf_cstr(&temp_path)) < 0) {
- giterr_set(GITERR_OS, "Failed to rename reflog for %s", new_name);
+ giterr_set(GITERR_OS, "failed to rename reflog for %s", new_name);
error = -1;
goto cleanup;
}
@@ -1878,7 +1952,7 @@ static int refdb_reflog_fs__rename(git_refdb_backend *_backend, const char *old_
}
if (p_rename(git_buf_cstr(&temp_path), git_buf_cstr(&new_path)) < 0) {
- giterr_set(GITERR_OS, "Failed to rename reflog for %s", new_name);
+ giterr_set(GITERR_OS, "failed to rename reflog for %s", new_name);
error = -1;
}
@@ -1920,7 +1994,7 @@ int git_refdb_backend_fs(
git_repository *repository)
{
int t = 0;
- git_buf path = GIT_BUF_INIT;
+ git_buf gitpath = GIT_BUF_INIT;
refdb_fs_backend *backend;
backend = git__calloc(1, sizeof(refdb_fs_backend));
@@ -1928,18 +2002,27 @@ int git_refdb_backend_fs(
backend->repo = repository;
- if (setup_namespace(&path, repository) < 0)
- goto fail;
+ if (repository->gitdir) {
+ backend->gitpath = setup_namespace(repository, repository->gitdir);
+
+ if (backend->gitpath == NULL)
+ goto fail;
+ }
- backend->path = git_buf_detach(&path);
+ if (repository->commondir) {
+ backend->commonpath = setup_namespace(repository, repository->commondir);
- if (git_buf_joinpath(&path, backend->path, GIT_PACKEDREFS_FILE) < 0 ||
+ if (backend->commonpath == NULL)
+ goto fail;
+ }
+
+ if (git_buf_joinpath(&gitpath, backend->commonpath, GIT_PACKEDREFS_FILE) < 0 ||
git_sortedcache_new(
&backend->refcache, offsetof(struct packref, name),
- NULL, NULL, packref_cmp, git_buf_cstr(&path)) < 0)
+ NULL, NULL, packref_cmp, git_buf_cstr(&gitpath)) < 0)
goto fail;
- git_buf_free(&path);
+ git_buf_free(&gitpath);
if (!git_repository__cvar(&t, backend->repo, GIT_CVAR_IGNORECASE) && t) {
backend->iterator_flags |= GIT_ITERATOR_IGNORE_CASE;
@@ -1949,6 +2032,9 @@ int git_refdb_backend_fs(
backend->iterator_flags |= GIT_ITERATOR_PRECOMPOSE_UNICODE;
backend->direach_flags |= GIT_PATH_DIR_PRECOMPOSE_UNICODE;
}
+ if ((!git_repository__cvar(&t, backend->repo, GIT_CVAR_FSYNCOBJECTFILES) && t) ||
+ git_repository__fsync_gitdir)
+ backend->fsync = 1;
backend->parent.exists = &refdb_fs_backend__exists;
backend->parent.lookup = &refdb_fs_backend__lookup;
@@ -1971,8 +2057,9 @@ int git_refdb_backend_fs(
return 0;
fail:
- git_buf_free(&path);
- git__free(backend->path);
+ git_buf_free(&gitpath);
+ git__free(backend->gitpath);
+ git__free(backend->commonpath);
git__free(backend);
return -1;
}
diff --git a/src/refdb_fs.h b/src/refdb_fs.h
index 79e296833..0c84814df 100644
--- a/src/refdb_fs.h
+++ b/src/refdb_fs.h
@@ -7,6 +7,10 @@
#ifndef INCLUDE_refdb_fs_h__
#define INCLUDE_refdb_fs_h__
+#include "common.h"
+
+#include "strmap.h"
+
typedef struct {
git_strmap *packfile;
time_t packfile_time;
diff --git a/src/reflog.c b/src/reflog.c
index 9ce9aee6f..938999218 100644
--- a/src/reflog.c
+++ b/src/reflog.c
@@ -6,6 +6,7 @@
*/
#include "reflog.h"
+
#include "repository.h"
#include "filebuf.h"
#include "signature.h"
@@ -93,7 +94,7 @@ int git_reflog_append(git_reflog *reflog, const git_oid *new_oid, const git_sign
if (newline) {
if (newline[1] != '\0') {
- giterr_set(GITERR_INVALID, "Reflog message cannot contain newline");
+ giterr_set(GITERR_INVALID, "reflog message cannot contain newline");
goto cleanup;
}
@@ -193,7 +194,7 @@ int git_reflog_drop(git_reflog *reflog, size_t idx, int rewrite_previous_entry)
entry = (git_reflog_entry *)git_reflog_entry_byindex(reflog, idx);
if (entry == NULL) {
- giterr_set(GITERR_REFERENCE, "No reflog entry at index %"PRIuZ, idx);
+ giterr_set(GITERR_REFERENCE, "no reflog entry at index %"PRIuZ, idx);
return GIT_ENOTFOUND;
}
diff --git a/src/reflog.h b/src/reflog.h
index 2d31ae47d..d54b4cde8 100644
--- a/src/reflog.h
+++ b/src/reflog.h
@@ -8,6 +8,7 @@
#define INCLUDE_reflog_h__
#include "common.h"
+
#include "git2/reflog.h"
#include "vector.h"
diff --git a/src/refs.c b/src/refs.c
index bff443ac9..942054001 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -6,6 +6,7 @@
*/
#include "refs.h"
+
#include "hash.h"
#include "repository.h"
#include "fileops.h"
@@ -24,7 +25,7 @@
#include <git2/signature.h>
#include <git2/commit.h>
-GIT__USE_STRMAP
+bool git_reference__enable_symbolic_ref_target_validation = true;
#define DEFAULT_NESTING_LEVEL 5
#define MAX_NESTING_LEVEL 10
@@ -178,7 +179,8 @@ int git_reference_name_to_id(
static int reference_normalize_for_repo(
git_refname_t out,
git_repository *repo,
- const char *name)
+ const char *name,
+ bool validate)
{
int precompose;
unsigned int flags = GIT_REF_FORMAT_ALLOW_ONELEVEL;
@@ -187,6 +189,9 @@ static int reference_normalize_for_repo(
precompose)
flags |= GIT_REF_FORMAT__PRECOMPOSE_UNICODE;
+ if (!validate)
+ flags |= GIT_REF_FORMAT__VALIDATION_DISABLE;
+
return git_reference_normalize_name(out, GIT_REFNAME_MAX, name, flags);
}
@@ -213,7 +218,7 @@ int git_reference_lookup_resolved(
scan_type = GIT_REF_SYMBOLIC;
- if ((error = reference_normalize_for_repo(scan_name, repo, name)) < 0)
+ if ((error = reference_normalize_for_repo(scan_name, repo, name, true)) < 0)
return error;
if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
@@ -236,7 +241,7 @@ int git_reference_lookup_resolved(
if (scan_type != GIT_REF_OID && max_nesting != 0) {
giterr_set(GITERR_REFERENCE,
- "Cannot resolve reference (>%u levels deep)", max_nesting);
+ "cannot resolve reference (>%u levels deep)", max_nesting);
git_reference_free(ref);
return -1;
}
@@ -245,6 +250,40 @@ int git_reference_lookup_resolved(
return 0;
}
+int git_reference__read_head(
+ git_reference **out,
+ git_repository *repo,
+ const char *path)
+{
+ git_buf reference = GIT_BUF_INIT;
+ char *name = NULL;
+ int error;
+
+ if ((error = git_futils_readbuffer(&reference, path)) < 0)
+ goto out;
+ git_buf_rtrim(&reference);
+
+ if (git__strncmp(reference.ptr, GIT_SYMREF, strlen(GIT_SYMREF)) == 0) {
+ git_buf_consume(&reference, reference.ptr + strlen(GIT_SYMREF));
+
+ name = git_path_basename(path);
+
+ if ((*out = git_reference__alloc_symbolic(name, reference.ptr)) == NULL) {
+ error = -1;
+ goto out;
+ }
+ } else {
+ if ((error = git_reference_lookup(out, repo, reference.ptr)) < 0)
+ goto out;
+ }
+
+out:
+ git__free(name);
+ git_buf_free(&reference);
+
+ return error;
+}
+
int git_reference_dwim(git_reference **out, git_repository *repo, const char *refname)
{
int error = 0, i;
@@ -298,7 +337,7 @@ cleanup:
if (error && !foundvalid) {
/* never found a valid reference name */
giterr_set(GITERR_REFERENCE,
- "Could not use '%s' as valid reference name", git_buf_cstr(&name));
+ "could not use '%s' as valid reference name", git_buf_cstr(&name));
}
if (error == GIT_ENOTFOUND)
@@ -383,7 +422,7 @@ static int reference__create(
if (ref_out)
*ref_out = NULL;
- error = reference_normalize_for_repo(normalized, repo, name);
+ error = reference_normalize_for_repo(normalized, repo, name, true);
if (error < 0)
return error;
@@ -396,7 +435,7 @@ static int reference__create(
if (!git_object__is_valid(repo, oid, GIT_OBJ_ANY)) {
giterr_set(GITERR_REFERENCE,
- "Target OID for the reference doesn't exist on the repository");
+ "target OID for the reference doesn't exist on the repository");
return -1;
}
@@ -404,7 +443,10 @@ static int reference__create(
} else {
git_refname_t normalized_target;
- if ((error = reference_normalize_for_repo(normalized_target, repo, symbolic)) < 0)
+ error = reference_normalize_for_repo(normalized_target, repo,
+ symbolic, git_reference__enable_symbolic_ref_target_validation);
+
+ if (error < 0)
return error;
ref = git_reference__alloc_symbolic(normalized, normalized_target);
@@ -524,7 +566,7 @@ static int ensure_is_an_updatable_direct_reference(git_reference *ref)
if (ref->type == GIT_REF_OID)
return 0;
- giterr_set(GITERR_REFERENCE, "Cannot set OID on symbolic reference");
+ giterr_set(GITERR_REFERENCE, "cannot set OID on symbolic reference");
return -1;
}
@@ -552,7 +594,7 @@ static int ensure_is_an_updatable_symbolic_reference(git_reference *ref)
if (ref->type == GIT_REF_SYMBOLIC)
return 0;
- giterr_set(GITERR_REFERENCE, "Cannot set symbolic target on a direct reference");
+ giterr_set(GITERR_REFERENCE, "cannot set symbolic target on a direct reference");
return -1;
}
@@ -573,20 +615,63 @@ int git_reference_symbolic_set_target(
out, ref->db->repo, ref->name, target, 1, ref->target.symbolic, log_message);
}
+typedef struct {
+ const char *old_name;
+ git_refname_t new_name;
+} rename_cb_data;
+
+static int update_wt_heads(git_repository *repo, const char *path, void *payload)
+{
+ rename_cb_data *data = (rename_cb_data *) payload;
+ git_reference *head = NULL;
+ char *gitdir = NULL;
+ int error;
+
+ if ((error = git_reference__read_head(&head, repo, path)) < 0) {
+ giterr_set(GITERR_REFERENCE, "could not read HEAD when renaming references");
+ goto out;
+ }
+
+ if ((gitdir = git_path_dirname(path)) == NULL) {
+ error = -1;
+ goto out;
+ }
+
+ if (git_reference_type(head) != GIT_REF_SYMBOLIC ||
+ git__strcmp(head->target.symbolic, data->old_name) != 0) {
+ error = 0;
+ goto out;
+ }
+
+ /* Update HEAD it was pointing to the reference being renamed */
+ if ((error = git_repository_create_head(gitdir, data->new_name)) < 0) {
+ giterr_set(GITERR_REFERENCE, "failed to update HEAD after renaming reference");
+ goto out;
+ }
+
+out:
+ git_reference_free(head);
+ git__free(gitdir);
+
+ return error;
+}
+
static int reference__rename(git_reference **out, git_reference *ref, const char *new_name, int force,
const git_signature *signature, const char *message)
{
+ git_repository *repo;
git_refname_t normalized;
bool should_head_be_updated = false;
int error = 0;
assert(ref && new_name && signature);
+ repo = git_reference_owner(ref);
+
if ((error = reference_normalize_for_repo(
- normalized, git_reference_owner(ref), new_name)) < 0)
+ normalized, repo, new_name, true)) < 0)
return error;
-
/* Check if we have to update HEAD. */
if ((error = git_branch_is_head(ref)) < 0)
return error;
@@ -596,14 +681,18 @@ static int reference__rename(git_reference **out, git_reference *ref, const char
if ((error = git_refdb_rename(out, ref->db, ref->name, normalized, force, signature, message)) < 0)
return error;
- /* Update HEAD it was pointing to the reference being renamed */
- if (should_head_be_updated &&
- (error = git_repository_set_head(ref->db->repo, normalized)) < 0) {
- giterr_set(GITERR_REFERENCE, "Failed to update HEAD after renaming reference");
- return error;
+ /* Update HEAD if it was pointing to the reference being renamed */
+ if (should_head_be_updated) {
+ error = git_repository_set_head(ref->db->repo, normalized);
+ } else {
+ rename_cb_data payload;
+ payload.old_name = ref->name;
+ memcpy(&payload.new_name, &normalized, sizeof(normalized));
+
+ error = git_repository_foreach_head(repo, update_wt_heads, &payload);
}
- return 0;
+ return error;
}
@@ -636,7 +725,7 @@ int git_reference_resolve(git_reference **ref_out, const git_reference *ref)
return git_reference_lookup_resolved(ref_out, ref->db->repo, ref->target.symbolic, -1);
default:
- giterr_set(GITERR_REFERENCE, "Invalid reference");
+ giterr_set(GITERR_REFERENCE, "invalid reference");
return -1;
}
}
@@ -876,6 +965,7 @@ int git_reference__normalize_name(
int segment_len, segments_count = 0, error = GIT_EINVALIDSPEC;
unsigned int process_flags;
bool normalize = (buf != NULL);
+ bool validate = (flags & GIT_REF_FORMAT__VALIDATION_DISABLE) == 0;
#ifdef GIT_USE_ICONV
git_path_iconv_t ic = GIT_PATH_ICONV_INIT;
@@ -886,7 +976,7 @@ int git_reference__normalize_name(
process_flags = flags;
current = (char *)name;
- if (*current == '/')
+ if (validate && *current == '/')
goto cleanup;
if (normalize)
@@ -902,6 +992,13 @@ int git_reference__normalize_name(
}
#endif
+ if (!validate) {
+ git_buf_sets(buf, current);
+
+ error = git_buf_oom(buf) ? -1 : 0;
+ goto cleanup;
+ }
+
while (true) {
segment_len = ensure_segment_validity(current);
if (segment_len < 0) {
@@ -973,7 +1070,7 @@ cleanup:
if (error == GIT_EINVALIDSPEC)
giterr_set(
GITERR_REFERENCE,
- "The given reference name '%s' is not valid", name);
+ "the given reference name '%s' is not valid", name);
if (error && normalize)
git_buf_free(buf);
@@ -1000,7 +1097,7 @@ int git_reference_normalize_name(
if (git_buf_len(&buf) > buffer_size - 1) {
giterr_set(
GITERR_REFERENCE,
- "The provided buffer is too short to hold the normalization of '%s'", name);
+ "the provided buffer is too short to hold the normalization of '%s'", name);
error = GIT_EBUFS;
goto cleanup;
}
@@ -1046,7 +1143,7 @@ static int get_terminal(git_reference **out, git_repository *repo, const char *r
int error = 0;
if (nesting > MAX_NESTING_LEVEL) {
- giterr_set(GITERR_REFERENCE, "Reference chain too deep (%d)", nesting);
+ giterr_set(GITERR_REFERENCE, "reference chain too deep (%d)", nesting);
return GIT_ENOTFOUND;
}
@@ -1115,6 +1212,18 @@ int git_reference__update_terminal(
return error;
}
+static const char *commit_type(const git_commit *commit)
+{
+ unsigned int count = git_commit_parentcount(commit);
+
+ if (count >= 2)
+ return " (merge)";
+ else if (count == 0)
+ return " (initial)";
+ else
+ return "";
+}
+
int git_reference__update_for_commit(
git_repository *repo,
git_reference *ref,
@@ -1131,7 +1240,7 @@ int git_reference__update_for_commit(
if ((error = git_commit_lookup(&commit, repo, id)) < 0 ||
(error = git_buf_printf(&reflog_msg, "%s%s: %s",
operation ? operation : "commit",
- git_commit_parentcount(commit) == 0 ? " (initial)" : "",
+ commit_type(commit),
git_commit_summary(commit))) < 0)
goto done;
@@ -1229,7 +1338,7 @@ static int peel_error(int error, git_reference *ref, const char* msg)
{
giterr_set(
GITERR_INVALID,
- "The reference '%s' cannot be peeled - %s", git_reference_name(ref), msg);
+ "the reference '%s' cannot be peeled - %s", git_reference_name(ref), msg);
return error;
}
diff --git a/src/refs.h b/src/refs.h
index fda9532de..7a1a9aed1 100644
--- a/src/refs.h
+++ b/src/refs.h
@@ -8,6 +8,7 @@
#define INCLUDE_refs_h__
#include "common.h"
+
#include "git2/oid.h"
#include "git2/refs.h"
#include "git2/refdb.h"
@@ -15,6 +16,8 @@
#include "buffer.h"
#include "oid.h"
+extern bool git_reference__enable_symbolic_ref_target_validation;
+
#define GIT_REFS_DIR "refs/"
#define GIT_REFS_HEADS_DIR GIT_REFS_DIR "heads/"
#define GIT_REFS_TAGS_DIR GIT_REFS_DIR "tags/"
@@ -53,6 +56,7 @@
#define GIT_REFS_STASH_FILE GIT_REFS_DIR GIT_STASH_FILE
#define GIT_REF_FORMAT__PRECOMPOSE_UNICODE (1u << 16)
+#define GIT_REF_FORMAT__VALIDATION_DISABLE (1u << 15)
#define GIT_REFNAME_MAX 1024
@@ -104,6 +108,20 @@ int git_reference_lookup_resolved(
const char *name,
int max_deref);
+/**
+ * Read reference from a file.
+ *
+ * This function will read in the file at `path`. If it is a
+ * symref, it will return a new unresolved symbolic reference
+ * with the given name pointing to the reference pointed to by
+ * the file. If it is not a symbolic reference, it will return
+ * the resolved reference.
+ */
+int git_reference__read_head(
+ git_reference **out,
+ git_repository *repo,
+ const char *path);
+
int git_reference__log_signature(git_signature **out, git_repository *repo);
/** Update a reference after a commit. */
diff --git a/src/refspec.c b/src/refspec.c
index d200e5609..01a77c97f 100644
--- a/src/refspec.c
+++ b/src/refspec.c
@@ -5,10 +5,10 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "refspec.h"
+
#include "git2/errors.h"
-#include "common.h"
-#include "refspec.h"
#include "util.h"
#include "posix.h"
#include "refs.h"
diff --git a/src/refspec.h b/src/refspec.h
index 9a87c97a5..fd2d8b312 100644
--- a/src/refspec.h
+++ b/src/refspec.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_refspec_h__
#define INCLUDE_refspec_h__
+#include "common.h"
+
#include "git2/refspec.h"
#include "buffer.h"
#include "vector.h"
diff --git a/src/remote.c b/src/remote.c
index c1d7d59ea..303911760 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -5,15 +5,15 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "remote.h"
+
#include "git2/config.h"
#include "git2/types.h"
#include "git2/oid.h"
#include "git2/net.h"
-#include "common.h"
#include "config.h"
#include "repository.h"
-#include "remote.h"
#include "fetch.h"
#include "refs.h"
#include "refspec.h"
@@ -192,15 +192,15 @@ static int canonicalize_url(git_buf *out, const char *in)
static int create_internal(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
{
git_remote *remote;
- git_config *config = NULL;
+ git_config *config_ro = NULL, *config_rw;
git_buf canonical_url = GIT_BUF_INIT;
git_buf var = GIT_BUF_INIT;
int error = -1;
- /* name is optional */
- assert(out && repo && url);
+ /* repo, name, and fetch are optional */
+ assert(out && url);
- if ((error = git_repository_config__weakptr(&config, repo)) < 0)
+ if (repo && (error = git_repository_config_snapshot(&config_ro, repo)) < 0)
return error;
remote = git__calloc(1, sizeof(git_remote));
@@ -212,7 +212,12 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n
(error = canonicalize_url(&canonical_url, url)) < 0)
goto on_error;
- remote->url = apply_insteadof(repo->_config, canonical_url.ptr, GIT_DIRECTION_FETCH);
+ if (repo) {
+ remote->url = apply_insteadof(config_ro, canonical_url.ptr, GIT_DIRECTION_FETCH);
+ } else {
+ remote->url = git__strdup(canonical_url.ptr);
+ }
+ GITERR_CHECK_ALLOC(remote->url);
if (name != NULL) {
remote->name = git__strdup(name);
@@ -221,7 +226,9 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n
if ((error = git_buf_printf(&var, CONFIG_URL_FMT, name)) < 0)
goto on_error;
- if ((error = git_config_set_string(config, var.ptr, canonical_url.ptr)) < 0)
+ if (repo &&
+ ((error = git_repository_config__weakptr(&config_rw, repo)) < 0 ||
+ (error = git_config_set_string(config_rw, var.ptr, canonical_url.ptr)) < 0))
goto on_error;
}
@@ -233,10 +240,7 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n
if (name && (error = write_add_refspec(repo, name, fetch, true)) < 0)
goto on_error;
- if ((error = git_repository_config_snapshot(&config, repo)) < 0)
- goto on_error;
-
- if ((error = lookup_remote_prune_config(remote, config, name)) < 0)
+ if (repo && (error = lookup_remote_prune_config(remote, config_ro, name)) < 0)
goto on_error;
/* Move the data over to where the matching functions can find them */
@@ -260,7 +264,7 @@ on_error:
if (error)
git_remote_free(remote);
- git_config_free(config);
+ git_config_free(config_ro);
git_buf_free(&canonical_url);
git_buf_free(&var);
return error;
@@ -283,7 +287,7 @@ static int ensure_remote_doesnot_exist(git_repository *repo, const char *name)
giterr_set(
GITERR_CONFIG,
- "Remote '%s' already exists.", name);
+ "remote '%s' already exists", name);
return GIT_EEXISTS;
}
@@ -331,6 +335,11 @@ int git_remote_create_anonymous(git_remote **out, git_repository *repo, const ch
return create_internal(out, repo, NULL, url, NULL);
}
+int git_remote_create_detached(git_remote **out, const char *url)
+{
+ return create_internal(out, NULL, NULL, url, NULL);
+}
+
int git_remote_dup(git_remote **dest, git_remote *source)
{
size_t i;
@@ -476,7 +485,7 @@ int git_remote_lookup(git_remote **out, git_repository *repo, const char *name)
if (!optional_setting_found) {
error = GIT_ENOTFOUND;
- giterr_set(GITERR_CONFIG, "Remote '%s' does not exist.", name);
+ giterr_set(GITERR_CONFIG, "remote '%s' does not exist", name);
goto cleanup;
}
@@ -675,7 +684,9 @@ int git_remote_connect(git_remote *remote, git_direction direction, const git_re
url = git_remote__urlfordirection(remote, direction);
if (url == NULL) {
giterr_set(GITERR_INVALID,
- "Malformed remote '%s' - missing URL", remote->name);
+ "Malformed remote '%s' - missing %s URL",
+ remote->name ? remote->name : "(anonymous)",
+ direction == GIT_DIRECTION_FETCH ? "fetch" : "push");
return -1;
}
@@ -770,8 +781,12 @@ int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_ur
goto found;
}
- /* HTTP_PROXY / HTTPS_PROXY environment variables */
- error = git__getenv(&val, use_ssl ? "HTTPS_PROXY" : "HTTP_PROXY");
+ /* http_proxy / https_proxy environment variables */
+ error = git__getenv(&val, use_ssl ? "https_proxy" : "http_proxy");
+
+ /* try uppercase environment variables */
+ if (error == GIT_ENOTFOUND)
+ error = git__getenv(&val, use_ssl ? "HTTPS_PROXY" : "HTTP_PROXY");
if (error < 0) {
if (error == GIT_ENOTFOUND) {
@@ -856,6 +871,11 @@ int git_remote_download(git_remote *remote, const git_strarray *refspecs, const
assert(remote);
+ if (!remote->repo) {
+ giterr_set(GITERR_INVALID, "cannot download detached remote");
+ return -1;
+ }
+
if (opts) {
GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
cbs = &opts->callbacks;
@@ -1718,7 +1738,7 @@ int git_remote_set_autotag(git_repository *repo, const char *remote, git_remote_
error = 0;
break;
default:
- giterr_set(GITERR_INVALID, "Invalid value for the tagopt setting");
+ giterr_set(GITERR_INVALID, "invalid value for the tagopt setting");
error = -1;
}
@@ -2341,6 +2361,11 @@ int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const gi
assert(remote);
+ if (!remote->repo) {
+ giterr_set(GITERR_INVALID, "cannot download detached remote");
+ return -1;
+ }
+
if (opts) {
cbs = &opts->callbacks;
custom_headers = &opts->custom_headers;
@@ -2400,6 +2425,13 @@ int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_
const git_strarray *custom_headers = NULL;
const git_proxy_options *proxy = NULL;
+ assert(remote);
+
+ if (!remote->repo) {
+ giterr_set(GITERR_INVALID, "cannot download detached remote");
+ return -1;
+ }
+
if (opts) {
GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
cbs = &opts->callbacks;
@@ -2408,7 +2440,7 @@ int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_
proxy = &opts->proxy_opts;
}
- assert(remote && refspecs);
+ assert(remote);
if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, proxy, custom_headers)) < 0)
return error;
diff --git a/src/remote.h b/src/remote.h
index e696997f4..a94481f25 100644
--- a/src/remote.h
+++ b/src/remote.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_remote_h__
#define INCLUDE_remote_h__
+#include "common.h"
+
#include "git2/remote.h"
#include "git2/transport.h"
#include "git2/sys/transport.h"
diff --git a/src/repository.c b/src/repository.c
index cf3d18a2d..fe549e6e8 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -4,6 +4,9 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
+
+#include "repository.h"
+
#include <ctype.h>
#include "git2/object.h"
@@ -11,7 +14,6 @@
#include "git2/sys/repository.h"
#include "common.h"
-#include "repository.h"
#include "commit.h"
#include "tag.h"
#include "blob.h"
@@ -27,13 +29,43 @@
#include "merge.h"
#include "diff_driver.h"
#include "annotated_commit.h"
+#include "submodule.h"
+#include "worktree.h"
+
+#include "strmap.h"
#ifdef GIT_WIN32
# include "win32/w32_util.h"
#endif
+bool git_repository__fsync_gitdir = false;
+
+static const struct {
+ git_repository_item_t parent;
+ const char *name;
+ bool directory;
+} items[] = {
+ { GIT_REPOSITORY_ITEM_GITDIR, NULL, true },
+ { GIT_REPOSITORY_ITEM_WORKDIR, NULL, true },
+ { GIT_REPOSITORY_ITEM_COMMONDIR, NULL, true },
+ { GIT_REPOSITORY_ITEM_GITDIR, "index", false },
+ { GIT_REPOSITORY_ITEM_COMMONDIR, "objects", true },
+ { GIT_REPOSITORY_ITEM_COMMONDIR, "refs", true },
+ { GIT_REPOSITORY_ITEM_COMMONDIR, "packed-refs", false },
+ { GIT_REPOSITORY_ITEM_COMMONDIR, "remotes", true },
+ { GIT_REPOSITORY_ITEM_COMMONDIR, "config", false },
+ { GIT_REPOSITORY_ITEM_COMMONDIR, "info", true },
+ { GIT_REPOSITORY_ITEM_COMMONDIR, "hooks", true },
+ { GIT_REPOSITORY_ITEM_COMMONDIR, "logs", true },
+ { GIT_REPOSITORY_ITEM_GITDIR, "modules", true },
+ { GIT_REPOSITORY_ITEM_COMMONDIR, "worktrees", true }
+};
+
static int check_repositoryformatversion(git_config *config);
+#define GIT_COMMONDIR_FILE "commondir"
+#define GIT_GITDIR_FILE "gitdir"
+
#define GIT_FILE_CONTENT_PREFIX "gitdir:"
#define GIT_BRANCH_MASTER "master"
@@ -109,6 +141,7 @@ void git_repository__cleanup(git_repository *repo)
{
assert(repo);
+ git_repository_submodule_cache_clear(repo);
git_cache_clear(&repo->objects);
git_attr_cache_flush(repo);
@@ -136,8 +169,9 @@ void git_repository_free(git_repository *repo)
git_buf_free(git_array_get(repo->reserved_names, i));
git_array_clear(repo->reserved_names);
- git__free(repo->path_gitlink);
- git__free(repo->path_repository);
+ git__free(repo->gitlink);
+ git__free(repo->gitdir);
+ git__free(repo->commondir);
git__free(repo->workdir);
git__free(repo->namespace);
git__free(repo->ident_name);
@@ -152,17 +186,41 @@ void git_repository_free(git_repository *repo)
*
* Open a repository object from its path
*/
-static bool valid_repository_path(git_buf *repository_path)
+static bool valid_repository_path(git_buf *repository_path, git_buf *common_path)
{
- /* Check OBJECTS_DIR first, since it will generate the longest path name */
- if (git_path_contains_dir(repository_path, GIT_OBJECTS_DIR) == false)
- return false;
+ /* Check if we have a separate commondir (e.g. we have a
+ * worktree) */
+ if (git_path_contains_file(repository_path, GIT_COMMONDIR_FILE)) {
+ git_buf common_link = GIT_BUF_INIT;
+ git_buf_joinpath(&common_link, repository_path->ptr, GIT_COMMONDIR_FILE);
+
+ git_futils_readbuffer(&common_link, common_link.ptr);
+ git_buf_rtrim(&common_link);
+
+ if (git_path_is_relative(common_link.ptr)) {
+ git_buf_joinpath(common_path, repository_path->ptr, common_link.ptr);
+ } else {
+ git_buf_swap(common_path, &common_link);
+ }
+
+ git_buf_free(&common_link);
+ }
+ else {
+ git_buf_set(common_path, repository_path->ptr, repository_path->size);
+ }
+
+ /* Make sure the commondir path always has a trailing * slash */
+ if (git_buf_rfind(common_path, '/') != (ssize_t)common_path->size - 1)
+ git_buf_putc(common_path, '/');
/* Ensure HEAD file exists */
if (git_path_contains_file(repository_path, GIT_HEAD_FILE) == false)
return false;
- if (git_path_contains_dir(repository_path, GIT_REFS_DIR) == false)
+ /* Check files in common dir */
+ if (git_path_contains_dir(common_path, GIT_OBJECTS_DIR) == false)
+ return false;
+ if (git_path_contains_dir(common_path, GIT_REFS_DIR) == false)
return false;
return true;
@@ -201,6 +259,7 @@ int git_repository_new(git_repository **out)
GITERR_CHECK_ALLOC(repo);
repo->is_bare = 1;
+ repo->is_worktree = 0;
return 0;
}
@@ -220,9 +279,10 @@ static int load_config_data(git_repository *repo, const git_config *config)
static int load_workdir(git_repository *repo, git_config *config, git_buf *parent_path)
{
- int error;
+ int error;
git_config_entry *ce;
- git_buf worktree = GIT_BUF_INIT;
+ git_buf worktree = GIT_BUF_INIT;
+ git_buf path = GIT_BUF_INIT;
if (repo->is_bare)
return 0;
@@ -231,9 +291,26 @@ static int load_workdir(git_repository *repo, git_config *config, git_buf *paren
&ce, config, "core.worktree", false)) < 0)
return error;
- if (ce && ce->value) {
+ if (repo->is_worktree) {
+ char *gitlink = git_worktree__read_link(repo->gitdir, GIT_GITDIR_FILE);
+ if (!gitlink) {
+ error = -1;
+ goto cleanup;
+ }
+
+ git_buf_attach(&worktree, gitlink, 0);
+
+ if ((git_path_dirname_r(&worktree, worktree.ptr)) < 0 ||
+ git_path_to_dir(&worktree) < 0) {
+ error = -1;
+ goto cleanup;
+ }
+
+ repo->workdir = git_buf_detach(&worktree);
+ }
+ else if (ce && ce->value) {
if ((error = git_path_prettify_dir(
- &worktree, ce->value, repo->path_repository)) < 0)
+ &worktree, ce->value, repo->gitdir)) < 0)
goto cleanup;
repo->workdir = git_buf_detach(&worktree);
@@ -241,7 +318,7 @@ static int load_workdir(git_repository *repo, git_config *config, git_buf *paren
else if (parent_path && git_path_isdir(parent_path->ptr))
repo->workdir = git_buf_detach(parent_path);
else {
- if (git_path_dirname_r(&worktree, repo->path_repository) < 0 ||
+ if (git_path_dirname_r(&worktree, repo->gitdir) < 0 ||
git_path_to_dir(&worktree) < 0) {
error = -1;
goto cleanup;
@@ -252,6 +329,7 @@ static int load_workdir(git_repository *repo, git_config *config, git_buf *paren
GITERR_CHECK_ALLOC(repo->workdir);
cleanup:
+ git_buf_free(&path);
git_config_entry_free(ce);
return error;
}
@@ -332,7 +410,7 @@ static int read_gitfile(git_buf *path_out, const char *file_path)
memcmp(git_buf_cstr(&file), GIT_FILE_CONTENT_PREFIX, prefix_len) != 0)
{
giterr_set(GITERR_REPOSITORY,
- "The `.git` file at '%s' is malformed", file_path);
+ "the `.git` file at '%s' is malformed", file_path);
error = -1;
}
else if ((error = git_path_dirname_r(path_out, file_path)) >= 0) {
@@ -348,9 +426,10 @@ static int read_gitfile(git_buf *path_out, const char *file_path)
}
static int find_repo(
- git_buf *repo_path,
- git_buf *parent_path,
- git_buf *link_path,
+ git_buf *gitdir_path,
+ git_buf *workdir_path,
+ git_buf *gitlink_path,
+ git_buf *commondir_path,
const char *start_path,
uint32_t flags,
const char *ceiling_dirs)
@@ -358,13 +437,14 @@ static int find_repo(
int error;
git_buf path = GIT_BUF_INIT;
git_buf repo_link = GIT_BUF_INIT;
+ git_buf common_link = GIT_BUF_INIT;
struct stat st;
dev_t initial_device = 0;
int min_iterations;
bool in_dot_git;
size_t ceiling_offset = 0;
- git_buf_free(repo_path);
+ git_buf_clear(gitdir_path);
error = git_path_prettify(&path, start_path, NULL);
if (error < 0)
@@ -404,21 +484,30 @@ static int find_repo(
break;
if (S_ISDIR(st.st_mode)) {
- if (valid_repository_path(&path)) {
+ if (valid_repository_path(&path, &common_link)) {
git_path_to_dir(&path);
- git_buf_set(repo_path, path.ptr, path.size);
+ git_buf_set(gitdir_path, path.ptr, path.size);
+
+ if (gitlink_path)
+ git_buf_attach(gitlink_path,
+ git_worktree__read_link(path.ptr, GIT_GITDIR_FILE), 0);
+ if (commondir_path)
+ git_buf_swap(&common_link, commondir_path);
+
break;
}
}
- else if (S_ISREG(st.st_mode)) {
+ else if (S_ISREG(st.st_mode) && git__suffixcmp(path.ptr, "/" DOT_GIT) == 0) {
error = read_gitfile(&repo_link, path.ptr);
if (error < 0)
break;
- if (valid_repository_path(&repo_link)) {
- git_buf_swap(repo_path, &repo_link);
+ if (valid_repository_path(&repo_link, &common_link)) {
+ git_buf_swap(gitdir_path, &repo_link);
- if (link_path)
- error = git_buf_put(link_path, path.ptr, path.size);
+ if (gitlink_path)
+ error = git_buf_put(gitlink_path, path.ptr, path.size);
+ if (commondir_path)
+ git_buf_swap(&common_link, commondir_path);
}
break;
}
@@ -444,27 +533,28 @@ static int find_repo(
break;
}
- if (!error && parent_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) {
- if (!git_buf_len(repo_path))
- git_buf_clear(parent_path);
+ if (!error && workdir_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) {
+ if (!git_buf_len(gitdir_path))
+ git_buf_clear(workdir_path);
else {
- git_path_dirname_r(parent_path, path.ptr);
- git_path_to_dir(parent_path);
+ git_path_dirname_r(workdir_path, path.ptr);
+ git_path_to_dir(workdir_path);
}
- if (git_buf_oom(parent_path))
+ if (git_buf_oom(workdir_path))
return -1;
}
/* If we didn't find the repository, and we don't have any other error
* to report, report that. */
- if (!git_buf_len(repo_path) && !error) {
+ if (!git_buf_len(gitdir_path) && !error) {
giterr_set(GITERR_REPOSITORY,
- "Could not find repository from '%s'", start_path);
+ "could not find repository from '%s'", start_path);
error = GIT_ENOTFOUND;
}
git_buf_free(&path);
git_buf_free(&repo_link);
+ git_buf_free(&common_link);
return error;
}
@@ -473,26 +563,30 @@ int git_repository_open_bare(
const char *bare_path)
{
int error;
- git_buf path = GIT_BUF_INIT;
+ git_buf path = GIT_BUF_INIT, common_path = GIT_BUF_INIT;
git_repository *repo = NULL;
if ((error = git_path_prettify_dir(&path, bare_path, NULL)) < 0)
return error;
- if (!valid_repository_path(&path)) {
+ if (!valid_repository_path(&path, &common_path)) {
git_buf_free(&path);
- giterr_set(GITERR_REPOSITORY, "Path is not a repository: %s", bare_path);
+ git_buf_free(&common_path);
+ giterr_set(GITERR_REPOSITORY, "path is not a repository: %s", bare_path);
return GIT_ENOTFOUND;
}
repo = repository_alloc();
GITERR_CHECK_ALLOC(repo);
- repo->path_repository = git_buf_detach(&path);
- GITERR_CHECK_ALLOC(repo->path_repository);
+ repo->gitdir = git_buf_detach(&path);
+ GITERR_CHECK_ALLOC(repo->gitdir);
+ repo->commondir = git_buf_detach(&common_path);
+ GITERR_CHECK_ALLOC(repo->commondir);
/* of course we're bare! */
repo->is_bare = 1;
+ repo->is_worktree = 0;
repo->workdir = NULL;
*repo_ptr = repo;
@@ -613,9 +707,10 @@ static int _git_repository_open_ext_from_env(
git_repository_set_odb(repo, odb);
error = git__getenv(&alts_buf, "GIT_ALTERNATE_OBJECT_DIRECTORIES");
- if (error == GIT_ENOTFOUND)
+ if (error == GIT_ENOTFOUND) {
giterr_clear();
- else if (error < 0)
+ error = 0;
+ } else if (error < 0)
goto error;
else {
const char *end;
@@ -638,9 +733,11 @@ static int _git_repository_open_ext_from_env(
}
}
- error = git_repository_set_namespace(repo, git_buf_cstr(&namespace_buf));
- if (error < 0)
- goto error;
+ if (git_buf_len(&namespace_buf)) {
+ error = git_repository_set_namespace(repo, git_buf_cstr(&namespace_buf));
+ if (error < 0)
+ goto error;
+ }
git_repository_set_index(repo, index);
@@ -665,6 +762,29 @@ success:
return error;
}
+static int repo_is_worktree(unsigned *out, const git_repository *repo)
+{
+ git_buf gitdir_link = GIT_BUF_INIT;
+ int error;
+
+ /* Worktrees cannot have the same commondir and gitdir */
+ if (repo->commondir && repo->gitdir
+ && !strcmp(repo->commondir, repo->gitdir)) {
+ *out = 0;
+ return 0;
+ }
+
+ if ((error = git_buf_joinpath(&gitdir_link, repo->gitdir, "gitdir")) < 0)
+ return -1;
+
+ /* A 'gitdir' file inside a git directory is currently
+ * only used when the repository is a working tree. */
+ *out = !!git_path_exists(gitdir_link.ptr);
+
+ git_buf_free(&gitdir_link);
+ return error;
+}
+
int git_repository_open_ext(
git_repository **repo_ptr,
const char *start_path,
@@ -672,8 +792,9 @@ int git_repository_open_ext(
const char *ceiling_dirs)
{
int error;
- git_buf path = GIT_BUF_INIT, parent = GIT_BUF_INIT,
- link_path = GIT_BUF_INIT;
+ unsigned is_worktree;
+ git_buf gitdir = GIT_BUF_INIT, workdir = GIT_BUF_INIT,
+ gitlink = GIT_BUF_INIT, commondir = GIT_BUF_INIT;
git_repository *repo;
git_config *config = NULL;
@@ -684,7 +805,7 @@ int git_repository_open_ext(
*repo_ptr = NULL;
error = find_repo(
- &path, &parent, &link_path, start_path, flags, ceiling_dirs);
+ &gitdir, &workdir, &gitlink, &commondir, start_path, flags, ceiling_dirs);
if (error < 0 || !repo_ptr)
return error;
@@ -692,14 +813,22 @@ int git_repository_open_ext(
repo = repository_alloc();
GITERR_CHECK_ALLOC(repo);
- repo->path_repository = git_buf_detach(&path);
- GITERR_CHECK_ALLOC(repo->path_repository);
+ repo->gitdir = git_buf_detach(&gitdir);
+ GITERR_CHECK_ALLOC(repo->gitdir);
- if (link_path.size) {
- repo->path_gitlink = git_buf_detach(&link_path);
- GITERR_CHECK_ALLOC(repo->path_gitlink);
+ if (gitlink.size) {
+ repo->gitlink = git_buf_detach(&gitlink);
+ GITERR_CHECK_ALLOC(repo->gitlink);
+ }
+ if (commondir.size) {
+ repo->commondir = git_buf_detach(&commondir);
+ GITERR_CHECK_ALLOC(repo->commondir);
}
+ if ((error = repo_is_worktree(&is_worktree, repo)) < 0)
+ goto cleanup;
+ repo->is_worktree = is_worktree;
+
/*
* We'd like to have the config, but git doesn't particularly
* care if it's not there, so we need to deal with that.
@@ -718,12 +847,13 @@ int git_repository_open_ext(
if (config &&
((error = load_config_data(repo, config)) < 0 ||
- (error = load_workdir(repo, config, &parent)) < 0))
+ (error = load_workdir(repo, config, &workdir)) < 0))
goto cleanup;
}
cleanup:
- git_buf_free(&parent);
+ git_buf_free(&gitdir);
+ git_buf_free(&workdir);
git_config_free(config);
if (error < 0)
@@ -740,6 +870,36 @@ int git_repository_open(git_repository **repo_out, const char *path)
repo_out, path, GIT_REPOSITORY_OPEN_NO_SEARCH, NULL);
}
+int git_repository_open_from_worktree(git_repository **repo_out, git_worktree *wt)
+{
+ git_buf path = GIT_BUF_INIT;
+ git_repository *repo = NULL;
+ int len, err;
+
+ assert(repo_out && wt);
+
+ *repo_out = NULL;
+ len = strlen(wt->gitlink_path);
+
+ if (len <= 4 || strcasecmp(wt->gitlink_path + len - 4, ".git")) {
+ err = -1;
+ goto out;
+ }
+
+ if ((err = git_buf_set(&path, wt->gitlink_path, len - 4)) < 0)
+ goto out;
+
+ if ((err = git_repository_open(&repo, path.ptr)) < 0)
+ goto out;
+
+ *repo_out = repo;
+
+out:
+ git_buf_free(&path);
+
+ return err;
+}
+
int git_repository_wrap_odb(git_repository **repo_out, git_odb *odb)
{
git_repository *repo;
@@ -765,7 +925,7 @@ int git_repository_discover(
git_buf_sanitize(out);
- return find_repo(out, NULL, NULL, start_path, flags, ceiling_dirs);
+ return find_repo(out, NULL, NULL, NULL, start_path, flags, ceiling_dirs);
}
static int load_config(
@@ -785,14 +945,10 @@ static int load_config(
if ((error = git_config_new(&cfg)) < 0)
return error;
- error = git_buf_joinpath(
- &config_path, repo->path_repository, GIT_CONFIG_FILENAME_INREPO);
- if (error < 0)
- goto on_error;
+ if ((error = git_repository_item_path(&config_path, repo, GIT_REPOSITORY_ITEM_CONFIG)) == 0)
+ error = git_config_add_file_ondisk(cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, 0);
- if ((error = git_config_add_file_ondisk(
- cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, 0)) < 0 &&
- error != GIT_ENOTFOUND)
+ if (error && error != GIT_ENOTFOUND)
goto on_error;
git_buf_free(&config_path);
@@ -920,18 +1076,23 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
git_buf odb_path = GIT_BUF_INIT;
git_odb *odb;
- if ((error = git_buf_joinpath(&odb_path, repo->path_repository, GIT_OBJECTS_DIR)) < 0)
+ if ((error = git_repository_item_path(&odb_path, repo,
+ GIT_REPOSITORY_ITEM_OBJECTS)) < 0 ||
+ (error = git_odb_new(&odb)) < 0)
return error;
- error = git_odb_open(&odb, odb_path.ptr);
- if (!error) {
- GIT_REFCOUNT_OWN(odb, repo);
+ GIT_REFCOUNT_OWN(odb, repo);
- odb = git__compare_and_swap(&repo->_odb, NULL, odb);
- if (odb != NULL) {
- GIT_REFCOUNT_OWN(odb, NULL);
- git_odb_free(odb);
- }
+ if ((error = git_odb__set_caps(odb, GIT_ODB_CAP_FROM_OWNER)) < 0 ||
+ (error = git_odb__add_default_backends(odb, odb_path.ptr, 0, 0)) < 0) {
+ git_odb_free(odb);
+ return error;
+ }
+
+ odb = git__compare_and_swap(&repo->_odb, NULL, odb);
+ if (odb != NULL) {
+ GIT_REFCOUNT_OWN(odb, NULL);
+ git_odb_free(odb);
}
git_buf_free(&odb_path);
@@ -1006,7 +1167,7 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo)
git_buf index_path = GIT_BUF_INIT;
git_index *index;
- if ((error = git_buf_joinpath(&index_path, repo->path_repository, GIT_INDEX_FILE)) < 0)
+ if ((error = git_buf_joinpath(&index_path, repo->gitdir, GIT_INDEX_FILE)) < 0)
return error;
error = git_index_open(&index, index_path.ptr);
@@ -1076,7 +1237,7 @@ static int reserved_names_add8dot3(git_repository *repo, const char *path)
name_len = strlen(name);
- if ((name_len == def_len && memcmp(name, def, def_len) == 0) ||
+ if ((name_len == def_len && memcmp(name, def, def_len) == 0) ||
(name_len == def_dot_git_len && memcmp(name, def_dot_git, def_dot_git_len) == 0)) {
git__free(name);
return 0;
@@ -1122,13 +1283,13 @@ bool git_repository__reserved_names(
prefixcmp = (error || ignorecase) ? git__prefixcmp_icase :
git__prefixcmp;
- if (repo->path_gitlink &&
- reserved_names_add8dot3(repo, repo->path_gitlink) < 0)
+ if (repo->gitlink &&
+ reserved_names_add8dot3(repo, repo->gitlink) < 0)
goto on_error;
- if (repo->path_repository &&
- prefixcmp(repo->path_repository, repo->workdir) == 0 &&
- reserved_names_add8dot3(repo, repo->path_repository) < 0)
+ if (repo->gitdir &&
+ prefixcmp(repo->gitdir, repo->workdir) == 0 &&
+ reserved_names_add8dot3(repo, repo->gitdir) < 0)
goto on_error;
}
}
@@ -1177,7 +1338,7 @@ static int check_repositoryformatversion(git_config *config)
if (GIT_REPO_VERSION < version) {
giterr_set(GITERR_REPOSITORY,
- "Unsupported repository version %d. Only versions up to %d are supported.",
+ "unsupported repository version %d. Only versions up to %d are supported.",
version, GIT_REPO_VERSION);
return -1;
}
@@ -1185,7 +1346,7 @@ static int check_repositoryformatversion(git_config *config)
return 0;
}
-static int repo_init_create_head(const char *git_dir, const char *ref_name)
+int git_repository_create_head(const char *git_dir, const char *ref_name)
{
git_buf ref_path = GIT_BUF_INIT;
git_filebuf ref = GIT_FILEBUF_INIT;
@@ -1271,12 +1432,12 @@ static int create_empty_file(const char *path, mode_t mode)
int fd;
if ((fd = p_creat(path, mode)) < 0) {
- giterr_set(GITERR_OS, "Error while creating '%s'", path);
+ giterr_set(GITERR_OS, "error while creating '%s'", path);
return -1;
}
if (p_close(fd) < 0) {
- giterr_set(GITERR_OS, "Error while closing '%s'", path);
+ giterr_set(GITERR_OS, "error while closing '%s'", path);
return -1;
}
@@ -1505,7 +1666,7 @@ static int repo_write_template(
if (error)
giterr_set(GITERR_OS,
- "Failed to initialize repository with template '%s'", file);
+ "failed to initialize repository with template '%s'", file);
return error;
}
@@ -1536,7 +1697,7 @@ static int repo_write_gitlink(
if (!p_stat(buf.ptr, &st) && !S_ISREG(st.st_mode)) {
giterr_set(GITERR_REPOSITORY,
- "Cannot overwrite gitlink file into path '%s'", in_dir);
+ "cannot overwrite gitlink file into path '%s'", in_dir);
error = GIT_EEXISTS;
goto cleanup;
}
@@ -1590,7 +1751,7 @@ static int repo_init_structure(
if ((opts->flags & GIT_REPOSITORY_INIT__HAS_DOTGIT) != 0) {
if (git_win32__set_hidden(repo_dir, true) < 0) {
giterr_set(GITERR_OS,
- "Failed to mark Git repository folder as hidden");
+ "failed to mark Git repository folder as hidden");
return -1;
}
}
@@ -1625,7 +1786,13 @@ static int repo_init_structure(
default_template = true;
}
- if (tdir) {
+ /*
+ * If tdir was the empty string, treat it like tdir was a path to an
+ * empty directory (so, don't do any copying). This is the behavior
+ * that git(1) exhibits, although it doesn't seem to be officially
+ * documented.
+ */
+ if (tdir && git__strcmp(tdir, "") != 0) {
uint32_t cpflags = GIT_CPDIR_COPY_SYMLINKS |
GIT_CPDIR_SIMPLE_TO_MODE |
GIT_CPDIR_COPY_DOTFILES;
@@ -1744,7 +1911,7 @@ static int repo_init_directories(
if (git_path_dirname_r(wd_path, repo_path->ptr) < 0)
return -1;
} else {
- giterr_set(GITERR_REPOSITORY, "Cannot pick working directory"
+ giterr_set(GITERR_REPOSITORY, "cannot pick working directory"
" for non-bare repository that isn't a '.git' directory");
return -1;
}
@@ -1848,7 +2015,8 @@ int git_repository_init_ext(
git_repository_init_options *opts)
{
int error;
- git_buf repo_path = GIT_BUF_INIT, wd_path = GIT_BUF_INIT;
+ git_buf repo_path = GIT_BUF_INIT, wd_path = GIT_BUF_INIT,
+ common_path = GIT_BUF_INIT;
const char *wd;
assert(out && given_repo && opts);
@@ -1860,11 +2028,11 @@ int git_repository_init_ext(
goto cleanup;
wd = (opts->flags & GIT_REPOSITORY_INIT_BARE) ? NULL : git_buf_cstr(&wd_path);
- if (valid_repository_path(&repo_path)) {
+ if (valid_repository_path(&repo_path, &common_path)) {
if ((opts->flags & GIT_REPOSITORY_INIT_NO_REINIT) != 0) {
giterr_set(GITERR_REPOSITORY,
- "Attempt to reinitialize '%s'", given_repo);
+ "attempt to reinitialize '%s'", given_repo);
error = GIT_EEXISTS;
goto cleanup;
}
@@ -1881,7 +2049,7 @@ int git_repository_init_ext(
repo_path.ptr, wd, opts)) &&
!(error = repo_init_config(
repo_path.ptr, wd, opts->flags, opts->mode)))
- error = repo_init_create_head(
+ error = git_repository_create_head(
repo_path.ptr, opts->initial_head);
}
if (error < 0)
@@ -1893,6 +2061,7 @@ int git_repository_init_ext(
error = repo_init_create_origin(*out, opts->origin_url);
cleanup:
+ git_buf_free(&common_path);
git_buf_free(&repo_path);
git_buf_free(&wd_path);
@@ -1922,6 +2091,29 @@ int git_repository_head_detached(git_repository *repo)
return exists;
}
+static int get_worktree_file_path(git_buf *out, git_repository *repo, const char *worktree, const char *file)
+{
+ git_buf_clear(out);
+ return git_buf_printf(out, "%s/worktrees/%s/%s", repo->commondir, worktree, file);
+}
+
+int git_repository_head_detached_for_worktree(git_repository *repo, const char *name)
+{
+ git_reference *ref = NULL;
+ int error;
+
+ assert(repo && name);
+
+ if ((error = git_repository_head_for_worktree(&ref, repo, name)) < 0)
+ goto out;
+
+ error = (git_reference_type(ref) != GIT_REF_SYMBOLIC);
+out:
+ git_reference_free(ref);
+
+ return error;
+}
+
int git_repository_head(git_reference **head_out, git_repository *repo)
{
git_reference *head;
@@ -1941,6 +2133,71 @@ int git_repository_head(git_reference **head_out, git_repository *repo)
return error == GIT_ENOTFOUND ? GIT_EUNBORNBRANCH : error;
}
+int git_repository_head_for_worktree(git_reference **out, git_repository *repo, const char *name)
+{
+ git_buf path = GIT_BUF_INIT;
+ git_reference *head = NULL;
+ int error;
+
+ assert(out && repo && name);
+
+ *out = NULL;
+
+ if ((error = get_worktree_file_path(&path, repo, name, GIT_HEAD_FILE)) < 0 ||
+ (error = git_reference__read_head(&head, repo, path.ptr)) < 0)
+ goto out;
+
+ if (git_reference_type(head) != GIT_REF_OID) {
+ git_reference *resolved;
+
+ error = git_reference_lookup_resolved(&resolved, repo, git_reference_symbolic_target(head), -1);
+ git_reference_free(head);
+ head = resolved;
+ }
+
+ *out = head;
+
+out:
+ if (error)
+ git_reference_free(head);
+
+ git_buf_free(&path);
+
+ return error;
+}
+
+int git_repository_foreach_head(git_repository *repo, git_repository_foreach_head_cb cb, void *payload)
+{
+ git_strarray worktrees = GIT_VECTOR_INIT;
+ git_buf path = GIT_BUF_INIT;
+ int error;
+ size_t i;
+
+ /* Execute callback for HEAD of commondir */
+ if ((error = git_buf_joinpath(&path, repo->commondir, GIT_HEAD_FILE)) < 0 ||
+ (error = cb(repo, path.ptr, payload) != 0))
+ goto out;
+
+ if ((error = git_worktree_list(&worktrees, repo)) < 0) {
+ error = 0;
+ goto out;
+ }
+
+ /* Execute callback for all worktree HEADs */
+ for (i = 0; i < worktrees.count; i++) {
+ if (get_worktree_file_path(&path, repo, worktrees.strings[i], GIT_HEAD_FILE) < 0)
+ continue;
+
+ if ((error = cb(repo, path.ptr, payload)) != 0)
+ goto out;
+ }
+
+out:
+ git_buf_free(&path);
+ git_strarray_free(&worktrees);
+ return error;
+}
+
int git_repository_head_unborn(git_repository *repo)
{
git_reference *ref = NULL;
@@ -1999,10 +2256,50 @@ int git_repository_is_empty(git_repository *repo)
return is_empty;
}
+int git_repository_item_path(git_buf *out, git_repository *repo, git_repository_item_t item)
+{
+ const char *parent;
+
+ switch (items[item].parent) {
+ case GIT_REPOSITORY_ITEM_GITDIR:
+ parent = git_repository_path(repo);
+ break;
+ case GIT_REPOSITORY_ITEM_WORKDIR:
+ parent = git_repository_workdir(repo);
+ break;
+ case GIT_REPOSITORY_ITEM_COMMONDIR:
+ parent = git_repository_commondir(repo);
+ break;
+ default:
+ giterr_set(GITERR_INVALID, "invalid item directory");
+ return -1;
+ }
+
+ if (parent == NULL) {
+ giterr_set(GITERR_INVALID, "path cannot exist in repository");
+ return GIT_ENOTFOUND;
+ }
+
+ if (git_buf_sets(out, parent) < 0)
+ return -1;
+
+ if (items[item].name) {
+ if (git_buf_joinpath(out, parent, items[item].name) < 0)
+ return -1;
+ }
+
+ if (items[item].directory) {
+ if (git_path_to_dir(out) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
const char *git_repository_path(git_repository *repo)
{
assert(repo);
- return repo->path_repository;
+ return repo->gitdir;
}
const char *git_repository_workdir(git_repository *repo)
@@ -2015,6 +2312,12 @@ const char *git_repository_workdir(git_repository *repo)
return repo->workdir;
}
+const char *git_repository_commondir(git_repository *repo)
+{
+ assert(repo);
+ return repo->commondir;
+}
+
int git_repository_set_workdir(
git_repository *repo, const char *workdir, int update_gitlink)
{
@@ -2065,6 +2368,12 @@ int git_repository_is_bare(git_repository *repo)
return repo->is_bare;
}
+int git_repository_is_worktree(git_repository *repo)
+{
+ assert(repo);
+ return repo->is_worktree;
+}
+
int git_repository_set_bare(git_repository *repo)
{
int error;
@@ -2119,7 +2428,7 @@ int git_repository__set_orig_head(git_repository *repo, const git_oid *orig_head
git_oid_fmt(orig_head_str, orig_head);
- if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_ORIG_HEAD_FILE)) == 0 &&
+ if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_ORIG_HEAD_FILE)) == 0 &&
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) == 0 &&
(error = git_filebuf_printf(&file, "%.*s\n", GIT_OID_HEXSZ, orig_head_str)) == 0)
error = git_filebuf_commit(&file);
@@ -2140,13 +2449,13 @@ int git_repository_message(git_buf *out, git_repository *repo)
git_buf_sanitize(out);
- if (git_buf_joinpath(&path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0)
+ if (git_buf_joinpath(&path, repo->gitdir, GIT_MERGE_MSG_FILE) < 0)
return -1;
if ((error = p_stat(git_buf_cstr(&path), &st)) < 0) {
if (errno == ENOENT)
error = GIT_ENOTFOUND;
- giterr_set(GITERR_OS, "Could not access message file");
+ giterr_set(GITERR_OS, "could not access message file");
} else {
error = git_futils_readbuffer(out, git_buf_cstr(&path));
}
@@ -2161,7 +2470,7 @@ int git_repository_message_remove(git_repository *repo)
git_buf path = GIT_BUF_INIT;
int error;
- if (git_buf_joinpath(&path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0)
+ if (git_buf_joinpath(&path, repo->gitdir, GIT_MERGE_MSG_FILE) < 0)
return -1;
error = p_unlink(git_buf_cstr(&path));
@@ -2224,7 +2533,7 @@ int git_repository_hashfile(
}
if (!git__is_sizet(len)) {
- giterr_set(GITERR_OS, "File size overflow for 32-bit systems");
+ giterr_set(GITERR_OS, "file size overflow for 32-bit systems");
error = -1;
goto cleanup;
}
@@ -2251,7 +2560,9 @@ static int checkout_message(git_buf *out, git_reference *old, const char *new)
git_buf_puts(out, " to ");
- if (git_reference__is_branch(new))
+ if (git_reference__is_branch(new) ||
+ git_reference__is_tag(new) ||
+ git_reference__is_remote(new))
git_buf_puts(out, git_reference__shorthand(new));
else
git_buf_puts(out, new);
@@ -2262,77 +2573,86 @@ static int checkout_message(git_buf *out, git_reference *old, const char *new)
return 0;
}
-int git_repository_set_head(
- git_repository* repo,
- const char* refname)
+static int detach(git_repository *repo, const git_oid *id, const char *new)
{
- git_reference *ref = NULL, *current = NULL, *new_head = NULL;
- git_buf log_message = GIT_BUF_INIT;
int error;
+ git_buf log_message = GIT_BUF_INIT;
+ git_object *object = NULL, *peeled = NULL;
+ git_reference *new_head = NULL, *current = NULL;
- assert(repo && refname);
+ assert(repo && id);
if ((error = git_reference_lookup(&current, repo, GIT_HEAD_FILE)) < 0)
return error;
- if ((error = checkout_message(&log_message, current, refname)) < 0)
+ if ((error = git_object_lookup(&object, repo, id, GIT_OBJ_ANY)) < 0)
goto cleanup;
- error = git_reference_lookup(&ref, repo, refname);
- if (error < 0 && error != GIT_ENOTFOUND)
+ if ((error = git_object_peel(&peeled, object, GIT_OBJ_COMMIT)) < 0)
goto cleanup;
- if (!error) {
- if (git_reference_is_branch(ref)) {
- error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE,
- git_reference_name(ref), true, git_buf_cstr(&log_message));
- } else {
- error = git_repository_set_head_detached(repo, git_reference_target(ref));
- }
- } else if (git_reference__is_branch(refname)) {
- error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, refname,
- true, git_buf_cstr(&log_message));
- }
+ if (new == NULL)
+ new = git_oid_tostr_s(git_object_id(peeled));
+
+ if ((error = checkout_message(&log_message, current, new)) < 0)
+ goto cleanup;
+
+ error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_object_id(peeled), true, git_buf_cstr(&log_message));
cleanup:
git_buf_free(&log_message);
+ git_object_free(object);
+ git_object_free(peeled);
git_reference_free(current);
- git_reference_free(ref);
git_reference_free(new_head);
return error;
}
-static int detach(git_repository *repo, const git_oid *id, const char *from)
+int git_repository_set_head(
+ git_repository* repo,
+ const char* refname)
{
- int error;
+ git_reference *ref = NULL, *current = NULL, *new_head = NULL;
git_buf log_message = GIT_BUF_INIT;
- git_object *object = NULL, *peeled = NULL;
- git_reference *new_head = NULL, *current = NULL;
+ int error;
- assert(repo && id);
+ assert(repo && refname);
if ((error = git_reference_lookup(&current, repo, GIT_HEAD_FILE)) < 0)
return error;
- if ((error = git_object_lookup(&object, repo, id, GIT_OBJ_ANY)) < 0)
+ if ((error = checkout_message(&log_message, current, refname)) < 0)
goto cleanup;
- if ((error = git_object_peel(&peeled, object, GIT_OBJ_COMMIT)) < 0)
+ error = git_reference_lookup(&ref, repo, refname);
+ if (error < 0 && error != GIT_ENOTFOUND)
goto cleanup;
- if (from == NULL)
- from = git_oid_tostr_s(git_object_id(peeled));
-
- if ((error = checkout_message(&log_message, current, from)) < 0)
+ if (ref && current->type == GIT_REF_SYMBOLIC && git__strcmp(current->target.symbolic, ref->name) &&
+ git_reference_is_branch(ref) && git_branch_is_checked_out(ref)) {
+ giterr_set(GITERR_REPOSITORY, "cannot set HEAD to reference '%s' as it is the current HEAD "
+ "of a linked repository.", git_reference_name(ref));
+ error = -1;
goto cleanup;
+ }
- error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_object_id(peeled), true, git_buf_cstr(&log_message));
+ if (!error) {
+ if (git_reference_is_branch(ref)) {
+ error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE,
+ git_reference_name(ref), true, git_buf_cstr(&log_message));
+ } else {
+ error = detach(repo, git_reference_target(ref),
+ git_reference_is_tag(ref) || git_reference_is_remote(ref) ? refname : NULL);
+ }
+ } else if (git_reference__is_branch(refname)) {
+ error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, refname,
+ true, git_buf_cstr(&log_message));
+ }
cleanup:
git_buf_free(&log_message);
- git_object_free(object);
- git_object_free(peeled);
git_reference_free(current);
+ git_reference_free(ref);
git_reference_free(new_head);
return error;
}
@@ -2397,7 +2717,7 @@ int git_repository_state(git_repository *repo)
assert(repo);
- if (git_buf_puts(&repo_path, repo->path_repository) < 0)
+ if (git_buf_puts(&repo_path, repo->gitdir) < 0)
return -1;
if (git_path_contains_file(&repo_path, GIT_REBASE_MERGE_INTERACTIVE_FILE))
@@ -2439,7 +2759,7 @@ int git_repository__cleanup_files(
for (error = 0, i = 0; !error && i < files_len; ++i) {
const char *path;
- if (git_buf_joinpath(&buf, repo->path_repository, files[i]) < 0)
+ if (git_buf_joinpath(&buf, repo->gitdir, files[i]) < 0)
return -1;
path = git_buf_cstr(&buf);
@@ -2450,7 +2770,7 @@ int git_repository__cleanup_files(
error = git_futils_rmdir_r(path, NULL,
GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS);
}
-
+
git_buf_clear(&buf);
}
@@ -2483,7 +2803,7 @@ int git_repository_is_shallow(git_repository *repo)
struct stat st;
int error;
- if ((error = git_buf_joinpath(&path, repo->path_repository, "shallow")) < 0)
+ if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0)
return error;
error = git_path_lstat(path.ptr, &st);
@@ -2538,3 +2858,31 @@ int git_repository_set_ident(git_repository *repo, const char *name, const char
return 0;
}
+
+int git_repository_submodule_cache_all(git_repository *repo)
+{
+ int error;
+
+ assert(repo);
+
+ if ((error = git_strmap_alloc(&repo->submodule_cache)))
+ return error;
+
+ error = git_submodule__map(repo, repo->submodule_cache);
+ return error;
+}
+
+int git_repository_submodule_cache_clear(git_repository *repo)
+{
+ git_submodule *sm;
+ assert(repo);
+ if (repo->submodule_cache == NULL) {
+ return 0;
+ }
+ git_strmap_foreach_value(repo->submodule_cache, sm, {
+ git_submodule_free(sm);
+ });
+ git_strmap_free(repo->submodule_cache);
+ repo->submodule_cache = 0;
+ return 0;
+}
diff --git a/src/repository.h b/src/repository.h
index fd679b483..fd6400cc1 100644
--- a/src/repository.h
+++ b/src/repository.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_repository_h__
#define INCLUDE_repository_h__
+#include "common.h"
+
#include "git2/common.h"
#include "git2/oid.h"
#include "git2/odb.h"
@@ -31,6 +33,8 @@
/* Default DOS-compatible 8.3 "short name" for a git repository, "GIT~1" */
#define GIT_DIR_SHORTNAME "GIT~1"
+extern bool git_repository__fsync_gitdir;
+
/** Cvar cache identifiers */
typedef enum {
GIT_CVAR_AUTO_CRLF = 0, /* core.autocrlf */
@@ -46,6 +50,7 @@ typedef enum {
GIT_CVAR_LOGALLREFUPDATES, /* core.logallrefupdates */
GIT_CVAR_PROTECTHFS, /* core.protectHFS */
GIT_CVAR_PROTECTNTFS, /* core.protectNTFS */
+ GIT_CVAR_FSYNCOBJECTFILES, /* core.fsyncObjectFiles */
GIT_CVAR_CACHE_MAX
} git_cvar_cached;
@@ -106,6 +111,8 @@ typedef enum {
GIT_PROTECTHFS_DEFAULT = GIT_CVAR_FALSE,
/* core.protectNTFS */
GIT_PROTECTNTFS_DEFAULT = GIT_CVAR_FALSE,
+ /* core.fsyncObjectFiles */
+ GIT_FSYNCOBJECTFILES_DEFAULT = GIT_CVAR_FALSE,
} git_cvar_value;
/* internal repository init flags */
@@ -126,8 +133,9 @@ struct git_repository {
git_attr_cache *attrcache;
git_diff_driver_registry *diff_drivers;
- char *path_repository;
- char *path_gitlink;
+ char *gitlink;
+ char *gitdir;
+ char *commondir;
char *workdir;
char *namespace;
@@ -137,12 +145,14 @@ struct git_repository {
git_array_t(git_buf) reserved_names;
unsigned is_bare:1;
+ unsigned is_worktree:1;
unsigned int lru_counter;
git_atomic attr_session_key;
git_cvar_value cvar_cache[GIT_CVAR_CACHE_MAX];
+ git_strmap *submodule_cache;
};
GIT_INLINE(git_attr_cache *) git_repository_attr_cache(git_repository *repo)
@@ -151,6 +161,27 @@ GIT_INLINE(git_attr_cache *) git_repository_attr_cache(git_repository *repo)
}
int git_repository_head_tree(git_tree **tree, git_repository *repo);
+int git_repository_create_head(const char *git_dir, const char *ref_name);
+
+/*
+ * Called for each HEAD.
+ *
+ * Can return either 0, causing the iteration over HEADs to
+ * continue, or a non-0 value causing the iteration to abort. The
+ * return value is passed back to the caller of
+ * `git_repository_foreach_head`
+ */
+typedef int (*git_repository_foreach_head_cb)(git_repository *repo, const char *path, void *payload);
+
+/*
+ * Iterate over repository and all worktree HEADs.
+ *
+ * This function will be called for the repository HEAD and for
+ * all HEADS of linked worktrees. For each HEAD, the callback is
+ * executed with the given payload. The return value equals the
+ * return value of the last executed callback function.
+ */
+int git_repository_foreach_head(git_repository *repo, git_repository_foreach_head_cb cb, void *payload);
/*
* Weak pointers to repository internals.
@@ -182,7 +213,7 @@ GIT_INLINE(int) git_repository__ensure_not_bare(
giterr_set(
GITERR_REPOSITORY,
- "Cannot %s. This operation is not allowed against bare repositories.",
+ "cannot %s. This operation is not allowed against bare repositories.",
operation_name);
return GIT_EBAREREPO;
diff --git a/src/reset.c b/src/reset.c
index db0bfb373..21596812f 100644
--- a/src/reset.c
+++ b/src/reset.c
@@ -6,6 +6,7 @@
*/
#include "common.h"
+
#include "commit.h"
#include "tag.h"
#include "merge.h"
@@ -20,8 +21,8 @@
int git_reset_default(
git_repository *repo,
- git_object *target,
- git_strarray* pathspecs)
+ const git_object *target,
+ const git_strarray* pathspecs)
{
git_object *commit = NULL;
git_tree *tree = NULL;
@@ -100,7 +101,7 @@ cleanup:
static int reset(
git_repository *repo,
- git_object *target,
+ const git_object *target,
const char *to,
git_reset_t reset_type,
const git_checkout_options *checkout_opts)
@@ -137,7 +138,7 @@ static int reset(
(git_repository_state(repo) == GIT_REPOSITORY_STATE_MERGE ||
git_index_has_conflicts(index)))
{
- giterr_set(GITERR_OBJECT, "%s (soft) in the middle of a merge.", ERROR_MSG);
+ giterr_set(GITERR_OBJECT, "%s (soft) in the middle of a merge", ERROR_MSG);
error = GIT_EUNMERGED;
goto cleanup;
}
@@ -182,7 +183,7 @@ cleanup:
int git_reset(
git_repository *repo,
- git_object *target,
+ const git_object *target,
git_reset_t reset_type,
const git_checkout_options *checkout_opts)
{
@@ -191,7 +192,7 @@ int git_reset(
int git_reset_from_annotated(
git_repository *repo,
- git_annotated_commit *commit,
+ const git_annotated_commit *commit,
git_reset_t reset_type,
const git_checkout_options *checkout_opts)
{
diff --git a/src/revert.c b/src/revert.c
index c481e7dea..54f6d48e4 100644
--- a/src/revert.c
+++ b/src/revert.c
@@ -6,6 +6,7 @@
*/
#include "common.h"
+
#include "repository.h"
#include "filebuf.h"
#include "merge.h"
@@ -27,7 +28,7 @@ static int write_revert_head(
git_buf file_path = GIT_BUF_INIT;
int error = 0;
- if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_REVERT_HEAD_FILE)) >= 0 &&
+ if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_REVERT_HEAD_FILE)) >= 0 &&
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_REVERT_FILE_MODE)) >= 0 &&
(error = git_filebuf_printf(&file, "%s\n", commit_oidstr)) >= 0)
error = git_filebuf_commit(&file);
@@ -49,7 +50,7 @@ static int write_merge_msg(
git_buf file_path = GIT_BUF_INIT;
int error = 0;
- if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_MSG_FILE)) < 0 ||
+ if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MSG_FILE)) < 0 ||
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_REVERT_FILE_MODE)) < 0 ||
(error = git_filebuf_printf(&file, "Revert \"%s\"\n\nThis reverts commit %s.\n",
commit_msgline, commit_oidstr)) < 0)
@@ -133,13 +134,13 @@ int git_revert_commit(
if (git_commit_parentcount(revert_commit) > 1) {
if (!mainline)
return revert_seterr(revert_commit,
- "Mainline branch is not specified but %s is a merge commit");
+ "mainline branch is not specified but %s is a merge commit");
parent = mainline;
} else {
if (mainline)
return revert_seterr(revert_commit,
- "Mainline branch specified but %s is not a merge commit");
+ "mainline branch specified but %s is not a merge commit");
parent = git_commit_parentcount(revert_commit);
}
diff --git a/src/revparse.c b/src/revparse.c
index e0ec3941d..4ab4fb96d 100644
--- a/src/revparse.c
+++ b/src/revparse.c
@@ -5,9 +5,10 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "common.h"
+
#include <assert.h>
-#include "common.h"
#include "buffer.h"
#include "tree.h"
#include "refdb.h"
@@ -46,11 +47,11 @@ static int build_regex(regex_t *regex, const char *pattern)
int error;
if (*pattern == '\0') {
- giterr_set(GITERR_REGEX, "Empty pattern");
+ giterr_set(GITERR_REGEX, "empty pattern");
return GIT_EINVALIDSPEC;
}
- error = regcomp(regex, pattern, REG_EXTENDED);
+ error = p_regcomp(regex, pattern, REG_EXTENDED);
if (!error)
return 0;
@@ -118,7 +119,7 @@ static int revparse_lookup_object(
if ((error = maybe_describe(object_out, repo, spec)) != GIT_ENOTFOUND)
return error;
- giterr_set(GITERR_REFERENCE, "Revspec '%s' not found.", spec);
+ giterr_set(GITERR_REFERENCE, "revspec '%s' not found", spec);
return GIT_ENOTFOUND;
}
@@ -245,7 +246,7 @@ static int retrieve_oid_from_reflog(git_oid *oid, git_reference *ref, size_t ide
notfound:
giterr_set(
GITERR_REFERENCE,
- "Reflog for '%s' has only %"PRIuZ" entries, asked for %"PRIuZ,
+ "reflog for '%s' has only %"PRIuZ" entries, asked for %"PRIuZ,
git_reference_name(ref), numentries, identifier);
git_reflog_free(reflog);
@@ -757,7 +758,7 @@ int revparse__ext(
* TODO: support merge-stage path lookup (":2:Makefile")
* and plain index blob lookup (:i-am/a/blob)
*/
- giterr_set(GITERR_INVALID, "Unimplemented");
+ giterr_set(GITERR_INVALID, "unimplemented");
error = GIT_ERROR;
goto cleanup;
}
@@ -816,7 +817,7 @@ cleanup:
if (error) {
if (error == GIT_EINVALIDSPEC)
giterr_set(GITERR_INVALID,
- "Failed to parse revision specifier - Invalid pattern '%s'", spec);
+ "failed to parse revision specifier - Invalid pattern '%s'", spec);
git_object_free(base_rev);
git_reference_free(reference);
@@ -892,6 +893,17 @@ int git_revparse(
const char *rstr;
revspec->flags = GIT_REVPARSE_RANGE;
+ /*
+ * Following git.git, don't allow '..' because it makes command line
+ * arguments which can be either paths or revisions ambiguous when the
+ * path is almost certainly intended. The empty range '...' is still
+ * allowed.
+ */
+ if (!git__strcmp(spec, "..")) {
+ giterr_set(GITERR_INVALID, "Invalid pattern '..'");
+ return GIT_EINVALIDSPEC;
+ }
+
lstr = git__substrdup(spec, dotdot - spec);
rstr = dotdot + 2;
if (dotdot[2] == '.') {
@@ -899,9 +911,17 @@ int git_revparse(
rstr++;
}
- error = git_revparse_single(&revspec->from, repo, lstr);
- if (!error)
- error = git_revparse_single(&revspec->to, repo, rstr);
+ error = git_revparse_single(
+ &revspec->from,
+ repo,
+ *lstr == '\0' ? "HEAD" : lstr);
+
+ if (!error) {
+ error = git_revparse_single(
+ &revspec->to,
+ repo,
+ *rstr == '\0' ? "HEAD" : rstr);
+ }
git__free((void*)lstr);
} else {
diff --git a/src/revwalk.c b/src/revwalk.c
index 4815a1089..b1aa8f91a 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -5,16 +5,15 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+#include "revwalk.h"
+
#include "commit.h"
#include "odb.h"
#include "pool.h"
-#include "revwalk.h"
#include "git2/revparse.h"
#include "merge.h"
-
-GIT__USE_OIDMAP
+#include "vector.h"
git_commit_list_node *git_revwalk__commit_lookup(
git_revwalk *walk, const git_oid *oid)
@@ -24,9 +23,9 @@ git_commit_list_node *git_revwalk__commit_lookup(
int ret;
/* lookup and reserve space if not already present */
- pos = kh_get(oid, walk->commits, oid);
- if (pos != kh_end(walk->commits))
- return kh_value(walk->commits, pos);
+ pos = git_oidmap_lookup_index(walk->commits, oid);
+ if (git_oidmap_valid_index(walk->commits, pos))
+ return git_oidmap_value_at(walk->commits, pos);
commit = git_commit_list_alloc_node(walk);
if (commit == NULL)
@@ -34,104 +33,13 @@ git_commit_list_node *git_revwalk__commit_lookup(
git_oid_cpy(&commit->oid, oid);
- pos = kh_put(oid, walk->commits, &commit->oid, &ret);
+ pos = git_oidmap_put(walk->commits, &commit->oid, &ret);
assert(ret != 0);
- kh_value(walk->commits, pos) = commit;
+ git_oidmap_set_value_at(walk->commits, pos, commit);
return commit;
}
-typedef git_array_t(git_commit_list_node*) commit_list_node_array;
-
-static bool interesting_arr(commit_list_node_array arr)
-{
- git_commit_list_node **n;
- size_t i = 0, size;
-
- size = git_array_size(arr);
- for (i = 0; i < size; i++) {
- n = git_array_get(arr, i);
- if (!*n)
- break;
-
- if (!(*n)->uninteresting)
- return true;
- }
-
- return false;
-}
-
-static int mark_uninteresting(git_revwalk *walk, git_commit_list_node *commit)
-{
- int error;
- unsigned short i;
- commit_list_node_array pending = GIT_ARRAY_INIT;
- git_commit_list_node **tmp;
-
- assert(commit);
-
- do {
- commit->uninteresting = 1;
-
- if ((error = git_commit_list_parse(walk, commit)) < 0)
- return error;
-
- for (i = 0; i < commit->out_degree; ++i)
- if (!commit->parents[i]->uninteresting) {
- git_commit_list_node **node = git_array_alloc(pending);
- GITERR_CHECK_ALLOC(node);
- *node = commit->parents[i];
- }
-
- tmp = git_array_pop(pending);
- commit = tmp ? *tmp : NULL;
-
- } while (commit != NULL && !interesting_arr(pending));
-
- git_array_clear(pending);
-
- return 0;
-}
-
-static int process_commit(git_revwalk *walk, git_commit_list_node *commit, int hide)
-{
- int error;
-
- if (!hide && walk->hide_cb)
- hide = walk->hide_cb(&commit->oid, walk->hide_cb_payload);
-
- if (hide && mark_uninteresting(walk, commit) < 0)
- return -1;
-
- if (commit->seen)
- return 0;
-
- commit->seen = 1;
-
- if ((error = git_commit_list_parse(walk, commit)) < 0)
- return error;
-
- if (!hide)
- return walk->enqueue(walk, commit);
-
- return 0;
-}
-
-static int process_commit_parents(git_revwalk *walk, git_commit_list_node *commit)
-{
- unsigned short i, max;
- int error = 0;
-
- max = commit->out_degree;
- if (walk->first_parent && commit->out_degree)
- max = 1;
-
- for (i = 0; i < max && !error; ++i)
- error = process_commit(walk, commit->parents[i], commit->uninteresting);
-
- return error;
-}
-
static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting, int from_glob)
{
git_oid commit_id;
@@ -151,7 +59,7 @@ static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting,
if (from_glob)
return 0;
- giterr_set(GITERR_INVALID, "Object is not a committish");
+ giterr_set(GITERR_INVALID, "object is not a committish");
return -1;
}
if (error < 0)
@@ -288,7 +196,7 @@ int git_revwalk_push_range(git_revwalk *walk, const char *range)
if (revspec.flags & GIT_REVPARSE_MERGE_BASE) {
/* TODO: support "<commit>...<commit>" */
- giterr_set(GITERR_INVALID, "Symmetric differences not implemented in revwalk");
+ giterr_set(GITERR_INVALID, "symmetric differences not implemented in revwalk");
return GIT_EINVALIDSPEC;
}
@@ -321,17 +229,15 @@ static int revwalk_enqueue_unsorted(git_revwalk *walk, git_commit_list_node *com
static int revwalk_next_timesort(git_commit_list_node **object_out, git_revwalk *walk)
{
- int error;
git_commit_list_node *next;
- while ((next = git_pqueue_pop(&walk->iterator_time)) != NULL)
+ while ((next = git_pqueue_pop(&walk->iterator_time)) != NULL) {
+ /* Some commits might become uninteresting after being added to the list */
if (!next->uninteresting) {
- if ((error = process_commit_parents(walk, next)) < 0)
- return error;
-
*object_out = next;
return 0;
}
+ }
giterr_clear();
return GIT_ITEROVER;
@@ -339,17 +245,15 @@ static int revwalk_next_timesort(git_commit_list_node **object_out, git_revwalk
static int revwalk_next_unsorted(git_commit_list_node **object_out, git_revwalk *walk)
{
- int error;
git_commit_list_node *next;
- while ((next = git_commit_list_pop(&walk->iterator_rand)) != NULL)
+ while ((next = git_commit_list_pop(&walk->iterator_rand)) != NULL) {
+ /* Some commits might become uninteresting after being added to the list */
if (!next->uninteresting) {
- if ((error = process_commit_parents(walk, next)) < 0)
- return error;
-
*object_out = next;
return 0;
}
+ }
giterr_clear();
return GIT_ITEROVER;
@@ -358,121 +262,283 @@ static int revwalk_next_unsorted(git_commit_list_node **object_out, git_revwalk
static int revwalk_next_toposort(git_commit_list_node **object_out, git_revwalk *walk)
{
git_commit_list_node *next;
- unsigned short i, max;
- for (;;) {
- next = git_commit_list_pop(&walk->iterator_topo);
- if (next == NULL) {
- giterr_clear();
- return GIT_ITEROVER;
+ while ((next = git_commit_list_pop(&walk->iterator_topo)) != NULL) {
+ /* Some commits might become uninteresting after being added to the list */
+ if (!next->uninteresting) {
+ *object_out = next;
+ return 0;
}
+ }
- if (next->in_degree > 0) {
- next->topo_delay = 1;
- continue;
+ giterr_clear();
+ return GIT_ITEROVER;
+}
+
+static int revwalk_next_reverse(git_commit_list_node **object_out, git_revwalk *walk)
+{
+ *object_out = git_commit_list_pop(&walk->iterator_reverse);
+ return *object_out ? 0 : GIT_ITEROVER;
+}
+
+static void mark_parents_uninteresting(git_commit_list_node *commit)
+{
+ unsigned short i;
+ git_commit_list *parents = NULL;
+
+ for (i = 0; i < commit->out_degree; i++)
+ git_commit_list_insert(commit->parents[i], &parents);
+
+
+ while (parents) {
+ commit = git_commit_list_pop(&parents);
+
+ while (commit) {
+ if (commit->uninteresting)
+ break;
+
+ commit->uninteresting = 1;
+ /*
+ * If we've reached this commit some other way
+ * already, we need to mark its parents uninteresting
+ * as well.
+ */
+ if (!commit->parents)
+ break;
+
+ for (i = 0; i < commit->out_degree; i++)
+ git_commit_list_insert(commit->parents[i], &parents);
+ commit = commit->parents[0];
}
+ }
+}
+
+static int add_parents_to_list(git_revwalk *walk, git_commit_list_node *commit, git_commit_list **list)
+{
+ unsigned short i;
+ int error;
+ if (commit->added)
+ return 0;
- max = next->out_degree;
- if (walk->first_parent && next->out_degree)
- max = 1;
+ commit->added = 1;
+
+ /*
+ * Go full on in the uninteresting case as we want to include
+ * as many of these as we can.
+ *
+ * Usually we haven't parsed the parent of a parent, but if we
+ * have it we reached it via other means so we want to mark
+ * its parents recursively too.
+ */
+ if (commit->uninteresting) {
+ for (i = 0; i < commit->out_degree; i++) {
+ git_commit_list_node *p = commit->parents[i];
+ p->uninteresting = 1;
- for (i = 0; i < max; ++i) {
- git_commit_list_node *parent = next->parents[i];
+ /* git does it gently here, but we don't like missing objects */
+ if ((error = git_commit_list_parse(walk, p)) < 0)
+ return error;
- if (--parent->in_degree == 0 && parent->topo_delay) {
- parent->topo_delay = 0;
- if (git_commit_list_insert(parent, &walk->iterator_topo) == NULL)
- return -1;
- }
+ if (p->parents)
+ mark_parents_uninteresting(p);
+
+ p->seen = 1;
+ git_commit_list_insert_by_date(p, list);
}
- *object_out = next;
return 0;
}
+
+ /*
+ * Now on to what we do if the commit is indeed
+ * interesting. Here we do want things like first-parent take
+ * effect as this is what we'll be showing.
+ */
+ for (i = 0; i < commit->out_degree; i++) {
+ git_commit_list_node *p = commit->parents[i];
+
+ if ((error = git_commit_list_parse(walk, p)) < 0)
+ return error;
+
+ if (walk->hide_cb && walk->hide_cb(&p->oid, walk->hide_cb_payload))
+ continue;
+
+ if (!p->seen) {
+ p->seen = 1;
+ git_commit_list_insert_by_date(p, list);
+ }
+
+ if (walk->first_parent)
+ break;
+ }
+ return 0;
}
-static int revwalk_next_reverse(git_commit_list_node **object_out, git_revwalk *walk)
+static int everybody_uninteresting(git_commit_list *orig)
{
- *object_out = git_commit_list_pop(&walk->iterator_reverse);
- return *object_out ? 0 : GIT_ITEROVER;
+ git_commit_list *list = orig;
+
+ while (list) {
+ git_commit_list_node *commit = list->item;
+ list = list->next;
+ if (!commit->uninteresting)
+ return 0;
+ }
+
+ return 1;
}
+/* How many unintersting commits we want to look at after we run out of interesting ones */
+#define SLOP 5
-static int interesting(git_pqueue *list)
+static int still_interesting(git_commit_list *list, int64_t time, int slop)
{
- size_t i;
+ /* The empty list is pretty boring */
+ if (!list)
+ return 0;
- for (i = 0; i < git_pqueue_size(list); i++) {
- git_commit_list_node *commit = git_pqueue_get(list, i);
- if (!commit->uninteresting)
- return 1;
- }
+ /*
+ * If the destination list has commits with an earlier date
+ * than our source we want to continue looking.
+ */
+ if (time <= list->item->time)
+ return SLOP;
- return 0;
+ /* If we find interesting commits, we reset the slop count */
+ if (!everybody_uninteresting(list))
+ return SLOP;
+
+ /* Everything's uninteresting, reduce the count */
+ return slop - 1;
}
-static int contains(git_pqueue *list, git_commit_list_node *node)
+static int limit_list(git_commit_list **out, git_revwalk *walk, git_commit_list *commits)
{
- size_t i;
+ int error, slop = SLOP;
+ int64_t time = ~0ll;
+ git_commit_list *list = commits;
+ git_commit_list *newlist = NULL;
+ git_commit_list **p = &newlist;
+
+ while (list) {
+ git_commit_list_node *commit = git_commit_list_pop(&list);
- for (i = 0; i < git_pqueue_size(list); i++) {
- git_commit_list_node *commit = git_pqueue_get(list, i);
- if (commit == node)
- return 1;
+ if ((error = add_parents_to_list(walk, commit, &list)) < 0)
+ return error;
+
+ if (commit->uninteresting) {
+ mark_parents_uninteresting(commit);
+
+ slop = still_interesting(list, time, slop);
+ if (slop)
+ continue;
+
+ break;
+ }
+
+ if (!commit->uninteresting && walk->hide_cb && walk->hide_cb(&commit->oid, walk->hide_cb_payload))
+ continue;
+
+ time = commit->time;
+ p = &git_commit_list_insert(commit, p)->next;
}
+ git_commit_list_free(&list);
+ *out = newlist;
return 0;
}
-static int premark_uninteresting(git_revwalk *walk)
+static int sort_in_topological_order(git_commit_list **out, git_revwalk *walk, git_commit_list *list)
{
- int error = 0;
+ git_commit_list *ll = NULL, *newlist, **pptr;
+ git_commit_list_node *next;
+ git_pqueue queue;
+ git_vector_cmp queue_cmp = NULL;
unsigned short i;
- git_pqueue q;
- git_commit_list *list;
- git_commit_list_node *commit, *parent;
+ int error;
- if ((error = git_pqueue_init(&q, 0, 8, git_commit_list_time_cmp)) < 0)
- return error;
+ if (walk->sorting & GIT_SORT_TIME)
+ queue_cmp = git_commit_list_time_cmp;
- for (list = walk->user_input; list; list = list->next) {
- if ((error = git_commit_list_parse(walk, list->item)) < 0)
- goto cleanup;
+ if ((error = git_pqueue_init(&queue, 0, 8, queue_cmp)))
+ return error;
- if ((error = git_pqueue_insert(&q, list->item)) < 0)
- goto cleanup;
+ /*
+ * Start by resetting the in-degree to 1 for the commits in
+ * our list. We want to go through this list again, so we
+ * store it in the commit list as we extract it from the lower
+ * machinery.
+ */
+ for (ll = list; ll; ll = ll->next) {
+ ll->item->in_degree = 1;
}
- while (interesting(&q)) {
- commit = git_pqueue_pop(&q);
-
- for (i = 0; i < commit->out_degree; i++) {
- parent = commit->parents[i];
+ /*
+ * Count up how many children each commit has. We limit
+ * ourselves to those commits in the original list (in-degree
+ * of 1) avoiding setting it for any parent that was hidden.
+ */
+ for(ll = list; ll; ll = ll->next) {
+ for (i = 0; i < ll->item->out_degree; ++i) {
+ git_commit_list_node *parent = ll->item->parents[i];
+ if (parent->in_degree)
+ parent->in_degree++;
+ }
+ }
- if ((error = git_commit_list_parse(walk, parent)) < 0)
+ /*
+ * Now we find the tips i.e. those not reachable from any other node
+ * i.e. those which still have an in-degree of 1.
+ */
+ for(ll = list; ll; ll = ll->next) {
+ if (ll->item->in_degree == 1) {
+ if ((error = git_pqueue_insert(&queue, ll->item)))
goto cleanup;
+ }
+ }
- if (commit->uninteresting)
- parent->uninteresting = 1;
+ /*
+ * We need to output the tips in the order that they came out of the
+ * traversal, so if we're not doing time-sorting, we need to reverse the
+ * pqueue in order to get them to come out as we inserted them.
+ */
+ if ((walk->sorting & GIT_SORT_TIME) == 0)
+ git_pqueue_reverse(&queue);
- if (contains(&q, parent))
+
+ pptr = &newlist;
+ newlist = NULL;
+ while ((next = git_pqueue_pop(&queue)) != NULL) {
+ for (i = 0; i < next->out_degree; ++i) {
+ git_commit_list_node *parent = next->parents[i];
+ if (parent->in_degree == 0)
continue;
- if ((error = git_pqueue_insert(&q, parent)) < 0)
- goto cleanup;
+ if (--parent->in_degree == 1) {
+ if ((error = git_pqueue_insert(&queue, parent)))
+ goto cleanup;
+ }
}
+
+ /* All the children of 'item' have been emitted (since we got to it via the priority queue) */
+ next->in_degree = 0;
+
+ pptr = &git_commit_list_insert(next, pptr)->next;
}
+ *out = newlist;
+ error = 0;
+
cleanup:
- git_pqueue_free(&q);
+ git_pqueue_free(&queue);
return error;
}
static int prepare_walk(git_revwalk *walk)
{
int error;
- git_commit_list *list;
+ git_commit_list *list, *commits = NULL;
git_commit_list_node *next;
/* If there were no pushes, we know that the walk is already over */
@@ -481,32 +547,42 @@ static int prepare_walk(git_revwalk *walk)
return GIT_ITEROVER;
}
- if (walk->did_hide && (error = premark_uninteresting(walk)) < 0)
- return error;
-
for (list = walk->user_input; list; list = list->next) {
- if (process_commit(walk, list->item, list->item->uninteresting) < 0)
- return -1;
- }
+ git_commit_list_node *commit = list->item;
+ if ((error = git_commit_list_parse(walk, commit)) < 0)
+ return error;
+ if (commit->uninteresting)
+ mark_parents_uninteresting(commit);
- if (walk->sorting & GIT_SORT_TOPOLOGICAL) {
- unsigned short i;
+ if (!commit->seen) {
+ commit->seen = 1;
+ git_commit_list_insert(commit, &commits);
+ }
+ }
- while ((error = walk->get_next(&next, walk)) == 0) {
- for (i = 0; i < next->out_degree; ++i) {
- git_commit_list_node *parent = next->parents[i];
- parent->in_degree++;
- }
+ if ((error = limit_list(&commits, walk, commits)) < 0)
+ return error;
- if (git_commit_list_insert(next, &walk->iterator_topo) == NULL)
- return -1;
- }
+ if (walk->sorting & GIT_SORT_TOPOLOGICAL) {
+ error = sort_in_topological_order(&walk->iterator_topo, walk, commits);
+ git_commit_list_free(&commits);
- if (error != GIT_ITEROVER)
+ if (error < 0)
return error;
walk->get_next = &revwalk_next_toposort;
+ } else if (walk->sorting & GIT_SORT_TIME) {
+ for (list = commits; list && !error; list = list->next)
+ error = walk->enqueue(walk, list->item);
+
+ git_commit_list_free(&commits);
+
+ if (error < 0)
+ return error;
+ } else {
+ walk->iterator_rand = commits;
+ walk->get_next = revwalk_next_unsorted;
}
if (walk->sorting & GIT_SORT_REVERSE) {
@@ -627,11 +703,12 @@ void git_revwalk_reset(git_revwalk *walk)
assert(walk);
- kh_foreach_value(walk->commits, commit, {
+ git_oidmap_foreach_value(walk->commits, commit, {
commit->seen = 0;
commit->in_degree = 0;
commit->topo_delay = 0;
commit->uninteresting = 0;
+ commit->added = 0;
commit->flags = 0;
});
@@ -657,7 +734,7 @@ int git_revwalk_add_hide_cb(
if (walk->hide_cb) {
/* There is already a callback added */
- giterr_set(GITERR_INVALID, "There is already a callback added to hide commits in revision walker.");
+ giterr_set(GITERR_INVALID, "there is already a callback added to hide commits in revwalk");
return -1;
}
diff --git a/src/revwalk.h b/src/revwalk.h
index 6b363d40f..578328b72 100644
--- a/src/revwalk.h
+++ b/src/revwalk.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_revwalk_h__
#define INCLUDE_revwalk_h__
+#include "common.h"
+
#include "git2/revwalk.h"
#include "oidmap.h"
#include "commit_list.h"
diff --git a/src/settings.c b/src/settings.c
index cb2317f74..ba2f6a4db 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -5,16 +5,20 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "common.h"
+
#ifdef GIT_OPENSSL
# include <openssl/err.h>
#endif
#include <git2.h>
-#include "common.h"
#include "sysdir.h"
#include "cache.h"
#include "global.h"
#include "object.h"
+#include "odb.h"
+#include "refs.h"
+#include "transports/smart.h"
void git_libgit2_version(int *major, int *minor, int *rev)
{
@@ -29,7 +33,9 @@ int git_libgit2_features(void)
#ifdef GIT_THREADS
| GIT_FEATURE_THREADS
#endif
+#ifdef GIT_HTTPS
| GIT_FEATURE_HTTPS
+#endif
#if defined(GIT_SSH)
| GIT_FEATURE_SSH
#endif
@@ -62,7 +68,7 @@ static int config_level_to_sysdir(int config_level)
break;
default:
giterr_set(
- GITERR_INVALID, "Invalid config path selector %d", config_level);
+ GITERR_INVALID, "invalid config path selector %d", config_level);
}
return val;
@@ -191,6 +197,10 @@ int git_libgit2_opts(int key, ...)
git_object__strict_input_validation = (va_arg(ap, int) != 0);
break;
+ case GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION:
+ git_reference__enable_symbolic_ref_target_validation = (va_arg(ap, int) != 0);
+ break;
+
case GIT_OPT_SET_SSL_CIPHERS:
#ifdef GIT_OPENSSL
{
@@ -215,6 +225,30 @@ int git_libgit2_opts(int key, ...)
}
break;
+ case GIT_OPT_ENABLE_OFS_DELTA:
+ git_smart__ofs_delta_enabled = (va_arg(ap, int) != 0);
+ break;
+
+ case GIT_OPT_ENABLE_FSYNC_GITDIR:
+ git_repository__fsync_gitdir = (va_arg(ap, int) != 0);
+ break;
+
+ case GIT_OPT_GET_WINDOWS_SHAREMODE:
+#ifdef GIT_WIN32
+ *(va_arg(ap, unsigned long *)) = git_win32__createfile_sharemode;
+#endif
+ break;
+
+ case GIT_OPT_SET_WINDOWS_SHAREMODE:
+#ifdef GIT_WIN32
+ git_win32__createfile_sharemode = va_arg(ap, unsigned long);
+#endif
+ break;
+
+ case GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION:
+ git_odb__strict_hash_verification = (va_arg(ap, int) != 0);
+ break;
+
default:
giterr_set(GITERR_INVALID, "invalid option key");
error = -1;
diff --git a/src/sha1_lookup.c b/src/sha1_lookup.c
index c6b561340..14fcb40e5 100644
--- a/src/sha1_lookup.c
+++ b/src/sha1_lookup.c
@@ -5,225 +5,11 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include <stdio.h>
-
#include "sha1_lookup.h"
-#include "common.h"
-#include "oid.h"
-/*
- * Conventional binary search loop looks like this:
- *
- * unsigned lo, hi;
- * do {
- * unsigned mi = (lo + hi) / 2;
- * int cmp = "entry pointed at by mi" minus "target";
- * if (!cmp)
- * return (mi is the wanted one)
- * if (cmp > 0)
- * hi = mi; "mi is larger than target"
- * else
- * lo = mi+1; "mi is smaller than target"
- * } while (lo < hi);
- *
- * The invariants are:
- *
- * - When entering the loop, lo points at a slot that is never
- * above the target (it could be at the target), hi points at a
- * slot that is guaranteed to be above the target (it can never
- * be at the target).
- *
- * - We find a point 'mi' between lo and hi (mi could be the same
- * as lo, but never can be as same as hi), and check if it hits
- * the target. There are three cases:
- *
- * - if it is a hit, we are happy.
- *
- * - if it is strictly higher than the target, we set it to hi,
- * and repeat the search.
- *
- * - if it is strictly lower than the target, we update lo to
- * one slot after it, because we allow lo to be at the target.
- *
- * If the loop exits, there is no matching entry.
- *
- * When choosing 'mi', we do not have to take the "middle" but
- * anywhere in between lo and hi, as long as lo <= mi < hi is
- * satisfied. When we somehow know that the distance between the
- * target and lo is much shorter than the target and hi, we could
- * pick mi that is much closer to lo than the midway.
- *
- * Now, we can take advantage of the fact that SHA-1 is a good hash
- * function, and as long as there are enough entries in the table, we
- * can expect uniform distribution. An entry that begins with for
- * example "deadbeef..." is much likely to appear much later than in
- * the midway of the table. It can reasonably be expected to be near
- * 87% (222/256) from the top of the table.
- *
- * However, we do not want to pick "mi" too precisely. If the entry at
- * the 87% in the above example turns out to be higher than the target
- * we are looking for, we would end up narrowing the search space down
- * only by 13%, instead of 50% we would get if we did a simple binary
- * search. So we would want to hedge our bets by being less aggressive.
- *
- * The table at "table" holds at least "nr" entries of "elem_size"
- * bytes each. Each entry has the SHA-1 key at "key_offset". The
- * table is sorted by the SHA-1 key of the entries. The caller wants
- * to find the entry with "key", and knows that the entry at "lo" is
- * not higher than the entry it is looking for, and that the entry at
- * "hi" is higher than the entry it is looking for.
- */
-int sha1_entry_pos(const void *table,
- size_t elem_size,
- size_t key_offset,
- unsigned lo, unsigned hi, unsigned nr,
- const unsigned char *key)
-{
- const unsigned char *base = (const unsigned char*)table;
- const unsigned char *hi_key, *lo_key;
- unsigned ofs_0;
-
- if (!nr || lo >= hi)
- return -1;
-
- if (nr == hi)
- hi_key = NULL;
- else
- hi_key = base + elem_size * hi + key_offset;
- lo_key = base + elem_size * lo + key_offset;
-
- ofs_0 = 0;
- do {
- int cmp;
- unsigned ofs, mi, range;
- unsigned lov, hiv, kyv;
- const unsigned char *mi_key;
-
- range = hi - lo;
- if (hi_key) {
- for (ofs = ofs_0; ofs < 20; ofs++)
- if (lo_key[ofs] != hi_key[ofs])
- break;
- ofs_0 = ofs;
- /*
- * byte 0 thru (ofs-1) are the same between
- * lo and hi; ofs is the first byte that is
- * different.
- *
- * If ofs==20, then no bytes are different,
- * meaning we have entries with duplicate
- * keys. We know that we are in a solid run
- * of this entry (because the entries are
- * sorted, and our lo and hi are the same,
- * there can be nothing but this single key
- * in between). So we can stop the search.
- * Either one of these entries is it (and
- * we do not care which), or we do not have
- * it.
- *
- * Furthermore, we know that one of our
- * endpoints must be the edge of the run of
- * duplicates. For example, given this
- * sequence:
- *
- * idx 0 1 2 3 4 5
- * key A C C C C D
- *
- * If we are searching for "B", we might
- * hit the duplicate run at lo=1, hi=3
- * (e.g., by first mi=3, then mi=0). But we
- * can never have lo > 1, because B < C.
- * That is, if our key is less than the
- * run, we know that "lo" is the edge, but
- * we can say nothing of "hi". Similarly,
- * if our key is greater than the run, we
- * know that "hi" is the edge, but we can
- * say nothing of "lo".
- *
- * Therefore if we do not find it, we also
- * know where it would go if it did exist:
- * just on the far side of the edge that we
- * know about.
- */
- if (ofs == 20) {
- mi = lo;
- mi_key = base + elem_size * mi + key_offset;
- cmp = memcmp(mi_key, key, 20);
- if (!cmp)
- return mi;
- if (cmp < 0)
- return -1 - hi;
- else
- return -1 - lo;
- }
-
- hiv = hi_key[ofs_0];
- if (ofs_0 < 19)
- hiv = (hiv << 8) | hi_key[ofs_0+1];
- } else {
- hiv = 256;
- if (ofs_0 < 19)
- hiv <<= 8;
- }
- lov = lo_key[ofs_0];
- kyv = key[ofs_0];
- if (ofs_0 < 19) {
- lov = (lov << 8) | lo_key[ofs_0+1];
- kyv = (kyv << 8) | key[ofs_0+1];
- }
- assert(lov < hiv);
-
- if (kyv < lov)
- return -1 - lo;
- if (hiv < kyv)
- return -1 - hi;
-
- /*
- * Even if we know the target is much closer to 'hi'
- * than 'lo', if we pick too precisely and overshoot
- * (e.g. when we know 'mi' is closer to 'hi' than to
- * 'lo', pick 'mi' that is higher than the target), we
- * end up narrowing the search space by a smaller
- * amount (i.e. the distance between 'mi' and 'hi')
- * than what we would have (i.e. about half of 'lo'
- * and 'hi'). Hedge our bets to pick 'mi' less
- * aggressively, i.e. make 'mi' a bit closer to the
- * middle than we would otherwise pick.
- */
- kyv = (kyv * 6 + lov + hiv) / 8;
- if (lov < hiv - 1) {
- if (kyv == lov)
- kyv++;
- else if (kyv == hiv)
- kyv--;
- }
- mi = (range - 1) * (kyv - lov) / (hiv - lov) + lo;
-
-#ifdef INDEX_DEBUG_LOOKUP
- printf("lo %u hi %u rg %u mi %u ", lo, hi, range, mi);
- printf("ofs %u lov %x, hiv %x, kyv %x\n",
- ofs_0, lov, hiv, kyv);
-#endif
-
- if (!(lo <= mi && mi < hi)) {
- giterr_set(GITERR_INVALID, "Assertion failure. Binary search invariant is false");
- return -1;
- }
+#include <stdio.h>
- mi_key = base + elem_size * mi + key_offset;
- cmp = memcmp(mi_key + ofs_0, key + ofs_0, 20 - ofs_0);
- if (!cmp)
- return mi;
- if (cmp > 0) {
- hi = mi;
- hi_key = mi_key;
- } else {
- lo = mi + 1;
- lo_key = mi_key + elem_size;
- }
- } while (lo < hi);
- return -((int)lo)-1;
-}
+#include "oid.h"
int sha1_position(const void *table,
size_t stride,
@@ -232,7 +18,7 @@ int sha1_position(const void *table,
{
const unsigned char *base = table;
- do {
+ while (lo < hi) {
unsigned mi = (lo + hi) / 2;
int cmp = git_oid__hashcmp(base + mi * stride, key);
@@ -243,7 +29,7 @@ int sha1_position(const void *table,
hi = mi;
else
lo = mi+1;
- } while (lo < hi);
+ }
return -((int)lo)-1;
}
diff --git a/src/sha1_lookup.h b/src/sha1_lookup.h
index 3799620c7..841ea5b22 100644
--- a/src/sha1_lookup.h
+++ b/src/sha1_lookup.h
@@ -7,13 +7,9 @@
#ifndef INCLUDE_sha1_lookup_h__
#define INCLUDE_sha1_lookup_h__
-#include <stdlib.h>
+#include "common.h"
-int sha1_entry_pos(const void *table,
- size_t elem_size,
- size_t key_offset,
- unsigned lo, unsigned hi, unsigned nr,
- const unsigned char *key);
+#include <stdlib.h>
int sha1_position(const void *table,
size_t stride,
diff --git a/src/signature.c b/src/signature.c
index dcc379717..bc3cf330a 100644
--- a/src/signature.c
+++ b/src/signature.c
@@ -5,8 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
#include "signature.h"
+
#include "repository.h"
#include "git2/common.h"
#include "posix.h"
@@ -25,7 +25,7 @@ void git_signature_free(git_signature *sig)
static int signature_error(const char *msg)
{
- giterr_set(GITERR_INVALID, "Failed to parse signature - %s", msg);
+ giterr_set(GITERR_INVALID, "failed to parse signature - %s", msg);
return -1;
}
@@ -228,8 +228,12 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
const char *time_start = email_end + 2;
const char *time_end;
- if (git__strtol64(&sig->when.time, time_start, &time_end, 10) < 0)
+ if (git__strtol64(&sig->when.time, time_start, &time_end, 10) < 0) {
+ git__free(sig->name);
+ git__free(sig->email);
+ sig->name = sig->email = NULL;
return signature_error("invalid Unix timestamp");
+ }
/* do we have a timezone? */
if (time_end + 1 < buffer_end) {
@@ -251,7 +255,7 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
* only store timezone if it's not overflowing;
* see http://www.worldtimezone.com/faq.html
*/
- if (hours < 14 && mins < 59) {
+ if (hours <= 14 && mins <= 59) {
sig->when.offset = (hours * 60) + mins;
if (tz_start[0] == '-')
sig->when.offset = -sig->when.offset;
diff --git a/src/signature.h b/src/signature.h
index 75265df52..40d7c54f9 100644
--- a/src/signature.h
+++ b/src/signature.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_signature_h__
#define INCLUDE_signature_h__
+#include "common.h"
+
#include "git2/common.h"
#include "git2/signature.h"
#include "repository.h"
diff --git a/src/socket_stream.c b/src/socket_stream.c
index 71f49118e..4c795e462 100644
--- a/src/socket_stream.c
+++ b/src/socket_stream.c
@@ -5,11 +5,11 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+#include "socket_stream.h"
+
#include "posix.h"
#include "netops.h"
#include "stream.h"
-#include "socket_stream.h"
#ifndef _WIN32
# include <sys/types.h>
@@ -57,7 +57,7 @@ static int close_socket(GIT_SOCKET s)
return -1;
if (0 != WSACleanup()) {
- giterr_set(GITERR_OS, "Winsock cleanup failed");
+ giterr_set(GITERR_OS, "winsock cleanup failed");
return -1;
}
@@ -82,13 +82,13 @@ int socket_connect(git_stream *stream)
WSADATA wsd;
if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) {
- giterr_set(GITERR_OS, "Winsock init failed");
+ giterr_set(GITERR_OS, "winsock init failed");
return -1;
}
if (LOBYTE(wsd.wVersion) != 2 || HIBYTE(wsd.wVersion) != 2) {
WSACleanup();
- giterr_set(GITERR_OS, "Winsock init failed");
+ giterr_set(GITERR_OS, "winsock init failed");
return -1;
}
#endif
@@ -99,17 +99,15 @@ int socket_connect(git_stream *stream)
if ((ret = p_getaddrinfo(st->host, st->port, &hints, &info)) != 0) {
giterr_set(GITERR_NET,
- "Failed to resolve address for %s: %s", st->host, p_gai_strerror(ret));
+ "failed to resolve address for %s: %s", st->host, p_gai_strerror(ret));
return -1;
}
for (p = info; p != NULL; p = p->ai_next) {
s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
- if (s == INVALID_SOCKET) {
- net_set_error("error creating socket");
- break;
- }
+ if (s == INVALID_SOCKET)
+ continue;
if (connect(s, p->ai_addr, (socklen_t)p->ai_addrlen) == 0)
break;
@@ -121,7 +119,7 @@ int socket_connect(git_stream *stream)
/* Oops, we couldn't connect to any address */
if (s == INVALID_SOCKET && p == NULL) {
- giterr_set(GITERR_OS, "Failed to connect to %s", st->host);
+ giterr_set(GITERR_OS, "failed to connect to %s", st->host);
p_freeaddrinfo(info);
return -1;
}
diff --git a/src/socket_stream.h b/src/socket_stream.h
index 8e9949fcd..1f9ff78d1 100644
--- a/src/socket_stream.h
+++ b/src/socket_stream.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_socket_stream_h__
#define INCLUDE_socket_stream_h__
+#include "common.h"
+
#include "netops.h"
typedef struct {
diff --git a/src/sortedcache.c b/src/sortedcache.c
index 5c2a167a7..76672d9f7 100644
--- a/src/sortedcache.c
+++ b/src/sortedcache.c
@@ -1,6 +1,11 @@
-#include "sortedcache.h"
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
-GIT__USE_STRMAP
+#include "sortedcache.h"
int git_sortedcache_new(
git_sortedcache **out,
@@ -27,7 +32,7 @@ int git_sortedcache_new(
goto fail;
if (git_rwlock_init(&sc->lock)) {
- giterr_set(GITERR_OS, "Failed to initialize lock");
+ giterr_set(GITERR_OS, "failed to initialize lock");
goto fail;
}
@@ -162,7 +167,7 @@ int git_sortedcache_wlock(git_sortedcache *sc)
GIT_UNUSED(sc); /* prevent warning when compiled w/o threads */
if (git_rwlock_wrlock(&sc->lock) < 0) {
- giterr_set(GITERR_OS, "Unable to acquire write lock on cache");
+ giterr_set(GITERR_OS, "unable to acquire write lock on cache");
return -1;
}
return 0;
@@ -181,7 +186,7 @@ int git_sortedcache_rlock(git_sortedcache *sc)
GIT_UNUSED(sc); /* prevent warning when compiled w/o threads */
if (git_rwlock_rdlock(&sc->lock) < 0) {
- giterr_set(GITERR_OS, "Unable to acquire read lock on cache");
+ giterr_set(GITERR_OS, "unable to acquire read lock on cache");
return -1;
}
return 0;
@@ -200,6 +205,7 @@ void git_sortedcache_runlock(git_sortedcache *sc)
int git_sortedcache_lockandload(git_sortedcache *sc, git_buf *buf)
{
int error, fd;
+ struct stat st;
if ((error = git_sortedcache_wlock(sc)) < 0)
return error;
@@ -207,19 +213,27 @@ int git_sortedcache_lockandload(git_sortedcache *sc, git_buf *buf)
if ((error = git_futils_filestamp_check(&sc->stamp, sc->path)) <= 0)
goto unlock;
- if (!git__is_sizet(sc->stamp.size)) {
- giterr_set(GITERR_INVALID, "Unable to load file larger than size_t");
+ if ((fd = git_futils_open_ro(sc->path)) < 0) {
+ error = fd;
+ goto unlock;
+ }
+
+ if (p_fstat(fd, &st) < 0) {
+ giterr_set(GITERR_OS, "failed to stat file");
error = -1;
+ (void)p_close(fd);
goto unlock;
}
- if ((fd = git_futils_open_ro(sc->path)) < 0) {
- error = fd;
+ if (!git__is_sizet(st.st_size)) {
+ giterr_set(GITERR_INVALID, "unable to load file larger than size_t");
+ error = -1;
+ (void)p_close(fd);
goto unlock;
}
if (buf)
- error = git_futils_readbuffer_fd(buf, fd, (size_t)sc->stamp.size);
+ error = git_futils_readbuffer_fd(buf, fd, (size_t)st.st_size);
(void)p_close(fd);
@@ -285,13 +299,13 @@ int git_sortedcache_upsert(void **out, git_sortedcache *sc, const char *key)
item_key = ((char *)item) + sc->item_path_offset;
memcpy(item_key, key, keylen);
- pos = kh_put(str, sc->map, item_key, &error);
+ pos = git_strmap_put(sc->map, item_key, &error);
if (error < 0)
goto done;
if (!error)
- kh_key(sc->map, pos) = item_key;
- kh_val(sc->map, pos) = item;
+ git_strmap_set_key_at(sc->map, pos, item_key);
+ git_strmap_set_value_at(sc->map, pos, item);
error = git_vector_insert(&sc->items, item);
if (error < 0)
@@ -364,7 +378,7 @@ int git_sortedcache_remove(git_sortedcache *sc, size_t pos)
*/
if ((item = git_vector_get(&sc->items, pos)) == NULL) {
- giterr_set(GITERR_INVALID, "Removing item out of range");
+ giterr_set(GITERR_INVALID, "removing item out of range");
return GIT_ENOTFOUND;
}
diff --git a/src/sortedcache.h b/src/sortedcache.h
index 4cacad62b..a53ff48a3 100644
--- a/src/sortedcache.h
+++ b/src/sortedcache.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_sorted_cache_h__
#define INCLUDE_sorted_cache_h__
+#include "common.h"
+
#include "util.h"
#include "fileops.h"
#include "vector.h"
diff --git a/src/stash.c b/src/stash.c
index f5f4f36bf..8a8c57a83 100644
--- a/src/stash.c
+++ b/src/stash.c
@@ -6,6 +6,7 @@
*/
#include "common.h"
+
#include "repository.h"
#include "commit.h"
#include "message.h"
@@ -27,7 +28,7 @@
static int create_error(int error, const char *msg)
{
- giterr_set(GITERR_STASH, "Cannot stash changes - %s", msg);
+ giterr_set(GITERR_STASH, "cannot stash changes - %s", msg);
return error;
}
@@ -36,7 +37,7 @@ static int retrieve_head(git_reference **out, git_repository *repo)
int error = git_repository_head(out, repo);
if (error == GIT_EUNBORNBRANCH)
- return create_error(error, "You do not have the initial commit yet.");
+ return create_error(error, "you do not have the initial commit yet.");
return error;
}
@@ -198,7 +199,7 @@ static int stash_update_index_from_diff(
/* Unimplemented */
giterr_set(
GITERR_INVALID,
- "Cannot update index. Unimplemented status (%d)",
+ "cannot update index. Unimplemented status (%d)",
delta->status);
return -1;
}
@@ -479,7 +480,7 @@ static int ensure_there_are_changes_to_stash(
return 0;
if (!error)
- return create_error(GIT_ENOTFOUND, "There is nothing to stash.");
+ return create_error(GIT_ENOTFOUND, "there is nothing to stash.");
return error;
}
@@ -593,7 +594,7 @@ static int retrieve_stash_commit(
max = git_reflog_entrycount(reflog);
if (!max || index > max - 1) {
error = GIT_ENOTFOUND;
- giterr_set(GITERR_STASH, "No stashed state at position %" PRIuZ, index);
+ giterr_set(GITERR_STASH, "no stashed state at position %" PRIuZ, index);
goto cleanup;
}
@@ -1036,7 +1037,7 @@ int git_stash_drop(
if (!max || index > max - 1) {
error = GIT_ENOTFOUND;
- giterr_set(GITERR_STASH, "No stashed state at position %" PRIuZ, index);
+ giterr_set(GITERR_STASH, "no stashed state at position %" PRIuZ, index);
goto cleanup;
}
diff --git a/src/status.c b/src/status.c
index e610f5fe1..03682bc72 100644
--- a/src/status.c
+++ b/src/status.c
@@ -5,13 +5,13 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+#include "status.h"
+
#include "git2.h"
#include "fileops.h"
#include "hash.h"
#include "vector.h"
#include "tree.h"
-#include "status.h"
#include "git2/status.h"
#include "repository.h"
#include "ignore.h"
@@ -243,13 +243,13 @@ static int status_validate_options(const git_status_options *opts)
GITERR_CHECK_VERSION(opts, GIT_STATUS_OPTIONS_VERSION, "git_status_options");
if (opts->show > GIT_STATUS_SHOW_WORKDIR_ONLY) {
- giterr_set(GITERR_INVALID, "Unknown status 'show' option");
+ giterr_set(GITERR_INVALID, "unknown status 'show' option");
return -1;
}
if ((opts->flags & GIT_STATUS_OPT_NO_REFRESH) != 0 &&
(opts->flags & GIT_STATUS_OPT_UPDATE_INDEX) != 0) {
- giterr_set(GITERR_INVALID, "Updating index from status "
+ giterr_set(GITERR_INVALID, "updating index from status "
"is not allowed when index refresh is disabled");
return -1;
}
@@ -510,13 +510,13 @@ int git_status_file(
if (error < 0 && sfi.ambiguous) {
giterr_set(GITERR_INVALID,
- "Ambiguous path '%s' given to git_status_file", sfi.expected);
+ "ambiguous path '%s' given to git_status_file", sfi.expected);
error = GIT_EAMBIGUOUS;
}
if (!error && !sfi.count) {
giterr_set(GITERR_INVALID,
- "Attempt to get status of nonexistent file '%s'", path);
+ "attempt to get status of nonexistent file '%s'", path);
error = GIT_ENOTFOUND;
}
diff --git a/src/status.h b/src/status.h
index 33008b89c..907479a22 100644
--- a/src/status.h
+++ b/src/status.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_status_h__
#define INCLUDE_status_h__
+#include "common.h"
+
#include "diff.h"
#include "git2/status.h"
#include "git2/diff.h"
diff --git a/src/stransport_stream.c b/src/stransport_stream.c
index 50ed9452c..18371ef92 100644
--- a/src/stransport_stream.c
+++ b/src/stransport_stream.c
@@ -5,6 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "stransport_stream.h"
+
#ifdef GIT_SECURE_TRANSPORT
#include <CoreFoundation/CoreFoundation.h>
diff --git a/src/stransport_stream.h b/src/stransport_stream.h
index 714f90273..f5bbfd952 100644
--- a/src/stransport_stream.h
+++ b/src/stransport_stream.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_stransport_stream_h__
#define INCLUDE_stransport_stream_h__
+#include "common.h"
+
#include "git2/sys/stream.h"
extern int git_stransport_stream_new(git_stream **out, const char *host, const char *port);
diff --git a/src/strmap.c b/src/strmap.c
index b26a13d1f..de6826d03 100644
--- a/src/strmap.c
+++ b/src/strmap.c
@@ -7,6 +7,101 @@
#include "strmap.h"
+__KHASH_IMPL(str, static kh_inline, const char *, void *, 1, kh_str_hash_func, kh_str_hash_equal)
+
+int git_strmap_alloc(git_strmap **map)
+{
+ if ((*map = kh_init(str)) == NULL) {
+ giterr_set_oom();
+ return -1;
+ }
+
+ return 0;
+}
+
+void git_strmap_free(git_strmap *map)
+{
+ kh_destroy(str, map);
+}
+
+void git_strmap_clear(git_strmap *map)
+{
+ kh_clear(str, map);
+}
+
+size_t git_strmap_num_entries(git_strmap *map)
+{
+ return kh_size(map);
+}
+
+size_t git_strmap_lookup_index(git_strmap *map, const char *key)
+{
+ return kh_get(str, map, key);
+}
+
+int git_strmap_valid_index(git_strmap *map, size_t idx)
+{
+ return idx != kh_end(map);
+}
+
+int git_strmap_exists(git_strmap *map, const char *key)
+{
+ return kh_get(str, map, key) != kh_end(map);
+}
+
+int git_strmap_has_data(git_strmap *map, size_t idx)
+{
+ return kh_exist(map, idx);
+}
+
+const char *git_strmap_key(git_strmap *map, size_t idx)
+{
+ return kh_key(map, idx);
+}
+
+void git_strmap_set_key_at(git_strmap *map, size_t idx, char *key)
+{
+ kh_val(map, idx) = key;
+}
+
+void *git_strmap_value_at(git_strmap *map, size_t idx)
+{
+ return kh_val(map, idx);
+}
+
+void git_strmap_set_value_at(git_strmap *map, size_t idx, void *value)
+{
+ kh_val(map, idx) = value;
+}
+
+void git_strmap_delete_at(git_strmap *map, size_t idx)
+{
+ kh_del(str, map, idx);
+}
+
+int git_strmap_put(git_strmap *map, const char *key, int *err)
+{
+ return kh_put(str, map, key, err);
+}
+
+void git_strmap_insert(git_strmap *map, const char *key, void *value, int *rval)
+{
+ khiter_t idx = kh_put(str, map, key, rval);
+
+ if ((*rval) >= 0) {
+ if ((*rval) == 0)
+ kh_key(map, idx) = key;
+ kh_val(map, idx) = value;
+ }
+}
+
+void git_strmap_delete(git_strmap *map, const char *key)
+{
+ khiter_t idx = git_strmap_lookup_index(map, key);
+ if (git_strmap_valid_index(map, idx))
+ git_strmap_delete_at(map, idx);
+}
+
int git_strmap_next(
void **data,
git_strmap_iter* iter,
diff --git a/src/strmap.h b/src/strmap.h
index 520984744..802b92494 100644
--- a/src/strmap.h
+++ b/src/strmap.h
@@ -20,49 +20,27 @@ __KHASH_TYPE(str, const char *, void *)
typedef khash_t(str) git_strmap;
typedef khiter_t git_strmap_iter;
-#define GIT__USE_STRMAP \
- __KHASH_IMPL(str, static kh_inline, const char *, void *, 1, kh_str_hash_func, kh_str_hash_equal)
+int git_strmap_alloc(git_strmap **map);
+void git_strmap_free(git_strmap *map);
+void git_strmap_clear(git_strmap *map);
-#define git_strmap_alloc(hp) \
- ((*(hp) = kh_init(str)) == NULL) ? giterr_set_oom(), -1 : 0
+size_t git_strmap_num_entries(git_strmap *map);
-#define git_strmap_free(h) kh_destroy(str, h), h = NULL
-#define git_strmap_clear(h) kh_clear(str, h)
+size_t git_strmap_lookup_index(git_strmap *map, const char *key);
+int git_strmap_valid_index(git_strmap *map, size_t idx);
-#define git_strmap_num_entries(h) kh_size(h)
+int git_strmap_exists(git_strmap *map, const char *key);
+int git_strmap_has_data(git_strmap *map, size_t idx);
-#define git_strmap_lookup_index(h, k) kh_get(str, h, k)
-#define git_strmap_valid_index(h, idx) (idx != kh_end(h))
+const char *git_strmap_key(git_strmap *map, size_t idx);
+void git_strmap_set_key_at(git_strmap *map, size_t idx, char *key);
+void *git_strmap_value_at(git_strmap *map, size_t idx);
+void git_strmap_set_value_at(git_strmap *map, size_t idx, void *value);
+void git_strmap_delete_at(git_strmap *map, size_t idx);
-#define git_strmap_exists(h, k) (kh_get(str, h, k) != kh_end(h))
-#define git_strmap_has_data(h, idx) kh_exist(h, idx)
-
-#define git_strmap_key(h, idx) kh_key(h, idx)
-#define git_strmap_value_at(h, idx) kh_val(h, idx)
-#define git_strmap_set_value_at(h, idx, v) kh_val(h, idx) = v
-#define git_strmap_delete_at(h, idx) kh_del(str, h, idx)
-
-#define git_strmap_insert(h, key, val, rval) do { \
- khiter_t __pos = kh_put(str, h, key, &rval); \
- if (rval >= 0) { \
- if (rval == 0) kh_key(h, __pos) = key; \
- kh_val(h, __pos) = val; \
- } } while (0)
-
-#define git_strmap_insert2(h, key, val, oldv, rval) do { \
- khiter_t __pos = kh_put(str, h, key, &rval); \
- if (rval >= 0) { \
- if (rval == 0) { \
- oldv = kh_val(h, __pos); \
- kh_key(h, __pos) = key; \
- } else { oldv = NULL; } \
- kh_val(h, __pos) = val; \
- } } while (0)
-
-#define git_strmap_delete(h, key) do { \
- khiter_t __pos = git_strmap_lookup_index(h, key); \
- if (git_strmap_valid_index(h, __pos)) \
- git_strmap_delete_at(h, __pos); } while (0)
+int git_strmap_put(git_strmap *map, const char *key, int *err);
+void git_strmap_insert(git_strmap *map, const char *key, void *value, int *rval);
+void git_strmap_delete(git_strmap *map, const char *key);
#define git_strmap_foreach kh_foreach
#define git_strmap_foreach_value kh_foreach_value
diff --git a/src/submodule.c b/src/submodule.c
index 86ad53be0..6c3e5f6bd 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -5,7 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+#include "submodule.h"
+
#include "git2/config.h"
#include "git2/sys/config.h"
#include "git2/types.h"
@@ -17,11 +18,11 @@
#include "config_file.h"
#include "config.h"
#include "repository.h"
-#include "submodule.h"
#include "tree.h"
#include "iterator.h"
#include "path.h"
#include "index.h"
+#include "worktree.h"
#define GIT_MODULES_FILE ".gitmodules"
@@ -124,8 +125,8 @@ static void submodule_set_lookup_error(int error, const char *name)
return;
giterr_set(GITERR_SUBMODULE, (error == GIT_ENOTFOUND) ?
- "No submodule named '%s'" :
- "Submodule '%s' has not been added yet", name);
+ "no submodule named '%s'" :
+ "submodule '%s' has not been added yet", name);
}
typedef struct {
@@ -149,40 +150,52 @@ static int find_by_path(const git_config_entry *entry, void *payload)
}
/**
- * Find out the name of a submodule from its path
+ * Release the name map returned by 'load_submodule_names'.
+ */
+static void free_submodule_names(git_strmap *names)
+{
+ git_buf *name = 0;
+ if (names == NULL)
+ return;
+ git_strmap_foreach_value(names, name, {
+ git__free(name);
+ });
+ git_strmap_free(names);
+ return;
+}
+
+/**
+ * Map submodule paths to names.
+ * TODO: for some use-cases, this might need case-folding on a
+ * case-insensitive filesystem
*/
-static int name_from_path(git_buf *out, git_config *cfg, const char *path)
+static int load_submodule_names(git_strmap *out, git_config *cfg)
{
const char *key = "submodule\\..*\\.path";
git_config_iterator *iter;
git_config_entry *entry;
- int error;
+ git_buf buf = GIT_BUF_INIT;
+ int rval;
+ int error = 0;
if ((error = git_config_iterator_glob_new(&iter, cfg, key)) < 0)
return error;
- while ((error = git_config_next(&entry, iter)) == 0) {
+ while (git_config_next(&entry, iter) == 0) {
const char *fdot, *ldot;
- /* TODO: this should maybe be strcasecmp on a case-insensitive fs */
- if (strcmp(path, entry->value) != 0)
- continue;
-
fdot = strchr(entry->name, '.');
ldot = strrchr(entry->name, '.');
- git_buf_clear(out);
- git_buf_put(out, fdot + 1, ldot - fdot - 1);
- goto cleanup;
- }
-
- if (error == GIT_ITEROVER) {
- giterr_set(GITERR_SUBMODULE, "could not find a submodule name for '%s'", path);
- error = GIT_ENOTFOUND;
+ git_buf_put(&buf, fdot + 1, ldot - fdot - 1);
+ git_strmap_insert(out, entry->value, git_buf_detach(&buf), &rval);
+ if (rval < 0) {
+ giterr_set(GITERR_NOMEMORY, "error inserting submodule into hash table");
+ return -1;
+ }
}
-cleanup:
git_config_iterator_free(iter);
- return error;
+ return 0;
}
int git_submodule_lookup(
@@ -196,6 +209,22 @@ int git_submodule_lookup(
assert(repo && name);
+ if (repo->is_bare) {
+ giterr_set(GITERR_SUBMODULE, "cannot get submodules without a working tree");
+ return -1;
+ }
+
+ if (repo->submodule_cache != NULL) {
+ khiter_t pos = git_strmap_lookup_index(repo->submodule_cache, name);
+ if (git_strmap_valid_index(repo->submodule_cache, pos)) {
+ if (out) {
+ *out = git_strmap_value_at(repo->submodule_cache, pos);
+ GIT_REFCOUNT_INC(*out);
+ }
+ return 0;
+ }
+ }
+
if ((error = submodule_alloc(&sm, repo, name)) < 0)
return error;
@@ -306,7 +335,7 @@ static int submodule_get_or_create(git_submodule **out, git_repository *repo, gi
if ((error = submodule_alloc(&sm, repo, name)) < 0)
return error;
- pos = kh_put(str, map, sm->name, &error);
+ pos = git_strmap_put(map, sm->name, &error);
/* nobody can beat us to adding it */
assert(error != 0);
if (error < 0) {
@@ -324,89 +353,108 @@ done:
static int submodules_from_index(git_strmap *map, git_index *idx, git_config *cfg)
{
- int error;
- git_iterator *i;
- const git_index_entry *entry;
- git_buf name = GIT_BUF_INIT;
-
- if ((error = git_iterator_for_index(&i, git_index_owner(idx), idx, NULL)) < 0)
- return error;
+ int error;
+ git_iterator *i = NULL;
+ const git_index_entry *entry;
+ git_strmap *names = 0;
- while (!(error = git_iterator_advance(&entry, i))) {
- khiter_t pos = git_strmap_lookup_index(map, entry->path);
- git_submodule *sm;
+ git_strmap_alloc(&names);
+ if ((error = load_submodule_names(names, cfg)))
+ goto done;
- git_buf_clear(&name);
- if (!name_from_path(&name, cfg, entry->path)) {
- git_strmap_lookup_index(map, name.ptr);
- }
+ if ((error = git_iterator_for_index(&i, git_index_owner(idx), idx, NULL)) < 0)
+ goto done;
- if (git_strmap_valid_index(map, pos)) {
- sm = git_strmap_value_at(map, pos);
+ while (!(error = git_iterator_advance(&entry, i))) {
+ khiter_t pos = git_strmap_lookup_index(map, entry->path);
+ git_submodule *sm;
+
+ if (git_strmap_valid_index(map, pos)) {
+ sm = git_strmap_value_at(map, pos);
+
+ if (S_ISGITLINK(entry->mode))
+ submodule_update_from_index_entry(sm, entry);
+ else
+ sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE;
+ } else if (S_ISGITLINK(entry->mode)) {
+ khiter_t name_pos;
+ const char *name;
+
+ name_pos = git_strmap_lookup_index(names, entry->path);
+ if (git_strmap_valid_index(names, name_pos)) {
+ name = git_strmap_value_at(names, name_pos);
+ } else {
+ name = entry->path;
+ }
- if (S_ISGITLINK(entry->mode))
- submodule_update_from_index_entry(sm, entry);
- else
- sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE;
- } else if (S_ISGITLINK(entry->mode)) {
- if (!submodule_get_or_create(&sm, git_index_owner(idx), map, name.ptr ? name.ptr : entry->path)) {
- submodule_update_from_index_entry(sm, entry);
- git_submodule_free(sm);
- }
- }
- }
+ if (!submodule_get_or_create(&sm, git_index_owner(idx), map, name)) {
+ submodule_update_from_index_entry(sm, entry);
+ git_submodule_free(sm);
+ }
+ }
+ }
- if (error == GIT_ITEROVER)
- error = 0;
+ if (error == GIT_ITEROVER)
+ error = 0;
- git_buf_free(&name);
- git_iterator_free(i);
+done:
+ git_iterator_free(i);
+ free_submodule_names(names);
- return error;
+ return error;
}
static int submodules_from_head(git_strmap *map, git_tree *head, git_config *cfg)
{
- int error;
- git_iterator *i;
- const git_index_entry *entry;
- git_buf name = GIT_BUF_INIT;
-
- if ((error = git_iterator_for_tree(&i, head, NULL)) < 0)
- return error;
-
- while (!(error = git_iterator_advance(&entry, i))) {
- khiter_t pos = git_strmap_lookup_index(map, entry->path);
- git_submodule *sm;
+ int error;
+ git_iterator *i = NULL;
+ const git_index_entry *entry;
+ git_strmap *names = 0;
+ git_strmap_alloc(&names);
+ if ((error = load_submodule_names(names, cfg)))
+ goto done;
- git_buf_clear(&name);
- if (!name_from_path(&name, cfg, entry->path)) {
- git_strmap_lookup_index(map, name.ptr);
- }
+ if ((error = git_iterator_for_tree(&i, head, NULL)) < 0)
+ goto done;
- if (git_strmap_valid_index(map, pos)) {
- sm = git_strmap_value_at(map, pos);
+ while (!(error = git_iterator_advance(&entry, i))) {
+ khiter_t pos = git_strmap_lookup_index(map, entry->path);
+ git_submodule *sm;
+
+ if (git_strmap_valid_index(map, pos)) {
+ sm = git_strmap_value_at(map, pos);
+
+ if (S_ISGITLINK(entry->mode))
+ submodule_update_from_head_data(sm, entry->mode, &entry->id);
+ else
+ sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE;
+ } else if (S_ISGITLINK(entry->mode)) {
+ khiter_t name_pos;
+ const char *name;
+
+ name_pos = git_strmap_lookup_index(names, entry->path);
+ if (git_strmap_valid_index(names, name_pos)) {
+ name = git_strmap_value_at(names, name_pos);
+ } else {
+ name = entry->path;
+ }
- if (S_ISGITLINK(entry->mode))
- submodule_update_from_head_data(sm, entry->mode, &entry->id);
- else
- sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE;
- } else if (S_ISGITLINK(entry->mode)) {
- if (!submodule_get_or_create(&sm, git_tree_owner(head), map, name.ptr ? name.ptr : entry->path)) {
- submodule_update_from_head_data(
- sm, entry->mode, &entry->id);
- git_submodule_free(sm);
- }
- }
- }
+ if (!submodule_get_or_create(&sm, git_tree_owner(head), map, name)) {
+ submodule_update_from_head_data(
+ sm, entry->mode, &entry->id);
+ git_submodule_free(sm);
+ }
+ }
+ }
- if (error == GIT_ITEROVER)
- error = 0;
+ if (error == GIT_ITEROVER)
+ error = 0;
- git_buf_free(&name);
- git_iterator_free(i);
+done:
+ git_iterator_free(i);
+ free_submodule_names(names);
- return error;
+ return error;
}
/* If have_sm is true, sm is populated, otherwise map an repo are. */
@@ -416,7 +464,7 @@ typedef struct {
git_repository *repo;
} lfc_data;
-static int all_submodules(git_repository *repo, git_strmap *map)
+int git_submodule__map(git_repository *repo, git_strmap *map)
{
int error = 0;
git_index *idx = NULL;
@@ -470,12 +518,12 @@ static int all_submodules(git_repository *repo, git_strmap *map)
goto cleanup;
}
/* add back submodule information from index */
- if (idx) {
+ if (mods && idx) {
if ((error = submodules_from_index(map, idx, mods)) < 0)
goto cleanup;
}
/* add submodule information from HEAD */
- if (head) {
+ if (mods && head) {
if ((error = submodules_from_head(map, head, mods)) < 0)
goto cleanup;
}
@@ -506,14 +554,19 @@ int git_submodule_foreach(
int error;
size_t i;
+ if (repo->is_bare) {
+ giterr_set(GITERR_SUBMODULE, "cannot get submodules without a working tree");
+ return -1;
+ }
+
if ((error = git_strmap_alloc(&submodules)) < 0)
return error;
- if ((error = all_submodules(repo, submodules)) < 0)
+ if ((error = git_submodule__map(repo, submodules)) < 0)
goto done;
if (!(error = git_vector_init(
- &snapshot, kh_size(submodules), submodule_cmp))) {
+ &snapshot, git_strmap_num_entries(submodules), submodule_cmp))) {
git_strmap_foreach_value(submodules, sm, {
if ((error = git_vector_insert(&snapshot, sm)) < 0)
@@ -574,8 +627,10 @@ static int submodule_repo_init(
* Old style: sub-repo goes directly into repo/<name>/.git/
*/
if (use_gitlink) {
- error = git_buf_join3(
- &repodir, '/', git_repository_path(parent_repo), "modules", path);
+ error = git_repository_item_path(&repodir, parent_repo, GIT_REPOSITORY_ITEM_MODULES);
+ if (error < 0)
+ goto cleanup;
+ error = git_buf_joinpath(&repodir, repodir.ptr, path);
if (error < 0)
goto cleanup;
@@ -618,7 +673,7 @@ int git_submodule_add_setup(
giterr_clear();
else {
giterr_set(GITERR_SUBMODULE,
- "Attempt to add submodule '%s' that already exists", path);
+ "attempt to add submodule '%s' that already exists", path);
return GIT_EEXISTS;
}
@@ -628,7 +683,7 @@ int git_submodule_add_setup(
path += strlen(git_repository_workdir(repo));
if (git_path_root(path) >= 0) {
- giterr_set(GITERR_SUBMODULE, "Submodule path must be a relative path");
+ giterr_set(GITERR_SUBMODULE, "submodule path must be a relative path");
error = -1;
goto cleanup;
}
@@ -637,7 +692,7 @@ int git_submodule_add_setup(
if (!(mods = open_gitmodules(repo, GITMODULES_CREATE))) {
giterr_set(GITERR_SUBMODULE,
- "Adding submodules to a bare repository is not supported");
+ "adding submodules to a bare repository is not supported");
return -1;
}
@@ -758,7 +813,7 @@ int git_submodule_add_to_index(git_submodule *sm, int write_index)
/* read stat information for submodule working directory */
if (p_stat(path.ptr, &st) < 0) {
giterr_set(GITERR_SUBMODULE,
- "Cannot add submodule without working directory");
+ "cannot add submodule without working directory");
error = -1;
goto cleanup;
}
@@ -771,7 +826,7 @@ int git_submodule_add_to_index(git_submodule *sm, int write_index)
/* calling git_submodule_open will have set sm->wd_oid if possible */
if ((sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) == 0) {
giterr_set(GITERR_SUBMODULE,
- "Cannot add submodule without HEAD to index");
+ "cannot add submodule without HEAD to index");
error = -1;
goto cleanup;
}
@@ -861,7 +916,7 @@ int git_submodule_resolve_url(git_buf *out, git_repository *repo, const char *ur
} else if (strchr(url, ':') != NULL || url[0] == '/') {
error = git_buf_sets(out, url);
} else {
- giterr_set(GITERR_SUBMODULE, "Invalid format for submodule URL");
+ giterr_set(GITERR_SUBMODULE, "invalid format for submodule URL");
error = -1;
}
@@ -1042,8 +1097,10 @@ static int submodule_repo_create(
* <repo-dir>/modules/<name>/ with a gitlink in the
* sub-repo workdir directory to that repository.
*/
- error = git_buf_join3(
- &repodir, '/', git_repository_path(parent_repo), "modules", path);
+ error = git_repository_item_path(&repodir, parent_repo, GIT_REPOSITORY_ITEM_MODULES);
+ if (error < 0)
+ goto cleanup;
+ error = git_buf_joinpath(&repodir, repodir.ptr, path);
if (error < 0)
goto cleanup;
@@ -1133,7 +1190,7 @@ int git_submodule_update(git_submodule *sm, int init, git_submodule_update_optio
goto done;
if (!init) {
- giterr_set(GITERR_SUBMODULE, "Submodule is not initialized.");
+ giterr_set(GITERR_SUBMODULE, "submodule is not initialized");
error = GIT_ERROR;
goto done;
}
@@ -1160,13 +1217,14 @@ int git_submodule_update(git_submodule *sm, int init, git_submodule_update_optio
* will checkout the specific commit manually.
*/
clone_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE;
- update_options.checkout_opts.checkout_strategy = update_options.clone_checkout_strategy;
if ((error = git_clone(&sub_repo, submodule_url, sm->path, &clone_options)) < 0 ||
(error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm))) < 0 ||
(error = git_checkout_head(sub_repo, &update_options.checkout_opts)) != 0)
goto done;
} else {
+ const git_oid *oid;
+
/**
* Work dir is initialized - look up the commit in the parent repository's index,
* update the workdir contents of the subrepository, and set the subrepository's
@@ -1175,8 +1233,14 @@ int git_submodule_update(git_submodule *sm, int init, git_submodule_update_optio
if ((error = git_submodule_open(&sub_repo, sm)) < 0)
goto done;
+ if ((oid = git_submodule_index_id(sm)) == NULL) {
+ giterr_set(GITERR_SUBMODULE, "could not get ID of submodule in index");
+ error = -1;
+ goto done;
+ }
+
/* Look up the target commit in the submodule. */
- if ((error = git_object_lookup(&target_commit, sub_repo, git_submodule_index_id(sm), GIT_OBJ_COMMIT)) < 0) {
+ if ((error = git_object_lookup(&target_commit, sub_repo, oid, GIT_OBJ_COMMIT)) < 0) {
/* If it isn't found then fetch and try again. */
if (error != GIT_ENOTFOUND || !update_options.allow_fetch ||
(error = lookup_default_remote(&remote, sub_repo)) < 0 ||
@@ -1215,7 +1279,7 @@ int git_submodule_init(git_submodule *sm, int overwrite)
if (!sm->url) {
giterr_set(GITERR_SUBMODULE,
- "No URL configured for submodule '%s'", sm->name);
+ "no URL configured for submodule '%s'", sm->name);
return -1;
}
@@ -1259,7 +1323,7 @@ int git_submodule_sync(git_submodule *sm)
if (!sm->url) {
giterr_set(GITERR_SUBMODULE,
- "No URL configured for submodule '%s'", sm->name);
+ "no URL configured for submodule '%s'", sm->name);
return -1;
}
@@ -1502,13 +1566,22 @@ int git_submodule__status(
return 0;
}
- /* refresh the index OID */
- if (submodule_update_index(sm) < 0)
- return -1;
+ /* If the user has requested caching submodule state, performing these
+ * expensive operations (especially `submodule_update_head`, which is
+ * bottlenecked on `git_repository_head_tree`) eliminates much of the
+ * advantage. We will, therefore, interpret the request for caching to
+ * apply here to and skip them.
+ */
- /* refresh the HEAD OID */
- if (submodule_update_head(sm) < 0)
- return -1;
+ if (sm->repo->submodule_cache == NULL) {
+ /* refresh the index OID */
+ if (submodule_update_index(sm) < 0)
+ return -1;
+
+ /* refresh the HEAD OID */
+ if (submodule_update_head(sm) < 0)
+ return -1;
+ }
/* for ignore == dirty, don't scan the working directory */
if (ign == GIT_SUBMODULE_IGNORE_DIRTY) {
@@ -1566,7 +1639,6 @@ int git_submodule_location(unsigned int *location, git_submodule *sm)
location, NULL, NULL, NULL, sm, GIT_SUBMODULE_IGNORE_ALL);
}
-
/*
* INTERNAL FUNCTIONS
*/
@@ -1578,7 +1650,7 @@ static int submodule_alloc(
git_submodule *sm;
if (!name || !(namelen = strlen(name))) {
- giterr_set(GITERR_SUBMODULE, "Invalid submodule name");
+ giterr_set(GITERR_SUBMODULE, "invalid submodule name");
return -1;
}
@@ -1630,7 +1702,7 @@ void git_submodule_free(git_submodule *sm)
static int submodule_config_error(const char *property, const char *value)
{
giterr_set(GITERR_INVALID,
- "Invalid value for submodule '%s' property: '%s'", property, value);
+ "invalid value for submodule '%s' property: '%s'", property, value);
return -1;
}
@@ -1813,7 +1885,7 @@ static int submodule_load_each(const git_config_entry *entry, void *payload)
goto done;
}
- git_strmap_insert(map, sm->name, sm, error);
+ git_strmap_insert(map, sm->name, sm, &error);
assert(error != 0);
if (error < 0)
goto done;
@@ -1968,7 +2040,7 @@ static int lookup_default_remote(git_remote **remote, git_repository *repo)
if (error == GIT_ENOTFOUND)
giterr_set(
GITERR_SUBMODULE,
- "Cannot get default remote for submodule - no local tracking "
+ "cannot get default remote for submodule - no local tracking "
"branch for HEAD and origin does not exist");
return error;
@@ -1977,17 +2049,28 @@ static int lookup_default_remote(git_remote **remote, git_repository *repo)
static int get_url_base(git_buf *url, git_repository *repo)
{
int error;
+ git_worktree *wt = NULL;
git_remote *remote = NULL;
- if (!(error = lookup_default_remote(&remote, repo))) {
+ if ((error = lookup_default_remote(&remote, repo)) == 0) {
error = git_buf_sets(url, git_remote_url(remote));
- git_remote_free(remote);
- }
- else if (error == GIT_ENOTFOUND) {
- /* if repository does not have a default remote, use workdir instead */
+ goto out;
+ } else if (error != GIT_ENOTFOUND)
+ goto out;
+ else
giterr_clear();
+
+ /* if repository does not have a default remote, use workdir instead */
+ if (git_repository_is_worktree(repo)) {
+ if ((error = git_worktree_open_from_repository(&wt, repo)) < 0)
+ goto out;
+ error = git_buf_sets(url, wt->parent_path);
+ } else
error = git_buf_sets(url, git_repository_workdir(repo));
- }
+
+out:
+ git_remote_free(remote);
+ git_worktree_free(wt);
return error;
}
diff --git a/src/submodule.h b/src/submodule.h
index 2ef2031b3..72867a322 100644
--- a/src/submodule.h
+++ b/src/submodule.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_submodule_h__
#define INCLUDE_submodule_h__
+#include "common.h"
+
#include "git2/submodule.h"
#include "git2/repository.h"
#include "fileops.h"
@@ -143,4 +145,7 @@ extern int git_submodule_parse_ignore(
extern int git_submodule_parse_update(
git_submodule_update_t *out, const char *value);
+extern int git_submodule__map(
+ git_repository *repo,
+ git_strmap *map);
#endif
diff --git a/src/sysdir.c b/src/sysdir.c
index 29e53e239..7480e82fd 100644
--- a/src/sysdir.c
+++ b/src/sysdir.c
@@ -5,8 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
#include "sysdir.h"
+
#include "global.h"
#include "buffer.h"
#include "path.h"
@@ -150,7 +150,7 @@ int git_sysdir_get_str(
GITERR_CHECK_ERROR(git_sysdir_get(&path, which));
if (!out || path->size >= outlen) {
- giterr_set(GITERR_NOMEMORY, "Buffer is too short for the path");
+ giterr_set(GITERR_NOMEMORY, "buffer is too short for the path");
return GIT_EBUFS;
}
@@ -171,7 +171,7 @@ int git_sysdir_set(git_sysdir_t which, const char *search_path)
expand_path = strstr(search_path, PATH_MAGIC);
/* reset the default if this path has been cleared */
- if (!search_path || expand_path)
+ if (!search_path)
git_sysdir__dirs[which].guess(&git_sysdir__dirs[which].buf);
/* if $PATH is not referenced, then just set the path */
@@ -241,7 +241,7 @@ static int git_sysdir_find_in_dirlist(
done:
git_buf_free(path);
- giterr_set(GITERR_OS, "The %s file '%s' doesn't exist", label, name);
+ giterr_set(GITERR_OS, "the %s file '%s' doesn't exist", label, name);
return GIT_ENOTFOUND;
}
@@ -275,3 +275,14 @@ int git_sysdir_find_template_dir(git_buf *path)
path, NULL, GIT_SYSDIR_TEMPLATE, "template");
}
+int git_sysdir_expand_global_file(git_buf *path, const char *filename)
+{
+ int error;
+
+ if ((error = git_sysdir_find_global_file(path, NULL)) == 0) {
+ if (filename)
+ error = git_buf_joinpath(path, path->ptr, filename);
+ }
+
+ return error;
+}
diff --git a/src/sysdir.h b/src/sysdir.h
index 11878981c..8f4466b46 100644
--- a/src/sysdir.h
+++ b/src/sysdir.h
@@ -8,6 +8,7 @@
#define INCLUDE_sysdir_h__
#include "common.h"
+
#include "posix.h"
#include "buffer.h"
@@ -55,6 +56,18 @@ extern int git_sysdir_find_programdata_file(git_buf *path, const char *filename)
*/
extern int git_sysdir_find_template_dir(git_buf *path);
+/**
+ * Expand the name of a "global" file (i.e. one in a user's home
+ * directory). Unlike `find_global_file` (above), this makes no
+ * attempt to check for the existence of the file, and is useful if
+ * you want the full path regardless of existence.
+ *
+ * @param path buffer to write the full path into
+ * @param filename name of file in the home directory
+ * @return 0 on success or -1 on error
+ */
+extern int git_sysdir_expand_global_file(git_buf *path, const char *filename);
+
typedef enum {
GIT_SYSDIR_SYSTEM = 0,
GIT_SYSDIR_GLOBAL = 1,
diff --git a/src/tag.c b/src/tag.c
index fe840fe82..445c3ff1d 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -5,9 +5,9 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
-#include "commit.h"
#include "tag.h"
+
+#include "commit.h"
#include "signature.h"
#include "message.h"
#include "git2/object.h"
@@ -61,7 +61,7 @@ const char *git_tag_message(const git_tag *t)
static int tag_error(const char *str)
{
- giterr_set(GITERR_TAG, "Failed to parse tag. %s", str);
+ giterr_set(GITERR_TAG, "failed to parse tag: %s", str);
return -1;
}
@@ -76,13 +76,13 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
char *search;
if (git_oid__parse(&tag->target, &buffer, buffer_end, "object ") < 0)
- return tag_error("Object field invalid");
+ return tag_error("object field invalid");
if (buffer + 5 >= buffer_end)
- return tag_error("Object too short");
+ return tag_error("object too short");
if (memcmp(buffer, "type ", 5) != 0)
- return tag_error("Type field not found");
+ return tag_error("type field not found");
buffer += 5;
tag->type = GIT_OBJ_BAD;
@@ -91,7 +91,7 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
size_t type_length = strlen(tag_types[i]);
if (buffer + type_length >= buffer_end)
- return tag_error("Object too short");
+ return tag_error("object too short");
if (memcmp(buffer, tag_types[i], type_length) == 0) {
tag->type = i;
@@ -101,19 +101,19 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
}
if (tag->type == GIT_OBJ_BAD)
- return tag_error("Invalid object type");
+ return tag_error("invalid object type");
if (buffer + 4 >= buffer_end)
- return tag_error("Object too short");
+ return tag_error("object too short");
if (memcmp(buffer, "tag ", 4) != 0)
- return tag_error("Tag field not found");
+ return tag_error("tag field not found");
buffer += 4;
search = memchr(buffer, '\n', buffer_end - buffer);
if (search == NULL)
- return tag_error("Object too short");
+ return tag_error("object too short");
text_len = search - buffer;
@@ -234,7 +234,7 @@ static int write_tag_annotation(
on_error:
git_buf_free(&tag);
- giterr_set(GITERR_OBJECT, "Failed to create tag annotation.");
+ giterr_set(GITERR_OBJECT, "failed to create tag annotation");
return -1;
}
@@ -257,7 +257,7 @@ static int git_tag_create__internal(
assert(!create_tag_annotation || (tagger && message));
if (git_object_owner(target) != repo) {
- giterr_set(GITERR_INVALID, "The given target does not belong to this repository");
+ giterr_set(GITERR_INVALID, "the given target does not belong to this repository");
return -1;
}
@@ -269,7 +269,7 @@ static int git_tag_create__internal(
* reference unless overwriting has explicitly been requested **/
if (error == 0 && !allow_ref_overwrite) {
git_buf_free(&ref_name);
- giterr_set(GITERR_TAG, "Tag already exists");
+ giterr_set(GITERR_TAG, "tag already exists");
return GIT_EEXISTS;
}
@@ -349,7 +349,7 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu
goto on_error;
if (tag.type != target_obj->cached.type) {
- giterr_set(GITERR_TAG, "The type for the given target is invalid");
+ giterr_set(GITERR_TAG, "the type for the given target is invalid");
goto on_error;
}
@@ -366,7 +366,7 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu
/** Ensure the tag name doesn't conflict with an already existing
* reference unless overwriting has explicitly been requested **/
if (error == 0 && !allow_ref_overwrite) {
- giterr_set(GITERR_TAG, "Tag already exists");
+ giterr_set(GITERR_TAG, "tag already exists");
return GIT_EEXISTS;
}
diff --git a/src/tag.h b/src/tag.h
index d0cd393c7..8aae37840 100644
--- a/src/tag.h
+++ b/src/tag.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_tag_h__
#define INCLUDE_tag_h__
+#include "common.h"
+
#include "git2/tag.h"
#include "repository.h"
#include "odb.h"
diff --git a/src/thread-utils.c b/src/thread-utils.c
index dc9b2f09e..e5ec6a843 100644
--- a/src/thread-utils.c
+++ b/src/thread-utils.c
@@ -4,6 +4,7 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
+
#include "common.h"
#include "thread-utils.h"
diff --git a/src/thread-utils.h b/src/thread-utils.h
index f0161989f..2df2aeb99 100644
--- a/src/thread-utils.h
+++ b/src/thread-utils.h
@@ -7,6 +7,12 @@
#ifndef INCLUDE_thread_utils_h__
#define INCLUDE_thread_utils_h__
+#if defined(__GNUC__) && defined(GIT_THREADS)
+# if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1))
+# error Atomic primitives do not exist on this version of gcc; configure libgit2 with -DTHREADSAFE=OFF
+# endif
+#endif
+
/* Common operations even if threading has been disabled */
typedef struct {
#if defined(GIT_WIN32)
diff --git a/src/tls_stream.c b/src/tls_stream.c
index 83e2d064a..fefb92f26 100644
--- a/src/tls_stream.c
+++ b/src/tls_stream.c
@@ -5,8 +5,9 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "tls_stream.h"
+
#include "git2/errors.h"
-#include "common.h"
#include "openssl_stream.h"
#include "stransport_stream.h"
diff --git a/src/tls_stream.h b/src/tls_stream.h
index 98a704174..8971f7efc 100644
--- a/src/tls_stream.h
+++ b/src/tls_stream.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_tls_stream_h__
#define INCLUDE_tls_stream_h__
+#include "common.h"
+
#include "git2/sys/stream.h"
/**
diff --git a/src/trace.c b/src/trace.c
index ee5039f56..080d1e891 100644
--- a/src/trace.c
+++ b/src/trace.c
@@ -5,10 +5,10 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "trace.h"
+
#include "buffer.h"
-#include "common.h"
#include "global.h"
-#include "trace.h"
#include "git2/trace.h"
#ifdef GIT_TRACE
@@ -32,7 +32,7 @@ int git_trace_set(git_trace_level_t level, git_trace_callback callback)
GIT_UNUSED(callback);
giterr_set(GITERR_INVALID,
- "This version of libgit2 was not built with tracing.");
+ "this version of libgit2 was not built with tracing.");
return -1;
#endif
}
diff --git a/src/trace.h b/src/trace.h
index 486084d01..498944035 100644
--- a/src/trace.h
+++ b/src/trace.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_trace_h__
#define INCLUDE_trace_h__
+#include "common.h"
+
#include <git2/trace.h>
#include "buffer.h"
diff --git a/src/transaction.c b/src/transaction.c
index 2c8a1e8bd..675023afd 100644
--- a/src/transaction.c
+++ b/src/transaction.c
@@ -5,7 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+#include "transaction.h"
+
#include "repository.h"
#include "strmap.h"
#include "refdb.h"
@@ -19,8 +20,6 @@
#include "git2/sys/refs.h"
#include "git2/sys/refdb_backend.h"
-GIT__USE_STRMAP
-
typedef enum {
TRANSACTION_NONE,
TRANSACTION_REFS,
@@ -120,7 +119,7 @@ int git_transaction_lock_ref(git_transaction *tx, const char *refname)
if ((error = git_refdb_lock(&node->payload, tx->db, refname)) < 0)
return error;
- git_strmap_insert(tx->locks, node->name, node, error);
+ git_strmap_insert(tx->locks, node->name, node, &error);
if (error < 0)
goto cleanup;
@@ -323,7 +322,6 @@ static int update_target(git_refdb *db, transaction_node *node)
int git_transaction_commit(git_transaction *tx)
{
transaction_node *node;
- git_strmap_iter pos;
int error = 0;
assert(tx);
@@ -335,11 +333,7 @@ int git_transaction_commit(git_transaction *tx)
return error;
}
- for (pos = kh_begin(tx->locks); pos < kh_end(tx->locks); pos++) {
- if (!git_strmap_has_data(tx->locks, pos))
- continue;
-
- node = git_strmap_value_at(tx->locks, pos);
+ git_strmap_foreach_value(tx->locks, node, {
if (node->reflog) {
if ((error = tx->db->backend->reflog_write(tx->db->backend, node->reflog)) < 0)
return error;
@@ -349,7 +343,7 @@ int git_transaction_commit(git_transaction *tx)
if ((error = update_target(tx->db, node)) < 0)
return error;
}
- }
+ });
return 0;
}
@@ -358,7 +352,6 @@ void git_transaction_free(git_transaction *tx)
{
transaction_node *node;
git_pool pool;
- git_strmap_iter pos;
assert(tx);
@@ -373,16 +366,12 @@ void git_transaction_free(git_transaction *tx)
}
/* start by unlocking the ones we've left hanging, if any */
- for (pos = kh_begin(tx->locks); pos < kh_end(tx->locks); pos++) {
- if (!git_strmap_has_data(tx->locks, pos))
- continue;
-
- node = git_strmap_value_at(tx->locks, pos);
+ git_strmap_foreach_value(tx->locks, node, {
if (node->committed)
continue;
git_refdb_unlock(tx->db, node->payload, false, false, NULL, NULL, NULL);
- }
+ });
git_refdb_free(tx->db);
git_strmap_free(tx->locks);
diff --git a/src/transport.c b/src/transport.c
index f08d2dc68..f1e18b323 100644
--- a/src/transport.c
+++ b/src/transport.c
@@ -4,7 +4,9 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
+
#include "common.h"
+
#include "git2/types.h"
#include "git2/remote.h"
#include "git2/net.h"
@@ -121,7 +123,7 @@ int git_transport_new(git_transport **out, git_remote *owner, const char *url)
int error;
if ((error = transport_find_fn(&fn, url, &param)) == GIT_ENOTFOUND) {
- giterr_set(GITERR_NET, "Unsupported URL protocol");
+ giterr_set(GITERR_NET, "unsupported URL protocol");
return -1;
} else if (error < 0)
return error;
diff --git a/src/transports/auth.c b/src/transports/auth.c
index c1154db34..9597cc249 100644
--- a/src/transports/auth.c
+++ b/src/transports/auth.c
@@ -5,9 +5,10 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "auth.h"
+
#include "git2.h"
#include "buffer.h"
-#include "auth.h"
static int basic_next_token(
git_buf *out, git_http_auth_context *ctx, git_cred *c)
diff --git a/src/transports/auth.h b/src/transports/auth.h
index 52138cf8f..06af79dec 100644
--- a/src/transports/auth.h
+++ b/src/transports/auth.h
@@ -8,6 +8,8 @@
#ifndef INCLUDE_http_auth_h__
#define INCLUDE_http_auth_h__
+#include "common.h"
+
#include "git2.h"
#include "netops.h"
diff --git a/src/transports/auth_negotiate.c b/src/transports/auth_negotiate.c
index 8b99fc735..c9bc3043d 100644
--- a/src/transports/auth_negotiate.c
+++ b/src/transports/auth_negotiate.c
@@ -5,10 +5,11 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "auth_negotiate.h"
+
#ifdef GIT_GSSAPI
#include "git2.h"
-#include "common.h"
#include "buffer.h"
#include "auth.h"
@@ -107,13 +108,13 @@ static int negotiate_next_token(
challenge_len = ctx->challenge ? strlen(ctx->challenge) : 0;
if (challenge_len < 9) {
- giterr_set(GITERR_NET, "No negotiate challenge sent from server");
+ giterr_set(GITERR_NET, "no negotiate challenge sent from server");
error = -1;
goto done;
} else if (challenge_len > 9) {
if (git_buf_decode_base64(&input_buf,
ctx->challenge + 10, challenge_len - 10) < 0) {
- giterr_set(GITERR_NET, "Invalid negotiate challenge from server");
+ giterr_set(GITERR_NET, "invalid negotiate challenge from server");
error = -1;
goto done;
}
@@ -122,7 +123,7 @@ static int negotiate_next_token(
input_token.length = input_buf.size;
input_token_ptr = &input_token;
} else if (ctx->gss_context != GSS_C_NO_CONTEXT) {
- giterr_set(GITERR_NET, "Could not restart authentication");
+ giterr_set(GITERR_NET, "could not restart authentication");
error = -1;
goto done;
}
@@ -228,7 +229,7 @@ static int negotiate_init_context(
gss_release_oid_set(&status_minor, &mechanism_list);
if (!ctx->oid) {
- giterr_set(GITERR_NET, "Negotiate authentication is not supported");
+ giterr_set(GITERR_NET, "negotiate authentication is not supported");
return -1;
}
diff --git a/src/transports/auth_negotiate.h b/src/transports/auth_negotiate.h
index d7270b7ab..5866c19c3 100644
--- a/src/transports/auth_negotiate.h
+++ b/src/transports/auth_negotiate.h
@@ -8,6 +8,7 @@
#ifndef INCLUDE_auth_negotiate_h__
#define INCLUDE_auth_negotiate_h__
+#include "common.h"
#include "git2.h"
#include "auth.h"
diff --git a/src/transports/cred.c b/src/transports/cred.c
index 49ede48bf..8055e2d65 100644
--- a/src/transports/cred.c
+++ b/src/transports/cred.c
@@ -5,6 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "cred.h"
+
#include "git2.h"
#include "smart.h"
#include "git2/cred_helpers.h"
@@ -216,7 +218,7 @@ int git_cred_ssh_key_memory_new(
GIT_UNUSED(passphrase);
giterr_set(GITERR_INVALID,
- "This version of libgit2 was not built with ssh memory credentials.");
+ "this version of libgit2 was not built with ssh memory credentials.");
return -1;
#endif
}
diff --git a/src/transports/cred.h b/src/transports/cred.h
index 2de8deee8..dceab9aa3 100644
--- a/src/transports/cred.h
+++ b/src/transports/cred.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_git_cred_h__
#define INCLUDE_git_cred_h__
+#include "common.h"
+
#include "git2/transport.h"
const char *git_cred__username(git_cred *cred);
diff --git a/src/transports/cred_helpers.c b/src/transports/cred_helpers.c
index 5cc9b0869..fdc56b17e 100644
--- a/src/transports/cred_helpers.c
+++ b/src/transports/cred_helpers.c
@@ -6,6 +6,7 @@
*/
#include "common.h"
+
#include "git2/cred_helpers.h"
int git_cred_userpass(
diff --git a/src/transports/git.c b/src/transports/git.c
index 6c6acf9c5..e019878b5 100644
--- a/src/transports/git.c
+++ b/src/transports/git.c
@@ -5,6 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "common.h"
+
#include "git2.h"
#include "buffer.h"
#include "netops.h"
@@ -45,7 +47,7 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url)
delim = strchr(url, '/');
if (delim == NULL) {
- giterr_set(GITERR_NET, "Malformed URL");
+ giterr_set(GITERR_NET, "malformed URL");
return -1;
}
@@ -240,7 +242,7 @@ static int _git_uploadpack(
return 0;
}
- giterr_set(GITERR_NET, "Must call UPLOADPACK_LS before UPLOADPACK");
+ giterr_set(GITERR_NET, "must call UPLOADPACK_LS before UPLOADPACK");
return -1;
}
@@ -296,7 +298,7 @@ static int _git_receivepack(
return 0;
}
- giterr_set(GITERR_NET, "Must call RECEIVEPACK_LS before RECEIVEPACK");
+ giterr_set(GITERR_NET, "must call RECEIVEPACK_LS before RECEIVEPACK");
return -1;
}
diff --git a/src/transports/http.c b/src/transports/http.c
index ca1f5042f..332e6280b 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -4,6 +4,9 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
+
+#include "common.h"
+
#ifndef GIT_WINHTTP
#include "git2.h"
@@ -208,7 +211,7 @@ static int gen_request(
git_buf_printf(buf, "%s %s%s HTTP/1.1\r\n", s->verb, path, s->service_url);
- git_buf_printf(buf, "User-Agent: git/1.0 (%s)\r\n", user_agent());
+ git_buf_printf(buf, "User-Agent: git/2.0 (%s)\r\n", user_agent());
git_buf_printf(buf, "Host: %s\r\n", t->connection_data.host);
if (s->chunked || content_length > 0) {
@@ -403,7 +406,7 @@ static int on_headers_complete(http_parser *parser)
t->location) {
if (s->redirect_count >= 7) {
- giterr_set(GITERR_NET, "Too many redirects");
+ giterr_set(GITERR_NET, "too many redirects");
return t->parse_error = PARSE_ERROR_GENERIC;
}
@@ -428,14 +431,14 @@ static int on_headers_complete(http_parser *parser)
/* Check for a 200 HTTP status code. */
if (parser->status_code != 200) {
giterr_set(GITERR_NET,
- "Unexpected HTTP status code: %d",
+ "unexpected HTTP status code: %d",
parser->status_code);
return t->parse_error = PARSE_ERROR_GENERIC;
}
/* The response must contain a Content-Type header. */
if (!t->content_type) {
- giterr_set(GITERR_NET, "No Content-Type header in response");
+ giterr_set(GITERR_NET, "no Content-Type header in response");
return t->parse_error = PARSE_ERROR_GENERIC;
}
@@ -455,7 +458,7 @@ static int on_headers_complete(http_parser *parser)
if (strcmp(t->content_type, git_buf_cstr(&buf))) {
git_buf_free(&buf);
giterr_set(GITERR_NET,
- "Invalid Content-Type: %s",
+ "invalid Content-Type: %s",
t->content_type);
return t->parse_error = PARSE_ERROR_GENERIC;
}
@@ -488,7 +491,7 @@ static int on_body_fill_buffer(http_parser *parser, const char *str, size_t len)
return 0;
if (ctx->buf_size < len) {
- giterr_set(GITERR_NET, "Can't fit data in the buffer");
+ giterr_set(GITERR_NET, "can't fit data in the buffer");
return t->parse_error = PARSE_ERROR_GENERIC;
}
@@ -575,6 +578,9 @@ static int apply_proxy_config(http_subtransport *t)
if ((error = git_remote__get_http_proxy(t->owner->owner, !!t->connection_data.use_ssl, &url)) < 0)
return error;
+ opts.credentials = t->owner->proxy.credentials;
+ opts.certificate_check = t->owner->proxy.certificate_check;
+ opts.payload = t->owner->proxy.payload;
opts.type = GIT_PROXY_SPECIFIED;
opts.url = url;
error = git_stream_set_proxy(t->io, &opts);
@@ -624,13 +630,12 @@ static int http_connect(http_subtransport *t)
if ((!error || error == GIT_ECERTIFICATE) && t->owner->certificate_check_cb != NULL &&
git_stream_is_encrypted(t->io)) {
git_cert *cert;
- int is_valid;
+ int is_valid = (error == GIT_OK);
if ((error = git_stream_certificate(&cert, t->io)) < 0)
return error;
giterr_clear();
- is_valid = error != GIT_ECERTIFICATE;
error = t->owner->certificate_check_cb(cert, is_valid, t->connection_data.host, t->owner->message_cb_payload);
if (error < 0) {
@@ -857,7 +862,7 @@ static int http_stream_write_single(
assert(t->connected);
if (s->sent_request) {
- giterr_set(GITERR_NET, "Subtransport configured for only one write");
+ giterr_set(GITERR_NET, "subtransport configured for only one write");
return -1;
}
diff --git a/src/transports/local.c b/src/transports/local.c
index 4eae9dead..733ed2c20 100644
--- a/src/transports/local.c
+++ b/src/transports/local.c
@@ -4,7 +4,9 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
+
#include "common.h"
+
#include "git2/types.h"
#include "git2/net.h"
#include "git2/repository.h"
@@ -16,6 +18,7 @@
#include "git2/pack.h"
#include "git2/commit.h"
#include "git2/revparse.h"
+
#include "pack-objects.h"
#include "refs.h"
#include "posix.h"
@@ -252,7 +255,7 @@ static int local_ls(const git_remote_head ***out, size_t *size, git_transport *t
transport_local *t = (transport_local *)transport;
if (!t->have_refs) {
- giterr_set(GITERR_NET, "The transport has not yet loaded the refs");
+ giterr_set(GITERR_NET, "the transport has not yet loaded the refs");
return -1;
}
@@ -371,11 +374,12 @@ static int local_push(
but we forbid all pushes just in case */
if (!remote_repo->is_bare) {
error = GIT_EBAREREPO;
- giterr_set(GITERR_INVALID, "Local push doesn't (yet) support pushing to non-bare repos.");
+ giterr_set(GITERR_INVALID, "local push doesn't (yet) support pushing to non-bare repos.");
goto on_error;
}
- if ((error = git_buf_joinpath(&odb_path, git_repository_path(remote_repo), "objects/pack")) < 0)
+ if ((error = git_repository_item_path(&odb_path, remote_repo, GIT_REPOSITORY_ITEM_OBJECTS)) < 0
+ || (error = git_buf_joinpath(&odb_path, odb_path.ptr, "pack")) < 0)
goto on_error;
error = git_packbuilder_write(push->pb, odb_path.ptr, 0, transfer_to_push_transfer, (void *) cbs);
diff --git a/src/transports/smart.c b/src/transports/smart.c
index 7a35c39d8..6d5d95fbf 100644
--- a/src/transports/smart.c
+++ b/src/transports/smart.c
@@ -4,8 +4,10 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "git2.h"
+
#include "smart.h"
+
+#include "git2.h"
#include "refs.h"
#include "refspec.h"
#include "proxy.h"
@@ -231,7 +233,7 @@ static int git_smart__connect(
else if (GIT_DIRECTION_PUSH == t->direction)
service = GIT_SERVICE_RECEIVEPACK_LS;
else {
- giterr_set(GITERR_NET, "Invalid direction");
+ giterr_set(GITERR_NET, "invalid direction");
return -1;
}
@@ -252,7 +254,7 @@ static int git_smart__connect(
pkt = (git_pkt *)git_vector_get(&t->refs, 0);
if (!pkt || GIT_PKT_COMMENT != pkt->type) {
- giterr_set(GITERR_NET, "Invalid response");
+ giterr_set(GITERR_NET, "invalid response");
return -1;
} else {
/* Remove the comment pkt from the list */
@@ -299,7 +301,7 @@ static int git_smart__ls(const git_remote_head ***out, size_t *size, git_transpo
transport_smart *t = (transport_smart *)transport;
if (!t->have_refs) {
- giterr_set(GITERR_NET, "The transport has not yet loaded the refs");
+ giterr_set(GITERR_NET, "the transport has not yet loaded the refs");
return -1;
}
@@ -319,7 +321,7 @@ int git_smart__negotiation_step(git_transport *transport, void *data, size_t len
return -1;
if (GIT_DIRECTION_FETCH != t->direction) {
- giterr_set(GITERR_NET, "This operation is only valid for fetch");
+ giterr_set(GITERR_NET, "this operation is only valid for fetch");
return -1;
}
@@ -348,7 +350,7 @@ int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream
return -1;
if (GIT_DIRECTION_PUSH != t->direction) {
- giterr_set(GITERR_NET, "This operation is only valid for push");
+ giterr_set(GITERR_NET, "this operation is only valid for push");
return -1;
}
@@ -472,6 +474,12 @@ int git_transport_smart_credentials(git_cred **out, git_transport *transport, co
return t->cred_acquire_cb(out, t->url, user, methods, t->cred_acquire_payload);
}
+int git_transport_smart_proxy_options(git_proxy_options *out, git_transport *transport)
+{
+ transport_smart *t = (transport_smart *) transport;
+ return git_proxy_options_dup(out, &t->proxy);
+}
+
int git_transport_smart(git_transport **out, git_remote *owner, void *param)
{
transport_smart *t;
diff --git a/src/transports/smart.h b/src/transports/smart.h
index 0a0c3fc1b..f1ad70479 100644
--- a/src/transports/smart.h
+++ b/src/transports/smart.h
@@ -4,6 +4,9 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
+
+#include "common.h"
+
#include "git2.h"
#include "vector.h"
#include "netops.h"
@@ -26,6 +29,8 @@
#define GIT_CAP_THIN_PACK "thin-pack"
#define GIT_CAP_SYMREF "symref"
+extern bool git_smart__ofs_delta_enabled;
+
enum git_pkt_type {
GIT_PKT_CMD,
GIT_PKT_FLUSH,
diff --git a/src/transports/smart_pkt.c b/src/transports/smart_pkt.c
index 2297cc94f..a661dfe13 100644
--- a/src/transports/smart_pkt.c
+++ b/src/transports/smart_pkt.c
@@ -226,7 +226,7 @@ static int ref_pkt(git_pkt **out, const char *line, size_t len)
/* Check for a bit of consistency */
if (line[GIT_OID_HEXSZ] != ' ') {
- giterr_set(GITERR_NET, "Error parsing pkt-line");
+ giterr_set(GITERR_NET, "error parsing pkt-line");
error = -1;
goto error_out;
}
@@ -270,7 +270,7 @@ static int ok_pkt(git_pkt **out, const char *line, size_t len)
line += 3; /* skip "ok " */
if (!(ptr = strchr(line, '\n'))) {
- giterr_set(GITERR_NET, "Invalid packet line");
+ giterr_set(GITERR_NET, "invalid packet line");
git__free(pkt);
return -1;
}
@@ -327,7 +327,7 @@ static int ng_pkt(git_pkt **out, const char *line, size_t len)
return 0;
out_err:
- giterr_set(GITERR_NET, "Invalid packet line");
+ giterr_set(GITERR_NET, "invalid packet line");
git__free(pkt->ref);
git__free(pkt);
return -1;
@@ -427,15 +427,23 @@ int git_pkt_parse_line(
if (bufflen > 0 && bufflen < (size_t)len)
return GIT_EBUFS;
+ /*
+ * The length has to be exactly 0 in case of a flush
+ * packet or greater than PKT_LEN_SIZE, as the decoded
+ * length includes its own encoded length of four bytes.
+ */
+ if (len != 0 && len < PKT_LEN_SIZE)
+ return GIT_ERROR;
+
line += PKT_LEN_SIZE;
/*
- * TODO: How do we deal with empty lines? Try again? with the next
- * line?
+ * The Git protocol does not specify empty lines as part
+ * of the protocol. Not knowing what to do with an empty
+ * line, we should return an error upon hitting one.
*/
if (len == PKT_LEN_SIZE) {
- *head = NULL;
- *out = line;
- return 0;
+ giterr_set_str(GITERR_NET, "Invalid empty packet");
+ return GIT_ERROR;
}
if (len == 0) { /* Flush pkt */
@@ -535,7 +543,7 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
if (len > 0xffff) {
giterr_set(GITERR_NET,
- "Tried to produce packet with invalid length %" PRIuZ, len);
+ "tried to produce packet with invalid length %" PRIuZ, len);
return -1;
}
diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c
index 3448fa7fb..d51238f12 100644
--- a/src/transports/smart_protocol.c
+++ b/src/transports/smart_protocol.c
@@ -4,6 +4,9 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
+
+#include "common.h"
+
#include "git2.h"
#include "git2/odb_backend.h"
@@ -19,6 +22,8 @@
/* The minimal interval between progress updates (in seconds). */
#define MIN_PROGRESS_UPDATE_INTERVAL 0.5
+bool git_smart__ofs_delta_enabled = true;
+
int git_smart__store_refs(transport_smart *t, int flushes)
{
gitno_buffer *buf = &t->buffer;
@@ -50,7 +55,7 @@ int git_smart__store_refs(transport_smart *t, int flushes)
if ((recvd = gitno_recv(buf)) < 0)
return recvd;
- if (recvd == 0 && !flush) {
+ if (recvd == 0) {
giterr_set(GITERR_NET, "early EOF");
return GIT_EEOF;
}
@@ -60,7 +65,7 @@ int git_smart__store_refs(transport_smart *t, int flushes)
gitno_consume(buf, line_end);
if (pkt->type == GIT_PKT_ERR) {
- giterr_set(GITERR_NET, "Remote error: %s", ((git_pkt_err *)pkt)->error);
+ giterr_set(GITERR_NET, "remote error: %s", ((git_pkt_err *)pkt)->error);
git__free(pkt);
return -1;
}
@@ -138,7 +143,7 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vec
if (*ptr == ' ')
ptr++;
- if (!git__prefixcmp(ptr, GIT_CAP_OFS_DELTA)) {
+ if (git_smart__ofs_delta_enabled && !git__prefixcmp(ptr, GIT_CAP_OFS_DELTA)) {
caps->common = caps->ofs_delta = 1;
ptr += strlen(GIT_CAP_OFS_DELTA);
continue;
@@ -222,8 +227,12 @@ static int recv_pkt(git_pkt **out, gitno_buffer *buf)
if (error < 0 && error != GIT_EBUFS)
return error;
- if ((ret = gitno_recv(buf)) < 0)
+ if ((ret = gitno_recv(buf)) < 0) {
return ret;
+ } else if (ret == 0) {
+ giterr_set(GITERR_NET, "early EOF");
+ return GIT_EEOF;
+ }
} while (error);
gitno_consume(buf, line_end);
@@ -319,7 +328,8 @@ static int wait_while_ack(gitno_buffer *buf)
if (pkt->type == GIT_PKT_ACK &&
(pkt->status != GIT_ACK_CONTINUE &&
- pkt->status != GIT_ACK_COMMON)) {
+ pkt->status != GIT_ACK_COMMON &&
+ pkt->status != GIT_ACK_READY)) {
git__free(pkt);
return 0;
}
@@ -408,12 +418,12 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
if (i % 20 == 0 && t->rpc) {
git_pkt_ack *pkt;
- unsigned int i;
+ unsigned int j;
if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0)
goto on_error;
- git_vector_foreach(&t->common, i, pkt) {
+ git_vector_foreach(&t->common, j, pkt) {
if ((error = git_pkt_buffer_have(&pkt->oid, &data)) < 0)
goto on_error;
}
@@ -428,12 +438,12 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
/* Tell the other end that we're done negotiating */
if (t->rpc && t->common.length > 0) {
git_pkt_ack *pkt;
- unsigned int i;
+ unsigned int j;
if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0)
goto on_error;
- git_vector_foreach(&t->common, i, pkt) {
+ git_vector_foreach(&t->common, j, pkt) {
if ((error = git_pkt_buffer_have(&pkt->oid, &data)) < 0)
goto on_error;
}
@@ -724,7 +734,7 @@ static int add_push_report_pkt(git_push *push, git_pkt *pkt)
static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt, git_buf *data_pkt_buf)
{
git_pkt *pkt;
- const char *line, *line_end;
+ const char *line, *line_end = NULL;
size_t line_len;
int error;
int reading_from_buf = data_pkt_buf->size > 0;
@@ -759,14 +769,6 @@ static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt,
line_len -= (line_end - line);
line = line_end;
- /* When a valid packet with no content has been
- * read, git_pkt_parse_line does not report an
- * error, but the pkt pointer has not been set.
- * Handle this by skipping over empty packets.
- */
- if (pkt == NULL)
- continue;
-
error = add_push_report_pkt(push, pkt);
git_pkt_free(pkt);
@@ -821,9 +823,6 @@ static int parse_report(transport_smart *transport, git_push *push)
error = 0;
- if (pkt == NULL)
- continue;
-
switch (pkt->type) {
case GIT_PKT_DATA:
/* This is a sideband packet which contains other packets */
diff --git a/src/transports/ssh.c b/src/transports/ssh.c
index cfd573665..47d328c41 100644
--- a/src/transports/ssh.c
+++ b/src/transports/ssh.c
@@ -5,17 +5,19 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "ssh.h"
+
#ifdef GIT_SSH
#include <libssh2.h>
#endif
+#include "global.h"
#include "git2.h"
#include "buffer.h"
#include "netops.h"
#include "smart.h"
#include "cred.h"
#include "socket_stream.h"
-#include "ssh.h"
#ifdef GIT_SSH
@@ -83,7 +85,7 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url)
done:
if (!repo) {
- giterr_set(GITERR_NET, "Malformed git protocol URL");
+ giterr_set(GITERR_NET, "malformed git protocol URL");
return -1;
}
@@ -274,7 +276,7 @@ static int git_ssh_extract_url_parts(
}
if (colon == NULL || (colon < start)) {
- giterr_set(GITERR_NET, "Malformed URL");
+ giterr_set(GITERR_NET, "malformed URL");
return -1;
}
@@ -445,7 +447,7 @@ static int request_creds(git_cred **out, ssh_subtransport *t, const char *user,
else if (error < 0)
return error;
else if (!cred) {
- giterr_set(GITERR_SSH, "Callback failed to initialize SSH credentials");
+ giterr_set(GITERR_SSH, "callback failed to initialize SSH credentials");
return -1;
}
}
@@ -478,7 +480,7 @@ static int _git_ssh_session_create(
s = libssh2_session_init();
if (!s) {
- giterr_set(GITERR_NET, "Failed to initialize SSH session");
+ giterr_set(GITERR_NET, "failed to initialize SSH session");
return -1;
}
@@ -487,7 +489,7 @@ static int _git_ssh_session_create(
} while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc);
if (rc != LIBSSH2_ERROR_NONE) {
- ssh_error(s, "Failed to start SSH session");
+ ssh_error(s, "failed to start SSH session");
libssh2_session_free(s);
return -1;
}
@@ -685,7 +687,7 @@ static int ssh_uploadpack(
return 0;
}
- giterr_set(GITERR_NET, "Must call UPLOADPACK_LS before UPLOADPACK");
+ giterr_set(GITERR_NET, "must call UPLOADPACK_LS before UPLOADPACK");
return -1;
}
@@ -712,7 +714,7 @@ static int ssh_receivepack(
return 0;
}
- giterr_set(GITERR_NET, "Must call RECEIVEPACK_LS before RECEIVEPACK");
+ giterr_set(GITERR_NET, "must call RECEIVEPACK_LS before RECEIVEPACK");
return -1;
}
@@ -844,7 +846,7 @@ int git_smart_subtransport_ssh(
assert(out);
*out = NULL;
- giterr_set(GITERR_INVALID, "Cannot create SSH transport. Library was built without SSH support");
+ giterr_set(GITERR_INVALID, "cannot create SSH transport. Library was built without SSH support");
return -1;
#endif
}
@@ -888,16 +890,27 @@ int git_transport_ssh_with_paths(git_transport **out, git_remote *owner, void *p
assert(out);
*out = NULL;
- giterr_set(GITERR_INVALID, "Cannot create SSH transport. Library was built without SSH support");
+ giterr_set(GITERR_INVALID, "cannot create SSH transport. Library was built without SSH support");
return -1;
#endif
}
+#ifdef GIT_SSH
+static void shutdown_ssh(void)
+{
+ libssh2_exit();
+}
+#endif
+
int git_transport_ssh_global_init(void)
{
#ifdef GIT_SSH
+ if (libssh2_init(0) < 0) {
+ giterr_set(GITERR_SSH, "unable to initialize libssh2");
+ return -1;
+ }
- libssh2_init(0);
+ git__on_shutdown(shutdown_ssh);
return 0;
#else
diff --git a/src/transports/ssh.h b/src/transports/ssh.h
index 2db2cc5df..e36e7246e 100644
--- a/src/transports/ssh.h
+++ b/src/transports/ssh.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_ssh_h__
#define INCLUDE_ssh_h__
+#include "common.h"
+
int git_transport_ssh_global_init(void);
#endif
diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c
index 78e42cf3b..6689c8ce3 100644
--- a/src/transports/winhttp.c
+++ b/src/transports/winhttp.c
@@ -5,6 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "common.h"
+
#ifdef GIT_WINHTTP
#include "git2.h"
@@ -68,7 +70,9 @@ static const IID IID_IInternetSecurityManager_mingw =
typedef enum {
GIT_WINHTTP_AUTH_BASIC = 1,
- GIT_WINHTTP_AUTH_NEGOTIATE = 2,
+ GIT_WINHTTP_AUTH_NTLM = 2,
+ GIT_WINHTTP_AUTH_NEGOTIATE = 4,
+ GIT_WINHTTP_AUTH_DIGEST = 8,
} winhttp_authmechanism_t;
typedef struct {
@@ -95,79 +99,71 @@ typedef struct {
git_cred *cred;
git_cred *url_cred;
git_cred *proxy_cred;
- int auth_mechanism;
+ int auth_mechanisms;
HINTERNET session;
HINTERNET connection;
} winhttp_subtransport;
-static int apply_basic_credential_proxy(HINTERNET request, git_cred *cred)
+static int _apply_userpass_credential(HINTERNET request, DWORD target, DWORD scheme, git_cred *cred)
{
git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred;
wchar_t *user, *pass;
- int error;
+ int user_len = 0, pass_len = 0, error = 0;
- if ((error = git__utf8_to_16_alloc(&user, c->username)) < 0)
- return error;
+ if ((error = user_len = git__utf8_to_16_alloc(&user, c->username)) < 0)
+ goto done;
- if ((error = git__utf8_to_16_alloc(&pass, c->password)) < 0)
- return error;
+ if ((error = pass_len = git__utf8_to_16_alloc(&pass, c->password)) < 0)
+ goto done;
- if (!WinHttpSetCredentials(request, WINHTTP_AUTH_TARGET_PROXY, WINHTTP_AUTH_SCHEME_BASIC,
- user, pass, NULL)) {
- giterr_set(GITERR_OS, "failed to set proxy auth");
+ if (!WinHttpSetCredentials(request, target, scheme, user, pass, NULL)) {
+ giterr_set(GITERR_OS, "failed to set credentials");
error = -1;
}
+done:
+ if (user_len > 0)
+ git__memzero(user, user_len * sizeof(wchar_t));
+
+ if (pass_len > 0)
+ git__memzero(pass, pass_len * sizeof(wchar_t));
+
git__free(user);
git__free(pass);
return error;
}
-static int apply_basic_credential(HINTERNET request, git_cred *cred)
+static int apply_userpass_credential_proxy(HINTERNET request, git_cred *cred, int mechanisms)
{
- git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred;
- git_buf buf = GIT_BUF_INIT, raw = GIT_BUF_INIT;
- wchar_t *wide = NULL;
- int error = -1, wide_len;
-
- git_buf_printf(&raw, "%s:%s", c->username, c->password);
-
- if (git_buf_oom(&raw) ||
- git_buf_puts(&buf, "Authorization: Basic ") < 0 ||
- git_buf_encode_base64(&buf, git_buf_cstr(&raw), raw.size) < 0)
- goto on_error;
-
- if ((wide_len = git__utf8_to_16_alloc(&wide, git_buf_cstr(&buf))) < 0) {
- giterr_set(GITERR_OS, "Failed to convert string to wide form");
- goto on_error;
- }
-
- if (!WinHttpAddRequestHeaders(request, wide, (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD)) {
- giterr_set(GITERR_OS, "Failed to add a header to the request");
- goto on_error;
+ if (GIT_WINHTTP_AUTH_DIGEST & mechanisms) {
+ return _apply_userpass_credential(request, WINHTTP_AUTH_TARGET_PROXY,
+ WINHTTP_AUTH_SCHEME_DIGEST, cred);
}
- error = 0;
-
-on_error:
- /* We were dealing with plaintext passwords, so clean up after ourselves a bit. */
- if (wide)
- memset(wide, 0x0, wide_len * sizeof(wchar_t));
+ return _apply_userpass_credential(request, WINHTTP_AUTH_TARGET_PROXY,
+ WINHTTP_AUTH_SCHEME_BASIC, cred);
+}
- if (buf.size)
- memset(buf.ptr, 0x0, buf.size);
+static int apply_userpass_credential(HINTERNET request, int mechanisms, git_cred *cred)
+{
+ DWORD native_scheme;
- if (raw.size)
- memset(raw.ptr, 0x0, raw.size);
+ if ((mechanisms & GIT_WINHTTP_AUTH_NTLM) ||
+ (mechanisms & GIT_WINHTTP_AUTH_NEGOTIATE)) {
+ native_scheme = WINHTTP_AUTH_SCHEME_NTLM;
+ } else if (mechanisms & GIT_WINHTTP_AUTH_BASIC) {
+ native_scheme = WINHTTP_AUTH_SCHEME_BASIC;
+ } else {
+ giterr_set(GITERR_NET, "invalid authentication scheme");
+ return -1;
+ }
- git__free(wide);
- git_buf_free(&buf);
- git_buf_free(&raw);
- return error;
+ return _apply_userpass_credential(request, WINHTTP_AUTH_TARGET_SERVER,
+ native_scheme, cred);
}
-static int apply_default_credentials(HINTERNET request)
+static int apply_default_credentials(HINTERNET request, int mechanisms)
{
/* Either the caller explicitly requested that default credentials be passed,
* or our fallback credential callback was invoked and checked that the target
@@ -177,6 +173,12 @@ static int apply_default_credentials(HINTERNET request)
* to Internet Explorer security zones, but in fact does not. */
DWORD data = WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW;
+ if ((mechanisms & GIT_WINHTTP_AUTH_NTLM) == 0 &&
+ (mechanisms & GIT_WINHTTP_AUTH_NEGOTIATE) == 0) {
+ giterr_set(GITERR_NET, "invalid authentication scheme");
+ return -1;
+ }
+
if (!WinHttpSetOption(request, WINHTTP_OPTION_AUTOLOGON_POLICY, &data, sizeof(DWORD)))
return -1;
@@ -202,7 +204,7 @@ static int fallback_cred_acquire_cb(
/* Convert URL to wide characters */
if (git__utf8_to_16_alloc(&wide_url, url) < 0) {
- giterr_set(GITERR_OS, "Failed to convert string to wide form");
+ giterr_set(GITERR_OS, "failed to convert string to wide form");
return -1;
}
@@ -248,8 +250,12 @@ static int certificate_check(winhttp_stream *s, int valid)
git_cert_x509 cert;
/* If there is no override, we should fail if WinHTTP doesn't think it's fine */
- if (t->owner->certificate_check_cb == NULL && !valid)
+ if (t->owner->certificate_check_cb == NULL && !valid) {
+ if (!giterr_last())
+ giterr_set(GITERR_NET, "unknown certificate check failure");
+
return GIT_ECERTIFICATE;
+ }
if (t->owner->certificate_check_cb == NULL || !t->connection_data.use_ssl)
return 0;
@@ -351,7 +357,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
/* Convert URL to wide characters */
if (git__utf8_to_16_alloc(&s->request_uri, git_buf_cstr(&buf)) < 0) {
- giterr_set(GITERR_OS, "Failed to convert string to wide form");
+ giterr_set(GITERR_OS, "failed to convert string to wide form");
goto on_error;
}
@@ -366,12 +372,12 @@ static int winhttp_stream_connect(winhttp_stream *s)
t->connection_data.use_ssl ? WINHTTP_FLAG_SECURE : 0);
if (!s->request) {
- giterr_set(GITERR_OS, "Failed to open request");
+ giterr_set(GITERR_OS, "failed to open request");
goto on_error;
}
if (!WinHttpSetTimeouts(s->request, default_timeout, default_connect_timeout, default_timeout, default_timeout)) {
- giterr_set(GITERR_OS, "Failed to set timeouts for WinHTTP");
+ giterr_set(GITERR_OS, "failed to set timeouts for WinHTTP");
goto on_error;
}
@@ -425,7 +431,6 @@ static int winhttp_stream_connect(winhttp_stream *s)
git_buf_printf(&processed_url, ":%s", t->proxy_connection_data.port);
if (git_buf_oom(&processed_url)) {
- giterr_set_oom();
error = -1;
goto on_error;
}
@@ -444,7 +449,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
WINHTTP_OPTION_PROXY,
&proxy_info,
sizeof(WINHTTP_PROXY_INFO))) {
- giterr_set(GITERR_OS, "Failed to set proxy");
+ giterr_set(GITERR_OS, "failed to set proxy");
git__free(proxy_wide);
goto on_error;
}
@@ -453,7 +458,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
if (t->proxy_cred) {
if (t->proxy_cred->credtype == GIT_CREDTYPE_USERPASS_PLAINTEXT) {
- if ((error = apply_basic_credential_proxy(s->request, t->proxy_cred)) < 0)
+ if ((error = apply_userpass_credential_proxy(s->request, t->proxy_cred, t->auth_mechanisms)) < 0)
goto on_error;
}
}
@@ -467,7 +472,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
WINHTTP_OPTION_DISABLE_FEATURE,
&disable_redirects,
sizeof(disable_redirects))) {
- giterr_set(GITERR_OS, "Failed to disable redirects");
+ giterr_set(GITERR_OS, "failed to disable redirects");
goto on_error;
}
@@ -481,7 +486,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
/* Send Pragma: no-cache header */
if (!WinHttpAddRequestHeaders(s->request, pragma_nocache, (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD)) {
- giterr_set(GITERR_OS, "Failed to add a header to the request");
+ giterr_set(GITERR_OS, "failed to add a header to the request");
goto on_error;
}
@@ -494,13 +499,13 @@ static int winhttp_stream_connect(winhttp_stream *s)
goto on_error;
if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf)) < 0) {
- giterr_set(GITERR_OS, "Failed to convert content-type to wide characters");
+ giterr_set(GITERR_OS, "failed to convert content-type to wide characters");
goto on_error;
}
if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG)-1L,
WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) {
- giterr_set(GITERR_OS, "Failed to add a header to the request");
+ giterr_set(GITERR_OS, "failed to add a header to the request");
goto on_error;
}
@@ -511,13 +516,13 @@ static int winhttp_stream_connect(winhttp_stream *s)
goto on_error;
if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf)) < 0) {
- giterr_set(GITERR_OS, "Failed to convert accept header to wide characters");
+ giterr_set(GITERR_OS, "failed to convert accept header to wide characters");
goto on_error;
}
if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG)-1L,
WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) {
- giterr_set(GITERR_OS, "Failed to add a header to the request");
+ giterr_set(GITERR_OS, "failed to add a header to the request");
goto on_error;
}
}
@@ -527,13 +532,13 @@ static int winhttp_stream_connect(winhttp_stream *s)
git_buf_clear(&buf);
git_buf_puts(&buf, t->owner->custom_headers.strings[i]);
if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf)) < 0) {
- giterr_set(GITERR_OS, "Failed to convert custom header to wide characters");
+ giterr_set(GITERR_OS, "failed to convert custom header to wide characters");
goto on_error;
}
if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG)-1L,
WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) {
- giterr_set(GITERR_OS, "Failed to add a header to the request");
+ giterr_set(GITERR_OS, "failed to add a header to the request");
goto on_error;
}
}
@@ -550,13 +555,11 @@ static int winhttp_stream_connect(winhttp_stream *s)
/* If we have a credential on the subtransport, apply it to the request */
if (t->cred &&
t->cred->credtype == GIT_CREDTYPE_USERPASS_PLAINTEXT &&
- t->auth_mechanism == GIT_WINHTTP_AUTH_BASIC &&
- apply_basic_credential(s->request, t->cred) < 0)
+ apply_userpass_credential(s->request, t->auth_mechanisms, t->cred) < 0)
goto on_error;
else if (t->cred &&
t->cred->credtype == GIT_CREDTYPE_DEFAULT &&
- t->auth_mechanism == GIT_WINHTTP_AUTH_NEGOTIATE &&
- apply_default_credentials(s->request) < 0)
+ apply_default_credentials(s->request, t->auth_mechanisms) < 0)
goto on_error;
/* If no other credentials have been applied and the URL has username and
@@ -565,7 +568,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
if (!t->url_cred &&
git_cred_userpass_plaintext_new(&t->url_cred, t->connection_data.user, t->connection_data.pass) < 0)
goto on_error;
- if (apply_basic_credential(s->request, t->url_cred) < 0)
+ if (apply_userpass_credential(s->request, GIT_WINHTTP_AUTH_BASIC, t->url_cred) < 0)
goto on_error;
}
@@ -585,30 +588,40 @@ on_error:
static int parse_unauthorized_response(
HINTERNET request,
int *allowed_types,
- int *auth_mechanism)
+ int *allowed_mechanisms)
{
DWORD supported, first, target;
*allowed_types = 0;
- *auth_mechanism = 0;
+ *allowed_mechanisms = 0;
- /* WinHttpQueryHeaders() must be called before WinHttpQueryAuthSchemes().
- * We can assume this was already done, since we know we are unauthorized.
+ /* WinHttpQueryHeaders() must be called before WinHttpQueryAuthSchemes().
+ * We can assume this was already done, since we know we are unauthorized.
*/
if (!WinHttpQueryAuthSchemes(request, &supported, &first, &target)) {
- giterr_set(GITERR_OS, "Failed to parse supported auth schemes");
+ giterr_set(GITERR_OS, "failed to parse supported auth schemes");
return -1;
}
- if (WINHTTP_AUTH_SCHEME_BASIC & supported) {
+ if (WINHTTP_AUTH_SCHEME_NTLM & supported) {
*allowed_types |= GIT_CREDTYPE_USERPASS_PLAINTEXT;
- *auth_mechanism = GIT_WINHTTP_AUTH_BASIC;
+ *allowed_types |= GIT_CREDTYPE_DEFAULT;
+ *allowed_mechanisms = GIT_WINHTTP_AUTH_NEGOTIATE;
}
- if ((WINHTTP_AUTH_SCHEME_NTLM & supported) ||
- (WINHTTP_AUTH_SCHEME_NEGOTIATE & supported)) {
+ if (WINHTTP_AUTH_SCHEME_NEGOTIATE & supported) {
*allowed_types |= GIT_CREDTYPE_DEFAULT;
- *auth_mechanism = GIT_WINHTTP_AUTH_NEGOTIATE;
+ *allowed_mechanisms = GIT_WINHTTP_AUTH_NEGOTIATE;
+ }
+
+ if (WINHTTP_AUTH_SCHEME_BASIC & supported) {
+ *allowed_types |= GIT_CREDTYPE_USERPASS_PLAINTEXT;
+ *allowed_mechanisms |= GIT_WINHTTP_AUTH_BASIC;
+ }
+
+ if (WINHTTP_AUTH_SCHEME_DIGEST & supported) {
+ *allowed_types |= GIT_CREDTYPE_USERPASS_PLAINTEXT;
+ *allowed_mechanisms |= GIT_WINHTTP_AUTH_DIGEST;
}
return 0;
@@ -629,7 +642,7 @@ static int write_chunk(HINTERNET request, const char *buffer, size_t len)
git_buf_cstr(&buf), (DWORD)git_buf_len(&buf),
&bytes_written)) {
git_buf_free(&buf);
- giterr_set(GITERR_OS, "Failed to write chunk header");
+ giterr_set(GITERR_OS, "failed to write chunk header");
return -1;
}
@@ -639,7 +652,7 @@ static int write_chunk(HINTERNET request, const char *buffer, size_t len)
if (!WinHttpWriteData(request,
buffer, (DWORD)len,
&bytes_written)) {
- giterr_set(GITERR_OS, "Failed to write chunk");
+ giterr_set(GITERR_OS, "failed to write chunk");
return -1;
}
@@ -647,7 +660,7 @@ static int write_chunk(HINTERNET request, const char *buffer, size_t len)
if (!WinHttpWriteData(request,
"\r\n", 2,
&bytes_written)) {
- giterr_set(GITERR_OS, "Failed to write chunk footer");
+ giterr_set(GITERR_OS, "failed to write chunk footer");
return -1;
}
@@ -660,7 +673,7 @@ static int winhttp_close_connection(winhttp_subtransport *t)
if (t->connection) {
if (!WinHttpCloseHandle(t->connection)) {
- giterr_set(GITERR_OS, "Unable to close connection");
+ giterr_set(GITERR_OS, "unable to close connection");
ret = -1;
}
@@ -669,7 +682,7 @@ static int winhttp_close_connection(winhttp_subtransport *t)
if (t->session) {
if (!WinHttpCloseHandle(t->session)) {
- giterr_set(GITERR_OS, "Unable to close session");
+ giterr_set(GITERR_OS, "unable to close session");
ret = -1;
}
@@ -694,6 +707,38 @@ static int user_agent(git_buf *ua)
return git_buf_putc(ua, ')');
}
+static void CALLBACK winhttp_status(
+ HINTERNET connection,
+ DWORD_PTR ctx,
+ DWORD code,
+ LPVOID info,
+ DWORD info_len)
+{
+ DWORD status;
+
+ if (code != WINHTTP_CALLBACK_STATUS_SECURE_FAILURE)
+ return;
+
+ status = *((DWORD *)info);
+
+ if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID))
+ giterr_set(GITERR_NET, "SSL certificate issued for different common name");
+ else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID))
+ giterr_set(GITERR_NET, "SSL certificate has expired");
+ else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA))
+ giterr_set(GITERR_NET, "SSL certificate signed by unknown CA");
+ else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT))
+ giterr_set(GITERR_NET, "SSL certificate is invalid");
+ else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED))
+ giterr_set(GITERR_NET, "certificate revocation check failed");
+ else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED))
+ giterr_set(GITERR_NET, "SSL certificate was revoked");
+ else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR))
+ giterr_set(GITERR_NET, "security libraries could not be loaded");
+ else
+ giterr_set(GITERR_NET, "unknown security error %d", status);
+}
+
static int winhttp_connect(
winhttp_subtransport *t)
{
@@ -714,7 +759,7 @@ static int winhttp_connect(
/* Prepare host */
if (git__utf8_to_16_alloc(&wide_host, t->connection_data.host) < 0) {
- giterr_set(GITERR_OS, "Unable to convert host to wide characters");
+ giterr_set(GITERR_OS, "unable to convert host to wide characters");
return -1;
}
@@ -724,7 +769,7 @@ static int winhttp_connect(
}
if (git__utf8_to_16_alloc(&wide_ua, git_buf_cstr(&ua)) < 0) {
- giterr_set(GITERR_OS, "Unable to convert host to wide characters");
+ giterr_set(GITERR_OS, "unable to convert host to wide characters");
git__free(wide_host);
git_buf_free(&ua);
return -1;
@@ -741,16 +786,16 @@ static int winhttp_connect(
0);
if (!t->session) {
- giterr_set(GITERR_OS, "Failed to init WinHTTP");
+ giterr_set(GITERR_OS, "failed to init WinHTTP");
goto on_error;
}
if (!WinHttpSetTimeouts(t->session, default_timeout, default_connect_timeout, default_timeout, default_timeout)) {
- giterr_set(GITERR_OS, "Failed to set timeouts for WinHTTP");
+ giterr_set(GITERR_OS, "failed to set timeouts for WinHTTP");
goto on_error;
}
-
+
/* Establish connection */
t->connection = WinHttpConnect(
t->session,
@@ -759,7 +804,12 @@ static int winhttp_connect(
0);
if (!t->connection) {
- giterr_set(GITERR_OS, "Failed to connect to host");
+ giterr_set(GITERR_OS, "failed to connect to host");
+ goto on_error;
+ }
+
+ if (WinHttpSetStatusCallback(t->connection, winhttp_status, WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, 0) == WINHTTP_INVALID_STATUS_CALLBACK) {
+ giterr_set(GITERR_OS, "failed to set status callback");
goto on_error;
}
@@ -801,16 +851,15 @@ static int send_request(winhttp_stream *s, size_t len, int ignore_length)
int request_failed = 0, cert_valid = 1, error = 0;
DWORD ignore_flags;
- if ((error = do_send_request(s, len, ignore_length)) < 0)
- request_failed = 1;
-
- if (request_failed) {
+ giterr_clear();
+ if ((error = do_send_request(s, len, ignore_length)) < 0) {
if (GetLastError() != ERROR_WINHTTP_SECURE_FAILURE) {
giterr_set(GITERR_OS, "failed to send request");
return -1;
- } else {
- cert_valid = 0;
}
+
+ request_failed = 1;
+ cert_valid = 0;
}
giterr_clear();
@@ -826,14 +875,14 @@ static int send_request(winhttp_stream *s, size_t len, int ignore_length)
return 0;
ignore_flags = no_check_cert_flags;
-
+
if (!WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS, &ignore_flags, sizeof(ignore_flags))) {
giterr_set(GITERR_OS, "failed to set security options");
return -1;
}
if ((error = do_send_request(s, len, ignore_length)) < 0)
- giterr_set(GITERR_OS, "failed to send request");
+ giterr_set(GITERR_OS, "failed to send request with unchecked certificate");
return error;
}
@@ -853,7 +902,7 @@ static int winhttp_stream_read(
replay:
/* Enforce a reasonable cap on the number of replays */
if (++replay_count >= 7) {
- giterr_set(GITERR_NET, "Too many redirects or authentication replays");
+ giterr_set(GITERR_NET, "too many redirects or authentication replays");
return -1;
}
@@ -888,7 +937,7 @@ replay:
if (!WinHttpWriteData(s->request,
"0\r\n\r\n", 5,
&bytes_written)) {
- giterr_set(GITERR_OS, "Failed to write final chunk");
+ giterr_set(GITERR_OS, "failed to write final chunk");
return -1;
}
}
@@ -899,7 +948,7 @@ replay:
if (INVALID_SET_FILE_POINTER == SetFilePointer(s->post_body,
0, 0, FILE_BEGIN) &&
NO_ERROR != GetLastError()) {
- giterr_set(GITERR_OS, "Failed to reset file pointer");
+ giterr_set(GITERR_OS, "failed to reset file pointer");
return -1;
}
@@ -913,14 +962,14 @@ replay:
&bytes_read, NULL) ||
!bytes_read) {
git__free(buffer);
- giterr_set(GITERR_OS, "Failed to read from temp file");
+ giterr_set(GITERR_OS, "failed to read from temp file");
return -1;
}
if (!WinHttpWriteData(s->request, buffer,
bytes_read, &bytes_written)) {
git__free(buffer);
- giterr_set(GITERR_OS, "Failed to write data");
+ giterr_set(GITERR_OS, "failed to write data");
return -1;
}
@@ -936,7 +985,7 @@ replay:
}
if (!WinHttpReceiveResponse(s->request, 0)) {
- giterr_set(GITERR_OS, "Failed to receive response");
+ giterr_set(GITERR_OS, "failed to receive response");
return -1;
}
@@ -948,7 +997,7 @@ replay:
WINHTTP_HEADER_NAME_BY_INDEX,
&status_code, &status_code_length,
WINHTTP_NO_HEADER_INDEX)) {
- giterr_set(GITERR_OS, "Failed to retrieve status code");
+ giterr_set(GITERR_OS, "failed to retrieve status code");
return -1;
}
@@ -978,7 +1027,7 @@ replay:
&location_length,
WINHTTP_NO_HEADER_INDEX) ||
GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
- giterr_set(GITERR_OS, "Failed to read Location header");
+ giterr_set(GITERR_OS, "failed to read Location header");
return -1;
}
@@ -991,14 +1040,14 @@ replay:
location,
&location_length,
WINHTTP_NO_HEADER_INDEX)) {
- giterr_set(GITERR_OS, "Failed to read Location header");
+ giterr_set(GITERR_OS, "failed to read Location header");
git__free(location);
return -1;
}
/* Convert the Location header to UTF-8 */
if (git__utf16_to_8_alloc(&location8, location) < 0) {
- giterr_set(GITERR_OS, "Failed to convert Location header to UTF-8");
+ giterr_set(GITERR_OS, "failed to convert Location header to UTF-8");
git__free(location);
return -1;
}
@@ -1029,13 +1078,13 @@ replay:
if (status_code == HTTP_STATUS_PROXY_AUTH_REQ) {
int allowed_types;
- if (parse_unauthorized_response(s->request, &allowed_types, &t->auth_mechanism) < 0)
+ if (parse_unauthorized_response(s->request, &allowed_types, &t->auth_mechanisms) < 0)
return -1;
/* TODO: extract the username from the url, no payload? */
if (t->owner->proxy.credentials) {
int cred_error = 1;
- cred_error = t->owner->proxy.credentials(&t->proxy_cred, t->owner->proxy.url, NULL, allowed_types, NULL);
+ cred_error = t->owner->proxy.credentials(&t->proxy_cred, t->owner->proxy.url, NULL, allowed_types, t->owner->proxy.payload);
if (cred_error < 0)
return cred_error;
@@ -1049,7 +1098,7 @@ replay:
if (HTTP_STATUS_DENIED == status_code && get_verb == s->verb) {
int allowed_types;
- if (parse_unauthorized_response(s->request, &allowed_types, &t->auth_mechanism) < 0)
+ if (parse_unauthorized_response(s->request, &allowed_types, &t->auth_mechanisms) < 0)
return -1;
if (allowed_types) {
@@ -1090,7 +1139,7 @@ replay:
}
if (HTTP_STATUS_OK != status_code) {
- giterr_set(GITERR_NET, "Request failed with status code: %d", status_code);
+ giterr_set(GITERR_NET, "request failed with status code: %d", status_code);
return -1;
}
@@ -1101,7 +1150,7 @@ replay:
p_snprintf(expected_content_type_8, MAX_CONTENT_TYPE_LEN, "application/x-git-%s-advertisement", s->service);
if (git__utf8_to_16(expected_content_type, MAX_CONTENT_TYPE_LEN, expected_content_type_8) < 0) {
- giterr_set(GITERR_OS, "Failed to convert expected content-type to wide characters");
+ giterr_set(GITERR_OS, "failed to convert expected content-type to wide characters");
return -1;
}
@@ -1112,12 +1161,12 @@ replay:
WINHTTP_HEADER_NAME_BY_INDEX,
&content_type, &content_type_length,
WINHTTP_NO_HEADER_INDEX)) {
- giterr_set(GITERR_OS, "Failed to retrieve response content-type");
+ giterr_set(GITERR_OS, "failed to retrieve response content-type");
return -1;
}
if (wcscmp(expected_content_type, content_type)) {
- giterr_set(GITERR_NET, "Received unexpected content-type");
+ giterr_set(GITERR_NET, "received unexpected content-type");
return -1;
}
@@ -1129,7 +1178,7 @@ replay:
(DWORD)buf_size,
&dw_bytes_read))
{
- giterr_set(GITERR_OS, "Failed to read data");
+ giterr_set(GITERR_OS, "failed to read data");
return -1;
}
@@ -1152,7 +1201,7 @@ static int winhttp_stream_write_single(
/* This implementation of write permits only a single call. */
if (s->sent_request) {
- giterr_set(GITERR_NET, "Subtransport configured for only one write");
+ giterr_set(GITERR_NET, "subtransport configured for only one write");
return -1;
}
@@ -1165,7 +1214,7 @@ static int winhttp_stream_write_single(
(LPCVOID)buffer,
(DWORD)len,
&bytes_written)) {
- giterr_set(GITERR_OS, "Failed to write data");
+ giterr_set(GITERR_OS, "failed to write data");
return -1;
}
@@ -1183,12 +1232,12 @@ static int put_uuid_string(LPWSTR buffer, size_t buffer_len_cch)
if (RPC_S_OK != status &&
RPC_S_UUID_LOCAL_ONLY != status &&
RPC_S_UUID_NO_ADDRESS != status) {
- giterr_set(GITERR_NET, "Unable to generate name for temp file");
+ giterr_set(GITERR_NET, "unable to generate name for temp file");
return -1;
}
if (buffer_len_cch < UUID_LENGTH_CCH + 1) {
- giterr_set(GITERR_NET, "Buffer too small for name of temp file");
+ giterr_set(GITERR_NET, "buffer too small for name of temp file");
return -1;
}
@@ -1203,7 +1252,7 @@ static int put_uuid_string(LPWSTR buffer, size_t buffer_len_cch)
uuid.Data4[4], uuid.Data4[5], uuid.Data4[6], uuid.Data4[7]);
if (result < UUID_LENGTH_CCH) {
- giterr_set(GITERR_OS, "Unable to generate name for temp file");
+ giterr_set(GITERR_OS, "unable to generate name for temp file");
return -1;
}
@@ -1215,7 +1264,7 @@ static int get_temp_file(LPWSTR buffer, DWORD buffer_len_cch)
size_t len;
if (!GetTempPathW(buffer_len_cch, buffer)) {
- giterr_set(GITERR_OS, "Failed to get temp path");
+ giterr_set(GITERR_OS, "failed to get temp path");
return -1;
}
@@ -1258,13 +1307,13 @@ static int winhttp_stream_write_buffered(
if (INVALID_HANDLE_VALUE == s->post_body) {
s->post_body = NULL;
- giterr_set(GITERR_OS, "Failed to create temporary file");
+ giterr_set(GITERR_OS, "failed to create temporary file");
return -1;
}
}
if (!WriteFile(s->post_body, buffer, (DWORD)len, &bytes_written, NULL)) {
- giterr_set(GITERR_OS, "Failed to write to temporary file");
+ giterr_set(GITERR_OS, "failed to write to temporary file");
return -1;
}
@@ -1291,7 +1340,7 @@ static int winhttp_stream_write_chunked(
if (!WinHttpAddRequestHeaders(s->request,
transfer_encoding, (ULONG) -1L,
WINHTTP_ADDREQ_FLAG_ADD)) {
- giterr_set(GITERR_OS, "Failed to add a header to the request");
+ giterr_set(GITERR_OS, "failed to add a header to the request");
return -1;
}
diff --git a/src/tree-cache.c b/src/tree-cache.c
index b37be0f0d..b331d22a2 100644
--- a/src/tree-cache.c
+++ b/src/tree-cache.c
@@ -6,6 +6,7 @@
*/
#include "tree-cache.h"
+
#include "pool.h"
#include "tree.h"
@@ -137,7 +138,7 @@ static int read_tree_internal(git_tree_cache **out,
return 0;
corrupted:
- giterr_set(GITERR_INDEX, "Corrupted TREE extension in index");
+ giterr_set(GITERR_INDEX, "corrupted TREE extension in index");
return -1;
}
@@ -149,7 +150,7 @@ int git_tree_cache_read(git_tree_cache **tree, const char *buffer, size_t buffer
return -1;
if (buffer < buffer_end) {
- giterr_set(GITERR_INDEX, "Corrupted TREE extension in index (unexpected trailing data)");
+ giterr_set(GITERR_INDEX, "corrupted TREE extension in index (unexpected trailing data)");
return -1;
}
diff --git a/src/tree-cache.h b/src/tree-cache.h
index c44ca7cf5..e02300e6e 100644
--- a/src/tree-cache.h
+++ b/src/tree-cache.h
@@ -9,6 +9,7 @@
#define INCLUDE_tree_cache_h__
#include "common.h"
+
#include "pool.h"
#include "buffer.h"
#include "git2/oid.h"
diff --git a/src/tree.c b/src/tree.c
index 5db2446bf..fcee7f3b3 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -5,9 +5,9 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
-#include "commit.h"
#include "tree.h"
+
+#include "commit.h"
#include "git2/repository.h"
#include "git2/object.h"
#include "fileops.h"
@@ -20,8 +20,6 @@
#define TREE_ENTRY_CHECK_NAMELEN(n) \
if (n > UINT16_MAX) { giterr_set(GITERR_INVALID, "tree entry path too long"); }
-GIT__USE_STRMAP
-
static bool valid_filemode(const int filemode)
{
return (filemode == GIT_FILEMODE_TREE
@@ -447,7 +445,12 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj)
if ((nul = memchr(buffer, 0, buffer_end - buffer)) == NULL)
return tree_error("Failed to parse tree. Object is corrupted", NULL);
- filename_len = nul - buffer;
+ if ((filename_len = nul - buffer) == 0)
+ return tree_error("Failed to parse tree. Can't parse filename", NULL);
+
+ if ((buffer_end - (nul + 1)) < GIT_OID_RAWSZ)
+ return tree_error("Failed to parse tree. Can't parse OID", NULL);
+
/* Allocate the entry */
{
entry = git_array_alloc(tree->entries);
@@ -500,7 +503,7 @@ static int append_entry(
entry->attr = (uint16_t)filemode;
- git_strmap_insert(bld->map, entry->filename, entry, error);
+ git_strmap_insert(bld->map, entry->filename, entry, &error);
if (error < 0) {
git_tree_entry_free(entry);
giterr_set(GITERR_TREE, "failed to append entry %s to the tree builder", filename);
@@ -515,7 +518,8 @@ static int write_tree(
git_repository *repo,
git_index *index,
const char *dirname,
- size_t start)
+ size_t start,
+ git_buf *shared_buf)
{
git_treebuilder *bld = NULL;
size_t i, entries = git_index_entrycount(index);
@@ -568,7 +572,7 @@ static int write_tree(
GITERR_CHECK_ALLOC(subdir);
/* Write out the subtree */
- written = write_tree(&sub_oid, repo, index, subdir, i);
+ written = write_tree(&sub_oid, repo, index, subdir, i, shared_buf);
if (written < 0) {
git__free(subdir);
goto on_error;
@@ -600,7 +604,7 @@ static int write_tree(
}
}
- if (git_treebuilder_write(oid, bld) < 0)
+ if (git_treebuilder_write_with_buffer(oid, bld, shared_buf) < 0)
goto on_error;
git_treebuilder_free(bld);
@@ -616,13 +620,14 @@ int git_tree__write_index(
{
int ret;
git_tree *tree;
+ git_buf shared_buf = GIT_BUF_INIT;
bool old_ignore_case = false;
assert(oid && index && repo);
if (git_index_has_conflicts(index)) {
giterr_set(GITERR_INDEX,
- "Cannot create a tree from a not fully merged index.");
+ "cannot create a tree from a not fully merged index.");
return GIT_EUNMERGED;
}
@@ -641,7 +646,8 @@ int git_tree__write_index(
git_index__set_ignore_case(index, false);
}
- ret = write_tree(oid, repo, index, "", 0);
+ ret = write_tree(oid, repo, index, "", 0, &shared_buf);
+ git_buf_free(&shared_buf);
if (old_ignore_case)
git_index__set_ignore_case(index, true);
@@ -746,7 +752,7 @@ int git_treebuilder_insert(
entry = alloc_entry(filename, strlen(filename), id);
GITERR_CHECK_ALLOC(entry);
- git_strmap_insert(bld->map, entry->filename, entry, error);
+ git_strmap_insert(bld->map, entry->filename, entry, &error);
if (error < 0) {
git_tree_entry_free(entry);
@@ -797,46 +803,60 @@ int git_treebuilder_remove(git_treebuilder *bld, const char *filename)
int git_treebuilder_write(git_oid *oid, git_treebuilder *bld)
{
+ int error;
+ git_buf buffer = GIT_BUF_INIT;
+
+ error = git_treebuilder_write_with_buffer(oid, bld, &buffer);
+
+ git_buf_free(&buffer);
+ return error;
+}
+
+int git_treebuilder_write_with_buffer(git_oid *oid, git_treebuilder *bld, git_buf *tree)
+{
int error = 0;
size_t i, entrycount;
- git_buf tree = GIT_BUF_INIT;
git_odb *odb;
git_tree_entry *entry;
- git_vector entries;
+ git_vector entries = GIT_VECTOR_INIT;
assert(bld);
+ assert(tree);
+
+ git_buf_clear(tree);
entrycount = git_strmap_num_entries(bld->map);
- if (git_vector_init(&entries, entrycount, entry_sort_cmp) < 0)
- return -1;
+ if ((error = git_vector_init(&entries, entrycount, entry_sort_cmp)) < 0)
+ goto out;
+
+ if (tree->asize == 0 &&
+ (error = git_buf_grow(tree, entrycount * 72)) < 0)
+ goto out;
git_strmap_foreach_value(bld->map, entry, {
- if (git_vector_insert(&entries, entry) < 0)
- return -1;
+ if ((error = git_vector_insert(&entries, entry)) < 0)
+ goto out;
});
git_vector_sort(&entries);
- /* Grow the buffer beforehand to an estimated size */
- error = git_buf_grow(&tree, entrycount * 72);
-
for (i = 0; i < entries.length && !error; ++i) {
- git_tree_entry *entry = git_vector_get(&entries, i);
+ entry = git_vector_get(&entries, i);
- git_buf_printf(&tree, "%o ", entry->attr);
- git_buf_put(&tree, entry->filename, entry->filename_len + 1);
- git_buf_put(&tree, (char *)entry->oid->id, GIT_OID_RAWSZ);
+ git_buf_printf(tree, "%o ", entry->attr);
+ git_buf_put(tree, entry->filename, entry->filename_len + 1);
+ git_buf_put(tree, (char *)entry->oid->id, GIT_OID_RAWSZ);
- if (git_buf_oom(&tree))
+ if (git_buf_oom(tree)) {
error = -1;
+ goto out;
+ }
}
+ if ((error = git_repository_odb__weakptr(&odb, bld->repo)) == 0)
+ error = git_odb_write(oid, odb, tree->ptr, tree->size, GIT_OBJ_TREE);
- if (!error &&
- !(error = git_repository_odb__weakptr(&odb, bld->repo)))
- error = git_odb_write(oid, odb, tree.ptr, tree.size, GIT_OBJ_TREE);
-
- git_buf_free(&tree);
+out:
git_vector_free(&entries);
return error;
@@ -904,7 +924,7 @@ int git_tree_entry_bypath(
filename_len = subpath_len(path);
if (filename_len == 0) {
- giterr_set(GITERR_TREE, "Invalid tree path given");
+ giterr_set(GITERR_TREE, "invalid tree path given");
return GIT_ENOTFOUND;
}
@@ -912,7 +932,7 @@ int git_tree_entry_bypath(
if (entry == NULL) {
giterr_set(GITERR_TREE,
- "the path '%.*s' does not exist in the given tree", filename_len, path);
+ "the path '%.*s' does not exist in the given tree", (int) filename_len, path);
return GIT_ENOTFOUND;
}
@@ -922,7 +942,7 @@ int git_tree_entry_bypath(
* then this entry *must* be a tree */
if (!git_tree_entry__is_tree(entry)) {
giterr_set(GITERR_TREE,
- "the path '%.*s' exists but is not a tree", filename_len, path);
+ "the path '%.*s' exists but is not a tree", (int) filename_len, path);
return GIT_ENOTFOUND;
}
@@ -1022,7 +1042,7 @@ int git_tree_walk(
git_buf root_path = GIT_BUF_INIT;
if (mode != GIT_TREEWALK_POST && mode != GIT_TREEWALK_PRE) {
- giterr_set(GITERR_INVALID, "Invalid walking mode for tree walk");
+ giterr_set(GITERR_INVALID, "invalid walking mode for tree walk");
return -1;
}
@@ -1159,8 +1179,8 @@ int git_tree_create_updated(git_oid *out, git_repository *repo, git_tree *baseli
goto cleanup;
for (i = 0; i < nupdates; i++) {
- const git_tree_update *last_update = i == 0 ? NULL : &updates[i-1];
- const git_tree_update *update = &updates[i];
+ const git_tree_update *last_update = i == 0 ? NULL : git_vector_get(&entries, i-1);
+ const git_tree_update *update = git_vector_get(&entries, i);
size_t common_prefix = 0, steps_up, j;
const char *path;
@@ -1195,6 +1215,9 @@ int git_tree_create_updated(git_oid *out, git_repository *repo, git_tree *baseli
last = git_array_last(stack);
entry = last->tree ? git_tree_entry_byname(last->tree, component.ptr) : NULL;
+ if (!entry)
+ entry = treebuilder_get(last->bld, component.ptr);
+
if (entry && git_tree_entry_type(entry) != GIT_OBJ_TREE) {
giterr_set(GITERR_TREE, "D/F conflict when updating tree");
error = -1;
@@ -1229,7 +1252,7 @@ int git_tree_create_updated(git_oid *out, git_repository *repo, git_tree *baseli
const git_tree_entry *e = git_treebuilder_get(last->bld, basename);
if (e && git_tree_entry_type(e) != git_object__type_from_filemode(update->filemode)) {
git__free(basename);
- giterr_set(GITERR_TREE, "Cannot replace '%s' with '%s' at '%s'",
+ giterr_set(GITERR_TREE, "cannot replace '%s' with '%s' at '%s'",
git_object_type2string(git_tree_entry_type(e)),
git_object_type2string(git_object__type_from_filemode(update->filemode)),
update->path);
@@ -1249,7 +1272,7 @@ int git_tree_create_updated(git_oid *out, git_repository *repo, git_tree *baseli
break;
}
default:
- giterr_set(GITERR_TREE, "unkown action for update");
+ giterr_set(GITERR_TREE, "unknown action for update");
error = -1;
goto cleanup;
}
diff --git a/src/tree.h b/src/tree.h
index 5e7a66e04..00f4b06eb 100644
--- a/src/tree.h
+++ b/src/tree.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_tree_h__
#define INCLUDE_tree_h__
+#include "common.h"
+
#include "git2/tree.h"
#include "repository.h"
#include "odb.h"
diff --git a/src/tsort.c b/src/tsort.c
index e59819204..8d1ed9787 100644
--- a/src/tsort.c
+++ b/src/tsort.c
@@ -310,7 +310,6 @@ static ssize_t collapse(void **dst, struct tsort_run *stack, ssize_t stack_curr,
#define PUSH_NEXT() do {\
len = count_run(dst, curr, size, store);\
run = minrun;\
- if (run < minrun) run = minrun;\
if (run > (ssize_t)size - curr) run = size - curr;\
if (run > len) {\
bisort(&dst[curr], len, run, cmp, payload);\
diff --git a/src/unix/map.c b/src/unix/map.c
index c55ad1aa7..8a07fcff9 100644
--- a/src/unix/map.c
+++ b/src/unix/map.c
@@ -4,7 +4,10 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include <git2/common.h>
+
+#include "common.h"
+
+#include "git2/common.h"
#if !defined(GIT_WIN32) && !defined(NO_MMAP)
@@ -52,7 +55,7 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs
out->data = mmap(NULL, len, mprot, mflag, fd, offset);
if (!out->data || out->data == MAP_FAILED) {
- giterr_set(GITERR_OS, "Failed to mmap. Could not write data");
+ giterr_set(GITERR_OS, "failed to mmap. Could not write data");
return -1;
}
diff --git a/src/unix/posix.h b/src/unix/posix.h
index 482d2c803..ee36ea0f3 100644
--- a/src/unix/posix.h
+++ b/src/unix/posix.h
@@ -7,6 +7,10 @@
#ifndef INCLUDE_posix__unix_h__
#define INCLUDE_posix__unix_h__
+#ifndef LIBGIT2_NO_FEATURES_H
+# include "git2/sys/features.h"
+#endif
+
#include <stdio.h>
#include <dirent.h>
#include <sys/param.h>
@@ -40,9 +44,14 @@ typedef int GIT_SOCKET;
#define p_link(o,n) link(o, n)
#define p_unlink(p) unlink(p)
#define p_mkdir(p,m) mkdir(p, m)
-#define p_fsync(fd) fsync(fd)
extern char *p_realpath(const char *, char *);
+GIT_INLINE(int) p_fsync(int fd)
+{
+ p_fsync__cnt++;
+ return fsync(fd);
+}
+
#define p_recv(s,b,l,f) recv(s,b,l,f)
#define p_send(s,b,l,f) send(s,b,l,f)
#define p_inet_pton(a, b, c) inet_pton(a, b, c)
@@ -50,7 +59,7 @@ extern char *p_realpath(const char *, char *);
#define p_strcasecmp(s1, s2) strcasecmp(s1, s2)
#define p_strncasecmp(s1, s2, c) strncasecmp(s1, s2, c)
#define p_vsnprintf(b, c, f, a) vsnprintf(b, c, f, a)
-#define p_snprintf(b, c, f, ...) snprintf(b, c, f, __VA_ARGS__)
+#define p_snprintf(b, c, ...) snprintf(b, c, __VA_ARGS__)
#define p_mkstemp(p) mkstemp(p)
#define p_chdir(p) chdir(p)
#define p_chmod(p,m) chmod(p, m)
@@ -66,7 +75,7 @@ extern char *p_realpath(const char *, char *);
#define p_timeval timeval
-#ifdef HAVE_FUTIMENS
+#ifdef GIT_USE_FUTIMENS
GIT_INLINE(int) p_futimes(int f, const struct p_timeval t[2])
{
struct timespec s[2];
@@ -80,4 +89,14 @@ GIT_INLINE(int) p_futimes(int f, const struct p_timeval t[2])
# define p_futimes futimes
#endif
+#ifdef GIT_USE_REGCOMP_L
+#include <xlocale.h>
+GIT_INLINE(int) p_regcomp(regex_t *preg, const char *pattern, int cflags)
+{
+ return regcomp_l(preg, pattern, cflags, (locale_t) 0);
+}
+#else
+# define p_regcomp regcomp
+#endif
+
#endif
diff --git a/src/unix/pthread.h b/src/unix/pthread.h
index 0f3f17927..3f23d10d5 100644
--- a/src/unix/pthread.h
+++ b/src/unix/pthread.h
@@ -17,6 +17,8 @@ typedef struct {
pthread_create(&(git_thread_ptr)->thread, NULL, start_routine, arg)
#define git_thread_join(git_thread_ptr, status) \
pthread_join((git_thread_ptr)->thread, status)
+#define git_thread_currentid() ((size_t)(pthread_self()))
+#define git_thread_exit(retval) pthread_exit(retval)
/* Git Mutex */
#define git_mutex pthread_mutex_t
diff --git a/src/unix/realpath.c b/src/unix/realpath.c
index 2e49150c2..893bac87b 100644
--- a/src/unix/realpath.c
+++ b/src/unix/realpath.c
@@ -4,7 +4,10 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include <git2/common.h>
+
+#include "common.h"
+
+#include "git2/common.h"
#ifndef GIT_WIN32
diff --git a/src/util.c b/src/util.c
index 76ca711b2..6ae5cdaec 100644
--- a/src/util.c
+++ b/src/util.c
@@ -4,8 +4,10 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include <git2.h>
-#include "common.h"
+
+#include "util.h"
+
+#include "git2.h"
#include <stdio.h>
#include <ctype.h>
#include "posix.h"
@@ -136,7 +138,7 @@ int git__strntol64(int64_t *result, const char *nptr, size_t nptr_len, const cha
Return:
if (ndig == 0) {
- giterr_set(GITERR_INVALID, "Failed to convert string to long. Not a number");
+ giterr_set(GITERR_INVALID, "failed to convert string to long: not a number");
return -1;
}
@@ -144,7 +146,7 @@ Return:
*endptr = p;
if (ovfl) {
- giterr_set(GITERR_INVALID, "Failed to convert string to long. Overflow error");
+ giterr_set(GITERR_INVALID, "failed to convert string to long: overflow error");
return -1;
}
@@ -169,7 +171,7 @@ int git__strntol32(int32_t *result, const char *nptr, size_t nptr_len, const cha
tmp_int = tmp_long & 0xFFFFFFFF;
if (tmp_int != tmp_long) {
- giterr_set(GITERR_INVALID, "Failed to convert. '%s' is too large", nptr);
+ giterr_set(GITERR_INVALID, "failed to convert: '%s' is too large", nptr);
return -1;
}
diff --git a/src/util.h b/src/util.h
index eb15250d8..b85e03b6d 100644
--- a/src/util.h
+++ b/src/util.h
@@ -7,39 +7,11 @@
#ifndef INCLUDE_util_h__
#define INCLUDE_util_h__
+#include "common.h"
+
#include "git2/buffer.h"
#include "buffer.h"
-
-#if defined(GIT_MSVC_CRTDBG)
-/* Enable MSVC CRTDBG memory leak reporting.
- *
- * We DO NOT use the "_CRTDBG_MAP_ALLOC" macro described in the MSVC
- * documentation because all allocs/frees in libgit2 already go through
- * the "git__" routines defined in this file. Simply using the normal
- * reporting mechanism causes all leaks to be attributed to a routine
- * here in util.h (ie, the actual call to calloc()) rather than the
- * caller of git__calloc().
- *
- * Therefore, we declare a set of "git__crtdbg__" routines to replace
- * the corresponding "git__" routines and re-define the "git__" symbols
- * as macros. This allows us to get and report the file:line info of
- * the real caller.
- *
- * We DO NOT replace the "git__free" routine because it needs to remain
- * a function pointer because it is used as a function argument when
- * setting up various structure "destructors".
- *
- * We also DO NOT use the "_CRTDBG_MAP_ALLOC" macro because it causes
- * "free" to be remapped to "_free_dbg" and this causes problems for
- * structures which define a field named "free".
- *
- * Finally, CRTDBG must be explicitly enabled and configured at program
- * startup. See tests/main.c for an example.
- */
-#include <stdlib.h>
-#include <crtdbg.h>
-#include "win32/w32_crtdbg_stacktrace.h"
-#endif
+#include "thread-utils.h"
#include "common.h"
#include "strnlen.h"
@@ -67,79 +39,33 @@
#if defined(GIT_MSVC_CRTDBG)
-GIT_INLINE(void *) git__crtdbg__malloc(size_t len, const char *file, int line)
-{
- void *ptr = _malloc_dbg(len, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
- if (!ptr) giterr_set_oom();
- return ptr;
-}
-
-GIT_INLINE(void *) git__crtdbg__calloc(size_t nelem, size_t elsize, const char *file, int line)
-{
- void *ptr = _calloc_dbg(nelem, elsize, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
- if (!ptr) giterr_set_oom();
- return ptr;
-}
-
-GIT_INLINE(char *) git__crtdbg__strdup(const char *str, const char *file, int line)
-{
- char *ptr = _strdup_dbg(str, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
- if (!ptr) giterr_set_oom();
- return ptr;
-}
-
-GIT_INLINE(char *) git__crtdbg__strndup(const char *str, size_t n, const char *file, int line)
-{
- size_t length = 0, alloclength;
- char *ptr;
-
- length = p_strnlen(str, n);
-
- if (GIT_ADD_SIZET_OVERFLOW(&alloclength, length, 1) ||
- !(ptr = git__crtdbg__malloc(alloclength, file, line)))
- return NULL;
-
- if (length)
- memcpy(ptr, str, length);
-
- ptr[length] = '\0';
-
- return ptr;
-}
-
-GIT_INLINE(char *) git__crtdbg__substrdup(const char *start, size_t n, const char *file, int line)
-{
- char *ptr;
- size_t alloclen;
-
- if (GIT_ADD_SIZET_OVERFLOW(&alloclen, n, 1) ||
- !(ptr = git__crtdbg__malloc(alloclen, file, line)))
- return NULL;
-
- memcpy(ptr, start, n);
- ptr[n] = '\0';
- return ptr;
-}
-
-GIT_INLINE(void *) git__crtdbg__realloc(void *ptr, size_t size, const char *file, int line)
-{
- void *new_ptr = _realloc_dbg(ptr, size, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
- if (!new_ptr) giterr_set_oom();
- return new_ptr;
-}
-
-GIT_INLINE(void *) git__crtdbg__reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line)
-{
- size_t newsize;
-
- return GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize) ?
- NULL : _realloc_dbg(ptr, newsize, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
-}
+/* Enable MSVC CRTDBG memory leak reporting.
+ *
+ * We DO NOT use the "_CRTDBG_MAP_ALLOC" macro described in the MSVC
+ * documentation because all allocs/frees in libgit2 already go through
+ * the "git__" routines defined in this file. Simply using the normal
+ * reporting mechanism causes all leaks to be attributed to a routine
+ * here in util.h (ie, the actual call to calloc()) rather than the
+ * caller of git__calloc().
+ *
+ * Therefore, we declare a set of "git__crtdbg__" routines to replace
+ * the corresponding "git__" routines and re-define the "git__" symbols
+ * as macros. This allows us to get and report the file:line info of
+ * the real caller.
+ *
+ * We DO NOT replace the "git__free" routine because it needs to remain
+ * a function pointer because it is used as a function argument when
+ * setting up various structure "destructors".
+ *
+ * We also DO NOT use the "_CRTDBG_MAP_ALLOC" macro because it causes
+ * "free" to be remapped to "_free_dbg" and this causes problems for
+ * structures which define a field named "free".
+ *
+ * Finally, CRTDBG must be explicitly enabled and configured at program
+ * startup. See tests/main.c for an example.
+ */
-GIT_INLINE(void *) git__crtdbg__mallocarray(size_t nelem, size_t elsize, const char *file, int line)
-{
- return git__crtdbg__reallocarray(NULL, nelem, elsize, file, line);
-}
+#include "win32/w32_crtdbg_stacktrace.h"
#define git__malloc(len) git__crtdbg__malloc(len, __FILE__, __LINE__)
#define git__calloc(nelem, elsize) git__crtdbg__calloc(nelem, elsize, __FILE__, __LINE__)
@@ -363,8 +289,6 @@ extern int git__strncasecmp(const char *a, const char *b, size_t sz);
extern int git__strcasesort_cmp(const char *a, const char *b);
-#include "thread-utils.h"
-
typedef struct {
git_atomic refcount;
void *owner;
diff --git a/src/varint.c b/src/varint.c
index 2f868607c..9ffc1d744 100644
--- a/src/varint.c
+++ b/src/varint.c
@@ -5,7 +5,6 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
#include "varint.h"
uintmax_t git_decode_varint(const unsigned char *bufp, size_t *varint_len)
@@ -36,7 +35,7 @@ int git_encode_varint(unsigned char *buf, size_t bufsize, uintmax_t value)
while (value >>= 7)
varint[--pos] = 128 | (--value & 127);
if (buf) {
- if (bufsize < pos)
+ if (bufsize < (sizeof(varint) - pos))
return -1;
memcpy(buf, varint + pos, sizeof(varint) - pos);
}
diff --git a/src/varint.h b/src/varint.h
index 650ec7d2a..652e22486 100644
--- a/src/varint.h
+++ b/src/varint.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_varint_h__
#define INCLUDE_varint_h__
+#include "common.h"
+
#include <stdint.h>
extern int git_encode_varint(unsigned char *, size_t, uintmax_t);
diff --git a/src/vector.c b/src/vector.c
index db1dcf89a..b12fa942d 100644
--- a/src/vector.c
+++ b/src/vector.c
@@ -5,8 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
#include "vector.h"
+
#include "integer.h"
/* In elements, not bytes */
@@ -401,3 +401,22 @@ int git_vector_verify_sorted(const git_vector *v)
return 0;
}
+
+void git_vector_reverse(git_vector *v)
+{
+ size_t a, b;
+
+ if (v->length == 0)
+ return;
+
+ a = 0;
+ b = v->length - 1;
+
+ while (a < b) {
+ void *tmp = v->contents[a];
+ v->contents[a] = v->contents[b];
+ v->contents[b] = tmp;
+ a++;
+ b--;
+ }
+}
diff --git a/src/vector.h b/src/vector.h
index 96d149e16..cc4c314d5 100644
--- a/src/vector.h
+++ b/src/vector.h
@@ -118,4 +118,9 @@ GIT_INLINE(void) git_vector_set_cmp(git_vector *v, git_vector_cmp cmp)
/* Just use this in tests, not for realz. returns -1 if not sorted */
int git_vector_verify_sorted(const git_vector *v);
+/**
+ * Reverse the vector in-place.
+ */
+void git_vector_reverse(git_vector *v);
+
#endif
diff --git a/src/win32/dir.c b/src/win32/dir.c
index c15757085..1d37874e4 100644
--- a/src/win32/dir.c
+++ b/src/win32/dir.c
@@ -4,6 +4,9 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
+
+#include "dir.h"
+
#define GIT__WIN32_NO_WRAP_DIR
#include "posix.h"
@@ -28,7 +31,7 @@ git__DIR *git__opendir(const char *dir)
new->h = FindFirstFileW(filter_w, &new->f);
if (new->h == INVALID_HANDLE_VALUE) {
- giterr_set(GITERR_OS, "Could not open directory '%s'", dir);
+ giterr_set(GITERR_OS, "could not open directory '%s'", dir);
git__free(new);
return NULL;
}
@@ -53,7 +56,7 @@ int git__readdir_ext(
else if (!FindNextFileW(d->h, &d->f)) {
if (GetLastError() == ERROR_NO_MORE_FILES)
return 0;
- giterr_set(GITERR_OS, "Could not read from directory '%s'", d->dir);
+ giterr_set(GITERR_OS, "could not read from directory '%s'", d->dir);
return -1;
}
@@ -98,7 +101,7 @@ void git__rewinddir(git__DIR *d)
d->h = FindFirstFileW(filter_w, &d->f);
if (d->h == INVALID_HANDLE_VALUE)
- giterr_set(GITERR_OS, "Could not open directory '%s'", d->dir);
+ giterr_set(GITERR_OS, "could not open directory '%s'", d->dir);
else
d->first = 1;
}
diff --git a/src/win32/dir.h b/src/win32/dir.h
index bef39d774..704a9a8a9 100644
--- a/src/win32/dir.h
+++ b/src/win32/dir.h
@@ -8,6 +8,7 @@
#define INCLUDE_dir_h__
#include "common.h"
+
#include "w32_util.h"
struct git__dirent {
diff --git a/src/win32/error.c b/src/win32/error.c
index 6b450093f..3a52fb5a9 100644
--- a/src/win32/error.c
+++ b/src/win32/error.c
@@ -5,8 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
#include "error.h"
+
#include "utf-conv.h"
#ifdef GIT_WINHTTP
diff --git a/src/win32/error.h b/src/win32/error.h
index 12947a2e6..a2ecf6a6a 100644
--- a/src/win32/error.h
+++ b/src/win32/error.h
@@ -8,6 +8,8 @@
#ifndef INCLUDE_git_win32_error_h__
#define INCLUDE_git_win32_error_h__
+#include "common.h"
+
extern char *git_win32_get_error_message(DWORD error_code);
#endif
diff --git a/src/win32/findfile.c b/src/win32/findfile.c
index 58c22279e..d56aa1fd2 100644
--- a/src/win32/findfile.c
+++ b/src/win32/findfile.c
@@ -5,10 +5,11 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "findfile.h"
+
#include "path_w32.h"
#include "utf-conv.h"
#include "path.h"
-#include "findfile.h"
#define REG_MSYSGIT_INSTALL_LOCAL L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1"
@@ -38,7 +39,7 @@ static int win32_path_to_8(git_buf *dest, const wchar_t *src)
git_win32_utf8_path utf8_path;
if (git_win32_path_to_utf8(utf8_path, src) < 0) {
- giterr_set(GITERR_OS, "Unable to convert path to UTF-8");
+ giterr_set(GITERR_OS, "unable to convert path to UTF-8");
return -1;
}
diff --git a/src/win32/findfile.h b/src/win32/findfile.h
index 3d5fff439..1eae4691c 100644
--- a/src/win32/findfile.h
+++ b/src/win32/findfile.h
@@ -8,6 +8,8 @@
#ifndef INCLUDE_git_findfile_h__
#define INCLUDE_git_findfile_h__
+#include "common.h"
+
extern int git_win32__find_system_dirs(git_buf *out, const wchar_t *subpath);
extern int git_win32__find_global_dirs(git_buf *out);
extern int git_win32__find_xdg_dirs(git_buf *out);
diff --git a/src/win32/map.c b/src/win32/map.c
index 03a3646a6..6a17aeb64 100644
--- a/src/win32/map.c
+++ b/src/win32/map.c
@@ -5,6 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "common.h"
+
#include "map.h"
#include <errno.h>
@@ -67,7 +69,7 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs
if (fh == INVALID_HANDLE_VALUE) {
errno = EBADF;
- giterr_set(GITERR_OS, "Failed to mmap. Invalid handle value");
+ giterr_set(GITERR_OS, "failed to mmap. Invalid handle value");
return -1;
}
@@ -86,13 +88,13 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs
if (page_offset != 0) { /* offset must be multiple of the allocation granularity */
errno = EINVAL;
- giterr_set(GITERR_OS, "Failed to mmap. Offset must be multiple of allocation granularity");
+ giterr_set(GITERR_OS, "failed to mmap. Offset must be multiple of allocation granularity");
return -1;
}
out->fmh = CreateFileMapping(fh, NULL, fmap_prot, 0, 0, NULL);
if (!out->fmh || out->fmh == INVALID_HANDLE_VALUE) {
- giterr_set(GITERR_OS, "Failed to mmap. Invalid handle value");
+ giterr_set(GITERR_OS, "failed to mmap. Invalid handle value");
out->fmh = NULL;
return -1;
}
@@ -103,7 +105,7 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs
off_hi = (DWORD)(page_start >> 32);
out->data = MapViewOfFile(out->fmh, view_prot, off_hi, off_low, len);
if (!out->data) {
- giterr_set(GITERR_OS, "Failed to mmap. No data written");
+ giterr_set(GITERR_OS, "failed to mmap. No data written");
CloseHandle(out->fmh);
out->fmh = NULL;
return -1;
@@ -121,7 +123,7 @@ int p_munmap(git_map *map)
if (map->data) {
if (!UnmapViewOfFile(map->data)) {
- giterr_set(GITERR_OS, "Failed to munmap. Could not unmap view of file");
+ giterr_set(GITERR_OS, "failed to munmap. Could not unmap view of file");
error = -1;
}
map->data = NULL;
@@ -129,7 +131,7 @@ int p_munmap(git_map *map)
if (map->fmh) {
if (!CloseHandle(map->fmh)) {
- giterr_set(GITERR_OS, "Failed to munmap. Could not close handle");
+ giterr_set(GITERR_OS, "failed to munmap. Could not close handle");
error = -1;
}
map->fmh = NULL;
diff --git a/src/win32/path_w32.c b/src/win32/path_w32.c
index 40b95c33b..f8416b848 100644
--- a/src/win32/path_w32.c
+++ b/src/win32/path_w32.c
@@ -5,9 +5,9 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
-#include "path.h"
#include "path_w32.h"
+
+#include "path.h"
#include "utf-conv.h"
#include "posix.h"
#include "reparse.h"
diff --git a/src/win32/path_w32.h b/src/win32/path_w32.h
index 3d9f82860..ac1fb4b9e 100644
--- a/src/win32/path_w32.h
+++ b/src/win32/path_w32.h
@@ -8,6 +8,7 @@
#define INCLUDE_git_path_w32_h__
#include "common.h"
+
#include "vector.h"
/*
diff --git a/src/win32/posix.h b/src/win32/posix.h
index 5fab267c2..64769ecd3 100644
--- a/src/win32/posix.h
+++ b/src/win32/posix.h
@@ -14,6 +14,9 @@
#include "utf-conv.h"
#include "dir.h"
+extern unsigned long git_win32__createfile_sharemode;
+extern int git_win32__retries;
+
typedef SOCKET GIT_SOCKET;
#define p_lseek(f,n,w) _lseeki64(f, n, w)
@@ -57,4 +60,7 @@ extern int p_lstat_posixly(const char *filename, struct stat *buf);
extern struct tm * p_localtime_r(const time_t *timer, struct tm *result);
extern struct tm * p_gmtime_r(const time_t *timer, struct tm *result);
+/* Use the bundled regcomp */
+#define p_regcomp regcomp
+
#endif
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index fea634b00..f51e1e546 100644
--- a/src/win32/posix_w32.c
+++ b/src/win32/posix_w32.c
@@ -4,6 +4,9 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
+
+#include "common.h"
+
#include "../posix.h"
#include "../fileops.h"
#include "path.h"
@@ -26,15 +29,6 @@
#define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
#endif
-/* Options which we always provide to _wopen.
- *
- * _O_BINARY - Raw access; no translation of CR or LF characters
- * _O_NOINHERIT - Do not mark the created handle as inheritable by child processes.
- * The Windows default is 'not inheritable', but the CRT's default (following
- * POSIX convention) is 'inheritable'. We have no desire for our handles to be
- * inheritable on Windows, so specify the flag to get default behavior back. */
-#define STANDARD_OPEN_FLAGS (_O_BINARY | _O_NOINHERIT)
-
/* Allowable mode bits on Win32. Using mode bits that are not supported on
* Win32 (eg S_IRWXU) is generally ignored, but Wine warns loudly about it
* so we simply remove them.
@@ -44,6 +38,167 @@
/* GetFinalPathNameByHandleW signature */
typedef DWORD(WINAPI *PFGetFinalPathNameByHandleW)(HANDLE, LPWSTR, DWORD, DWORD);
+unsigned long git_win32__createfile_sharemode =
+ FILE_SHARE_READ | FILE_SHARE_WRITE;
+int git_win32__retries = 10;
+
+GIT_INLINE(void) set_errno(void)
+{
+ switch (GetLastError()) {
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ case ERROR_INVALID_DRIVE:
+ case ERROR_NO_MORE_FILES:
+ case ERROR_BAD_NETPATH:
+ case ERROR_BAD_NET_NAME:
+ case ERROR_BAD_PATHNAME:
+ case ERROR_FILENAME_EXCED_RANGE:
+ errno = ENOENT;
+ break;
+ case ERROR_BAD_ENVIRONMENT:
+ errno = E2BIG;
+ break;
+ case ERROR_BAD_FORMAT:
+ case ERROR_INVALID_STARTING_CODESEG:
+ case ERROR_INVALID_STACKSEG:
+ case ERROR_INVALID_MODULETYPE:
+ case ERROR_INVALID_EXE_SIGNATURE:
+ case ERROR_EXE_MARKED_INVALID:
+ case ERROR_BAD_EXE_FORMAT:
+ case ERROR_ITERATED_DATA_EXCEEDS_64k:
+ case ERROR_INVALID_MINALLOCSIZE:
+ case ERROR_DYNLINK_FROM_INVALID_RING:
+ case ERROR_IOPL_NOT_ENABLED:
+ case ERROR_INVALID_SEGDPL:
+ case ERROR_AUTODATASEG_EXCEEDS_64k:
+ case ERROR_RING2SEG_MUST_BE_MOVABLE:
+ case ERROR_RELOC_CHAIN_XEEDS_SEGLIM:
+ case ERROR_INFLOOP_IN_RELOC_CHAIN:
+ errno = ENOEXEC;
+ break;
+ case ERROR_INVALID_HANDLE:
+ case ERROR_INVALID_TARGET_HANDLE:
+ case ERROR_DIRECT_ACCESS_HANDLE:
+ errno = EBADF;
+ break;
+ case ERROR_WAIT_NO_CHILDREN:
+ case ERROR_CHILD_NOT_COMPLETE:
+ errno = ECHILD;
+ break;
+ case ERROR_NO_PROC_SLOTS:
+ case ERROR_MAX_THRDS_REACHED:
+ case ERROR_NESTING_NOT_ALLOWED:
+ errno = EAGAIN;
+ break;
+ case ERROR_ARENA_TRASHED:
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_INVALID_BLOCK:
+ case ERROR_NOT_ENOUGH_QUOTA:
+ errno = ENOMEM;
+ break;
+ case ERROR_ACCESS_DENIED:
+ case ERROR_CURRENT_DIRECTORY:
+ case ERROR_WRITE_PROTECT:
+ case ERROR_BAD_UNIT:
+ case ERROR_NOT_READY:
+ case ERROR_BAD_COMMAND:
+ case ERROR_CRC:
+ case ERROR_BAD_LENGTH:
+ case ERROR_SEEK:
+ case ERROR_NOT_DOS_DISK:
+ case ERROR_SECTOR_NOT_FOUND:
+ case ERROR_OUT_OF_PAPER:
+ case ERROR_WRITE_FAULT:
+ case ERROR_READ_FAULT:
+ case ERROR_GEN_FAILURE:
+ case ERROR_SHARING_VIOLATION:
+ case ERROR_LOCK_VIOLATION:
+ case ERROR_WRONG_DISK:
+ case ERROR_SHARING_BUFFER_EXCEEDED:
+ case ERROR_NETWORK_ACCESS_DENIED:
+ case ERROR_CANNOT_MAKE:
+ case ERROR_FAIL_I24:
+ case ERROR_DRIVE_LOCKED:
+ case ERROR_SEEK_ON_DEVICE:
+ case ERROR_NOT_LOCKED:
+ case ERROR_LOCK_FAILED:
+ errno = EACCES;
+ break;
+ case ERROR_FILE_EXISTS:
+ case ERROR_ALREADY_EXISTS:
+ errno = EEXIST;
+ break;
+ case ERROR_NOT_SAME_DEVICE:
+ errno = EXDEV;
+ break;
+ case ERROR_INVALID_FUNCTION:
+ case ERROR_INVALID_ACCESS:
+ case ERROR_INVALID_DATA:
+ case ERROR_INVALID_PARAMETER:
+ case ERROR_NEGATIVE_SEEK:
+ errno = EINVAL;
+ break;
+ case ERROR_TOO_MANY_OPEN_FILES:
+ errno = EMFILE;
+ break;
+ case ERROR_DISK_FULL:
+ errno = ENOSPC;
+ break;
+ case ERROR_BROKEN_PIPE:
+ errno = EPIPE;
+ break;
+ case ERROR_DIR_NOT_EMPTY:
+ errno = ENOTEMPTY;
+ break;
+ default:
+ errno = EINVAL;
+ }
+}
+
+GIT_INLINE(bool) last_error_retryable(void)
+{
+ int os_error = GetLastError();
+
+ return (os_error == ERROR_SHARING_VIOLATION ||
+ os_error == ERROR_ACCESS_DENIED);
+}
+
+#define do_with_retries(fn, remediation) \
+ do { \
+ int __retry, __ret; \
+ for (__retry = git_win32__retries; __retry; __retry--) { \
+ if ((__ret = (fn)) != GIT_RETRY) \
+ return __ret; \
+ if (__retry > 1 && (__ret = (remediation)) != 0) { \
+ if (__ret == GIT_RETRY) \
+ continue; \
+ return __ret; \
+ } \
+ Sleep(5); \
+ } \
+ return -1; \
+ } while (0) \
+
+static int ensure_writable(wchar_t *path)
+{
+ DWORD attrs;
+
+ if ((attrs = GetFileAttributesW(path)) == INVALID_FILE_ATTRIBUTES)
+ goto on_error;
+
+ if ((attrs & FILE_ATTRIBUTE_READONLY) == 0)
+ return 0;
+
+ if (!SetFileAttributesW(path, (attrs & ~FILE_ATTRIBUTE_READONLY)))
+ goto on_error;
+
+ return GIT_RETRY;
+
+on_error:
+ set_errno();
+ return -1;
+}
+
/**
* Truncate or extend file.
*
@@ -89,30 +244,34 @@ int p_link(const char *old, const char *new)
return -1;
}
-int p_unlink(const char *path)
+GIT_INLINE(int) unlink_once(const wchar_t *path)
{
- git_win32_path buf;
- int error;
+ if (DeleteFileW(path))
+ return 0;
- if (git_win32_path_from_utf8(buf, path) < 0)
- return -1;
+ if (last_error_retryable())
+ return GIT_RETRY;
- error = _wunlink(buf);
+ set_errno();
+ return -1;
+}
- /* If the file could not be deleted because it was
- * read-only, clear the bit and try again */
- if (error == -1 && errno == EACCES) {
- _wchmod(buf, 0666);
- error = _wunlink(buf);
- }
+int p_unlink(const char *path)
+{
+ git_win32_path wpath;
- return error;
+ if (git_win32_path_from_utf8(wpath, path) < 0)
+ return -1;
+
+ do_with_retries(unlink_once(wpath), ensure_writable(wpath));
}
int p_fsync(int fd)
{
HANDLE fh = (HANDLE)_get_osfhandle(fd);
+ p_fsync__cnt++;
+
if (fh == INVALID_HANDLE_VALUE) {
errno = EBADF;
return -1;
@@ -210,44 +369,6 @@ int p_lstat_posixly(const char *filename, struct stat *buf)
return do_lstat(filename, buf, true);
}
-int p_utimes(const char *filename, const struct p_timeval times[2])
-{
- int fd, error;
-
- if ((fd = p_open(filename, O_RDWR)) < 0)
- return fd;
-
- error = p_futimes(fd, times);
-
- close(fd);
- return error;
-}
-
-int p_futimes(int fd, const struct p_timeval times[2])
-{
- HANDLE handle;
- FILETIME atime = {0}, mtime = {0};
-
- if (times == NULL) {
- SYSTEMTIME st;
-
- GetSystemTime(&st);
- SystemTimeToFileTime(&st, &atime);
- SystemTimeToFileTime(&st, &mtime);
- } else {
- git_win32__timeval_to_filetime(&atime, times[0]);
- git_win32__timeval_to_filetime(&mtime, times[1]);
- }
-
- if ((handle = (HANDLE)_get_osfhandle(fd)) == INVALID_HANDLE_VALUE)
- return -1;
-
- if (SetFileTime(handle, NULL, &atime, &mtime) == 0)
- return -1;
-
- return 0;
-}
-
int p_readlink(const char *path, char *buf, size_t bufsiz)
{
git_win32_path path_w, target_w;
@@ -280,12 +401,91 @@ int p_symlink(const char *old, const char *new)
return git_futils_fake_symlink(old, new);
}
+struct open_opts {
+ DWORD access;
+ DWORD sharing;
+ SECURITY_ATTRIBUTES security;
+ DWORD creation_disposition;
+ DWORD attributes;
+ int osf_flags;
+};
+
+GIT_INLINE(void) open_opts_from_posix(struct open_opts *opts, int flags, mode_t mode)
+{
+ memset(opts, 0, sizeof(struct open_opts));
+
+ switch (flags & (O_WRONLY | O_RDWR)) {
+ case O_WRONLY:
+ opts->access = GENERIC_WRITE;
+ break;
+ case O_RDWR:
+ opts->access = GENERIC_READ | GENERIC_WRITE;
+ break;
+ default:
+ opts->access = GENERIC_READ;
+ break;
+ }
+
+ opts->sharing = (DWORD)git_win32__createfile_sharemode;
+
+ switch (flags & (O_CREAT | O_TRUNC | O_EXCL)) {
+ case O_CREAT | O_EXCL:
+ case O_CREAT | O_TRUNC | O_EXCL:
+ opts->creation_disposition = CREATE_NEW;
+ break;
+ case O_CREAT | O_TRUNC:
+ opts->creation_disposition = CREATE_ALWAYS;
+ break;
+ case O_TRUNC:
+ opts->creation_disposition = TRUNCATE_EXISTING;
+ break;
+ case O_CREAT:
+ opts->creation_disposition = OPEN_ALWAYS;
+ break;
+ default:
+ opts->creation_disposition = OPEN_EXISTING;
+ break;
+ }
+
+ opts->attributes = ((flags & O_CREAT) && !(mode & S_IWRITE)) ?
+ FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_NORMAL;
+ opts->osf_flags = flags & (O_RDONLY | O_APPEND);
+
+ opts->security.nLength = sizeof(SECURITY_ATTRIBUTES);
+ opts->security.lpSecurityDescriptor = NULL;
+ opts->security.bInheritHandle = 0;
+}
+
+GIT_INLINE(int) open_once(
+ const wchar_t *path,
+ struct open_opts *opts)
+{
+ int fd;
+
+ HANDLE handle = CreateFileW(path, opts->access, opts->sharing,
+ &opts->security, opts->creation_disposition, opts->attributes, 0);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ if (last_error_retryable())
+ return GIT_RETRY;
+
+ set_errno();
+ return -1;
+ }
+
+ if ((fd = _open_osfhandle((intptr_t)handle, opts->osf_flags)) < 0)
+ CloseHandle(handle);
+
+ return fd;
+}
+
int p_open(const char *path, int flags, ...)
{
- git_win32_path buf;
+ git_win32_path wpath;
mode_t mode = 0;
+ struct open_opts opts = {0};
- if (git_win32_path_from_utf8(buf, path) < 0)
+ if (git_win32_path_from_utf8(wpath, path) < 0)
return -1;
if (flags & O_CREAT) {
@@ -296,19 +496,83 @@ int p_open(const char *path, int flags, ...)
va_end(arg_list);
}
- return _wopen(buf, flags | STANDARD_OPEN_FLAGS, mode & WIN32_MODE_MASK);
+ open_opts_from_posix(&opts, flags, mode);
+
+ do_with_retries(
+ open_once(wpath, &opts),
+ 0);
}
int p_creat(const char *path, mode_t mode)
{
- git_win32_path buf;
+ return p_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
+}
- if (git_win32_path_from_utf8(buf, path) < 0)
+int p_utimes(const char *path, const struct p_timeval times[2])
+{
+ git_win32_path wpath;
+ int fd, error;
+ DWORD attrs_orig, attrs_new = 0;
+ struct open_opts opts = { 0 };
+
+ if (git_win32_path_from_utf8(wpath, path) < 0)
return -1;
- return _wopen(buf,
- _O_WRONLY | _O_CREAT | _O_TRUNC | STANDARD_OPEN_FLAGS,
- mode & WIN32_MODE_MASK);
+ attrs_orig = GetFileAttributesW(wpath);
+
+ if (attrs_orig & FILE_ATTRIBUTE_READONLY) {
+ attrs_new = attrs_orig & ~FILE_ATTRIBUTE_READONLY;
+
+ if (!SetFileAttributesW(wpath, attrs_new)) {
+ giterr_set(GITERR_OS, "failed to set attributes");
+ return -1;
+ }
+ }
+
+ open_opts_from_posix(&opts, O_RDWR, 0);
+
+ if ((fd = open_once(wpath, &opts)) < 0) {
+ error = -1;
+ goto done;
+ }
+
+ error = p_futimes(fd, times);
+ close(fd);
+
+done:
+ if (attrs_orig != attrs_new) {
+ DWORD os_error = GetLastError();
+ SetFileAttributesW(wpath, attrs_orig);
+ SetLastError(os_error);
+ }
+
+ return error;
+}
+
+int p_futimes(int fd, const struct p_timeval times[2])
+{
+ HANDLE handle;
+ FILETIME atime = { 0 }, mtime = { 0 };
+
+ if (times == NULL) {
+ SYSTEMTIME st;
+
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, &atime);
+ SystemTimeToFileTime(&st, &mtime);
+ }
+ else {
+ git_win32__timeval_to_filetime(&atime, times[0]);
+ git_win32__timeval_to_filetime(&mtime, times[1]);
+ }
+
+ if ((handle = (HANDLE)_get_osfhandle(fd)) == INVALID_HANDLE_VALUE)
+ return -1;
+
+ if (SetFileTime(handle, NULL, &atime, &mtime) == 0)
+ return -1;
+
+ return 0;
}
int p_getcwd(char *buffer_out, size_t size)
@@ -581,62 +845,27 @@ int p_access(const char* path, mode_t mode)
return _waccess(buf, mode & WIN32_MODE_MASK);
}
-static int ensure_writable(wchar_t *fpath)
+GIT_INLINE(int) rename_once(const wchar_t *from, const wchar_t *to)
{
- DWORD attrs;
-
- attrs = GetFileAttributesW(fpath);
- if (attrs == INVALID_FILE_ATTRIBUTES) {
- if (GetLastError() == ERROR_FILE_NOT_FOUND)
- return 0;
-
- giterr_set(GITERR_OS, "failed to get attributes");
- return -1;
- }
-
- if (!(attrs & FILE_ATTRIBUTE_READONLY))
+ if (MoveFileExW(from, to, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
return 0;
- attrs &= ~FILE_ATTRIBUTE_READONLY;
- if (!SetFileAttributesW(fpath, attrs)) {
- giterr_set(GITERR_OS, "failed to set attributes");
- return -1;
- }
+ if (last_error_retryable())
+ return GIT_RETRY;
- return 0;
+ set_errno();
+ return -1;
}
int p_rename(const char *from, const char *to)
{
- git_win32_path wfrom;
- git_win32_path wto;
- int rename_tries;
- int rename_succeeded;
- int error;
+ git_win32_path wfrom, wto;
if (git_win32_path_from_utf8(wfrom, from) < 0 ||
git_win32_path_from_utf8(wto, to) < 0)
return -1;
- /* wait up to 50ms if file is locked by another thread or process */
- rename_tries = 0;
- rename_succeeded = 0;
- while (rename_tries < 10) {
- if (ensure_writable(wto) == 0 &&
- MoveFileExW(wfrom, wto, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) != 0) {
- rename_succeeded = 1;
- break;
- }
-
- error = GetLastError();
- if (error == ERROR_SHARING_VIOLATION || error == ERROR_ACCESS_DENIED) {
- Sleep(5);
- rename_tries++;
- } else
- break;
- }
-
- return rename_succeeded ? 0 : -1;
+ do_with_retries(rename_once(wfrom, wto), ensure_writable(wto));
}
int p_recv(GIT_SOCKET socket, void *buffer, size_t length, int flags)
diff --git a/src/win32/precompiled.h b/src/win32/precompiled.h
index 10ca0b80c..851a083d5 100644
--- a/src/win32/precompiled.h
+++ b/src/win32/precompiled.h
@@ -1,3 +1,5 @@
+#include "common.h"
+
#include <assert.h>
#include <errno.h>
#include <limits.h>
@@ -20,4 +22,3 @@
#endif
#include "git2.h"
-#include "common.h"
diff --git a/src/win32/thread.c b/src/win32/thread.c
index 80d56ce5d..2d9600515 100644
--- a/src/win32/thread.c
+++ b/src/win32/thread.c
@@ -6,6 +6,7 @@
*/
#include "thread.h"
+
#include "../global.h"
#define CLEAN_THREAD_EXIT 0x6F012842
@@ -26,6 +27,9 @@ static DWORD WINAPI git_win32__threadproc(LPVOID lpParameter)
{
git_thread *thread = lpParameter;
+ /* Set the current thread for `git_thread_exit` */
+ GIT_GLOBAL->current_thread = thread;
+
thread->result = thread->proc(thread->param);
git__free_tls_data();
@@ -95,6 +99,21 @@ int git_thread_join(
return 0;
}
+void git_thread_exit(void *value)
+{
+ assert(GIT_GLOBAL->current_thread);
+ GIT_GLOBAL->current_thread->result = value;
+
+ git__free_tls_data();
+
+ ExitThread(CLEAN_THREAD_EXIT);
+}
+
+size_t git_thread_currentid(void)
+{
+ return GetCurrentThreadId();
+}
+
int git_mutex_init(git_mutex *GIT_RESTRICT mutex)
{
InitializeCriticalSection(mutex);
diff --git a/src/win32/thread.h b/src/win32/thread.h
index 0d01822a6..d217722ec 100644
--- a/src/win32/thread.h
+++ b/src/win32/thread.h
@@ -8,7 +8,7 @@
#ifndef INCLUDE_win32_thread_h__
#define INCLUDE_win32_thread_h__
-#include "../common.h"
+#include "common.h"
#if defined (_MSC_VER)
# define GIT_RESTRICT __restrict
@@ -41,6 +41,8 @@ int git_thread_create(git_thread *GIT_RESTRICT,
void *(*) (void *),
void *GIT_RESTRICT);
int git_thread_join(git_thread *, void **);
+size_t git_thread_currentid(void);
+void git_thread_exit(void *);
int git_mutex_init(git_mutex *GIT_RESTRICT mutex);
int git_mutex_free(git_mutex *);
diff --git a/src/win32/utf-conv.c b/src/win32/utf-conv.c
index 96fd4606e..4bde3023a 100644
--- a/src/win32/utf-conv.c
+++ b/src/win32/utf-conv.c
@@ -5,7 +5,6 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
#include "utf-conv.h"
GIT_INLINE(void) git__set_errno(void)
diff --git a/src/win32/utf-conv.h b/src/win32/utf-conv.h
index 33b95f59f..bab7ba9fd 100644
--- a/src/win32/utf-conv.h
+++ b/src/win32/utf-conv.h
@@ -7,9 +7,10 @@
#ifndef INCLUDE_git_utfconv_h__
#define INCLUDE_git_utfconv_h__
-#include <wchar.h>
#include "common.h"
+#include <wchar.h>
+
#ifndef WC_ERR_INVALID_CHARS
# define WC_ERR_INVALID_CHARS 0x80
#endif
diff --git a/src/win32/w32_buffer.c b/src/win32/w32_buffer.c
index 9122baaa6..45c024d31 100644
--- a/src/win32/w32_buffer.c
+++ b/src/win32/w32_buffer.c
@@ -5,8 +5,8 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
#include "w32_buffer.h"
+
#include "../buffer.h"
#include "utf-conv.h"
diff --git a/src/win32/w32_buffer.h b/src/win32/w32_buffer.h
index 62243986f..e15ea6864 100644
--- a/src/win32/w32_buffer.h
+++ b/src/win32/w32_buffer.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_git_win32_buffer_h__
#define INCLUDE_git_win32_buffer_h__
+#include "common.h"
+
#include "../buffer.h"
/**
diff --git a/src/win32/w32_crtdbg_stacktrace.c b/src/win32/w32_crtdbg_stacktrace.c
index a778f4164..7b3c3fb4c 100644
--- a/src/win32/w32_crtdbg_stacktrace.c
+++ b/src/win32/w32_crtdbg_stacktrace.c
@@ -5,9 +5,10 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "w32_crtdbg_stacktrace.h"
+
#if defined(GIT_MSVC_CRTDBG)
#include "w32_stack.h"
-#include "w32_crtdbg_stacktrace.h"
#define CRTDBG_STACKTRACE__UID_LEN (15)
@@ -253,11 +254,11 @@ int git_win32__crtdbg_stacktrace__dump(
bool b_quiet = IS_BIT_SET(opt, GIT_WIN32__CRTDBG_STACKTRACE__QUIET);
if (b_leaks_since_mark && b_leaks_total) {
- giterr_set(GITERR_INVALID, "Cannot combine LEAKS_SINCE_MARK and LEAKS_TOTAL.");
+ giterr_set(GITERR_INVALID, "cannot combine LEAKS_SINCE_MARK and LEAKS_TOTAL.");
return GIT_ERROR;
}
if (!b_set_mark && !b_leaks_since_mark && !b_leaks_total) {
- giterr_set(GITERR_INVALID, "Nothing to do.");
+ giterr_set(GITERR_INVALID, "nothing to do.");
return GIT_ERROR;
}
diff --git a/src/win32/w32_crtdbg_stacktrace.h b/src/win32/w32_crtdbg_stacktrace.h
index 40ca60d53..bb869b347 100644
--- a/src/win32/w32_crtdbg_stacktrace.h
+++ b/src/win32/w32_crtdbg_stacktrace.h
@@ -7,8 +7,16 @@
#ifndef INCLUDE_w32_crtdbg_stacktrace_h__
#define INCLUDE_w32_crtdbg_stacktrace_h__
+#include "common.h"
+
#if defined(GIT_MSVC_CRTDBG)
+#include <stdlib.h>
+#include <crtdbg.h>
+
+#include "git2/errors.h"
+#include "strnlen.h"
+
/**
* Initialize our memory leak tracking and de-dup data structures.
* This should ONLY be called by git_libgit2_init().
@@ -89,5 +97,80 @@ GIT_EXTERN(int) git_win32__crtdbg_stacktrace__dump(
*/
const char *git_win32__crtdbg_stacktrace(int skip, const char *file);
+GIT_INLINE(void *) git__crtdbg__malloc(size_t len, const char *file, int line)
+{
+ void *ptr = _malloc_dbg(len, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
+ if (!ptr) giterr_set_oom();
+ return ptr;
+}
+
+GIT_INLINE(void *) git__crtdbg__calloc(size_t nelem, size_t elsize, const char *file, int line)
+{
+ void *ptr = _calloc_dbg(nelem, elsize, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
+ if (!ptr) giterr_set_oom();
+ return ptr;
+}
+
+GIT_INLINE(char *) git__crtdbg__strdup(const char *str, const char *file, int line)
+{
+ char *ptr = _strdup_dbg(str, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
+ if (!ptr) giterr_set_oom();
+ return ptr;
+}
+
+GIT_INLINE(char *) git__crtdbg__strndup(const char *str, size_t n, const char *file, int line)
+{
+ size_t length = 0, alloclength;
+ char *ptr;
+
+ length = p_strnlen(str, n);
+
+ if (GIT_ADD_SIZET_OVERFLOW(&alloclength, length, 1) ||
+ !(ptr = git__crtdbg__malloc(alloclength, file, line)))
+ return NULL;
+
+ if (length)
+ memcpy(ptr, str, length);
+
+ ptr[length] = '\0';
+
+ return ptr;
+}
+
+GIT_INLINE(char *) git__crtdbg__substrdup(const char *start, size_t n, const char *file, int line)
+{
+ char *ptr;
+ size_t alloclen;
+
+ if (GIT_ADD_SIZET_OVERFLOW(&alloclen, n, 1) ||
+ !(ptr = git__crtdbg__malloc(alloclen, file, line)))
+ return NULL;
+
+ memcpy(ptr, start, n);
+ ptr[n] = '\0';
+ return ptr;
+}
+
+GIT_INLINE(void *) git__crtdbg__realloc(void *ptr, size_t size, const char *file, int line)
+{
+ void *new_ptr = _realloc_dbg(ptr, size, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
+ if (!new_ptr) giterr_set_oom();
+ return new_ptr;
+}
+
+GIT_INLINE(void *) git__crtdbg__reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line)
+{
+ size_t newsize;
+
+ return GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize) ?
+ NULL : _realloc_dbg(ptr, newsize, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
+}
+
+GIT_INLINE(void *) git__crtdbg__mallocarray(size_t nelem, size_t elsize, const char *file, int line)
+{
+ return git__crtdbg__reallocarray(NULL, nelem, elsize, file, line);
+}
+
+
#endif
#endif
diff --git a/src/win32/w32_stack.c b/src/win32/w32_stack.c
index 15af3dcb7..b40f9d2b4 100644
--- a/src/win32/w32_stack.c
+++ b/src/win32/w32_stack.c
@@ -5,11 +5,12 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "w32_stack.h"
+
#if defined(GIT_MSVC_CRTDBG)
#include "Windows.h"
#include "Dbghelp.h"
#include "win32/posix.h"
-#include "w32_stack.h"
#include "hash.h"
/**
diff --git a/src/win32/w32_stack.h b/src/win32/w32_stack.h
index 21170bd2f..a514ace6f 100644
--- a/src/win32/w32_stack.h
+++ b/src/win32/w32_stack.h
@@ -8,6 +8,8 @@
#ifndef INCLUDE_w32_stack_h__
#define INCLUDE_w32_stack_h__
+#include "common.h"
+
#if defined(GIT_MSVC_CRTDBG)
/**
diff --git a/src/win32/w32_util.c b/src/win32/w32_util.c
index 60311bb50..b7b1ffa10 100644
--- a/src/win32/w32_util.c
+++ b/src/win32/w32_util.c
@@ -68,7 +68,7 @@ int git_win32__set_hidden(const char *path, bool hidden)
newattrs = attrs & ~FILE_ATTRIBUTE_HIDDEN;
if (attrs != newattrs && !SetFileAttributesW(buf, newattrs)) {
- giterr_set(GITERR_OS, "Failed to %s hidden bit for '%s'",
+ giterr_set(GITERR_OS, "failed to %s hidden bit for '%s'",
hidden ? "set" : "unset", path);
return -1;
}
diff --git a/src/win32/w32_util.h b/src/win32/w32_util.h
index 2e475e5e9..d81e55a00 100644
--- a/src/win32/w32_util.h
+++ b/src/win32/w32_util.h
@@ -8,6 +8,8 @@
#ifndef INCLUDE_w32_util_h__
#define INCLUDE_w32_util_h__
+#include "common.h"
+
#include "utf-conv.h"
#include "posix.h"
#include "path_w32.h"
@@ -174,7 +176,7 @@ GIT_INLINE(int) git_win32__file_attribute_to_stat(
/* st_size gets the UTF-8 length of the target name, in bytes,
* not counting the NULL terminator */
if ((st->st_size = git__utf16_to_8(NULL, 0, target)) < 0) {
- giterr_set(GITERR_OS, "Could not convert reparse point name for '%s'", path);
+ giterr_set(GITERR_OS, "could not convert reparse point name for '%ls'", path);
return -1;
}
}
diff --git a/src/worktree.c b/src/worktree.c
new file mode 100644
index 000000000..5a814a2ec
--- /dev/null
+++ b/src/worktree.c
@@ -0,0 +1,557 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "worktree.h"
+
+#include "git2/branch.h"
+#include "git2/commit.h"
+#include "git2/worktree.h"
+
+#include "repository.h"
+
+static bool is_worktree_dir(const char *dir)
+{
+ git_buf buf = GIT_BUF_INIT;
+ int error;
+
+ if (git_buf_sets(&buf, dir) < 0)
+ return -1;
+
+ error = git_path_contains_file(&buf, "commondir")
+ && git_path_contains_file(&buf, "gitdir")
+ && git_path_contains_file(&buf, "HEAD");
+
+ git_buf_free(&buf);
+ return error;
+}
+
+int git_worktree_list(git_strarray *wts, git_repository *repo)
+{
+ git_vector worktrees = GIT_VECTOR_INIT;
+ git_buf path = GIT_BUF_INIT;
+ char *worktree;
+ unsigned i, len;
+ int error;
+
+ assert(wts && repo);
+
+ wts->count = 0;
+ wts->strings = NULL;
+
+ if ((error = git_buf_printf(&path, "%s/worktrees/", repo->commondir)) < 0)
+ goto exit;
+ if (!git_path_exists(path.ptr) || git_path_is_empty_dir(path.ptr))
+ goto exit;
+ if ((error = git_path_dirload(&worktrees, path.ptr, path.size, 0x0)) < 0)
+ goto exit;
+
+ len = path.size;
+
+ git_vector_foreach(&worktrees, i, worktree) {
+ git_buf_truncate(&path, len);
+ git_buf_puts(&path, worktree);
+
+ if (!is_worktree_dir(path.ptr)) {
+ git_vector_remove(&worktrees, i);
+ git__free(worktree);
+ }
+ }
+
+ wts->strings = (char **)git_vector_detach(&wts->count, NULL, &worktrees);
+
+exit:
+ git_buf_free(&path);
+
+ return error;
+}
+
+char *git_worktree__read_link(const char *base, const char *file)
+{
+ git_buf path = GIT_BUF_INIT, buf = GIT_BUF_INIT;
+
+ assert(base && file);
+
+ if (git_buf_joinpath(&path, base, file) < 0)
+ goto err;
+ if (git_futils_readbuffer(&buf, path.ptr) < 0)
+ goto err;
+ git_buf_free(&path);
+
+ git_buf_rtrim(&buf);
+
+ if (!git_path_is_relative(buf.ptr))
+ return git_buf_detach(&buf);
+
+ if (git_buf_sets(&path, base) < 0)
+ goto err;
+ if (git_path_apply_relative(&path, buf.ptr) < 0)
+ goto err;
+ git_buf_free(&buf);
+
+ return git_buf_detach(&path);
+
+err:
+ git_buf_free(&buf);
+ git_buf_free(&path);
+
+ return NULL;
+}
+
+static int write_wtfile(const char *base, const char *file, const git_buf *buf)
+{
+ git_buf path = GIT_BUF_INIT;
+ int err;
+
+ assert(base && file && buf);
+
+ if ((err = git_buf_joinpath(&path, base, file)) < 0)
+ goto out;
+
+ if ((err = git_futils_writebuffer(buf, path.ptr, O_CREAT|O_EXCL|O_WRONLY, 0644)) < 0)
+ goto out;
+
+out:
+ git_buf_free(&path);
+
+ return err;
+}
+
+static int open_worktree_dir(git_worktree **out, const char *parent, const char *dir, const char *name)
+{
+ git_buf gitdir = GIT_BUF_INIT;
+ git_worktree *wt = NULL;
+ int error = 0;
+
+ if (!is_worktree_dir(dir)) {
+ error = -1;
+ goto out;
+ }
+
+ if ((wt = git__calloc(1, sizeof(struct git_repository))) == NULL) {
+ error = -1;
+ goto out;
+ }
+
+ if ((wt->name = git__strdup(name)) == NULL
+ || (wt->commondir_path = git_worktree__read_link(dir, "commondir")) == NULL
+ || (wt->gitlink_path = git_worktree__read_link(dir, "gitdir")) == NULL
+ || (wt->parent_path = git__strdup(parent)) == NULL) {
+ error = -1;
+ goto out;
+ }
+
+ if ((error = git_path_prettify_dir(&gitdir, dir, NULL)) < 0)
+ goto out;
+ wt->gitdir_path = git_buf_detach(&gitdir);
+
+ wt->locked = !!git_worktree_is_locked(NULL, wt);
+
+ *out = wt;
+
+out:
+ if (error)
+ git_worktree_free(wt);
+ git_buf_free(&gitdir);
+
+ return error;
+}
+
+int git_worktree_lookup(git_worktree **out, git_repository *repo, const char *name)
+{
+ git_buf path = GIT_BUF_INIT;
+ git_worktree *wt = NULL;
+ int error;
+
+ assert(repo && name);
+
+ *out = NULL;
+
+ if ((error = git_buf_printf(&path, "%s/worktrees/%s", repo->commondir, name)) < 0)
+ goto out;
+
+ if ((error = (open_worktree_dir(out, git_repository_workdir(repo), path.ptr, name))) < 0)
+ goto out;
+
+out:
+ git_buf_free(&path);
+
+ if (error)
+ git_worktree_free(wt);
+
+ return error;
+}
+
+int git_worktree_open_from_repository(git_worktree **out, git_repository *repo)
+{
+ git_buf parent = GIT_BUF_INIT;
+ const char *gitdir, *commondir;
+ char *name = NULL;
+ int error = 0;
+
+ if (!git_repository_is_worktree(repo)) {
+ giterr_set(GITERR_WORKTREE, "cannot open worktree of a non-worktree repo");
+ error = -1;
+ goto out;
+ }
+
+ gitdir = git_repository_path(repo);
+ commondir = git_repository_commondir(repo);
+
+ if ((error = git_path_prettify_dir(&parent, "..", commondir)) < 0)
+ goto out;
+
+ /* The name is defined by the last component in '.git/worktree/%s' */
+ name = git_path_basename(gitdir);
+
+ if ((error = open_worktree_dir(out, parent.ptr, gitdir, name)) < 0)
+ goto out;
+
+out:
+ git__free(name);
+ git_buf_free(&parent);
+
+ return error;
+}
+
+void git_worktree_free(git_worktree *wt)
+{
+ if (!wt)
+ return;
+
+ git__free(wt->commondir_path);
+ git__free(wt->gitlink_path);
+ git__free(wt->gitdir_path);
+ git__free(wt->parent_path);
+ git__free(wt->name);
+ git__free(wt);
+}
+
+int git_worktree_validate(const git_worktree *wt)
+{
+ git_buf buf = GIT_BUF_INIT;
+ int err = 0;
+
+ assert(wt);
+
+ git_buf_puts(&buf, wt->gitdir_path);
+ if (!is_worktree_dir(buf.ptr)) {
+ giterr_set(GITERR_WORKTREE,
+ "Worktree gitdir ('%s') is not valid",
+ wt->gitlink_path);
+ err = -1;
+ goto out;
+ }
+
+ if (!git_path_exists(wt->parent_path)) {
+ giterr_set(GITERR_WORKTREE,
+ "Worktree parent directory ('%s') does not exist ",
+ wt->parent_path);
+ err = -2;
+ goto out;
+ }
+
+ if (!git_path_exists(wt->commondir_path)) {
+ giterr_set(GITERR_WORKTREE,
+ "Worktree common directory ('%s') does not exist ",
+ wt->commondir_path);
+ err = -3;
+ goto out;
+ }
+
+out:
+ git_buf_free(&buf);
+
+ return err;
+}
+
+int git_worktree_add_init_options(git_worktree_add_options *opts,
+ unsigned int version)
+{
+ GIT_INIT_STRUCTURE_FROM_TEMPLATE(opts, version,
+ git_worktree_add_options, GIT_WORKTREE_ADD_OPTIONS_INIT);
+ return 0;
+}
+
+int git_worktree_add(git_worktree **out, git_repository *repo,
+ const char *name, const char *worktree,
+ const git_worktree_add_options *opts)
+{
+ git_buf gitdir = GIT_BUF_INIT, wddir = GIT_BUF_INIT, buf = GIT_BUF_INIT;
+ git_reference *ref = NULL, *head = NULL;
+ git_commit *commit = NULL;
+ git_repository *wt = NULL;
+ git_checkout_options coopts = GIT_CHECKOUT_OPTIONS_INIT;
+ git_worktree_add_options wtopts = GIT_WORKTREE_ADD_OPTIONS_INIT;
+ int err;
+
+ GITERR_CHECK_VERSION(
+ opts, GIT_WORKTREE_ADD_OPTIONS_VERSION, "git_worktree_add_options");
+
+ if (opts)
+ memcpy(&wtopts, opts, sizeof(wtopts));
+
+ assert(out && repo && name && worktree);
+
+ *out = NULL;
+
+ /* Create gitdir directory ".git/worktrees/<name>" */
+ if ((err = git_buf_joinpath(&gitdir, repo->commondir, "worktrees")) < 0)
+ goto out;
+ if (!git_path_exists(gitdir.ptr))
+ if ((err = git_futils_mkdir(gitdir.ptr, 0755, GIT_MKDIR_EXCL)) < 0)
+ goto out;
+ if ((err = git_buf_joinpath(&gitdir, gitdir.ptr, name)) < 0)
+ goto out;
+ if ((err = git_futils_mkdir(gitdir.ptr, 0755, GIT_MKDIR_EXCL)) < 0)
+ goto out;
+ if ((err = git_path_prettify_dir(&gitdir, gitdir.ptr, NULL)) < 0)
+ goto out;
+
+ /* Create worktree work dir */
+ if ((err = git_futils_mkdir(worktree, 0755, GIT_MKDIR_EXCL)) < 0)
+ goto out;
+ if ((err = git_path_prettify_dir(&wddir, worktree, NULL)) < 0)
+ goto out;
+
+ if (wtopts.lock) {
+ int fd;
+
+ if ((err = git_buf_joinpath(&buf, gitdir.ptr, "locked")) < 0)
+ goto out;
+
+ if ((fd = p_creat(buf.ptr, 0644)) < 0) {
+ err = fd;
+ goto out;
+ }
+
+ p_close(fd);
+ git_buf_clear(&buf);
+ }
+
+ /* Create worktree .git file */
+ if ((err = git_buf_printf(&buf, "gitdir: %s\n", gitdir.ptr)) < 0)
+ goto out;
+ if ((err = write_wtfile(wddir.ptr, ".git", &buf)) < 0)
+ goto out;
+
+ /* Create gitdir files */
+ if ((err = git_path_prettify_dir(&buf, repo->commondir, NULL) < 0)
+ || (err = git_buf_putc(&buf, '\n')) < 0
+ || (err = write_wtfile(gitdir.ptr, "commondir", &buf)) < 0)
+ goto out;
+ if ((err = git_buf_joinpath(&buf, wddir.ptr, ".git")) < 0
+ || (err = git_buf_putc(&buf, '\n')) < 0
+ || (err = write_wtfile(gitdir.ptr, "gitdir", &buf)) < 0)
+ goto out;
+
+ /* Create new branch */
+ if ((err = git_repository_head(&head, repo)) < 0)
+ goto out;
+ if ((err = git_commit_lookup(&commit, repo, &head->target.oid)) < 0)
+ goto out;
+ if ((err = git_branch_create(&ref, repo, name, commit, false)) < 0)
+ goto out;
+
+ /* Set worktree's HEAD */
+ if ((err = git_repository_create_head(gitdir.ptr, git_reference_name(ref))) < 0)
+ goto out;
+ if ((err = git_repository_open(&wt, wddir.ptr)) < 0)
+ goto out;
+
+ /* Checkout worktree's HEAD */
+ coopts.checkout_strategy = GIT_CHECKOUT_FORCE;
+ if ((err = git_checkout_head(wt, &coopts)) < 0)
+ goto out;
+
+ /* Load result */
+ if ((err = git_worktree_lookup(out, repo, name)) < 0)
+ goto out;
+
+out:
+ git_buf_free(&gitdir);
+ git_buf_free(&wddir);
+ git_buf_free(&buf);
+ git_reference_free(ref);
+ git_reference_free(head);
+ git_commit_free(commit);
+ git_repository_free(wt);
+
+ return err;
+}
+
+int git_worktree_lock(git_worktree *wt, char *creason)
+{
+ git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT;
+ int err;
+
+ assert(wt);
+
+ if ((err = git_worktree_is_locked(NULL, wt)) < 0)
+ goto out;
+
+ if ((err = git_buf_joinpath(&path, wt->gitdir_path, "locked")) < 0)
+ goto out;
+
+ if (creason)
+ git_buf_attach_notowned(&buf, creason, strlen(creason));
+
+ if ((err = git_futils_writebuffer(&buf, path.ptr, O_CREAT|O_EXCL|O_WRONLY, 0644)) < 0)
+ goto out;
+
+ wt->locked = 1;
+
+out:
+ git_buf_free(&path);
+
+ return err;
+}
+
+int git_worktree_unlock(git_worktree *wt)
+{
+ git_buf path = GIT_BUF_INIT;
+
+ assert(wt);
+
+ if (!git_worktree_is_locked(NULL, wt))
+ return 0;
+
+ if (git_buf_joinpath(&path, wt->gitdir_path, "locked") < 0)
+ return -1;
+
+ if (p_unlink(path.ptr) != 0) {
+ git_buf_free(&path);
+ return -1;
+ }
+
+ wt->locked = 0;
+
+ git_buf_free(&path);
+
+ return 0;
+}
+
+int git_worktree_is_locked(git_buf *reason, const git_worktree *wt)
+{
+ git_buf path = GIT_BUF_INIT;
+ int ret;
+
+ assert(wt);
+
+ if (reason)
+ git_buf_clear(reason);
+
+ if ((ret = git_buf_joinpath(&path, wt->gitdir_path, "locked")) < 0)
+ goto out;
+ if ((ret = git_path_exists(path.ptr)) && reason)
+ git_futils_readbuffer(reason, path.ptr);
+
+out:
+ git_buf_free(&path);
+
+ return ret;
+}
+
+int git_worktree_prune_init_options(
+ git_worktree_prune_options *opts,
+ unsigned int version)
+{
+ GIT_INIT_STRUCTURE_FROM_TEMPLATE(opts, version,
+ git_worktree_prune_options, GIT_WORKTREE_PRUNE_OPTIONS_INIT);
+ return 0;
+}
+
+int git_worktree_is_prunable(git_worktree *wt,
+ git_worktree_prune_options *opts)
+{
+ git_buf reason = GIT_BUF_INIT;
+ git_worktree_prune_options popts = GIT_WORKTREE_PRUNE_OPTIONS_INIT;
+
+ GITERR_CHECK_VERSION(
+ opts, GIT_WORKTREE_PRUNE_OPTIONS_VERSION,
+ "git_worktree_prune_options");
+
+ if (opts)
+ memcpy(&popts, opts, sizeof(popts));
+
+ if ((popts.flags & GIT_WORKTREE_PRUNE_LOCKED) == 0 &&
+ git_worktree_is_locked(&reason, wt))
+ {
+ if (!reason.size)
+ git_buf_attach_notowned(&reason, "no reason given", 15);
+ giterr_set(GITERR_WORKTREE, "Not pruning locked working tree: '%s'", reason.ptr);
+ git_buf_free(&reason);
+
+ return 0;
+ }
+
+ if ((popts.flags & GIT_WORKTREE_PRUNE_VALID) == 0 &&
+ git_worktree_validate(wt) == 0)
+ {
+ giterr_set(GITERR_WORKTREE, "Not pruning valid working tree");
+ return 0;
+ }
+
+ return 1;
+}
+
+int git_worktree_prune(git_worktree *wt,
+ git_worktree_prune_options *opts)
+{
+ git_worktree_prune_options popts = GIT_WORKTREE_PRUNE_OPTIONS_INIT;
+ git_buf path = GIT_BUF_INIT;
+ char *wtpath;
+ int err;
+
+ GITERR_CHECK_VERSION(
+ opts, GIT_WORKTREE_PRUNE_OPTIONS_VERSION,
+ "git_worktree_prune_options");
+
+ if (opts)
+ memcpy(&popts, opts, sizeof(popts));
+
+ if (!git_worktree_is_prunable(wt, &popts)) {
+ err = -1;
+ goto out;
+ }
+
+ /* Delete gitdir in parent repository */
+ if ((err = git_buf_printf(&path, "%s/worktrees/%s", wt->commondir_path, wt->name)) < 0)
+ goto out;
+ if (!git_path_exists(path.ptr))
+ {
+ giterr_set(GITERR_WORKTREE, "Worktree gitdir '%s' does not exist", path.ptr);
+ err = -1;
+ goto out;
+ }
+ if ((err = git_futils_rmdir_r(path.ptr, NULL, GIT_RMDIR_REMOVE_FILES)) < 0)
+ goto out;
+
+ /* Skip deletion of the actual working tree if it does
+ * not exist or deletion was not requested */
+ if ((popts.flags & GIT_WORKTREE_PRUNE_WORKING_TREE) == 0 ||
+ !git_path_exists(wt->gitlink_path))
+ {
+ goto out;
+ }
+
+ if ((wtpath = git_path_dirname(wt->gitlink_path)) == NULL)
+ goto out;
+ git_buf_attach(&path, wtpath, 0);
+ if (!git_path_exists(path.ptr))
+ {
+ giterr_set(GITERR_WORKTREE, "Working tree '%s' does not exist", path.ptr);
+ err = -1;
+ goto out;
+ }
+ if ((err = git_futils_rmdir_r(path.ptr, NULL, GIT_RMDIR_REMOVE_FILES)) < 0)
+ goto out;
+
+out:
+ git_buf_free(&path);
+
+ return err;
+}
diff --git a/src/worktree.h b/src/worktree.h
new file mode 100644
index 000000000..52d13cced
--- /dev/null
+++ b/src/worktree.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_worktree_h__
+#define INCLUDE_worktree_h__
+
+#include "common.h"
+
+#include "git2/common.h"
+#include "git2/worktree.h"
+
+struct git_worktree {
+ /* Name of the working tree. This is the name of the
+ * containing directory in the `$PARENT/.git/worktrees/`
+ * directory. */
+ char *name;
+
+ /* Path to the .git file in the working tree's repository */
+ char *gitlink_path;
+ /* Path to the .git directory inside the parent's
+ * worktrees directory */
+ char *gitdir_path;
+ /* Path to the common directory contained in the parent
+ * repository */
+ char *commondir_path;
+ /* Path to the parent's working directory */
+ char *parent_path;
+
+ int locked:1;
+};
+
+char *git_worktree__read_link(const char *base, const char *file);
+
+#endif
diff --git a/src/zstream.c b/src/zstream.c
index d9ad4ca89..4895bdb16 100644
--- a/src/zstream.c
+++ b/src/zstream.c
@@ -5,9 +5,10 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "zstream.h"
+
#include <zlib.h>
-#include "zstream.h"
#include "buffer.h"
#define ZSTREAM_BUFFER_SIZE (1024 * 1024)
@@ -21,9 +22,9 @@ static int zstream_seterr(git_zstream *zs)
if (zs->zerr == Z_MEM_ERROR)
giterr_set_oom();
else if (zs->z.msg)
- giterr_set(GITERR_ZLIB, zs->z.msg);
+ giterr_set_str(GITERR_ZLIB, zs->z.msg);
else
- giterr_set(GITERR_ZLIB, "Unknown compression error");
+ giterr_set(GITERR_ZLIB, "unknown compression error");
return -1;
}
diff --git a/src/zstream.h b/src/zstream.h
index f0006d32e..fcc4a3148 100644
--- a/src/zstream.h
+++ b/src/zstream.h
@@ -7,9 +7,10 @@
#ifndef INCLUDE_zstream_h__
#define INCLUDE_zstream_h__
+#include "common.h"
+
#include <zlib.h>
-#include "common.h"
#include "buffer.h"
typedef enum {
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 000000000..5aba2914a
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,63 @@
+FIND_PACKAGE(PythonInterp)
+
+IF(NOT PYTHONINTERP_FOUND)
+ MESSAGE(FATAL_ERROR "Could not find a python interpeter, which is needed to build the tests. "
+ "Make sure python is available, or pass -DBUILD_CLAR=OFF to skip building the tests")
+ENDIF()
+
+SET(CLAR_FIXTURES "${CMAKE_CURRENT_SOURCE_DIR}/resources/")
+SET(CLAR_PATH "${CMAKE_CURRENT_SOURCE_DIR}")
+ADD_DEFINITIONS(-DCLAR_FIXTURE_PATH=\"${CLAR_FIXTURES}\")
+ADD_DEFINITIONS(-DCLAR_TMPDIR=\"libgit2_tests\")
+
+INCLUDE_DIRECTORIES(${CLAR_PATH} ${CMAKE_BINARY_DIR}/src)
+FILE(GLOB_RECURSE SRC_TEST ${CLAR_PATH}/*/*.c ${CLAR_PATH}/*/*.h)
+SET(SRC_CLAR "main.c" "clar_libgit2.c" "clar_libgit2_trace.c" "clar_libgit2_timer.c" "clar.c")
+
+IF(MSVC_IDE)
+ LIST(APPEND SRC_CLAR "precompiled.c")
+ENDIF()
+
+ADD_CUSTOM_COMMAND(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/clar.suite
+ COMMAND ${PYTHON_EXECUTABLE} generate.py -o "${CMAKE_CURRENT_BINARY_DIR}" -f -xonline -xstress .
+ DEPENDS ${SRC_TEST}
+ WORKING_DIRECTORY ${CLAR_PATH}
+)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
+
+SET_SOURCE_FILES_PROPERTIES(
+ ${CLAR_PATH}/clar.c
+ PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/clar.suite)
+
+LINK_DIRECTORIES(${LIBGIT2_LIBDIRS})
+INCLUDE_DIRECTORIES(${LIBGIT2_INCLUDES})
+
+ADD_EXECUTABLE(libgit2_clar ${SRC_CLAR} ${SRC_TEST} ${GIT2INTERNAL_OBJECTS})
+
+SET_TARGET_PROPERTIES(libgit2_clar PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
+
+IF (${CMAKE_VERSION} VERSION_GREATER 2.8.11)
+ TARGET_INCLUDE_DIRECTORIES(libgit2_clar PRIVATE ../src PUBLIC ../include)
+ENDIF()
+
+TARGET_LINK_LIBRARIES(libgit2_clar ${LIBGIT2_LIBS})
+IDE_SPLIT_SOURCES(libgit2_clar)
+
+IF (MSVC_IDE)
+ # Precompiled headers
+ SET_TARGET_PROPERTIES(libgit2_clar PROPERTIES COMPILE_FLAGS "/Yuprecompiled.h /FIprecompiled.h")
+ SET_SOURCE_FILES_PROPERTIES("precompiled.c" COMPILE_FLAGS "/Ycprecompiled.h")
+ENDIF ()
+
+IF (WINHTTP OR OPENSSL_FOUND OR SECURITY_FOUND)
+ ADD_TEST(libgit2_clar "${CMAKE_BINARY_DIR}/libgit2_clar" -ionline -xclone::local::git_style_unc_paths -xclone::local::standard_unc_paths_are_written_git_style)
+ELSE ()
+ ADD_TEST(libgit2_clar "${CMAKE_BINARY_DIR}/libgit2_clar" -v -xclone::local::git_style_unc_paths -xclone::local::standard_unc_paths_are_written_git_style)
+ENDIF ()
+
+# Add a test target which runs the cred callback tests, to be
+# called after setting the url and user
+ADD_TEST(libgit2_clar-cred_callback "${CMAKE_BINARY_DIR}/libgit2_clar" -v -sonline::clone::cred_callback)
+ADD_TEST(libgit2_clar-proxy_credentials_in_url "${CMAKE_BINARY_DIR}/libgit2_clar" -v -sonline::clone::proxy_credentials_in_url)
+ADD_TEST(libgit2_clar-proxy_credentials_request "${CMAKE_BINARY_DIR}/libgit2_clar" -v -sonline::clone::proxy_credentials_request)
diff --git a/tests/attr/ignore.c b/tests/attr/ignore.c
index f1fe1c71f..856e61f90 100644
--- a/tests/attr/ignore.c
+++ b/tests/attr/ignore.c
@@ -21,8 +21,8 @@ static void assert_is_ignored_(
{
int is_ignored = 0;
- cl_git_pass_(
- git_ignore_path_is_ignored(&is_ignored, g_repo, filepath), file, line);
+ cl_git_expect(
+ git_ignore_path_is_ignored(&is_ignored, g_repo, filepath), 0, file, line);
clar__assert_equal(
file, line, "expected != is_ignored", 1, "%d",
@@ -291,3 +291,58 @@ void test_attr_ignore__symlink_to_outside(void)
assert_is_ignored(true, "symlink");
assert_is_ignored(true, "lala/../symlink");
}
+
+void test_attr_ignore__test(void)
+{
+ cl_git_rewritefile("attr/.gitignore",
+ "/*/\n"
+ "!/src\n");
+ assert_is_ignored(false, "src/foo.c");
+ assert_is_ignored(false, "src/foo/foo.c");
+ assert_is_ignored(false, "README.md");
+ assert_is_ignored(true, "dist/foo.o");
+ assert_is_ignored(true, "bin/foo");
+}
+
+void test_attr_ignore__unignore_dir_succeeds(void)
+{
+ cl_git_rewritefile("attr/.gitignore",
+ "*.c\n"
+ "!src/*.c\n");
+ assert_is_ignored(false, "src/foo.c");
+ assert_is_ignored(true, "src/foo/foo.c");
+}
+
+void test_attr_ignore__case_insensitive_unignores_previous_rule(void)
+{
+ git_config *cfg;
+
+ cl_git_rewritefile("attr/.gitignore",
+ "/case\n"
+ "!/Case/\n");
+
+ cl_git_pass(git_repository_config(&cfg, g_repo));
+ cl_git_pass(git_config_set_bool(cfg, "core.ignorecase", true));
+
+ cl_must_pass(p_mkdir("attr/case", 0755));
+ cl_git_mkfile("attr/case/file", "content");
+
+ assert_is_ignored(false, "case/file");
+}
+
+void test_attr_ignore__case_sensitive_unignore_does_nothing(void)
+{
+ git_config *cfg;
+
+ cl_git_rewritefile("attr/.gitignore",
+ "/case\n"
+ "!/Case/\n");
+
+ cl_git_pass(git_repository_config(&cfg, g_repo));
+ cl_git_pass(git_config_set_bool(cfg, "core.ignorecase", false));
+
+ cl_must_pass(p_mkdir("attr/case", 0755));
+ cl_git_mkfile("attr/case/file", "content");
+
+ assert_is_ignored(true, "case/file");
+}
diff --git a/tests/checkout/head.c b/tests/checkout/head.c
index 07cc1d209..ded86df33 100644
--- a/tests/checkout/head.c
+++ b/tests/checkout/head.c
@@ -38,7 +38,7 @@ void test_checkout_head__with_index_only_tree(void)
cl_git_pass(git_repository_index(&index, g_repo));
p_mkdir("testrepo/newdir", 0777);
- cl_git_mkfile("testrepo/newdir/newfile.txt", "new file\n");
+ cl_git_mkfile("testrepo/newdir/newfile.txt", "new file\n");
cl_git_pass(git_index_add_bypath(index, "newdir/newfile.txt"));
cl_git_pass(git_index_write(index));
@@ -60,3 +60,79 @@ void test_checkout_head__with_index_only_tree(void)
git_index_free(index);
}
+
+void test_checkout_head__do_not_remove_untracked_file(void)
+{
+ git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+ git_index *index;
+
+ cl_git_pass(p_mkdir("testrepo/tracked", 0755));
+ cl_git_mkfile("testrepo/tracked/tracked", "tracked\n");
+ cl_git_mkfile("testrepo/tracked/untracked", "untracked\n");
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+ cl_git_pass(git_index_add_bypath(index, "tracked/tracked"));
+ cl_git_pass(git_index_write(index));
+
+ git_index_free(index);
+
+ opts.checkout_strategy = GIT_CHECKOUT_FORCE;
+ cl_git_pass(git_checkout_head(g_repo, &opts));
+
+ cl_assert(!git_path_isfile("testrepo/tracked/tracked"));
+ cl_assert(git_path_isfile("testrepo/tracked/untracked"));
+}
+
+void test_checkout_head__do_not_remove_untracked_file_in_subdir(void)
+{
+ git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+ git_index *index;
+
+ cl_git_pass(p_mkdir("testrepo/tracked", 0755));
+ cl_git_pass(p_mkdir("testrepo/tracked/subdir", 0755));
+ cl_git_mkfile("testrepo/tracked/tracked", "tracked\n");
+ cl_git_mkfile("testrepo/tracked/subdir/tracked", "tracked\n");
+ cl_git_mkfile("testrepo/tracked/subdir/untracked", "untracked\n");
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+ cl_git_pass(git_index_add_bypath(index, "tracked/tracked"));
+ cl_git_pass(git_index_add_bypath(index, "tracked/subdir/tracked"));
+ cl_git_pass(git_index_write(index));
+
+ git_index_free(index);
+
+ opts.checkout_strategy = GIT_CHECKOUT_FORCE;
+ cl_git_pass(git_checkout_head(g_repo, &opts));
+
+ cl_assert(!git_path_isfile("testrepo/tracked/tracked"));
+ cl_assert(!git_path_isfile("testrepo/tracked/subdir/tracked"));
+ cl_assert(git_path_isfile("testrepo/tracked/subdir/untracked"));
+}
+
+void test_checkout_head__do_remove_tracked_subdir(void)
+{
+ git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+ git_index *index;
+
+ cl_git_pass(p_mkdir("testrepo/subdir", 0755));
+ cl_git_pass(p_mkdir("testrepo/subdir/tracked", 0755));
+ cl_git_mkfile("testrepo/subdir/tracked-file", "tracked\n");
+ cl_git_mkfile("testrepo/subdir/untracked-file", "untracked\n");
+ cl_git_mkfile("testrepo/subdir/tracked/tracked1", "tracked\n");
+ cl_git_mkfile("testrepo/subdir/tracked/tracked2", "tracked\n");
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+ cl_git_pass(git_index_add_bypath(index, "subdir/tracked-file"));
+ cl_git_pass(git_index_add_bypath(index, "subdir/tracked/tracked1"));
+ cl_git_pass(git_index_add_bypath(index, "subdir/tracked/tracked2"));
+ cl_git_pass(git_index_write(index));
+
+ git_index_free(index);
+
+ opts.checkout_strategy = GIT_CHECKOUT_FORCE;
+ cl_git_pass(git_checkout_head(g_repo, &opts));
+
+ cl_assert(!git_path_isdir("testrepo/subdir/tracked"));
+ cl_assert(!git_path_isfile("testrepo/subdir/tracked-file"));
+ cl_assert(git_path_isfile("testrepo/subdir/untracked-file"));
+}
diff --git a/tests/checkout/tree.c b/tests/checkout/tree.c
index 4a0314a9e..b3b860c63 100644
--- a/tests/checkout/tree.c
+++ b/tests/checkout/tree.c
@@ -422,6 +422,41 @@ void test_checkout_tree__can_checkout_with_pattern(void)
cl_assert(git_path_exists("testrepo/new.txt"));
}
+void test_checkout_tree__pathlist_checkout_ignores_non_matches(void)
+{
+ char *entries[] = { "branch_file.txt", "link_to_new.txt" };
+
+ /* reset to beginning of history (i.e. just a README file) */
+
+ g_opts.checkout_strategy =
+ GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED;
+
+ cl_git_pass(git_revparse_single(&g_object, g_repo, "refs/heads/master"));
+
+ cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts));
+ cl_git_pass(git_repository_set_head(g_repo, "refs/heads/master"));
+
+ cl_assert(git_path_exists("testrepo/README"));
+ cl_assert(git_path_exists("testrepo/branch_file.txt"));
+ cl_assert(git_path_exists("testrepo/link_to_new.txt"));
+ cl_assert(git_path_exists("testrepo/new.txt"));
+
+ git_object_free(g_object);
+ cl_git_pass(git_revparse_single(&g_object, g_repo, "8496071c1b46c854b31185ea97743be6a8774479"));
+
+ g_opts.checkout_strategy =
+ GIT_CHECKOUT_FORCE | GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH;
+ g_opts.paths.strings = entries;
+ g_opts.paths.count = 2;
+
+ cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts));
+
+ cl_assert(git_path_exists("testrepo/README"));
+ cl_assert(!git_path_exists("testrepo/branch_file.txt"));
+ cl_assert(!git_path_exists("testrepo/link_to_new.txt"));
+ cl_assert(git_path_exists("testrepo/new.txt"));
+}
+
void test_checkout_tree__can_disable_pattern_match(void)
{
char *entries[] = { "b*.txt" };
diff --git a/tests/clar_libgit2.c b/tests/clar_libgit2.c
index 314d3441e..bd10c009d 100644
--- a/tests/clar_libgit2.c
+++ b/tests/clar_libgit2.c
@@ -4,12 +4,20 @@
#include "git2/sys/repository.h"
void cl_git_report_failure(
- int error, const char *file, int line, const char *fncall)
+ int error, int expected, const char *file, int line, const char *fncall)
{
char msg[4096];
const git_error *last = giterr_last();
- p_snprintf(msg, 4096, "error %d - %s",
- error, last ? last->message : "<no message>");
+
+ if (expected)
+ p_snprintf(msg, 4096, "error %d (expected %d) - %s",
+ error, expected, last ? last->message : "<no message>");
+ else if (error || last)
+ p_snprintf(msg, 4096, "error %d - %s",
+ error, last ? last->message : "<no message>");
+ else
+ p_snprintf(msg, 4096, "no error, expected non-zero return");
+
clar__assert(0, file, line, fncall, msg, 1);
}
diff --git a/tests/clar_libgit2.h b/tests/clar_libgit2.h
index d7e635302..c72d37db3 100644
--- a/tests/clar_libgit2.h
+++ b/tests/clar_libgit2.h
@@ -12,13 +12,15 @@
*
* Use this wrapper around all `git_` library calls that return error codes!
*/
-#define cl_git_pass(expr) cl_git_pass_((expr), __FILE__, __LINE__)
+#define cl_git_pass(expr) cl_git_expect((expr), 0, __FILE__, __LINE__)
-#define cl_git_pass_(expr, file, line) do { \
+#define cl_git_fail_with(error, expr) cl_git_expect((expr), error, __FILE__, __LINE__)
+
+#define cl_git_expect(expr, expected, file, line) do { \
int _lg2_error; \
giterr_clear(); \
- if ((_lg2_error = (expr)) != 0) \
- cl_git_report_failure(_lg2_error, file, line, "Function call failed: " #expr); \
+ if ((_lg2_error = (expr)) != expected) \
+ cl_git_report_failure(_lg2_error, expected, file, line, "Function call failed: " #expr); \
} while (0)
/**
@@ -26,9 +28,11 @@
* just for consistency. Use with `git_` library
* calls that are supposed to fail!
*/
-#define cl_git_fail(expr) cl_must_fail(expr)
-
-#define cl_git_fail_with(expr, error) cl_assert_equal_i(error,expr)
+#define cl_git_fail(expr) do { \
+ giterr_clear(); \
+ if ((expr) == 0) \
+ cl_git_report_failure(0, 0, __FILE__, __LINE__, "Function call succeeded: " #expr); \
+ } while (0)
/**
* Like cl_git_pass, only for Win32 error code conventions
@@ -37,11 +41,56 @@
int _win32_res; \
if ((_win32_res = (expr)) == 0) { \
giterr_set(GITERR_OS, "Returned: %d, system error code: %d", _win32_res, GetLastError()); \
- cl_git_report_failure(_win32_res, __FILE__, __LINE__, "System call failed: " #expr); \
+ cl_git_report_failure(_win32_res, 0, __FILE__, __LINE__, "System call failed: " #expr); \
} \
} while(0)
-void cl_git_report_failure(int, const char *, int, const char *);
+/**
+ * Thread safe assertions; you cannot use `cl_git_report_failure` from a
+ * child thread since it will try to `longjmp` to abort and "the effect of
+ * a call to longjmp() where initialization of the jmp_buf structure was
+ * not performed in the calling thread is undefined."
+ *
+ * Instead, callers can provide a clar thread error context to a thread,
+ * which will populate and return it on failure. Callers can check the
+ * status with `cl_git_thread_check`.
+ */
+typedef struct {
+ int error;
+ const char *file;
+ int line;
+ const char *expr;
+ char error_msg[4096];
+} cl_git_thread_err;
+
+#ifdef GIT_THREADS
+# define cl_git_thread_pass(threaderr, expr) cl_git_thread_pass_(threaderr, (expr), __FILE__, __LINE__)
+#else
+# define cl_git_thread_pass(threaderr, expr) cl_git_pass(expr)
+#endif
+
+#define cl_git_thread_pass_(__threaderr, __expr, __file, __line) do { \
+ giterr_clear(); \
+ if ((((cl_git_thread_err *)__threaderr)->error = (__expr)) != 0) { \
+ const git_error *_last = giterr_last(); \
+ ((cl_git_thread_err *)__threaderr)->file = __file; \
+ ((cl_git_thread_err *)__threaderr)->line = __line; \
+ ((cl_git_thread_err *)__threaderr)->expr = "Function call failed: " #__expr; \
+ p_snprintf(((cl_git_thread_err *)__threaderr)->error_msg, 4096, "thread 0x%" PRIxZ " - error %d - %s", \
+ git_thread_currentid(), ((cl_git_thread_err *)__threaderr)->error, \
+ _last ? _last->message : "<no message>"); \
+ git_thread_exit(__threaderr); \
+ } \
+ } while (0)
+
+GIT_INLINE(void) cl_git_thread_check(void *data)
+{
+ cl_git_thread_err *threaderr = (cl_git_thread_err *)data;
+ if (threaderr->error != 0)
+ clar__assert(0, threaderr->file, threaderr->line, threaderr->expr, threaderr->error_msg, 1);
+}
+
+void cl_git_report_failure(int, int, const char *, int, const char *);
#define cl_assert_at_line(expr,file,line) \
clar__assert((expr) != 0, file, line, "Expression is not true: " #expr, NULL, 1)
diff --git a/tests/clone/local.c b/tests/clone/local.c
index 91a0a1c2a..7f54d05de 100644
--- a/tests/clone/local.c
+++ b/tests/clone/local.c
@@ -16,6 +16,7 @@ static int file_url(git_buf *buf, const char *host, const char *path)
return git_buf_printf(buf, "file://%s/%s", host, path);
}
+#ifdef GIT_WIN32
static int git_style_unc_path(git_buf *buf, const char *host, const char *path)
{
git_buf_clear(buf);
@@ -49,6 +50,7 @@ static int unc_path(git_buf *buf, const char *host, const char *path)
return 0;
}
+#endif
void test_clone_local__should_clone_local(void)
{
diff --git a/tests/config/include.c b/tests/config/include.c
index 882b89b16..e440b9a78 100644
--- a/tests/config/include.c
+++ b/tests/config/include.c
@@ -2,25 +2,31 @@
#include "buffer.h"
#include "fileops.h"
-void test_config_include__relative(void)
+static git_config *cfg;
+static git_buf buf;
+
+void test_config_include__initialize(void)
{
- git_config *cfg;
- git_buf buf = GIT_BUF_INIT;
+ cfg = NULL;
+ git_buf_init(&buf, 0);
+}
+void test_config_include__cleanup(void)
+{
+ git_config_free(cfg);
+ git_buf_free(&buf);
+}
+
+void test_config_include__relative(void)
+{
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config-include")));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar.baz"));
cl_assert_equal_s("huzzah", git_buf_cstr(&buf));
-
- git_buf_free(&buf);
- git_config_free(cfg);
}
void test_config_include__absolute(void)
{
- git_config *cfg;
- git_buf buf = GIT_BUF_INIT;
-
cl_git_pass(git_buf_printf(&buf, "[include]\npath = %s/config-included", cl_fixture("config")));
cl_git_mkfile("config-include-absolute", git_buf_cstr(&buf));
@@ -29,16 +35,10 @@ void test_config_include__absolute(void)
cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar.baz"));
cl_assert_equal_s("huzzah", git_buf_cstr(&buf));
-
- git_buf_free(&buf);
- git_config_free(cfg);
}
void test_config_include__homedir(void)
{
- git_config *cfg;
- git_buf buf = GIT_BUF_INIT;
-
cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, cl_fixture("config")));
cl_git_mkfile("config-include-homedir", "[include]\npath = ~/config-included");
@@ -47,18 +47,12 @@ void test_config_include__homedir(void)
cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar.baz"));
cl_assert_equal_s("huzzah", git_buf_cstr(&buf));
- git_buf_free(&buf);
- git_config_free(cfg);
-
cl_sandbox_set_search_path_defaults();
}
/* We need to pretend that the variables were defined where the file was included */
void test_config_include__ordering(void)
{
- git_config *cfg;
- git_buf buf = GIT_BUF_INIT;
-
cl_git_mkfile("included", "[foo \"bar\"]\nbaz = hurrah\nfrotz = hiya");
cl_git_mkfile("including",
"[foo \"bar\"]\nfrotz = hello\n"
@@ -72,16 +66,11 @@ void test_config_include__ordering(void)
git_buf_clear(&buf);
cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar.baz"));
cl_assert_equal_s("huzzah", git_buf_cstr(&buf));
-
- git_buf_free(&buf);
- git_config_free(cfg);
}
/* We need to pretend that the variables were defined where the file was included */
void test_config_include__depth(void)
{
- git_config *cfg;
-
cl_git_mkfile("a", "[include]\npath = b");
cl_git_mkfile("b", "[include]\npath = a");
@@ -93,9 +82,6 @@ void test_config_include__depth(void)
void test_config_include__missing(void)
{
- git_config *cfg;
- git_buf buf = GIT_BUF_INIT;
-
cl_git_mkfile("including", "[include]\npath = nonexistentfile\n[foo]\nbar = baz");
giterr_clear();
@@ -103,16 +89,25 @@ void test_config_include__missing(void)
cl_assert(giterr_last() == NULL);
cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar"));
cl_assert_equal_s("baz", git_buf_cstr(&buf));
+}
- git_buf_free(&buf);
- git_config_free(cfg);
+void test_config_include__missing_homedir(void)
+{
+ cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, cl_fixture("config")));
+ cl_git_mkfile("including", "[include]\npath = ~/.nonexistentfile\n[foo]\nbar = baz");
+
+ giterr_clear();
+ cl_git_pass(git_config_open_ondisk(&cfg, "including"));
+ cl_assert(giterr_last() == NULL);
+ cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar"));
+ cl_assert_equal_s("baz", git_buf_cstr(&buf));
+
+ cl_sandbox_set_search_path_defaults();
}
#define replicate10(s) s s s s s s s s s s
void test_config_include__depth2(void)
{
- git_config *cfg;
- git_buf buf = GIT_BUF_INIT;
const char *content = "[include]\n" replicate10(replicate10("path=bottom\n"));
cl_git_mkfile("top-level", "[include]\npath = middle\n[foo]\nbar = baz");
@@ -127,7 +122,45 @@ void test_config_include__depth2(void)
git_buf_clear(&buf);
cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar2"));
cl_assert_equal_s("baz2", git_buf_cstr(&buf));
+}
- git_buf_free(&buf);
- git_config_free(cfg);
+void test_config_include__removing_include_removes_values(void)
+{
+ cl_git_mkfile("top-level", "[include]\npath = included");
+ cl_git_mkfile("included", "[foo]\nbar = value");
+
+ cl_git_pass(git_config_open_ondisk(&cfg, "top-level"));
+ cl_git_mkfile("top-level", "");
+ cl_git_fail(git_config_get_string_buf(&buf, cfg, "foo.bar"));
+}
+
+void test_config_include__rewriting_include_refreshes_values(void)
+{
+ cl_git_mkfile("top-level", "[include]\npath = first\n[include]\npath = second");
+ cl_git_mkfile("first", "[first]\nfoo = bar");
+ cl_git_mkfile("second", "[second]\nfoo = bar");
+
+ cl_git_pass(git_config_open_ondisk(&cfg, "top-level"));
+ cl_git_mkfile("first", "[first]\nother = value");
+ cl_git_fail(git_config_get_string_buf(&buf, cfg, "foo.bar"));
+ cl_git_pass(git_config_get_string_buf(&buf, cfg, "first.other"));
+ cl_assert_equal_s(buf.ptr, "value");
+}
+
+void test_config_include__included_variables_cannot_be_deleted(void)
+{
+ cl_git_mkfile("top-level", "[include]\npath = included\n");
+ cl_git_mkfile("included", "[foo]\nbar = value");
+
+ cl_git_pass(git_config_open_ondisk(&cfg, "top-level"));
+ cl_git_fail(git_config_delete_entry(cfg, "foo.bar"));
+}
+
+void test_config_include__included_variables_cannot_be_modified(void)
+{
+ cl_git_mkfile("top-level", "[include]\npath = included\n");
+ cl_git_mkfile("included", "[foo]\nbar = value");
+
+ cl_git_pass(git_config_open_ondisk(&cfg, "top-level"));
+ cl_git_fail(git_config_set_string(cfg, "foo.bar", "other-value"));
}
diff --git a/tests/config/readonly.c b/tests/config/readonly.c
new file mode 100644
index 000000000..6d6819eef
--- /dev/null
+++ b/tests/config/readonly.c
@@ -0,0 +1,65 @@
+#include "clar_libgit2.h"
+#include "config_file.h"
+#include "config.h"
+#include "path.h"
+
+static git_config *cfg;
+
+void test_config_readonly__initialize(void)
+{
+ cl_git_pass(git_config_new(&cfg));
+}
+
+void test_config_readonly__cleanup(void)
+{
+ git_config_free(cfg);
+ cfg = NULL;
+}
+
+void test_config_readonly__writing_to_readonly_fails(void)
+{
+ git_config_backend *backend;
+
+ cl_git_pass(git_config_file__ondisk(&backend, "global"));
+ backend->readonly = 1;
+ cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_GLOBAL, 0));
+
+ cl_git_fail_with(GIT_ENOTFOUND, git_config_set_string(cfg, "foo.bar", "baz"));
+ cl_assert(!git_path_exists("global"));
+}
+
+void test_config_readonly__writing_to_cfg_with_rw_precedence_succeeds(void)
+{
+ git_config_backend *backend;
+
+ cl_git_pass(git_config_file__ondisk(&backend, "global"));
+ backend->readonly = 1;
+ cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_GLOBAL, 0));
+
+ cl_git_pass(git_config_file__ondisk(&backend, "local"));
+ cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_LOCAL, 0));
+
+ cl_git_pass(git_config_set_string(cfg, "foo.bar", "baz"));
+
+ cl_assert(git_path_exists("local"));
+ cl_assert(!git_path_exists("global"));
+ cl_git_pass(p_unlink("local"));
+}
+
+void test_config_readonly__writing_to_cfg_with_ro_precedence_succeeds(void)
+{
+ git_config_backend *backend;
+
+ cl_git_pass(git_config_file__ondisk(&backend, "local"));
+ backend->readonly = 1;
+ cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_LOCAL, 0));
+
+ cl_git_pass(git_config_file__ondisk(&backend, "global"));
+ cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_GLOBAL, 0));
+
+ cl_git_pass(git_config_set_string(cfg, "foo.bar", "baz"));
+
+ cl_assert(!git_path_exists("local"));
+ cl_assert(git_path_exists("global"));
+ cl_git_pass(p_unlink("global"));
+}
diff --git a/tests/core/encoding.c b/tests/core/encoding.c
index 7d91720f4..a677afe2e 100644
--- a/tests/core/encoding.c
+++ b/tests/core/encoding.c
@@ -29,6 +29,9 @@ void test_core_encoding__encode(void)
cl_assert(git_encode_varint(buf, 100, 65) == 1);
cl_assert(buf[0] == 'A');
+ cl_assert(git_encode_varint(buf, 1, 1) == 1);
+ cl_assert(!memcmp(buf, "\x01", 1));
+
cl_assert(git_encode_varint(buf, 100, 267869656) == 4);
cl_assert(!memcmp(buf, "\xfe\xdc\xbaX", 4));
diff --git a/tests/core/env.c b/tests/core/env.c
index ee08258a6..1af0e6e5d 100644
--- a/tests/core/env.c
+++ b/tests/core/env.c
@@ -298,3 +298,24 @@ void test_core_env__2(void)
git_buf_free(&path);
git_buf_free(&found);
}
+
+void test_core_env__substitution(void)
+{
+ git_buf buf = GIT_BUF_INIT, expected = GIT_BUF_INIT;
+
+ /* Set it to something non-default so we have controllable values */
+ cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, "/tmp/a"));
+ cl_git_pass(git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, &buf));
+ cl_assert_equal_s("/tmp/a", buf.ptr);
+
+ git_buf_clear(&buf);
+ cl_git_pass(git_buf_join(&buf, GIT_PATH_LIST_SEPARATOR, "$PATH", "/tmp/b"));
+ cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, buf.ptr));
+ cl_git_pass(git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, &buf));
+
+ cl_git_pass(git_buf_join(&expected, GIT_PATH_LIST_SEPARATOR, "/tmp/a", "/tmp/b"));
+ cl_assert_equal_s(expected.ptr, buf.ptr);
+
+ git_buf_free(&expected);
+ git_buf_free(&buf);
+}
diff --git a/tests/core/features.c b/tests/core/features.c
index cf5e19063..7b28cc0cb 100644
--- a/tests/core/features.c
+++ b/tests/core/features.c
@@ -17,7 +17,9 @@ void test_core_features__0(void)
cl_assert((caps & GIT_FEATURE_THREADS) == 0);
#endif
+#ifdef GIT_HTTPS
cl_assert((caps & GIT_FEATURE_HTTPS) != 0);
+#endif
#if defined(GIT_SSH)
cl_assert((caps & GIT_FEATURE_SSH) != 0);
diff --git a/tests/core/filebuf.c b/tests/core/filebuf.c
index 04a380b20..ef7ac6bd9 100644
--- a/tests/core/filebuf.c
+++ b/tests/core/filebuf.c
@@ -187,6 +187,35 @@ void test_core_filebuf__symlink_follow(void)
cl_git_pass(git_futils_rmdir_r(dir, NULL, GIT_RMDIR_REMOVE_FILES));
}
+void test_core_filebuf__symlink_follow_absolute_paths(void)
+{
+ git_filebuf file = GIT_FILEBUF_INIT;
+ git_buf source = GIT_BUF_INIT, target = GIT_BUF_INIT;
+
+#ifdef GIT_WIN32
+ cl_skip();
+#endif
+
+ cl_git_pass(git_buf_joinpath(&source, clar_sandbox_path(), "linkdir/link"));
+ cl_git_pass(git_buf_joinpath(&target, clar_sandbox_path(), "linkdir/target"));
+ cl_git_pass(p_mkdir("linkdir", 0777));
+ cl_git_pass(p_symlink(target.ptr, source.ptr));
+
+ cl_git_pass(git_filebuf_open(&file, source.ptr, 0, 0666));
+ cl_git_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks"));
+
+ cl_assert_equal_i(true, git_path_exists("linkdir/target.lock"));
+
+ cl_git_pass(git_filebuf_commit(&file));
+ cl_assert_equal_i(true, git_path_exists("linkdir/target"));
+
+ git_filebuf_cleanup(&file);
+ git_buf_free(&source);
+ git_buf_free(&target);
+
+ cl_git_pass(git_futils_rmdir_r("linkdir", NULL, GIT_RMDIR_REMOVE_FILES));
+}
+
void test_core_filebuf__symlink_depth(void)
{
git_filebuf file = GIT_FILEBUF_INIT;
diff --git a/tests/core/init.c b/tests/core/init.c
index e17b7845f..a8cbd930b 100644
--- a/tests/core/init.c
+++ b/tests/core/init.c
@@ -12,3 +12,43 @@ void test_core_init__returns_count(void)
cl_assert_equal_i(1, git_libgit2_shutdown());
}
+void test_core_init__reinit_succeeds(void)
+{
+ cl_assert_equal_i(0, git_libgit2_shutdown());
+ cl_assert_equal_i(1, git_libgit2_init());
+ cl_sandbox_set_search_path_defaults();
+}
+
+#ifdef GIT_THREADS
+static void *reinit(void *unused)
+{
+ unsigned i;
+
+ for (i = 0; i < 20; i++) {
+ cl_assert(git_libgit2_init() > 0);
+ cl_assert(git_libgit2_shutdown() >= 0);
+ }
+
+ return unused;
+}
+#endif
+
+void test_core_init__concurrent_init_succeeds(void)
+{
+#ifdef GIT_THREADS
+ git_thread threads[10];
+ unsigned i;
+
+ cl_assert_equal_i(2, git_libgit2_init());
+
+ for (i = 0; i < ARRAY_SIZE(threads); i++)
+ git_thread_create(&threads[i], reinit, NULL);
+ for (i = 0; i < ARRAY_SIZE(threads); i++)
+ git_thread_join(&threads[i], NULL);
+
+ cl_assert_equal_i(1, git_libgit2_shutdown());
+ cl_sandbox_set_search_path_defaults();
+#else
+ cl_skip();
+#endif
+}
diff --git a/tests/core/oidmap.c b/tests/core/oidmap.c
index 556a6ca4a..617da5483 100644
--- a/tests/core/oidmap.c
+++ b/tests/core/oidmap.c
@@ -1,8 +1,6 @@
#include "clar_libgit2.h"
#include "oidmap.h"
-GIT__USE_OIDMAP
-
typedef struct {
git_oid oid;
size_t extra;
@@ -33,23 +31,23 @@ void test_core_oidmap__basic(void)
khiter_t pos;
int ret;
- pos = kh_get(oid, map, &items[i].oid);
- cl_assert(pos == kh_end(map));
+ pos = git_oidmap_lookup_index(map, &items[i].oid);
+ cl_assert(!git_oidmap_valid_index(map, pos));
- pos = kh_put(oid, map, &items[i].oid, &ret);
+ pos = git_oidmap_put(map, &items[i].oid, &ret);
cl_assert(ret != 0);
- kh_val(map, pos) = &items[i];
+ git_oidmap_set_value_at(map, pos, &items[i]);
}
for (i = 0; i < NITEMS; ++i) {
khiter_t pos;
- pos = kh_get(oid, map, &items[i].oid);
- cl_assert(pos != kh_end(map));
+ pos = git_oidmap_lookup_index(map, &items[i].oid);
+ cl_assert(git_oidmap_valid_index(map, pos));
- cl_assert_equal_p(kh_val(map, pos), &items[i]);
+ cl_assert_equal_p(git_oidmap_value_at(map, pos), &items[i]);
}
git_oidmap_free(map);
@@ -87,23 +85,23 @@ void test_core_oidmap__hash_collision(void)
khiter_t pos;
int ret;
- pos = kh_get(oid, map, &items[i].oid);
- cl_assert(pos == kh_end(map));
+ pos = git_oidmap_lookup_index(map, &items[i].oid);
+ cl_assert(!git_oidmap_valid_index(map, pos));
- pos = kh_put(oid, map, &items[i].oid, &ret);
+ pos = git_oidmap_put(map, &items[i].oid, &ret);
cl_assert(ret != 0);
- kh_val(map, pos) = &items[i];
+ git_oidmap_set_value_at(map, pos, &items[i]);
}
for (i = 0; i < NITEMS; ++i) {
khiter_t pos;
- pos = kh_get(oid, map, &items[i].oid);
- cl_assert(pos != kh_end(map));
+ pos = git_oidmap_lookup_index(map, &items[i].oid);
+ cl_assert(git_oidmap_valid_index(map, pos));
- cl_assert_equal_p(kh_val(map, pos), &items[i]);
+ cl_assert_equal_p(git_oidmap_value_at(map, pos), &items[i]);
}
git_oidmap_free(map);
diff --git a/tests/core/path.c b/tests/core/path.c
index 71c6eda58..fefe2aeac 100644
--- a/tests/core/path.c
+++ b/tests/core/path.c
@@ -89,8 +89,12 @@ void test_core_path__00_dirname(void)
check_dirname(REP16("/abc"), REP15("/abc"));
#ifdef GIT_WIN32
+ check_dirname("C:/", "C:/");
+ check_dirname("C:", "C:/");
check_dirname("C:/path/", "C:/");
check_dirname("C:/path", "C:/");
+ check_dirname("//computername/", "//computername/");
+ check_dirname("//computername", "//computername/");
check_dirname("//computername/path/", "//computername/");
check_dirname("//computername/path", "//computername/");
check_dirname("//computername/sub/path/", "//computername/sub");
diff --git a/tests/core/posix.c b/tests/core/posix.c
index 34a67bf47..172462073 100644
--- a/tests/core/posix.c
+++ b/tests/core/posix.c
@@ -9,8 +9,11 @@
# endif
#endif
+#include <locale.h>
+
#include "clar_libgit2.h"
#include "posix.h"
+#include "userdiff.h"
void test_core_posix__initialize(void)
{
@@ -39,7 +42,7 @@ void test_core_posix__inet_pton(void)
struct in_addr addr;
struct in6_addr addr6;
size_t i;
-
+
struct in_addr_data {
const char *p;
const uint8_t n[4];
@@ -91,10 +94,7 @@ void test_core_posix__inet_pton(void)
cl_assert(p_inet_pton(AF_INET, "10.foo.bar.1", &addr) == 0);
/* Test unsupported address families */
- cl_git_fail(p_inet_pton(12, "52.472", NULL)); /* AF_DECnet */
- cl_assert_equal_i(EAFNOSUPPORT, errno);
-
- cl_git_fail(p_inet_pton(5, "315.124", NULL)); /* AF_CHAOS */
+ cl_git_fail(p_inet_pton(INT_MAX-1, "52.472", &addr));
cl_assert_equal_i(EAFNOSUPPORT, errno);
}
@@ -146,3 +146,47 @@ void test_core_posix__utimes(void)
p_unlink("foo");
}
+
+void test_core_posix__p_regcomp_ignores_global_locale_ctype(void)
+{
+ regex_t preg;
+ int error = 0;
+
+ const char* oldlocale = setlocale(LC_CTYPE, NULL);
+
+ if (!setlocale(LC_CTYPE, "UTF-8") &&
+ !setlocale(LC_CTYPE, "c.utf8") &&
+ !setlocale(LC_CTYPE, "en_US.UTF-8"))
+ cl_skip();
+
+ if (MB_CUR_MAX == 1) {
+ setlocale(LC_CTYPE, oldlocale);
+ cl_fail("Expected locale to be switched to multibyte");
+ }
+
+ p_regcomp(&preg, "[\xc0-\xff][\x80-\xbf]", REG_EXTENDED);
+ regfree(&preg);
+
+ setlocale(LC_CTYPE, oldlocale);
+
+ cl_must_pass(error);
+}
+
+void test_core_posix__p_regcomp_compile_userdiff_regexps(void)
+{
+ size_t idx;
+
+ for (idx = 0; idx < ARRAY_SIZE(builtin_defs); ++idx) {
+ git_diff_driver_definition ddef = builtin_defs[idx];
+ int error = 0;
+ regex_t preg;
+
+ error = p_regcomp(&preg, ddef.fns, REG_EXTENDED | ddef.flags);
+ regfree(&preg);
+ cl_must_pass(error);
+
+ error = p_regcomp(&preg, ddef.words, REG_EXTENDED);
+ regfree(&preg);
+ cl_must_pass(error);
+ }
+}
diff --git a/tests/core/pqueue.c b/tests/core/pqueue.c
index bcd4eea9f..2b90f4172 100644
--- a/tests/core/pqueue.c
+++ b/tests/core/pqueue.c
@@ -93,7 +93,29 @@ void test_core_pqueue__max_heap_size(void)
cl_assert_equal_i(0, git_pqueue_size(&pq));
git_pqueue_free(&pq);
+}
+
+void test_core_pqueue__max_heap_size_without_comparison(void)
+{
+ git_pqueue pq;
+ int i, vals[100] = { 0 };
+
+ cl_git_pass(git_pqueue_init(&pq, GIT_PQUEUE_FIXED_SIZE, 50, NULL));
+
+ for (i = 0; i < 100; ++i)
+ cl_git_pass(git_pqueue_insert(&pq, &vals[i]));
+ cl_assert_equal_i(50, git_pqueue_size(&pq));
+
+ /* As we have no comparison function, we cannot make any
+ * actual assumptions about which entries are part of the
+ * pqueue */
+ for (i = 0; i < 50; ++i)
+ cl_assert(git_pqueue_pop(&pq));
+
+ cl_assert_equal_i(0, git_pqueue_size(&pq));
+
+ git_pqueue_free(&pq);
}
static int cmp_ints_like_commit_time(const void *a, const void *b)
diff --git a/tests/core/sha1.c b/tests/core/sha1.c
new file mode 100644
index 000000000..c5b20f6e0
--- /dev/null
+++ b/tests/core/sha1.c
@@ -0,0 +1,64 @@
+#include "clar_libgit2.h"
+#include "hash.h"
+
+#define FIXTURE_DIR "sha1"
+
+void test_core_sha1__initialize(void)
+{
+ cl_fixture_sandbox(FIXTURE_DIR);
+}
+
+void test_core_sha1__cleanup(void)
+{
+ cl_fixture_cleanup(FIXTURE_DIR);
+}
+
+static int sha1_file(git_oid *oid, const char *filename)
+{
+ git_hash_ctx ctx;
+ char buf[2048];
+ int fd, ret;
+ ssize_t read_len;
+
+ fd = p_open(filename, O_RDONLY);
+ cl_assert(fd >= 0);
+
+ cl_git_pass(git_hash_ctx_init(&ctx));
+
+ while ((read_len = p_read(fd, buf, 2048)) > 0)
+ cl_git_pass(git_hash_update(&ctx, buf, (size_t)read_len));
+
+ cl_assert_equal_i(0, read_len);
+ p_close(fd);
+
+ ret = git_hash_final(oid, &ctx);
+ git_hash_ctx_cleanup(&ctx);
+
+ return ret;
+}
+
+void test_core_sha1__sum(void)
+{
+ git_oid oid, expected;
+
+ cl_git_pass(sha1_file(&oid, FIXTURE_DIR "/hello_c"));
+ git_oid_fromstr(&expected, "4e72679e3ea4d04e0c642f029e61eb8056c7ed94");
+ cl_assert_equal_oid(&expected, &oid);
+}
+
+/* test that sha1 collision detection works when enabled */
+void test_core_sha1__detect_collision_attack(void)
+{
+ git_oid oid, expected;
+
+#ifdef GIT_SHA1_COLLISIONDETECT
+ GIT_UNUSED(expected);
+ cl_git_fail(sha1_file(&oid, FIXTURE_DIR "/shattered-1.pdf"));
+ cl_assert_equal_s("SHA1 collision attack detected", giterr_last()->message);
+#else
+ cl_git_pass(sha1_file(&oid, FIXTURE_DIR "/shattered-1.pdf"));
+ git_oid_fromstr(&expected, "38762cf7f55934b34d179ae6a4c80cadccbb7f0a");
+ cl_assert_equal_oid(&expected, &oid);
+#endif
+}
+
diff --git a/tests/core/strmap.c b/tests/core/strmap.c
index 3b4276aea..2fa594d43 100644
--- a/tests/core/strmap.c
+++ b/tests/core/strmap.c
@@ -1,8 +1,6 @@
#include "clar_libgit2.h"
#include "strmap.h"
-GIT__USE_STRMAP
-
git_strmap *g_table;
void test_core_strmap__initialize(void)
@@ -36,7 +34,7 @@ static void insert_strings(git_strmap *table, int count)
for (j = 0, over = i / 26; over > 0; j++, over = over / 26)
str[j] = 'A' + (over % 26);
- git_strmap_insert(table, str, str, err);
+ git_strmap_insert(table, str, str, &err);
cl_assert(err >= 0);
}
diff --git a/tests/core/structinit.c b/tests/core/structinit.c
index e9f7b4a74..8feba864e 100644
--- a/tests/core/structinit.c
+++ b/tests/core/structinit.c
@@ -1,5 +1,6 @@
#include "clar_libgit2.h"
#include <git2/sys/config.h>
+#include <git2/sys/filter.h>
#include <git2/sys/odb_backend.h>
#include <git2/sys/refdb_backend.h>
#include <git2/sys/transport.h>
@@ -96,6 +97,11 @@ void test_core_structinit__compare(void)
git_diff_find_options, GIT_DIFF_FIND_OPTIONS_VERSION, \
GIT_DIFF_FIND_OPTIONS_INIT, git_diff_find_init_options);
+ /* filter */
+ CHECK_MACRO_FUNC_INIT_EQUAL( \
+ git_filter, GIT_FILTER_VERSION, \
+ GIT_FILTER_INIT, git_filter_init);
+
/* merge_file_input */
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_merge_file_input, GIT_MERGE_FILE_INPUT_VERSION, \
@@ -165,4 +171,13 @@ void test_core_structinit__compare(void)
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_submodule_update_options, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, \
GIT_SUBMODULE_UPDATE_OPTIONS_INIT, git_submodule_update_init_options);
+
+ /* submodule update */
+ CHECK_MACRO_FUNC_INIT_EQUAL( \
+ git_proxy_options, GIT_PROXY_OPTIONS_VERSION, \
+ GIT_PROXY_OPTIONS_INIT, git_proxy_init_options);
+
+ CHECK_MACRO_FUNC_INIT_EQUAL( \
+ git_diff_patchid_options, GIT_DIFF_PATCHID_OPTIONS_VERSION, \
+ GIT_DIFF_PATCHID_OPTIONS_INIT, git_diff_patchid_init_options);
}
diff --git a/tests/core/vector.c b/tests/core/vector.c
index c351655a7..c2e5d3f34 100644
--- a/tests/core/vector.c
+++ b/tests/core/vector.c
@@ -376,3 +376,34 @@ void test_core_vector__grow_and_shrink(void)
git_vector_free(&x);
}
+
+void test_core_vector__reverse(void)
+{
+ git_vector v = GIT_VECTOR_INIT;
+ size_t i;
+
+ void *in1[] = {(void *) 0x0, (void *) 0x1, (void *) 0x2, (void *) 0x3};
+ void *out1[] = {(void *) 0x3, (void *) 0x2, (void *) 0x1, (void *) 0x0};
+
+ void *in2[] = {(void *) 0x0, (void *) 0x1, (void *) 0x2, (void *) 0x3, (void *) 0x4};
+ void *out2[] = {(void *) 0x4, (void *) 0x3, (void *) 0x2, (void *) 0x1, (void *) 0x0};
+
+ for (i = 0; i < 4; i++)
+ cl_git_pass(git_vector_insert(&v, in1[i]));
+
+ git_vector_reverse(&v);
+
+ for (i = 0; i < 4; i++)
+ cl_assert_equal_p(out1[i], git_vector_get(&v, i));
+
+ git_vector_clear(&v);
+ for (i = 0; i < 5; i++)
+ cl_git_pass(git_vector_insert(&v, in2[i]));
+
+ git_vector_reverse(&v);
+
+ for (i = 0; i < 5; i++)
+ cl_assert_equal_p(out2[i], git_vector_get(&v, i));
+
+ git_vector_free(&v);
+}
diff --git a/tests/diff/format_email.c b/tests/diff/format_email.c
index 9f8fe3142..c3c04107b 100644
--- a/tests/diff/format_email.c
+++ b/tests/diff/format_email.c
@@ -113,7 +113,7 @@ void test_diff_format_email__with_message(void)
"Also test if new paragraphs are included correctly.\n" \
"---\n" \
" file3.txt | 1 +\n" \
- " 1 file changed, 1 insertion(+), 0 deletions(-)\n" \
+ " 1 file changed, 1 insertion(+)\n" \
"\n" \
"diff --git a/file3.txt b/file3.txt\n" \
"index 9a2d780..7309653 100644\n" \
@@ -156,7 +156,7 @@ void test_diff_format_email__multiple(void)
"---\n" \
" file2.txt | 5 +++++\n" \
" file3.txt | 5 +++++\n" \
- " 2 files changed, 10 insertions(+), 0 deletions(-)\n" \
+ " 2 files changed, 10 insertions(+)\n" \
" create mode 100644 file2.txt\n" \
" create mode 100644 file3.txt\n" \
"\n" \
diff --git a/tests/diff/parse.c b/tests/diff/parse.c
index a06813d1b..acb6eb8a5 100644
--- a/tests/diff/parse.c
+++ b/tests/diff/parse.c
@@ -196,3 +196,74 @@ void test_diff_parse__get_patch_from_diff(void)
cl_git_sandbox_cleanup();
}
+
+static int file_cb(const git_diff_delta *delta, float progress, void *payload)
+{
+ int *called = (int *) payload;
+ GIT_UNUSED(delta);
+ GIT_UNUSED(progress);
+ (*called)++;
+ return 0;
+}
+
+void test_diff_parse__foreach_works_with_parsed_patch(void)
+{
+ const char patch[] =
+ "diff --git a/obj1 b/obj2\n"
+ "index 1234567..7654321 10644\n"
+ "--- a/obj1\n"
+ "+++ b/obj2\n"
+ "@@ -1 +1 @@\n"
+ "-abcde\n"
+ "+12345\n";
+ int called = 0;
+ git_diff *diff;
+
+ cl_git_pass(git_diff_from_buffer(&diff, patch, strlen(patch)));
+ cl_git_pass(git_diff_foreach(diff, file_cb, NULL, NULL, NULL, &called));
+ cl_assert_equal_i(called, 1);
+
+ git_diff_free(diff);
+}
+
+void test_diff_parse__parsing_minimal_patch_succeeds(void)
+{
+ const char patch[] =
+ "diff --git a/obj1 b/obj2\n"
+ "index 1234567..7654321 10644\n"
+ "--- a/obj1\n"
+ "+++ b/obj2\n"
+ "@@ -1 +1 @@\n"
+ "-a\n"
+ "+\n";
+ git_buf buf = GIT_BUF_INIT;
+ git_diff *diff;
+
+ cl_git_pass(git_diff_from_buffer(&diff, patch, strlen(patch)));
+ cl_git_pass(git_diff_to_buf(&buf, diff, GIT_DIFF_FORMAT_PATCH));
+ cl_assert_equal_s(patch, buf.ptr);
+
+ git_diff_free(diff);
+ git_buf_free(&buf);
+}
+
+void test_diff_parse__patch_roundtrip_succeeds(void)
+{
+ const char buf1[] = "a\n", buf2[] = "b\n";
+ git_buf patchbuf = GIT_BUF_INIT, diffbuf = GIT_BUF_INIT;
+ git_patch *patch;
+ git_diff *diff;
+
+ cl_git_pass(git_patch_from_buffers(&patch, buf1, strlen(buf1), "obj1", buf2, strlen(buf2), "obj2", NULL));
+ cl_git_pass(git_patch_to_buf(&patchbuf, patch));
+
+ cl_git_pass(git_diff_from_buffer(&diff, patchbuf.ptr, patchbuf.size));
+ cl_git_pass(git_diff_to_buf(&diffbuf, diff, GIT_DIFF_FORMAT_PATCH));
+
+ cl_assert_equal_s(patchbuf.ptr, diffbuf.ptr);
+
+ git_patch_free(patch);
+ git_diff_free(diff);
+ git_buf_free(&patchbuf);
+ git_buf_free(&diffbuf);
+}
diff --git a/tests/diff/patchid.c b/tests/diff/patchid.c
new file mode 100644
index 000000000..75a2aa814
--- /dev/null
+++ b/tests/diff/patchid.c
@@ -0,0 +1,60 @@
+#include "clar_libgit2.h"
+#include "patch/patch_common.h"
+
+static void verify_patch_id(const char *diff_content, const char *expected_id)
+{
+ git_oid expected_oid, actual_oid;
+ git_diff *diff;
+
+ cl_git_pass(git_oid_fromstr(&expected_oid, expected_id));
+ cl_git_pass(git_diff_from_buffer(&diff, diff_content, strlen(diff_content)));
+ cl_git_pass(git_diff_patchid(&actual_oid, diff, NULL));
+
+ cl_assert_equal_oid(&expected_oid, &actual_oid);
+
+ git_diff_free(diff);
+}
+
+void test_diff_patchid__simple_commit(void)
+{
+ verify_patch_id(PATCH_SIMPLE_COMMIT, "06094b1948b878b7d9ff7560b4eae672a014b0ec");
+}
+
+void test_diff_patchid__filename_with_spaces(void)
+{
+ verify_patch_id(PATCH_APPEND_NO_NL, "f0ba05413beaef743b630e796153839462ee477a");
+}
+
+void test_diff_patchid__multiple_hunks(void)
+{
+ verify_patch_id(PATCH_MULTIPLE_HUNKS, "81e26c34643d17f521e57c483a6a637e18ba1f57");
+}
+
+void test_diff_patchid__multiple_files(void)
+{
+ verify_patch_id(PATCH_MULTIPLE_FILES, "192d1f49d23f2004517963aecd3f8a6c467f50ff");
+}
+
+void test_diff_patchid__same_diff_with_differing_whitespace_has_same_id(void)
+{
+ const char *tabs =
+ "diff --git a/file.txt b/file.txt\n"
+ "index 8fecc09..1d43a92 100644\n"
+ "--- a/file.txt\n"
+ "+++ b/file.txt\n"
+ "@@ -1 +1 @@\n"
+ "-old text\n"
+ "+ new text\n";
+ const char *spaces =
+ "diff --git a/file.txt b/file.txt\n"
+ "index 8fecc09..1d43a92 100644\n"
+ "--- a/file.txt\n"
+ "+++ b/file.txt\n"
+ "@@ -1 +1 @@\n"
+ "-old text\n"
+ "+ new text\n";
+ const char *id = "11efdd13c30f7a1056eac2ae2fb952da475e2c23";
+
+ verify_patch_id(tabs, id);
+ verify_patch_id(spaces, id);
+}
diff --git a/tests/diff/stats.c b/tests/diff/stats.c
index 8f146e2a4..3171a4486 100644
--- a/tests/diff/stats.c
+++ b/tests/diff/stats.c
@@ -114,6 +114,42 @@ void test_diff_stats__shortstat(void)
git_buf_free(&buf);
}
+void test_diff_stats__shortstat_noinsertions(void)
+{
+ git_buf buf = GIT_BUF_INIT;
+ const char *stat =
+ " 1 file changed, 2 deletions(-)\n";
+
+ diff_stats_from_commit_oid(
+ &_stats, "06b7b69a62cbd1e53c6c4e0c3f16473dcfdb4af6", false);
+
+ cl_assert_equal_sz(1, git_diff_stats_files_changed(_stats));
+ cl_assert_equal_sz(0, git_diff_stats_insertions(_stats));
+ cl_assert_equal_sz(2, git_diff_stats_deletions(_stats));
+
+ cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_SHORT, 0));
+ cl_assert_equal_s(stat, git_buf_cstr(&buf));
+ git_buf_free(&buf);
+}
+
+void test_diff_stats__shortstat_nodeletions(void)
+{
+ git_buf buf = GIT_BUF_INIT;
+ const char *stat =
+ " 1 file changed, 3 insertions(+)\n";
+
+ diff_stats_from_commit_oid(
+ &_stats, "5219b9784f9a92d7bd7cb567a6d6a21bfb86697e", false);
+
+ cl_assert_equal_sz(1, git_diff_stats_files_changed(_stats));
+ cl_assert_equal_sz(3, git_diff_stats_insertions(_stats));
+ cl_assert_equal_sz(0, git_diff_stats_deletions(_stats));
+
+ cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_SHORT, 0));
+ cl_assert_equal_s(stat, git_buf_cstr(&buf));
+ git_buf_free(&buf);
+}
+
void test_diff_stats__rename(void)
{
git_buf buf = GIT_BUF_INIT;
diff --git a/tests/fetchhead/nonetwork.c b/tests/fetchhead/nonetwork.c
index 3b750af5e..ea4b70e4a 100644
--- a/tests/fetchhead/nonetwork.c
+++ b/tests/fetchhead/nonetwork.c
@@ -293,7 +293,7 @@ void test_fetchhead_nonetwork__invalid_for_merge(void)
cl_git_rewritefile("./test1/.git/FETCH_HEAD", "49322bb17d3acc9146f98c97d078513228bbf3c0\tinvalid-merge\t\n");
cl_git_fail(git_repository_fetchhead_foreach(g_repo, read_noop, NULL));
- cl_assert(git__prefixcmp(giterr_last()->message, "Invalid for-merge") == 0);
+ cl_assert(git__prefixcmp(giterr_last()->message, "invalid for-merge") == 0);
}
void test_fetchhead_nonetwork__invalid_description(void)
@@ -304,7 +304,7 @@ void test_fetchhead_nonetwork__invalid_description(void)
cl_git_rewritefile("./test1/.git/FETCH_HEAD", "49322bb17d3acc9146f98c97d078513228bbf3c0\tnot-for-merge\n");
cl_git_fail(git_repository_fetchhead_foreach(g_repo, read_noop, NULL));
- cl_assert(git__prefixcmp(giterr_last()->message, "Invalid description") == 0);
+ cl_assert(git__prefixcmp(giterr_last()->message, "invalid description") == 0);
}
static int assert_master_for_merge(const char *ref, const char *url, const git_oid *id, unsigned int is_merge, void *data)
diff --git a/tests/filter/custom.c b/tests/filter/custom.c
index fd1cd271c..799beef62 100644
--- a/tests/filter/custom.c
+++ b/tests/filter/custom.c
@@ -55,6 +55,7 @@ void test_filter_custom__initialize(void)
"hero* bitflip reverse\n"
"herofile text\n"
"heroflip -reverse binary\n"
+ "villain erroneous\n"
"*.bin binary\n");
}
@@ -82,6 +83,11 @@ static void register_custom_filters(void)
create_reverse_filter("+prereverse"),
GIT_FILTER_DRIVER_PRIORITY));
+ cl_git_pass(git_filter_register(
+ "erroneous",
+ create_erroneous_filter("+erroneous"),
+ GIT_FILTER_DRIVER_PRIORITY));
+
filters_registered = 1;
}
}
@@ -235,3 +241,18 @@ void test_filter_custom__filter_registry_failure_cases(void)
cl_git_fail(git_filter_unregister(GIT_FILTER_IDENT));
cl_assert_equal_i(GIT_ENOTFOUND, git_filter_unregister("not-a-filter"));
}
+
+void test_filter_custom__erroneous_filter_fails(void)
+{
+ git_filter_list *filters;
+ git_buf out = GIT_BUF_INIT;
+ git_buf in = GIT_BUF_INIT_CONST(workdir_data, strlen(workdir_data));
+
+ cl_git_pass(git_filter_list_load(
+ &filters, g_repo, NULL, "villain", GIT_FILTER_TO_WORKTREE, 0));
+
+ cl_git_fail(git_filter_list_apply_to_data(&out, filters, &in));
+
+ git_filter_list_free(filters);
+ git_buf_free(&out);
+}
diff --git a/tests/filter/custom_helpers.c b/tests/filter/custom_helpers.c
index 2c80212be..d7f2afe7a 100644
--- a/tests/filter/custom_helpers.c
+++ b/tests/filter/custom_helpers.c
@@ -106,3 +106,36 @@ git_filter *create_reverse_filter(const char *attrs)
return filter;
}
+
+int erroneous_filter_stream(
+ git_writestream **out,
+ git_filter *self,
+ void **payload,
+ const git_filter_source *src,
+ git_writestream *next)
+{
+ GIT_UNUSED(out);
+ GIT_UNUSED(self);
+ GIT_UNUSED(payload);
+ GIT_UNUSED(src);
+ GIT_UNUSED(next);
+ return -1;
+}
+
+static void erroneous_filter_free(git_filter *f)
+{
+ git__free(f);
+}
+
+git_filter *create_erroneous_filter(const char *attrs)
+{
+ git_filter *filter = git__calloc(1, sizeof(git_filter));
+ cl_assert(filter);
+
+ filter->version = GIT_FILTER_VERSION;
+ filter->attributes = attrs;
+ filter->stream = erroneous_filter_stream;
+ filter->shutdown = erroneous_filter_free;
+
+ return filter;
+}
diff --git a/tests/filter/custom_helpers.h b/tests/filter/custom_helpers.h
index 13cfb23ae..537a51da2 100644
--- a/tests/filter/custom_helpers.h
+++ b/tests/filter/custom_helpers.h
@@ -2,6 +2,7 @@
extern git_filter *create_bitflip_filter(void);
extern git_filter *create_reverse_filter(const char *attr);
+extern git_filter *create_erroneous_filter(const char *attr);
extern int bitflip_filter_apply(
git_filter *self,
diff --git a/tests/generate.py b/tests/generate.py
index 587efb519..0a94d4952 100644
--- a/tests/generate.py
+++ b/tests/generate.py
@@ -8,7 +8,7 @@
from __future__ import with_statement
from string import Template
-import re, fnmatch, os, codecs, pickle
+import re, fnmatch, os, sys, codecs, pickle
class Module(object):
class Template(object):
@@ -128,8 +128,9 @@ class Module(object):
class TestSuite(object):
- def __init__(self, path):
+ def __init__(self, path, output):
self.path = path
+ self.output = output
def should_generate(self, path):
if not os.path.isfile(path):
@@ -157,7 +158,7 @@ class TestSuite(object):
return modules
def load_cache(self):
- path = os.path.join(self.path, '.clarcache')
+ path = os.path.join(self.output, '.clarcache')
cache = {}
try:
@@ -170,7 +171,7 @@ class TestSuite(object):
return cache
def save_cache(self):
- path = os.path.join(self.path, '.clarcache')
+ path = os.path.join(self.output, '.clarcache')
with open(path, 'wb') as cache:
pickle.dump(self.modules, cache)
@@ -200,22 +201,24 @@ class TestSuite(object):
return sum(len(module.callbacks) for module in self.modules.values())
def write(self):
- output = os.path.join(self.path, 'clar.suite')
+ output = os.path.join(self.output, 'clar.suite')
if not self.should_generate(output):
return False
with open(output, 'w') as data:
- for module in self.modules.values():
+ modules = sorted(self.modules.values(), key=lambda module: module.name)
+
+ for module in modules:
t = Module.DeclarationTemplate(module)
data.write(t.render())
- for module in self.modules.values():
+ for module in modules:
t = Module.CallbacksTemplate(module)
data.write(t.render())
suites = "static struct clar_suite _clar_suites[] = {" + ','.join(
- Module.InfoTemplate(module).render() for module in sorted(self.modules.values(), key=lambda module: module.name)
+ Module.InfoTemplate(module).render() for module in modules
) + "\n};\n"
data.write(suites)
@@ -232,13 +235,18 @@ if __name__ == '__main__':
parser = OptionParser()
parser.add_option('-f', '--force', action="store_true", dest='force', default=False)
parser.add_option('-x', '--exclude', dest='excluded', action='append', default=[])
+ parser.add_option('-o', '--output', dest='output')
options, args = parser.parse_args()
-
- for path in args or ['.']:
- suite = TestSuite(path)
- suite.load(options.force)
- suite.disable(options.excluded)
- if suite.write():
- print("Written `clar.suite` (%d tests in %d suites)" % (suite.callback_count(), suite.suite_count()))
+ if len(args) > 1:
+ print("More than one path given")
+ sys.exit(1)
+
+ path = args.pop() if args else '.'
+ output = options.output or path
+ suite = TestSuite(path, output)
+ suite.load(options.force)
+ suite.disable(options.excluded)
+ if suite.write():
+ print("Written `clar.suite` (%d tests in %d suites)" % (suite.callback_count(), suite.suite_count()))
diff --git a/tests/index/tests.c b/tests/index/tests.c
index 1498196b2..ea8335b48 100644
--- a/tests/index/tests.c
+++ b/tests/index/tests.c
@@ -856,11 +856,14 @@ void test_index_tests__change_icase_on_instance(void)
void test_index_tests__can_lock_index(void)
{
+ git_repository *repo;
git_index *index;
git_indexwriter one = GIT_INDEXWRITER_INIT,
two = GIT_INDEXWRITER_INIT;
- cl_git_pass(git_index_open(&index, TEST_INDEX_PATH));
+ repo = cl_git_sandbox_init("testrepo.git");
+
+ cl_git_pass(git_repository_index(&index, repo));
cl_git_pass(git_indexwriter_init(&one, index));
cl_git_fail_with(GIT_ELOCKED, git_indexwriter_init(&two, index));
@@ -873,4 +876,5 @@ void test_index_tests__can_lock_index(void)
git_indexwriter_cleanup(&one);
git_indexwriter_cleanup(&two);
git_index_free(index);
+ cl_git_sandbox_cleanup();
}
diff --git a/tests/index/version.c b/tests/index/version.c
index 3fd240d3c..7ada302b5 100644
--- a/tests/index/version.c
+++ b/tests/index/version.c
@@ -3,39 +3,135 @@
static git_repository *g_repo = NULL;
-void test_index_version__can_write_v4(void)
+void test_index_version__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+ g_repo = NULL;
+}
+
+void test_index_version__can_read_v4(void)
{
+ const char *paths[] = {
+ "file.tx", "file.txt", "file.txz", "foo", "zzz",
+ };
git_index *index;
- const git_index_entry *entry;
+ size_t i;
+
+ g_repo = cl_git_sandbox_init("indexv4");
- g_repo = cl_git_sandbox_init("filemodes");
cl_git_pass(git_repository_index(&index, g_repo));
+ cl_assert_equal_sz(git_index_entrycount(index), 5);
- cl_assert(index->on_disk);
- cl_assert(git_index_version(index) == 2);
+ for (i = 0; i < ARRAY_SIZE(paths); i++) {
+ const git_index_entry *entry =
+ git_index_get_bypath(index, paths[i], GIT_INDEX_STAGE_NORMAL);
- cl_assert(git_index_entrycount(index) == 6);
+ cl_assert(entry != NULL);
+ }
+ git_index_free(index);
+}
+
+void test_index_version__can_write_v4(void)
+{
+ const char *paths[] = {
+ "foo",
+ "foox",
+ "foobar",
+ "foobal",
+ "x",
+ "xz",
+ "xyzzyx"
+ };
+ git_index_entry entry;
+ git_index *index;
+ size_t i;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+ cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(git_index_set_version(index, 4));
+ for (i = 0; i < ARRAY_SIZE(paths); i++) {
+ memset(&entry, 0, sizeof(entry));
+ entry.path = paths[i];
+ entry.mode = GIT_FILEMODE_BLOB;
+ cl_git_pass(git_index_add_frombuffer(index, &entry, paths[i],
+ strlen(paths[i]) + 1));
+ }
+ cl_assert_equal_sz(git_index_entrycount(index), ARRAY_SIZE(paths));
+
cl_git_pass(git_index_write(index));
git_index_free(index);
cl_git_pass(git_repository_index(&index, g_repo));
cl_assert(git_index_version(index) == 4);
- entry = git_index_get_bypath(index, "exec_off", 0);
- cl_assert(entry);
- entry = git_index_get_bypath(index, "exec_off2on_staged", 0);
- cl_assert(entry);
- entry = git_index_get_bypath(index, "exec_on", 0);
- cl_assert(entry);
+ for (i = 0; i < ARRAY_SIZE(paths); i++) {
+ const git_index_entry *e;
+
+ cl_assert(e = git_index_get_bypath(index, paths[i], 0));
+ cl_assert_equal_s(paths[i], e->path);
+ }
git_index_free(index);
}
-void test_index_version__cleanup(void)
+void test_index_version__v4_uses_path_compression(void)
{
- cl_git_sandbox_cleanup();
- g_repo = NULL;
+ git_index_entry entry;
+ git_index *index;
+ char path[250], buf[1];
+ struct stat st;
+ char i, j;
+
+ memset(path, 'a', sizeof(path));
+ memset(buf, 'a', sizeof(buf));
+
+ memset(&entry, 0, sizeof(entry));
+ entry.path = path;
+ entry.mode = GIT_FILEMODE_BLOB;
+
+ g_repo = cl_git_sandbox_init("indexv4");
+ cl_git_pass(git_repository_index(&index, g_repo));
+
+ /* write 676 paths of 250 bytes length */
+ for (i = 'a'; i <= 'z'; i++) {
+ for (j = 'a'; j < 'z'; j++) {
+ path[ARRAY_SIZE(path) - 3] = i;
+ path[ARRAY_SIZE(path) - 2] = j;
+ path[ARRAY_SIZE(path) - 1] = '\0';
+ cl_git_pass(git_index_add_frombuffer(index, &entry, buf, sizeof(buf)));
+ }
+ }
+
+ cl_git_pass(git_index_write(index));
+ cl_git_pass(p_stat(git_index_path(index), &st));
+
+ /*
+ * Without path compression, the written paths would at
+ * least take
+ *
+ * (entries * pathlen) = len
+ * (676 * 250) = 169000
+ *
+ * bytes. As index v4 uses suffix-compression and our
+ * written paths only differ in the last two entries,
+ * this number will be much smaller, e.g.
+ *
+ * (1 * pathlen) + (675 * 2) = len
+ * 676 + 1350 = 2026
+ *
+ * bytes.
+ *
+ * Note that the above calculations do not include
+ * additional metadata of the index, e.g. OIDs or
+ * index extensions. Including those we get an index
+ * of approx. 200kB without compression and 40kB with
+ * compression. As this is a lot smaller than without
+ * compression, we can verify that path compression is
+ * used.
+ */
+ cl_assert_(st.st_size < 75000, "path compression not enabled");
+
+ git_index_free(index);
}
diff --git a/tests/iterator/workdir.c b/tests/iterator/workdir.c
index 28fcc0d23..f33fd98f1 100644
--- a/tests/iterator/workdir.c
+++ b/tests/iterator/workdir.c
@@ -613,9 +613,11 @@ void test_iterator_workdir__filesystem2(void)
"heads/ident",
"heads/long-file-name",
"heads/master",
+ "heads/merge-conflict",
"heads/packed-test",
"heads/subtrees",
"heads/test",
+ "heads/testrepo-worktree",
"tags/e90810b",
"tags/foo/bar",
"tags/foo/foo/bar",
@@ -628,7 +630,7 @@ void test_iterator_workdir__filesystem2(void)
cl_git_pass(git_iterator_for_filesystem(
&i, "testrepo/.git/refs", NULL));
- expect_iterator_items(i, 13, expect_base, 13, expect_base);
+ expect_iterator_items(i, 15, expect_base, 15, expect_base);
git_iterator_free(i);
}
diff --git a/tests/merge/trees/renames.c b/tests/merge/trees/renames.c
index d7721c894..853bf2fa0 100644
--- a/tests/merge/trees/renames.c
+++ b/tests/merge/trees/renames.c
@@ -242,6 +242,8 @@ void test_merge_trees_renames__no_rename_index(void)
{ 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 3, "7-both-renamed.txt" },
};
+ opts.flags &= ~GIT_MERGE_FIND_RENAMES;
+
cl_git_pass(merge_trees_from_branches(&index, repo,
BRANCH_RENAME_OURS, BRANCH_RENAME_THEIRS,
&opts));
@@ -250,3 +252,25 @@ void test_merge_trees_renames__no_rename_index(void)
git_index_free(index);
}
+
+void test_merge_trees_renames__submodules(void)
+{
+ git_index *index;
+ git_merge_options *opts = NULL;
+
+ struct merge_index_entry merge_index_entries[] = {
+ { 0100644, "cd3e8d4aa06bdc781f264171030bc28f2b370fee", 0, ".gitmodules" },
+ { 0100644, "4dd1ef7569b18d92d93c0a35bb6b93049137b355", 1, "file.txt" },
+ { 0100644, "a2d8d1824c68541cca94ffb90f79291eba495921", 2, "file.txt" },
+ { 0100644, "63ec604d491161ddafdae4179843c26d54bd999a", 3, "file.txt" },
+ { 0160000, "0000000000000000000000000000000000000001", 1, "submodule1" },
+ { 0160000, "0000000000000000000000000000000000000002", 3, "submodule1" },
+ { 0160000, "0000000000000000000000000000000000000003", 0, "submodule2" },
+ };
+
+ cl_git_pass(merge_trees_from_branches(&index, repo,
+ "submodule_rename1", "submodule_rename2",
+ opts));
+ cl_assert(merge_test_index(index, merge_index_entries, 7));
+ git_index_free(index);
+}
diff --git a/tests/network/remote/local.c b/tests/network/remote/local.c
index 6194802af..76872e51f 100644
--- a/tests/network/remote/local.c
+++ b/tests/network/remote/local.c
@@ -2,6 +2,7 @@
#include "buffer.h"
#include "path.h"
#include "posix.h"
+#include "git2/sys/repository.h"
static git_repository *repo;
static git_buf file_path_buf = GIT_BUF_INIT;
@@ -465,3 +466,19 @@ void test_network_remote_local__push_delete(void)
cl_fixture_cleanup("target.git");
cl_git_sandbox_cleanup();
}
+
+void test_network_remote_local__anonymous_remote_inmemory_repo(void)
+{
+ git_repository *inmemory;
+ git_remote *remote;
+
+ git_buf_sets(&file_path_buf, cl_git_path_url(cl_fixture("testrepo.git")));
+
+ cl_git_pass(git_repository_new(&inmemory));
+ cl_git_pass(git_remote_create_anonymous(&remote, inmemory, git_buf_cstr(&file_path_buf)));
+ cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL));
+ cl_assert(git_remote_connected(remote));
+ git_remote_disconnect(remote);
+ git_remote_free(remote);
+ git_repository_free(inmemory);
+}
diff --git a/tests/object/lookup.c b/tests/object/lookup.c
index cfa6d4678..544f32bc4 100644
--- a/tests/object/lookup.c
+++ b/tests/object/lookup.c
@@ -6,13 +6,12 @@ static git_repository *g_repo;
void test_object_lookup__initialize(void)
{
- cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git")));
+ g_repo = cl_git_sandbox_init("testrepo.git");
}
void test_object_lookup__cleanup(void)
{
- git_repository_free(g_repo);
- g_repo = NULL;
+ cl_git_sandbox_cleanup();
}
void test_object_lookup__lookup_wrong_type_returns_enotfound(void)
@@ -63,3 +62,61 @@ void test_object_lookup__lookup_wrong_type_eventually_returns_enotfound(void)
GIT_ENOTFOUND, git_object_lookup(&object, g_repo, &oid, GIT_OBJ_TAG));
}
+void test_object_lookup__lookup_corrupt_object_returns_error(void)
+{
+ const char *commit = "8e73b769e97678d684b809b163bebdae2911720f",
+ *file = "objects/8e/73b769e97678d684b809b163bebdae2911720f";
+ git_buf path = GIT_BUF_INIT, contents = GIT_BUF_INIT;
+ git_oid oid;
+ git_object *object;
+ size_t i;
+
+ cl_git_pass(git_oid_fromstr(&oid, commit));
+ cl_git_pass(git_buf_joinpath(&path, git_repository_path(g_repo), file));
+ cl_git_pass(git_futils_readbuffer(&contents, path.ptr));
+
+ /* Corrupt and try to read the object */
+ for (i = 0; i < contents.size; i++) {
+ contents.ptr[i] ^= 0x1;
+ cl_git_pass(git_futils_writebuffer(&contents, path.ptr, O_RDWR, 0644));
+ cl_git_fail(git_object_lookup(&object, g_repo, &oid, GIT_OBJ_COMMIT));
+ contents.ptr[i] ^= 0x1;
+ }
+
+ /* Restore original content and assert we can read the object */
+ cl_git_pass(git_futils_writebuffer(&contents, path.ptr, O_RDWR, 0644));
+ cl_git_pass(git_object_lookup(&object, g_repo, &oid, GIT_OBJ_COMMIT));
+
+ git_object_free(object);
+ git_buf_free(&path);
+ git_buf_free(&contents);
+}
+
+void test_object_lookup__lookup_object_with_wrong_hash_returns_error(void)
+{
+ const char *oldloose = "objects/8e/73b769e97678d684b809b163bebdae2911720f",
+ *newloose = "objects/8e/73b769e97678d684b809b163bebdae2911720e",
+ *commit = "8e73b769e97678d684b809b163bebdae2911720e";
+ git_buf oldpath = GIT_BUF_INIT, newpath = GIT_BUF_INIT;
+ git_object *object;
+ git_oid oid;
+
+ cl_git_pass(git_oid_fromstr(&oid, commit));
+
+ /* Copy object to another location with wrong hash */
+ cl_git_pass(git_buf_joinpath(&oldpath, git_repository_path(g_repo), oldloose));
+ cl_git_pass(git_buf_joinpath(&newpath, git_repository_path(g_repo), newloose));
+ cl_git_pass(git_futils_cp(oldpath.ptr, newpath.ptr, 0644));
+
+ /* Verify that lookup fails due to a hashsum mismatch */
+ cl_git_fail_with(GIT_EMISMATCH, git_object_lookup(&object, g_repo, &oid, GIT_OBJ_COMMIT));
+
+ /* Disable verification and try again */
+ cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0));
+ cl_git_pass(git_object_lookup(&object, g_repo, &oid, GIT_OBJ_COMMIT));
+ cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 1));
+
+ git_object_free(object);
+ git_buf_free(&oldpath);
+ git_buf_free(&newpath);
+}
diff --git a/tests/object/tree/update.c b/tests/object/tree/update.c
index 54c4335f5..b76e8612a 100644
--- a/tests/object/tree/update.c
+++ b/tests/object/tree/update.c
@@ -196,6 +196,63 @@ void test_object_tree_update__add_blobs(void)
git_tree_free(base_tree);
}
+void test_object_tree_update__add_blobs_unsorted(void)
+{
+ git_oid tree_index_id, tree_updater_id, base_id;
+ git_tree *base_tree;
+ git_index *idx;
+ git_index_entry entry = { {0} };
+ int i;
+ const char *paths[] = {
+ "some/deep/path",
+ "a/path/elsewhere",
+ "some/other/path",
+ };
+
+ git_tree_update updates[] = {
+ { GIT_TREE_UPDATE_UPSERT, {{0}}, GIT_FILEMODE_BLOB, paths[0]},
+ { GIT_TREE_UPDATE_UPSERT, {{0}}, GIT_FILEMODE_BLOB, paths[1]},
+ { GIT_TREE_UPDATE_UPSERT, {{0}}, GIT_FILEMODE_BLOB, paths[2]},
+ };
+
+ cl_git_pass(git_oid_fromstr(&base_id, "c4dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b"));
+
+ entry.mode = GIT_FILEMODE_BLOB;
+ cl_git_pass(git_oid_fromstr(&entry.id, "fa49b077972391ad58037050f2a75f74e3671e92"));
+
+ for (i = 0; i < 3; i++) {
+ cl_git_pass(git_oid_fromstr(&updates[i].id, "fa49b077972391ad58037050f2a75f74e3671e92"));
+ }
+
+ for (i = 0; i < 2; i++) {
+ int j;
+
+ /* Create it with an index */
+ cl_git_pass(git_index_new(&idx));
+
+ base_tree = NULL;
+ if (i == 1) {
+ cl_git_pass(git_tree_lookup(&base_tree, g_repo, &base_id));
+ cl_git_pass(git_index_read_tree(idx, base_tree));
+ }
+
+ for (j = 0; j < 3; j++) {
+ entry.path = paths[j];
+ cl_git_pass(git_index_add(idx, &entry));
+ }
+
+ cl_git_pass(git_index_write_tree_to(&tree_index_id, idx, g_repo));
+ git_index_free(idx);
+
+ /* Perform the same operations via the tree updater */
+ cl_git_pass(git_tree_create_updated(&tree_updater_id, g_repo, base_tree, 3, updates));
+
+ cl_assert_equal_oid(&tree_index_id, &tree_updater_id);
+ }
+
+ git_tree_free(base_tree);
+}
+
void test_object_tree_update__add_conflict(void)
{
int i;
diff --git a/tests/odb/backend/backend_helpers.c b/tests/odb/backend/backend_helpers.c
new file mode 100644
index 000000000..37a8fd200
--- /dev/null
+++ b/tests/odb/backend/backend_helpers.c
@@ -0,0 +1,159 @@
+#include "clar_libgit2.h"
+#include "git2/sys/odb_backend.h"
+#include "backend_helpers.h"
+
+static int search_object(const fake_object **out, fake_backend *fake, const git_oid *oid, size_t len)
+{
+ const fake_object *obj = fake->objects, *found = NULL;
+
+ while (obj && obj->oid) {
+ git_oid current_oid;
+
+ git_oid_fromstr(&current_oid, obj->oid);
+
+ if (git_oid_ncmp(&current_oid, oid, len) == 0) {
+ if (found)
+ return GIT_EAMBIGUOUS;
+ found = obj;
+ }
+
+ obj++;
+ }
+
+ if (found && out)
+ *out = found;
+
+ return found ? GIT_OK : GIT_ENOTFOUND;
+}
+
+static int fake_backend__exists(git_odb_backend *backend, const git_oid *oid)
+{
+ fake_backend *fake;
+
+ fake = (fake_backend *)backend;
+
+ fake->exists_calls++;
+
+ return search_object(NULL, fake, oid, GIT_OID_HEXSZ) == GIT_OK;
+}
+
+static int fake_backend__exists_prefix(
+ git_oid *out, git_odb_backend *backend, const git_oid *oid, size_t len)
+{
+ const fake_object *obj;
+ fake_backend *fake;
+ int error;
+
+ fake = (fake_backend *)backend;
+
+ fake->exists_prefix_calls++;
+
+ if ((error = search_object(&obj, fake, oid, len)) < 0)
+ return error;
+
+ if (out)
+ git_oid_fromstr(out, obj->oid);
+
+ return 0;
+}
+
+static int fake_backend__read(
+ void **buffer_p, size_t *len_p, git_otype *type_p,
+ git_odb_backend *backend, const git_oid *oid)
+{
+ const fake_object *obj;
+ fake_backend *fake;
+ int error;
+
+ fake = (fake_backend *)backend;
+
+ fake->read_calls++;
+
+ if ((error = search_object(&obj, fake, oid, GIT_OID_HEXSZ)) < 0)
+ return error;
+
+ *len_p = strlen(obj->content);
+ *buffer_p = git__strdup(obj->content);
+ *type_p = GIT_OBJ_BLOB;
+
+ return 0;
+}
+
+static int fake_backend__read_header(
+ size_t *len_p, git_otype *type_p,
+ git_odb_backend *backend, const git_oid *oid)
+{
+ const fake_object *obj;
+ fake_backend *fake;
+ int error;
+
+ fake = (fake_backend *)backend;
+
+ fake->read_header_calls++;
+
+ if ((error = search_object(&obj, fake, oid, GIT_OID_HEXSZ)) < 0)
+ return error;
+
+ *len_p = strlen(obj->content);
+ *type_p = GIT_OBJ_BLOB;
+
+ return 0;
+}
+
+static int fake_backend__read_prefix(
+ git_oid *out_oid, void **buffer_p, size_t *len_p, git_otype *type_p,
+ git_odb_backend *backend, const git_oid *short_oid, size_t len)
+{
+ const fake_object *obj;
+ fake_backend *fake;
+ int error;
+
+ fake = (fake_backend *)backend;
+
+ fake->read_prefix_calls++;
+
+ if ((error = search_object(&obj, fake, short_oid, len)) < 0)
+ return error;
+
+ git_oid_fromstr(out_oid, obj->oid);
+ *len_p = strlen(obj->content);
+ *buffer_p = git__strdup(obj->content);
+ *type_p = GIT_OBJ_BLOB;
+
+ return 0;
+}
+
+static void fake_backend__free(git_odb_backend *_backend)
+{
+ fake_backend *backend;
+
+ backend = (fake_backend *)_backend;
+
+ git__free(backend);
+}
+
+int build_fake_backend(
+ git_odb_backend **out,
+ const fake_object *objects)
+{
+ fake_backend *backend;
+
+ backend = git__calloc(1, sizeof(fake_backend));
+ GITERR_CHECK_ALLOC(backend);
+
+ backend->parent.version = GIT_ODB_BACKEND_VERSION;
+
+ backend->parent.refresh = NULL;
+ backend->objects = objects;
+
+ backend->parent.read = fake_backend__read;
+ backend->parent.read_prefix = fake_backend__read_prefix;
+ backend->parent.read_header = fake_backend__read_header;
+ backend->parent.exists = fake_backend__exists;
+ backend->parent.exists_prefix = fake_backend__exists_prefix;
+ backend->parent.free = &fake_backend__free;
+
+ *out = (git_odb_backend *)backend;
+
+ return 0;
+}
diff --git a/tests/odb/backend/backend_helpers.h b/tests/odb/backend/backend_helpers.h
new file mode 100644
index 000000000..5c393c0a5
--- /dev/null
+++ b/tests/odb/backend/backend_helpers.h
@@ -0,0 +1,22 @@
+#include "git2/sys/odb_backend.h"
+
+typedef struct {
+ const char *oid;
+ const char *content;
+} fake_object;
+
+typedef struct {
+ git_odb_backend parent;
+
+ int exists_calls;
+ int exists_prefix_calls;
+ int read_calls;
+ int read_header_calls;
+ int read_prefix_calls;
+
+ const fake_object *objects;
+} fake_backend;
+
+int build_fake_backend(
+ git_odb_backend **out,
+ const fake_object *objects);
diff --git a/tests/odb/backend/multiple.c b/tests/odb/backend/multiple.c
new file mode 100644
index 000000000..1c6068df3
--- /dev/null
+++ b/tests/odb/backend/multiple.c
@@ -0,0 +1,121 @@
+#include "clar_libgit2.h"
+#include "repository.h"
+#include "backend_helpers.h"
+
+#define EXISTING_HASH "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
+
+static git_repository *_repo;
+static git_odb_object *_obj;
+static fake_backend *_fake_empty;
+static fake_backend *_fake_filled;
+
+static git_oid _existing_oid;
+
+static const fake_object _objects_filled[] = {
+ { EXISTING_HASH, "" },
+ { NULL, NULL }
+};
+
+static const fake_object _objects_empty[] = {
+ { NULL, NULL }
+};
+
+void test_odb_backend_multiple__initialize(void)
+{
+ git_odb_backend *backend;
+
+ git_oid_fromstr(&_existing_oid, EXISTING_HASH);
+
+ _obj = NULL;
+ _repo = cl_git_sandbox_init("testrepo.git");
+
+ cl_git_pass(build_fake_backend(&backend, _objects_filled));
+ _fake_filled = (fake_backend *)backend;
+
+ cl_git_pass(build_fake_backend(&backend, _objects_empty));
+ _fake_empty = (fake_backend *)backend;
+}
+
+void test_odb_backend_multiple__cleanup(void)
+{
+ git_odb_object_free(_obj);
+ cl_git_sandbox_cleanup();
+}
+
+void test_odb_backend_multiple__read_with_empty_first_succeeds(void)
+{
+ git_odb *odb;
+
+ cl_git_pass(git_repository_odb__weakptr(&odb, _repo));
+ cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_filled, 10));
+ cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_empty, 50));
+
+ cl_git_pass(git_odb_read(&_obj, odb, &_existing_oid));
+
+ cl_assert_equal_i(1, _fake_filled->read_calls);
+ cl_assert_equal_i(1, _fake_empty->read_calls);
+}
+
+void test_odb_backend_multiple__read_with_first_matching_stops(void)
+{
+ git_odb *odb;
+
+ cl_git_pass(git_repository_odb__weakptr(&odb, _repo));
+ cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_empty, 10));
+ cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_filled, 50));
+
+ cl_git_pass(git_odb_read(&_obj, odb, &_existing_oid));
+
+ cl_assert_equal_i(1, _fake_filled->read_calls);
+ cl_assert_equal_i(0, _fake_empty->read_calls);
+}
+
+void test_odb_backend_multiple__read_prefix_with_first_empty_succeeds(void)
+{
+ git_odb *odb;
+
+ cl_git_pass(git_repository_odb__weakptr(&odb, _repo));
+ cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_filled, 10));
+ cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_empty, 50));
+
+ cl_git_pass(git_odb_read_prefix(&_obj, odb, &_existing_oid, 7));
+
+ cl_assert_equal_i(1, _fake_filled->read_prefix_calls);
+ cl_assert_equal_i(1, _fake_empty->read_prefix_calls);
+}
+
+void test_odb_backend_multiple__read_prefix_with_first_matching_reads_both(void)
+{
+ git_odb *odb;
+
+ cl_git_pass(git_repository_odb__weakptr(&odb, _repo));
+ cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_empty, -10));
+ cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_filled, 50));
+
+ cl_git_pass(git_odb_read_prefix(&_obj, odb, &_existing_oid, 7));
+
+ cl_assert_equal_i(1, _fake_filled->read_prefix_calls);
+ cl_assert_equal_i(1, _fake_empty->read_prefix_calls);
+}
+
+void test_odb_backend_multiple__read_prefix_with_first_matching_succeeds_without_hash_verification(void)
+{
+ git_odb *odb;
+
+ git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0);
+
+ cl_git_pass(git_repository_odb__weakptr(&odb, _repo));
+ cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_empty, -10));
+ cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_filled, 50));
+
+ cl_git_pass(git_odb_read_prefix(&_obj, odb, &_existing_oid, 7));
+
+ /*
+ * Both backends should be checked as we have to check
+ * for collisions
+ */
+ cl_assert_equal_i(1, _fake_filled->read_prefix_calls);
+ cl_assert_equal_i(1, _fake_empty->read_prefix_calls);
+
+ git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 1);
+}
diff --git a/tests/odb/backend/nobackend.c b/tests/odb/backend/nobackend.c
index 783641e8f..3c4f344b1 100644
--- a/tests/odb/backend/nobackend.c
+++ b/tests/odb/backend/nobackend.c
@@ -40,7 +40,7 @@ void test_odb_backend_nobackend__write_fails_gracefully(void)
cl_git_fail(git_odb_write(&id, odb, "Hello world!\n", 13, GIT_OBJ_BLOB));
err = giterr_last();
- cl_assert_equal_s(err->message, "Cannot write object - unsupported in the loaded odb backends");
+ cl_assert_equal_s(err->message, "cannot write object - unsupported in the loaded odb backends");
git_odb_free(odb);
}
diff --git a/tests/odb/backend/nonrefreshing.c b/tests/odb/backend/nonrefreshing.c
index b43529479..6abc0c6d2 100644
--- a/tests/odb/backend/nonrefreshing.c
+++ b/tests/odb/backend/nonrefreshing.c
@@ -1,150 +1,41 @@
#include "clar_libgit2.h"
-#include "git2/sys/odb_backend.h"
#include "repository.h"
-
-typedef struct fake_backend {
- git_odb_backend parent;
-
- git_error_code error_code;
-
- int exists_calls;
- int read_calls;
- int read_header_calls;
- int read_prefix_calls;
-} fake_backend;
+#include "backend_helpers.h"
static git_repository *_repo;
static fake_backend *_fake;
-static git_oid _oid;
-
-static int fake_backend__exists(git_odb_backend *backend, const git_oid *oid)
-{
- fake_backend *fake;
-
- GIT_UNUSED(oid);
-
- fake = (fake_backend *)backend;
-
- fake->exists_calls++;
-
- return (fake->error_code == GIT_OK);
-}
-
-static int fake_backend__read(
- void **buffer_p, size_t *len_p, git_otype *type_p,
- git_odb_backend *backend, const git_oid *oid)
-{
- fake_backend *fake;
-
- GIT_UNUSED(buffer_p);
- GIT_UNUSED(len_p);
- GIT_UNUSED(type_p);
- GIT_UNUSED(oid);
-
- fake = (fake_backend *)backend;
-
- fake->read_calls++;
-
- *len_p = 0;
- *buffer_p = NULL;
- *type_p = GIT_OBJ_BLOB;
-
- return fake->error_code;
-}
-
-static int fake_backend__read_header(
- size_t *len_p, git_otype *type_p,
- git_odb_backend *backend, const git_oid *oid)
-{
- fake_backend *fake;
-
- GIT_UNUSED(len_p);
- GIT_UNUSED(type_p);
- GIT_UNUSED(oid);
-
- fake = (fake_backend *)backend;
-
- fake->read_header_calls++;
-
- *len_p = 0;
- *type_p = GIT_OBJ_BLOB;
-
- return fake->error_code;
-}
-
-static int fake_backend__read_prefix(
- git_oid *out_oid, void **buffer_p, size_t *len_p, git_otype *type_p,
- git_odb_backend *backend, const git_oid *short_oid, size_t len)
-{
- fake_backend *fake;
- GIT_UNUSED(out_oid);
- GIT_UNUSED(buffer_p);
- GIT_UNUSED(len_p);
- GIT_UNUSED(type_p);
- GIT_UNUSED(short_oid);
- GIT_UNUSED(len);
+#define NONEXISTING_HASH "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
+#define EXISTING_HASH "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
- fake = (fake_backend *)backend;
+static const fake_object _objects[] = {
+ { EXISTING_HASH, "" },
+ { NULL, NULL }
+};
- fake->read_prefix_calls++;
+static git_oid _nonexisting_oid;
+static git_oid _existing_oid;
- *len_p = 0;
- *buffer_p = NULL;
- *type_p = GIT_OBJ_BLOB;
-
- return fake->error_code;
-}
-
-static void fake_backend__free(git_odb_backend *_backend)
-{
- fake_backend *backend;
-
- backend = (fake_backend *)_backend;
-
- git__free(backend);
-}
-
-static int build_fake_backend(
- git_odb_backend **out,
- git_error_code error_code)
-{
- fake_backend *backend;
-
- backend = git__calloc(1, sizeof(fake_backend));
- GITERR_CHECK_ALLOC(backend);
-
- backend->parent.version = GIT_ODB_BACKEND_VERSION;
-
- backend->parent.refresh = NULL;
- backend->error_code = error_code;
-
- backend->parent.read = fake_backend__read;
- backend->parent.read_prefix = fake_backend__read_prefix;
- backend->parent.read_header = fake_backend__read_header;
- backend->parent.exists = fake_backend__exists;
- backend->parent.free = &fake_backend__free;
-
- *out = (git_odb_backend *)backend;
-
- return 0;
-}
-
-static void setup_repository_and_backend(git_error_code error_code)
+static void setup_repository_and_backend(void)
{
git_odb *odb = NULL;
git_odb_backend *backend = NULL;
_repo = cl_git_sandbox_init("testrepo.git");
- cl_git_pass(build_fake_backend(&backend, error_code));
+ cl_git_pass(build_fake_backend(&backend, _objects));
cl_git_pass(git_repository_odb__weakptr(&odb, _repo));
cl_git_pass(git_odb_add_backend(odb, backend, 10));
_fake = (fake_backend *)backend;
+}
- cl_git_pass(git_oid_fromstr(&_oid, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"));
+void test_odb_backend_nonrefreshing__initialize(void)
+{
+ git_oid_fromstr(&_nonexisting_oid, NONEXISTING_HASH);
+ git_oid_fromstr(&_existing_oid, EXISTING_HASH);
+ setup_repository_and_backend();
}
void test_odb_backend_nonrefreshing__cleanup(void)
@@ -156,10 +47,8 @@ void test_odb_backend_nonrefreshing__exists_is_invoked_once_on_failure(void)
{
git_odb *odb;
- setup_repository_and_backend(GIT_ENOTFOUND);
-
cl_git_pass(git_repository_odb__weakptr(&odb, _repo));
- cl_assert_equal_b(false, git_odb_exists(odb, &_oid));
+ cl_assert_equal_b(false, git_odb_exists(odb, &_nonexisting_oid));
cl_assert_equal_i(1, _fake->exists_calls);
}
@@ -168,10 +57,8 @@ void test_odb_backend_nonrefreshing__read_is_invoked_once_on_failure(void)
{
git_object *obj;
- setup_repository_and_backend(GIT_ENOTFOUND);
-
cl_git_fail_with(
- git_object_lookup(&obj, _repo, &_oid, GIT_OBJ_ANY),
+ git_object_lookup(&obj, _repo, &_nonexisting_oid, GIT_OBJ_ANY),
GIT_ENOTFOUND);
cl_assert_equal_i(1, _fake->read_calls);
@@ -181,10 +68,8 @@ void test_odb_backend_nonrefreshing__readprefix_is_invoked_once_on_failure(void)
{
git_object *obj;
- setup_repository_and_backend(GIT_ENOTFOUND);
-
cl_git_fail_with(
- git_object_lookup_prefix(&obj, _repo, &_oid, 7, GIT_OBJ_ANY),
+ git_object_lookup_prefix(&obj, _repo, &_nonexisting_oid, 7, GIT_OBJ_ANY),
GIT_ENOTFOUND);
cl_assert_equal_i(1, _fake->read_prefix_calls);
@@ -196,12 +81,10 @@ void test_odb_backend_nonrefreshing__readheader_is_invoked_once_on_failure(void)
size_t len;
git_otype type;
- setup_repository_and_backend(GIT_ENOTFOUND);
-
cl_git_pass(git_repository_odb__weakptr(&odb, _repo));
cl_git_fail_with(
- git_odb_read_header(&len, &type, odb, &_oid),
+ git_odb_read_header(&len, &type, odb, &_nonexisting_oid),
GIT_ENOTFOUND);
cl_assert_equal_i(1, _fake->read_header_calls);
@@ -211,10 +94,8 @@ void test_odb_backend_nonrefreshing__exists_is_invoked_once_on_success(void)
{
git_odb *odb;
- setup_repository_and_backend(GIT_OK);
-
cl_git_pass(git_repository_odb__weakptr(&odb, _repo));
- cl_assert_equal_b(true, git_odb_exists(odb, &_oid));
+ cl_assert_equal_b(true, git_odb_exists(odb, &_existing_oid));
cl_assert_equal_i(1, _fake->exists_calls);
}
@@ -223,9 +104,7 @@ void test_odb_backend_nonrefreshing__read_is_invoked_once_on_success(void)
{
git_object *obj;
- setup_repository_and_backend(GIT_OK);
-
- cl_git_pass(git_object_lookup(&obj, _repo, &_oid, GIT_OBJ_ANY));
+ cl_git_pass(git_object_lookup(&obj, _repo, &_existing_oid, GIT_OBJ_ANY));
cl_assert_equal_i(1, _fake->read_calls);
@@ -236,9 +115,7 @@ void test_odb_backend_nonrefreshing__readprefix_is_invoked_once_on_success(void)
{
git_object *obj;
- setup_repository_and_backend(GIT_OK);
-
- cl_git_pass(git_object_lookup_prefix(&obj, _repo, &_oid, 7, GIT_OBJ_ANY));
+ cl_git_pass(git_object_lookup_prefix(&obj, _repo, &_existing_oid, 7, GIT_OBJ_ANY));
cl_assert_equal_i(1, _fake->read_prefix_calls);
@@ -251,11 +128,9 @@ void test_odb_backend_nonrefreshing__readheader_is_invoked_once_on_success(void)
size_t len;
git_otype type;
- setup_repository_and_backend(GIT_OK);
-
cl_git_pass(git_repository_odb__weakptr(&odb, _repo));
- cl_git_pass(git_odb_read_header(&len, &type, odb, &_oid));
+ cl_git_pass(git_odb_read_header(&len, &type, odb, &_existing_oid));
cl_assert_equal_i(1, _fake->read_header_calls);
}
@@ -264,8 +139,6 @@ void test_odb_backend_nonrefreshing__read_is_invoked_once_when_revparsing_a_full
{
git_object *obj;
- setup_repository_and_backend(GIT_ENOTFOUND);
-
cl_git_fail_with(
git_revparse_single(&obj, _repo, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"),
GIT_ENOTFOUND);
diff --git a/tests/odb/backend/simple.c b/tests/odb/backend/simple.c
new file mode 100644
index 000000000..c0fcd403b
--- /dev/null
+++ b/tests/odb/backend/simple.c
@@ -0,0 +1,232 @@
+#include "clar_libgit2.h"
+#include "repository.h"
+#include "backend_helpers.h"
+
+#define EMPTY_HASH "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
+
+static git_repository *_repo;
+static git_odb *_odb;
+static git_odb_object *_obj;
+static git_oid _oid;
+
+static void setup_backend(const fake_object *objs)
+{
+ git_odb_backend *backend;
+
+ cl_git_pass(build_fake_backend(&backend, objs));
+
+ cl_git_pass(git_repository_odb__weakptr(&_odb, _repo));
+ cl_git_pass(git_odb_add_backend(_odb, backend, 10));
+}
+
+static void assert_object_contains(git_odb_object *obj, const char *expected)
+{
+ const char *actual = (const char *) git_odb_object_data(obj);
+
+ cl_assert_equal_s(actual, expected);
+}
+
+void test_odb_backend_simple__initialize(void)
+{
+ _repo = cl_git_sandbox_init("testrepo.git");
+ _odb = NULL;
+ _obj = NULL;
+}
+
+void test_odb_backend_simple__cleanup(void)
+{
+ git_odb_object_free(_obj);
+ cl_git_sandbox_cleanup();
+ cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 1));
+}
+
+void test_odb_backend_simple__read_of_object_succeeds(void)
+{
+ const fake_object objs[] = {
+ { "f6ea0495187600e7b2288c8ac19c5886383a4632", "foobar" },
+ { NULL, NULL }
+ };
+
+ setup_backend(objs);
+
+ cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid));
+ cl_git_pass(git_odb_read(&_obj, _odb, &_oid));
+
+ assert_object_contains(_obj, objs[0].content);
+}
+
+void test_odb_backend_simple__read_of_nonexisting_object_fails(void)
+{
+ const fake_object objs[] = {
+ { "f6ea0495187600e7b2288c8ac19c5886383a4632", "foobar" },
+ { NULL, NULL }
+ };
+
+ setup_backend(objs);
+
+ cl_git_pass(git_oid_fromstr(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4633"));
+ cl_git_fail_with(GIT_ENOTFOUND, git_odb_read(&_obj, _odb, &_oid));
+}
+
+void test_odb_backend_simple__read_with_hash_mismatch_fails(void)
+{
+ const fake_object objs[] = {
+ { "1234567890123456789012345678901234567890", "nonmatching content" },
+ { NULL, NULL }
+ };
+
+ setup_backend(objs);
+
+ cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid));
+ cl_git_fail_with(GIT_EMISMATCH, git_odb_read(&_obj, _odb, &_oid));
+}
+
+void test_odb_backend_simple__read_with_hash_mismatch_succeeds_without_verification(void)
+{
+ const fake_object objs[] = {
+ { "1234567890123456789012345678901234567890", "nonmatching content" },
+ { NULL, NULL }
+ };
+
+ setup_backend(objs);
+ cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid));
+
+ cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0));
+ cl_git_pass(git_odb_read(&_obj, _odb, &_oid));
+
+ assert_object_contains(_obj, objs[0].content);
+}
+
+void test_odb_backend_simple__read_prefix_succeeds(void)
+{
+ const fake_object objs[] = {
+ { "f6ea0495187600e7b2288c8ac19c5886383a4632", "foobar" },
+ { NULL, NULL }
+ };
+
+ setup_backend(objs);
+
+ cl_git_pass(git_oid_fromstr(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4632"));
+ cl_git_pass(git_odb_read(&_obj, _odb, &_oid));
+
+ assert_object_contains(_obj, objs[0].content);
+}
+
+void test_odb_backend_simple__read_prefix_of_nonexisting_object_fails(void)
+{
+ const fake_object objs[] = {
+ { "f6ea0495187600e7b2288c8ac19c5886383a4632", "foobar" },
+ { NULL, NULL }
+ };
+ char *hash = "f6ea0495187600e8";
+
+ setup_backend(objs);
+
+ cl_git_pass(git_oid_fromstrn(&_oid, hash, strlen(hash)));
+ cl_git_fail_with(GIT_ENOTFOUND, git_odb_read(&_obj, _odb, &_oid));
+}
+
+void test_odb_backend_simple__read_with_ambiguous_prefix_fails(void)
+{
+ const fake_object objs[] = {
+ { "1234567890111111111111111111111111111111", "first content" },
+ { "1234567890222222222222222222222222222222", "second content" },
+ { NULL, NULL }
+ };
+
+ setup_backend(objs);
+
+ cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid));
+ cl_git_fail_with(GIT_EAMBIGUOUS, git_odb_read_prefix(&_obj, _odb, &_oid, 7));
+}
+
+void test_odb_backend_simple__read_with_highly_ambiguous_prefix(void)
+{
+ const fake_object objs[] = {
+ { "1234567890111111111111111111111111111111", "first content" },
+ { "1234567890111111111111111111111111111112", "second content" },
+ { NULL, NULL }
+ };
+
+ setup_backend(objs);
+
+ cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid));
+ cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0));
+ cl_git_fail_with(GIT_EAMBIGUOUS, git_odb_read_prefix(&_obj, _odb, &_oid, 39));
+ cl_git_pass(git_odb_read_prefix(&_obj, _odb, &_oid, 40));
+ assert_object_contains(_obj, objs[0].content);
+}
+
+void test_odb_backend_simple__exists_succeeds(void)
+{
+ const fake_object objs[] = {
+ { "f6ea0495187600e7b2288c8ac19c5886383a4632", "foobar" },
+ { NULL, NULL }
+ };
+
+ setup_backend(objs);
+
+ cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid));
+ cl_assert(git_odb_exists(_odb, &_oid));
+}
+
+void test_odb_backend_simple__exists_fails_for_nonexisting_object(void)
+{
+ const fake_object objs[] = {
+ { "f6ea0495187600e7b2288c8ac19c5886383a4632", "foobar" },
+ { NULL, NULL }
+ };
+
+ setup_backend(objs);
+
+ cl_git_pass(git_oid_fromstr(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4633"));
+ cl_assert(git_odb_exists(_odb, &_oid) == 0);
+}
+
+void test_odb_backend_simple__exists_prefix_succeeds(void)
+{
+ const fake_object objs[] = {
+ { "1234567890111111111111111111111111111111", "first content" },
+ { "1234567890222222222222222222222222222222", "second content" },
+ { NULL, NULL }
+ };
+ git_oid found;
+
+ setup_backend(objs);
+
+ cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid));
+ cl_git_pass(git_odb_exists_prefix(&found, _odb, &_oid, 12));
+ cl_assert(git_oid_equal(&found, &_oid));
+}
+
+void test_odb_backend_simple__exists_with_ambiguous_prefix_fails(void)
+{
+ const fake_object objs[] = {
+ { "1234567890111111111111111111111111111111", "first content" },
+ { "1234567890222222222222222222222222222222", "second content" },
+ { NULL, NULL }
+ };
+
+ setup_backend(objs);
+
+ cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid));
+ cl_git_fail_with(GIT_EAMBIGUOUS, git_odb_exists_prefix(NULL, _odb, &_oid, 7));
+}
+
+void test_odb_backend_simple__exists_with_highly_ambiguous_prefix(void)
+{
+ const fake_object objs[] = {
+ { "1234567890111111111111111111111111111111", "first content" },
+ { "1234567890111111111111111111111111111112", "second content" },
+ { NULL, NULL }
+ };
+ git_oid found;
+
+ setup_backend(objs);
+
+ cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid));
+ cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0));
+ cl_git_fail_with(GIT_EAMBIGUOUS, git_odb_exists_prefix(&found, _odb, &_oid, 39));
+ cl_git_pass(git_odb_exists_prefix(&found, _odb, &_oid, 40));
+ cl_assert(git_oid_equal(&found, &_oid));
+}
diff --git a/tests/odb/foreach.c b/tests/odb/foreach.c
index 12b81b4f1..42d706467 100644
--- a/tests/odb/foreach.c
+++ b/tests/odb/foreach.c
@@ -28,8 +28,8 @@ static int foreach_cb(const git_oid *oid, void *data)
/*
* $ git --git-dir tests/resources/testrepo.git count-objects --verbose
- * count: 47
- * size: 4
+ * count: 60
+ * size: 240
* in-pack: 1640
* packs: 3
* size-pack: 425
@@ -44,7 +44,7 @@ void test_odb_foreach__foreach(void)
git_repository_odb(&_odb, _repo);
cl_git_pass(git_odb_foreach(_odb, foreach_cb, &nobj));
- cl_assert_equal_i(47 + 1640, nobj); /* count + in-pack */
+ cl_assert_equal_i(60 + 1640, nobj); /* count + in-pack */
}
void test_odb_foreach__one_pack(void)
@@ -118,7 +118,7 @@ void test_odb_foreach__files_in_objects_dir(void)
cl_git_pass(git_repository_odb(&odb, repo));
cl_git_pass(git_odb_foreach(odb, foreach_cb, &nobj));
- cl_assert_equal_i(47 + 1640, nobj); /* count + in-pack */
+ cl_assert_equal_i(60 + 1640, nobj); /* count + in-pack */
git_odb_free(odb);
git_repository_free(repo);
diff --git a/tests/odb/freshen.c b/tests/odb/freshen.c
index d8d6c029a..9d3cf51dc 100644
--- a/tests/odb/freshen.c
+++ b/tests/odb/freshen.c
@@ -17,36 +17,126 @@ void test_odb_freshen__cleanup(void)
cl_git_sandbox_cleanup();
}
-#define LOOSE_STR "hey\n"
-#define LOOSE_ID "1385f264afb75a56a5bec74243be9b367ba4ca08"
-#define LOOSE_FN "13/85f264afb75a56a5bec74243be9b367ba4ca08"
+static void set_time_wayback(struct stat *out, const char *fn)
+{
+ git_buf fullpath = GIT_BUF_INIT;
+ struct p_timeval old[2];
+
+ old[0].tv_sec = 1234567890;
+ old[0].tv_usec = 0;
+ old[1].tv_sec = 1234567890;
+ old[1].tv_usec = 0;
-void test_odb_freshen__loose_object(void)
+ git_buf_joinpath(&fullpath, "testrepo.git/objects", fn);
+
+ cl_must_pass(p_utimes(git_buf_cstr(&fullpath), old));
+ cl_must_pass(p_lstat(git_buf_cstr(&fullpath), out));
+ git_buf_free(&fullpath);
+}
+
+#define LOOSE_STR "my new file\n"
+#define LOOSE_BLOB_ID "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd"
+#define LOOSE_BLOB_FN "a7/1586c1dfe8a71c6cbf6c129f404c5642ff31bd"
+
+void test_odb_freshen__loose_blob(void)
{
git_oid expected_id, id;
struct stat before, after;
- struct p_timeval old_times[2];
- cl_git_pass(git_oid_fromstr(&expected_id, LOOSE_ID));
+ cl_git_pass(git_oid_fromstr(&expected_id, LOOSE_BLOB_ID));
+ set_time_wayback(&before, LOOSE_BLOB_FN);
- old_times[0].tv_sec = 1234567890;
- old_times[0].tv_usec = 0;
- old_times[1].tv_sec = 1234567890;
- old_times[1].tv_usec = 0;
+ /* make sure we freshen a blob */
+ cl_git_pass(git_blob_create_frombuffer(&id, repo, LOOSE_STR, CONST_STRLEN(LOOSE_STR)));
+ cl_assert_equal_oid(&expected_id, &id);
+ cl_must_pass(p_lstat("testrepo.git/objects/" LOOSE_BLOB_FN, &after));
- /* set time to way back */
- cl_must_pass(p_utimes("testrepo.git/objects/" LOOSE_FN, old_times));
- cl_must_pass(p_lstat("testrepo.git/objects/" LOOSE_FN, &before));
+ cl_assert(before.st_atime < after.st_atime);
+ cl_assert(before.st_mtime < after.st_mtime);
+}
+
+#define UNIQUE_STR "doesnt exist in the odb yet\n"
+#define UNIQUE_BLOB_ID "78a87d0b8878c5953b9a63015ff4e22a3d898826"
+#define UNIQUE_BLOB_FN "78/a87d0b8878c5953b9a63015ff4e22a3d898826"
- cl_git_pass(git_odb_write(&id, odb, LOOSE_STR, CONST_STRLEN(LOOSE_STR),
- GIT_OBJ_BLOB));
+void test_odb_freshen__readonly_object(void)
+{
+ git_oid expected_id, id;
+ struct stat before, after;
+
+ cl_git_pass(git_oid_fromstr(&expected_id, UNIQUE_BLOB_ID));
+
+ cl_git_pass(git_blob_create_frombuffer(&id, repo, UNIQUE_STR, CONST_STRLEN(UNIQUE_STR)));
+ cl_assert_equal_oid(&expected_id, &id);
+
+ set_time_wayback(&before, UNIQUE_BLOB_FN);
+ cl_assert((before.st_mode & S_IWUSR) == 0);
+
+ cl_git_pass(git_blob_create_frombuffer(&id, repo, UNIQUE_STR, CONST_STRLEN(UNIQUE_STR)));
cl_assert_equal_oid(&expected_id, &id);
- cl_must_pass(p_lstat("testrepo.git/objects/" LOOSE_FN, &after));
+ cl_must_pass(p_lstat("testrepo.git/objects/" UNIQUE_BLOB_FN, &after));
cl_assert(before.st_atime < after.st_atime);
cl_assert(before.st_mtime < after.st_mtime);
}
+#define LOOSE_TREE_ID "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162"
+#define LOOSE_TREE_FN "94/4c0f6e4dfa41595e6eb3ceecdb14f50fe18162"
+
+void test_odb_freshen__loose_tree(void)
+{
+ git_oid expected_id, id;
+ git_tree *tree;
+ struct stat before, after;
+
+ cl_git_pass(git_oid_fromstr(&expected_id, LOOSE_TREE_ID));
+ set_time_wayback(&before, LOOSE_TREE_FN);
+
+ cl_git_pass(git_tree_lookup(&tree, repo, &expected_id));
+ cl_git_pass(git_tree_create_updated(&id, repo, tree, 0, NULL));
+
+ /* make sure we freshen a tree */
+ cl_assert_equal_oid(&expected_id, &id);
+ cl_must_pass(p_lstat("testrepo.git/objects/" LOOSE_TREE_FN, &after));
+
+ cl_assert(before.st_atime < after.st_atime);
+ cl_assert(before.st_mtime < after.st_mtime);
+
+ git_tree_free(tree);
+}
+
+void test_odb_freshen__tree_during_commit(void)
+{
+ git_oid tree_id, parent_id, commit_id;
+ git_tree *tree;
+ git_commit *parent;
+ git_signature *signature;
+ struct stat before, after;
+
+ cl_git_pass(git_oid_fromstr(&tree_id, LOOSE_TREE_ID));
+ cl_git_pass(git_tree_lookup(&tree, repo, &tree_id));
+ set_time_wayback(&before, LOOSE_TREE_FN);
+
+ cl_git_pass(git_oid_fromstr(&parent_id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"));
+ cl_git_pass(git_commit_lookup(&parent, repo, &parent_id));
+
+ cl_git_pass(git_signature_new(&signature,
+ "Refresher", "refresher@example.com", 1488547083, 0));
+
+ cl_git_pass(git_commit_create(&commit_id, repo, NULL,
+ signature, signature, NULL, "New commit pointing to old tree",
+ tree, 1, (const git_commit **)&parent));
+
+ /* make sure we freshen the tree the commit points to */
+ cl_must_pass(p_lstat("testrepo.git/objects/" LOOSE_TREE_FN, &after));
+ cl_assert(before.st_atime < after.st_atime);
+ cl_assert(before.st_mtime < after.st_mtime);
+
+ git_signature_free(signature);
+ git_commit_free(parent);
+ git_tree_free(tree);
+}
+
#define PACKED_STR "Testing a readme.txt\n"
#define PACKED_ID "6336846bd5c88d32f93ae57d846683e61ab5c530"
#define PACKED_FN "pack-d85f5d483273108c9d8dd0e4728ccf0b2982423a.pack"
diff --git a/tests/odb/loose.c b/tests/odb/loose.c
index c91927c4a..2e24d6723 100644
--- a/tests/odb/loose.c
+++ b/tests/odb/loose.c
@@ -3,6 +3,7 @@
#include "git2/odb_backend.h"
#include "posix.h"
#include "loose_data.h"
+#include "repository.h"
#ifdef __ANDROID_API__
# define S_IREAD S_IRUSR
@@ -56,11 +57,13 @@ static void test_read_object(object_data *data)
void test_odb_loose__initialize(void)
{
+ p_fsync__cnt = 0;
cl_must_pass(p_mkdir("test-objects", GIT_OBJECT_DIR_MODE));
}
void test_odb_loose__cleanup(void)
{
+ cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 0));
cl_fixture_cleanup("test-objects");
}
@@ -150,3 +153,55 @@ void test_odb_loose__permissions_readwrite(void)
{
test_write_object_permission(0777, 0666, 0777, 0666);
}
+
+static void write_object_to_loose_odb(int fsync)
+{
+ git_odb *odb;
+ git_odb_backend *backend;
+ git_oid oid;
+
+ cl_git_pass(git_odb_new(&odb));
+ cl_git_pass(git_odb_backend_loose(&backend, "test-objects", -1, fsync, 0777, 0666));
+ cl_git_pass(git_odb_add_backend(odb, backend, 1));
+ cl_git_pass(git_odb_write(&oid, odb, "Test data\n", 10, GIT_OBJ_BLOB));
+ git_odb_free(odb);
+}
+
+void test_odb_loose__does_not_fsync_by_default(void)
+{
+ write_object_to_loose_odb(0);
+ cl_assert_equal_sz(0, p_fsync__cnt);
+}
+
+void test_odb_loose__fsync_obeys_odb_option(void)
+{
+ write_object_to_loose_odb(1);
+ cl_assert(p_fsync__cnt > 0);
+}
+
+void test_odb_loose__fsync_obeys_global_setting(void)
+{
+ cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 1));
+ write_object_to_loose_odb(0);
+ cl_assert(p_fsync__cnt > 0);
+}
+
+void test_odb_loose__fsync_obeys_repo_setting(void)
+{
+ git_repository *repo;
+ git_odb *odb;
+ git_oid oid;
+
+ cl_git_pass(git_repository_init(&repo, "test-objects", 1));
+ cl_git_pass(git_repository_odb__weakptr(&odb, repo));
+ cl_git_pass(git_odb_write(&oid, odb, "No fsync here\n", 14, GIT_OBJ_BLOB));
+ cl_assert(p_fsync__cnt == 0);
+ git_repository_free(repo);
+
+ cl_git_pass(git_repository_open(&repo, "test-objects"));
+ cl_repo_set_bool(repo, "core.fsyncObjectFiles", true);
+ cl_git_pass(git_repository_odb__weakptr(&odb, repo));
+ cl_git_pass(git_odb_write(&oid, odb, "Now fsync\n", 10, GIT_OBJ_BLOB));
+ cl_assert(p_fsync__cnt > 0);
+ git_repository_free(repo);
+}
diff --git a/tests/online/badssl.c b/tests/online/badssl.c
index 66b090df4..6524fcd8e 100644
--- a/tests/online/badssl.c
+++ b/tests/online/badssl.c
@@ -4,43 +4,77 @@
static git_repository *g_repo;
-#if defined(GIT_OPENSSL) || defined(GIT_WINHTTP) || defined(GIT_SECURE_TRANSPORT)
+#ifdef GIT_HTTPS
static bool g_has_ssl = true;
#else
static bool g_has_ssl = false;
#endif
+static int cert_check_assert_invalid(git_cert *cert, int valid, const char* host, void *payload)
+{
+ GIT_UNUSED(cert); GIT_UNUSED(host); GIT_UNUSED(payload);
+
+ cl_assert_equal_i(0, valid);
+
+ return GIT_ECERTIFICATE;
+}
+
void test_online_badssl__expired(void)
{
+ git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
+ opts.fetch_opts.callbacks.certificate_check = cert_check_assert_invalid;
+
if (!g_has_ssl)
cl_skip();
cl_git_fail_with(GIT_ECERTIFICATE,
git_clone(&g_repo, "https://expired.badssl.com/fake.git", "./fake", NULL));
+
+ cl_git_fail_with(GIT_ECERTIFICATE,
+ git_clone(&g_repo, "https://expired.badssl.com/fake.git", "./fake", &opts));
}
void test_online_badssl__wrong_host(void)
{
+ git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
+ opts.fetch_opts.callbacks.certificate_check = cert_check_assert_invalid;
+
if (!g_has_ssl)
cl_skip();
cl_git_fail_with(GIT_ECERTIFICATE,
git_clone(&g_repo, "https://wrong.host.badssl.com/fake.git", "./fake", NULL));
+ cl_git_fail_with(GIT_ECERTIFICATE,
+ git_clone(&g_repo, "https://wrong.host.badssl.com/fake.git", "./fake", &opts));
}
void test_online_badssl__self_signed(void)
{
+ git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
+ opts.fetch_opts.callbacks.certificate_check = cert_check_assert_invalid;
+
if (!g_has_ssl)
cl_skip();
cl_git_fail_with(GIT_ECERTIFICATE,
git_clone(&g_repo, "https://self-signed.badssl.com/fake.git", "./fake", NULL));
+ cl_git_fail_with(GIT_ECERTIFICATE,
+ git_clone(&g_repo, "https://self-signed.badssl.com/fake.git", "./fake", &opts));
}
void test_online_badssl__old_cipher(void)
{
+ git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
+ opts.fetch_opts.callbacks.certificate_check = cert_check_assert_invalid;
+
+ /* FIXME: we don't actually reject RC4 anywhere, figure out what to tweak */
+ cl_skip();
+
if (!g_has_ssl)
cl_skip();
- cl_git_fail(git_clone(&g_repo, "https://rc4.badssl.com/fake.git", "./fake", NULL));
+ cl_git_fail_with(GIT_ECERTIFICATE,
+ git_clone(&g_repo, "https://rc4.badssl.com/fake.git", "./fake", NULL));
+ cl_git_fail_with(GIT_ECERTIFICATE,
+ git_clone(&g_repo, "https://rc4.badssl.com/fake.git", "./fake", &opts));
}
diff --git a/tests/online/clone.c b/tests/online/clone.c
index 04fd22d45..5eda73f87 100644
--- a/tests/online/clone.c
+++ b/tests/online/clone.c
@@ -547,7 +547,7 @@ void test_online_clone__ssh_cert(void)
if (!_remote_ssh_fingerprint)
cl_skip();
- cl_git_fail_with(GIT_EUSER, git_clone(&g_repo, "ssh://localhost/foo", "./foo", &g_options));
+ cl_git_fail_with(GIT_EUSER, git_clone(&g_repo, _remote_url, "./foo", &g_options));
}
static char *read_key_file(const char *path)
diff --git a/tests/online/fetchhead.c b/tests/online/fetchhead.c
index 9aaad253c..c1ac06dbe 100644
--- a/tests/online/fetchhead.c
+++ b/tests/online/fetchhead.c
@@ -126,6 +126,8 @@ void test_online_fetchhead__explicit_dst_refspec_creates_branch(void)
cl_git_pass(git_branch_lookup(&ref, g_repo, "explicit-refspec", GIT_BRANCH_ALL));
cl_assert_equal_i(refs + 1, count_references());
+
+ git_reference_free(ref);
}
void test_online_fetchhead__empty_dst_refspec_creates_no_branch(void)
diff --git a/tests/online/remotes.c b/tests/online/remotes.c
index a86f2d9ae..d79eb1f59 100644
--- a/tests/online/remotes.c
+++ b/tests/online/remotes.c
@@ -1,12 +1,13 @@
#include "clar_libgit2.h"
-static const char *refspec = "refs/heads/first-merge:refs/remotes/origin/first-merge";
+#define URL "git://github.com/libgit2/TestGitRepository"
+#define REFSPEC "refs/heads/first-merge:refs/remotes/origin/first-merge"
static int remote_single_branch(git_remote **out, git_repository *repo, const char *name, const char *url, void *payload)
{
GIT_UNUSED(payload);
- cl_git_pass(git_remote_create_with_fetchspec(out, repo, name, url, refspec));
+ cl_git_pass(git_remote_create_with_fetchspec(out, repo, name, url, REFSPEC));
return 0;
}
@@ -22,7 +23,7 @@ void test_online_remotes__single_branch(void)
opts.remote_cb = remote_single_branch;
opts.checkout_branch = "first-merge";
- cl_git_pass(git_clone(&repo, "git://github.com/libgit2/TestGitRepository", "./single-branch", &opts));
+ cl_git_pass(git_clone(&repo, URL, "./single-branch", &opts));
cl_git_pass(git_reference_list(&refs, repo));
for (i = 0; i < refs.count; i++) {
@@ -37,7 +38,7 @@ void test_online_remotes__single_branch(void)
cl_git_pass(git_remote_get_fetch_refspecs(&refs, remote));
cl_assert_equal_i(1, refs.count);
- cl_assert_equal_s(refspec, refs.strings[0]);
+ cl_assert_equal_s(REFSPEC, refs.strings[0]);
git_strarray_free(&refs);
git_remote_free(remote);
@@ -51,5 +52,76 @@ void test_online_remotes__restricted_refspecs(void)
opts.remote_cb = remote_single_branch;
- cl_git_fail_with(GIT_EINVALIDSPEC, git_clone(&repo, "git://github.com/libgit2/TestGitRepository", "./restrict-refspec", &opts));
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_clone(&repo, URL, "./restrict-refspec", &opts));
+}
+
+void test_online_remotes__detached_remote_fails_downloading(void)
+{
+ git_remote *remote;
+
+ cl_git_pass(git_remote_create_detached(&remote, URL));
+ cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL));
+ cl_git_fail(git_remote_download(remote, NULL, NULL));
+
+ git_remote_free(remote);
+}
+
+void test_online_remotes__detached_remote_fails_uploading(void)
+{
+ git_remote *remote;
+
+ cl_git_pass(git_remote_create_detached(&remote, URL));
+ cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL));
+ cl_git_fail(git_remote_upload(remote, NULL, NULL));
+
+ git_remote_free(remote);
+}
+
+void test_online_remotes__detached_remote_fails_pushing(void)
+{
+ git_remote *remote;
+
+ cl_git_pass(git_remote_create_detached(&remote, URL));
+ cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL));
+ cl_git_fail(git_remote_push(remote, NULL, NULL));
+
+ git_remote_free(remote);
+}
+
+void test_online_remotes__detached_remote_succeeds_ls(void)
+{
+ const char *refs[] = {
+ "HEAD",
+ "refs/heads/first-merge",
+ "refs/heads/master",
+ "refs/heads/no-parent",
+ "refs/tags/annotated_tag",
+ "refs/tags/annotated_tag^{}",
+ "refs/tags/blob",
+ "refs/tags/commit_tree",
+ "refs/tags/nearly-dangling",
+ };
+ const git_remote_head **heads;
+ git_remote *remote;
+ size_t i, j, n;
+
+ cl_git_pass(git_remote_create_detached(&remote, URL));
+ cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL));
+ cl_git_pass(git_remote_ls(&heads, &n, remote));
+
+ cl_assert_equal_sz(n, 9);
+ for (i = 0; i < n; i++) {
+ char found = false;
+
+ for (j = 0; j < ARRAY_SIZE(refs); j++) {
+ if (!strcmp(heads[i]->name, refs[j])) {
+ found = true;
+ break;
+ }
+ }
+
+ cl_assert_(found, heads[i]->name);
+ }
+
+ git_remote_free(remote);
}
diff --git a/tests/pack/indexer.c b/tests/pack/indexer.c
index 49a106d98..c73d3974e 100644
--- a/tests/pack/indexer.c
+++ b/tests/pack/indexer.c
@@ -85,7 +85,7 @@ void test_pack_indexer__fix_thin(void)
cl_assert_equal_i(stats.indexed_objects, 2);
cl_assert_equal_i(stats.local_objects, 1);
- git_oid_fromstr(&should_id, "11f0f69b334728fdd8bc86b80499f22f29d85b15");
+ git_oid_fromstr(&should_id, "fefdb2d740a3a6b6c03a0c7d6ce431c6d5810e13");
cl_assert_equal_oid(&should_id, git_indexer_hash(idx));
git_indexer_free(idx);
@@ -102,7 +102,7 @@ void test_pack_indexer__fix_thin(void)
int fd;
ssize_t read;
struct stat st;
- const char *name = "pack-11f0f69b334728fdd8bc86b80499f22f29d85b15.pack";
+ const char *name = "pack-fefdb2d740a3a6b6c03a0c7d6ce431c6d5810e13.pack";
fd = p_open(name, O_RDONLY);
cl_assert(fd != -1);
@@ -125,3 +125,44 @@ void test_pack_indexer__fix_thin(void)
git_indexer_free(idx);
}
}
+
+static int find_tmp_file_recurs(void *opaque, git_buf *path)
+{
+ int error = 0;
+ git_buf *first_tmp_file = opaque;
+ struct stat st;
+
+ if ((error = p_lstat_posixly(path->ptr, &st)) < 0)
+ return error;
+
+ if (S_ISDIR(st.st_mode))
+ return git_path_direach(path, 0, find_tmp_file_recurs, opaque);
+
+ /* This is the template that's used in git_futils_mktmp. */
+ if (strstr(git_buf_cstr(path), "_git2_") != NULL)
+ return git_buf_sets(first_tmp_file, git_buf_cstr(path));
+
+ return 0;
+}
+
+void test_pack_indexer__no_tmp_files(void)
+{
+ git_indexer *idx = NULL;
+ git_buf path = GIT_BUF_INIT;
+ git_buf first_tmp_file = GIT_BUF_INIT;
+
+ /* Precondition: there are no temporary files. */
+ cl_git_pass(git_buf_sets(&path, clar_sandbox_path()));
+ cl_git_pass(find_tmp_file_recurs(&first_tmp_file, &path));
+ git_buf_free(&path);
+ cl_assert(git_buf_len(&first_tmp_file) == 0);
+
+ cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL, NULL));
+ git_indexer_free(idx);
+
+ cl_git_pass(git_buf_sets(&path, clar_sandbox_path()));
+ cl_git_pass(find_tmp_file_recurs(&first_tmp_file, &path));
+ git_buf_free(&path);
+ cl_assert(git_buf_len(&first_tmp_file) == 0);
+ git_buf_free(&first_tmp_file);
+}
diff --git a/tests/pack/packbuilder.c b/tests/pack/packbuilder.c
index 29f3e2d64..13ee07353 100644
--- a/tests/pack/packbuilder.c
+++ b/tests/pack/packbuilder.c
@@ -23,6 +23,7 @@ void test_pack_packbuilder__initialize(void)
cl_git_pass(git_vector_init(&_commits, 0, NULL));
_commits_is_initialized = 1;
memset(&_stats, 0, sizeof(_stats));
+ p_fsync__cnt = 0;
}
void test_pack_packbuilder__cleanup(void)
@@ -30,6 +31,8 @@ void test_pack_packbuilder__cleanup(void)
git_oid *o;
unsigned int i;
+ cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 0));
+
if (_commits_is_initialized) {
_commits_is_initialized = 0;
git_vector_foreach(&_commits, i, o) {
@@ -113,7 +116,7 @@ void test_pack_packbuilder__create_pack(void)
* $ cd tests/resources/testrepo.git
* $ git rev-list --objects HEAD | \
* git pack-objects -q --no-reuse-delta --threads=1 pack
- * $ sha1sum git-80e61eb315239ef3c53033e37fee43b744d57122.pack
+ * $ sha1sum pack-7f5fa362c664d68ba7221259be1cbd187434b2f0.pack
* 5d410bdf97cf896f9007681b92868471d636954b
*
*/
@@ -142,7 +145,7 @@ void test_pack_packbuilder__get_hash(void)
git_packbuilder_write(_packbuilder, ".", 0, NULL, NULL);
git_oid_fmt(hex, git_packbuilder_hash(_packbuilder));
- cl_assert_equal_s(hex, "80e61eb315239ef3c53033e37fee43b744d57122");
+ cl_assert_equal_s(hex, "7f5fa362c664d68ba7221259be1cbd187434b2f0");
}
static void test_write_pack_permission(mode_t given, mode_t expected)
@@ -166,10 +169,10 @@ static void test_write_pack_permission(mode_t given, mode_t expected)
mask = p_umask(0);
p_umask(mask);
- cl_git_pass(p_stat("pack-80e61eb315239ef3c53033e37fee43b744d57122.idx", &statbuf));
+ cl_git_pass(p_stat("pack-7f5fa362c664d68ba7221259be1cbd187434b2f0.idx", &statbuf));
cl_assert_equal_i(statbuf.st_mode & os_mask, (expected & ~mask) & os_mask);
- cl_git_pass(p_stat("pack-80e61eb315239ef3c53033e37fee43b744d57122.pack", &statbuf));
+ cl_git_pass(p_stat("pack-7f5fa362c664d68ba7221259be1cbd187434b2f0.pack", &statbuf));
cl_assert_equal_i(statbuf.st_mode & os_mask, (expected & ~mask) & os_mask);
}
@@ -188,6 +191,40 @@ void test_pack_packbuilder__permissions_readwrite(void)
test_write_pack_permission(0666, 0666);
}
+void test_pack_packbuilder__does_not_fsync_by_default(void)
+{
+ seed_packbuilder();
+ git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL);
+ cl_assert_equal_sz(0, p_fsync__cnt);
+}
+
+/* We fsync the packfile and index. On non-Windows, we also fsync
+ * the parent directories.
+ */
+#ifdef GIT_WIN32
+static int expected_fsyncs = 2;
+#else
+static int expected_fsyncs = 4;
+#endif
+
+void test_pack_packbuilder__fsync_global_setting(void)
+{
+ cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 1));
+ p_fsync__cnt = 0;
+ seed_packbuilder();
+ git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL);
+ cl_assert_equal_sz(expected_fsyncs, p_fsync__cnt);
+}
+
+void test_pack_packbuilder__fsync_repo_setting(void)
+{
+ cl_repo_set_bool(_repo, "core.fsyncObjectFiles", true);
+ p_fsync__cnt = 0;
+ seed_packbuilder();
+ git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL);
+ cl_assert_equal_sz(expected_fsyncs, p_fsync__cnt);
+}
+
static int foreach_cb(void *buf, size_t len, void *payload)
{
git_indexer *idx = (git_indexer *) payload;
diff --git a/tests/patch/patch_common.h b/tests/patch/patch_common.h
index 6ec554690..a20ebd617 100644
--- a/tests/patch/patch_common.h
+++ b/tests/patch/patch_common.h
@@ -253,7 +253,66 @@
"@@ -9,0 +10 @@ below it!\n" \
"+insert at end\n"
-/* An insertion at the beginning and end of file (and the resultant patch) */
+#define PATCH_SIMPLE_COMMIT \
+ "commit 15e119375018fba121cf58e02a9f17fe22df0df8\n" \
+ "Author: Edward Thomson <ethomson@edwardthomson.com>\n" \
+ "Date: Wed Jun 14 13:31:20 2017 +0200\n" \
+ "\n" \
+ " CHANGELOG: document git_filter_init and GIT_FILTER_INIT\n" \
+ "\n" \
+ "diff --git a/CHANGELOG.md b/CHANGELOG.md\n" \
+ "index 1b9e0c90a..24ecba426 100644\n" \
+ "--- a/CHANGELOG.md\n" \
+ "+++ b/CHANGELOG.md\n" \
+ "@@ -96,6 +96,9 @@ v0.26\n" \
+ " * `git_transport_smart_proxy_options()' enables you to get the proxy options for\n" \
+ " smart transports.\n" \
+ "\n" \
+ "+* The `GIT_FILTER_INIT` macro and the `git_filter_init` function are provided\n" \
+ "+ to initialize a `git_filter` structure.\n" \
+ "+\n" \
+ " ### Breaking API changes\n" \
+ "\n" \
+ " * `clone_checkout_strategy` has been removed from\n"
+
+#define PATCH_MULTIPLE_HUNKS \
+ "diff --git a/x b/x\n" \
+ "index 0719398..fa0350c 100644\n" \
+ "--- a/x\n" \
+ "+++ b/x\n" \
+ "@@ -1,5 +1,4 @@\n" \
+ " 1\n" \
+ "-2\n" \
+ " 3\n" \
+ " 4\n" \
+ " 5\n" \
+ "@@ -7,3 +6,4 @@\n" \
+ " 7\n" \
+ " 8\n" \
+ " 9\n" \
+ "+10\n"
+
+#define PATCH_MULTIPLE_FILES \
+ "diff --git a/x b/x\n" \
+ "index 8a1218a..7059ba5 100644\n" \
+ "--- a/x\n" \
+ "+++ b/x\n" \
+ "@@ -1,5 +1,4 @@\n" \
+ " 1\n" \
+ " 2\n" \
+ "-3\n" \
+ " 4\n" \
+ " 5\n" \
+ "diff --git a/y b/y\n" \
+ "index e006065..9405325 100644\n" \
+ "--- a/y\n" \
+ "+++ b/y\n" \
+ "@@ -1,4 +1,5 @@\n" \
+ " a\n" \
+ " b\n" \
+ "+c\n" \
+ " d\n" \
+ " e\n"
#define FILE_PREPEND_AND_APPEND \
"first and\n" \
diff --git a/tests/precompiled.c b/tests/precompiled.c
new file mode 100644
index 000000000..5f656a45d
--- /dev/null
+++ b/tests/precompiled.c
@@ -0,0 +1 @@
+#include "precompiled.h"
diff --git a/tests/precompiled.h b/tests/precompiled.h
new file mode 100644
index 000000000..ea53a60e9
--- /dev/null
+++ b/tests/precompiled.h
@@ -0,0 +1,4 @@
+#include "common.h"
+#include "git2.h"
+#include "clar.h"
+#include "clar_libgit2.h"
diff --git a/tests/rebase/merge.c b/tests/rebase/merge.c
index 0f06ed153..7b2d6876c 100644
--- a/tests/rebase/merge.c
+++ b/tests/rebase/merge.c
@@ -1,4 +1,5 @@
#include "clar_libgit2.h"
+#include "git2/checkout.h"
#include "git2/rebase.h"
#include "posix.h"
#include "signature.h"
@@ -475,6 +476,59 @@ void test_rebase_merge__finish(void)
git_rebase_free(rebase);
}
+void test_rebase_merge__detached_finish(void)
+{
+ git_rebase *rebase;
+ git_reference *branch_ref, *upstream_ref, *head_ref;
+ git_annotated_commit *branch_head, *upstream_head;
+ git_rebase_operation *rebase_operation;
+ git_oid commit_id;
+ git_reflog *reflog;
+ const git_reflog_entry *reflog_entry;
+ git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+ int error;
+
+ cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/gravy"));
+ cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/veal"));
+
+ cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref));
+ cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref));
+
+ cl_git_pass(git_repository_set_head_detached_from_annotated(repo, branch_head));
+ opts.checkout_strategy = GIT_CHECKOUT_FORCE;
+ git_checkout_head(repo, &opts);
+
+ cl_git_pass(git_rebase_init(&rebase, repo, NULL, upstream_head, NULL, NULL));
+
+ cl_git_pass(git_rebase_next(&rebase_operation, rebase));
+ cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature,
+ NULL, NULL));
+
+ cl_git_fail(error = git_rebase_next(&rebase_operation, rebase));
+ cl_assert_equal_i(GIT_ITEROVER, error);
+
+ cl_git_pass(git_rebase_finish(rebase, signature));
+
+ cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo));
+
+ cl_git_pass(git_reference_lookup(&head_ref, repo, "HEAD"));
+ cl_assert_equal_i(GIT_REF_OID, git_reference_type(head_ref));
+
+ /* Make sure the reflogs are updated appropriately */
+ cl_git_pass(git_reflog_read(&reflog, repo, "HEAD"));
+ cl_assert(reflog_entry = git_reflog_entry_byindex(reflog, 0));
+ cl_assert_equal_oid(git_annotated_commit_id(upstream_head), git_reflog_entry_id_old(reflog_entry));
+ cl_assert_equal_oid(&commit_id, git_reflog_entry_id_new(reflog_entry));
+
+ git_reflog_free(reflog);
+ git_annotated_commit_free(branch_head);
+ git_annotated_commit_free(upstream_head);
+ git_reference_free(head_ref);
+ git_reference_free(branch_ref);
+ git_reference_free(upstream_ref);
+ git_rebase_free(rebase);
+}
+
void test_rebase_merge__finish_with_ids(void)
{
git_rebase *rebase;
diff --git a/tests/rebase/submodule.c b/tests/rebase/submodule.c
new file mode 100644
index 000000000..8ae78ce5b
--- /dev/null
+++ b/tests/rebase/submodule.c
@@ -0,0 +1,94 @@
+#include "clar_libgit2.h"
+#include "git2/checkout.h"
+#include "git2/rebase.h"
+#include "posix.h"
+#include "signature.h"
+#include "../submodule/submodule_helpers.h"
+
+#include <fcntl.h>
+
+static git_repository *repo;
+static git_signature *signature;
+
+// Fixture setup and teardown
+void test_rebase_submodule__initialize(void)
+{
+ git_index *index;
+ git_oid tree_oid, commit_id;
+ git_tree *tree;
+ git_commit *parent;
+ git_object *obj;
+ git_reference *master_ref;
+ git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+ opts.checkout_strategy = GIT_CHECKOUT_FORCE;
+
+ repo = cl_git_sandbox_init("rebase-submodule");
+ cl_git_pass(git_signature_new(&signature,
+ "Rebaser", "rebaser@rebaser.rb", 1405694510, 0));
+
+ rewrite_gitmodules(git_repository_workdir(repo));
+
+ cl_git_pass(git_submodule_set_url(repo, "my-submodule", git_repository_path(repo)));
+
+ /* We have to commit the rewritten .gitmodules file */
+ cl_git_pass(git_repository_index(&index, repo));
+ cl_git_pass(git_index_add_bypath(index, ".gitmodules"));
+ cl_git_pass(git_index_write_tree(&tree_oid, index));
+
+ cl_git_pass(git_tree_lookup(&tree, repo, &tree_oid));
+
+ cl_git_pass(git_repository_head(&master_ref, repo));
+ cl_git_pass(git_commit_lookup(&parent, repo, git_reference_target(master_ref)));
+
+ cl_git_pass(git_commit_create_v(&commit_id, repo, git_reference_name(master_ref), signature, signature, NULL, "Fixup .gitmodules", tree, 1, parent));
+
+ /* And a final reset, for good measure */
+ cl_git_pass(git_object_lookup(&obj, repo, &commit_id, GIT_OBJ_COMMIT));
+ cl_git_pass(git_reset(repo, obj, GIT_RESET_HARD, &opts));
+
+ git_index_free(index);
+ git_object_free(obj);
+ git_commit_free(parent);
+ git_reference_free(master_ref);
+ git_tree_free(tree);
+}
+
+void test_rebase_submodule__cleanup(void)
+{
+ git_signature_free(signature);
+ cl_git_sandbox_cleanup();
+}
+
+void test_rebase_submodule__init_untracked(void)
+{
+ git_rebase *rebase;
+ git_reference *branch_ref, *upstream_ref;
+ git_annotated_commit *branch_head, *upstream_head;
+ git_buf untracked_path = GIT_BUF_INIT;
+ FILE *fp;
+ git_submodule *submodule;
+
+ cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/asparagus"));
+ cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master"));
+
+ cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref));
+ cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref));
+
+ cl_git_pass(git_submodule_lookup(&submodule, repo, "my-submodule"));
+ cl_git_pass(git_submodule_update(submodule, 1, NULL));
+
+ git_buf_printf(&untracked_path, "%s/my-submodule/untracked", git_repository_workdir(repo));
+ fp = fopen(git_buf_cstr(&untracked_path), "w");
+ fprintf(fp, "An untracked file in a submodule should not block a rebase\n");
+ fclose(fp);
+ git_buf_free(&untracked_path);
+
+ cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL));
+
+ git_submodule_free(submodule);
+ git_annotated_commit_free(branch_head);
+ git_annotated_commit_free(upstream_head);
+ git_reference_free(branch_ref);
+ git_reference_free(upstream_ref);
+ git_rebase_free(rebase);
+}
diff --git a/tests/refs/branches/create.c b/tests/refs/branches/create.c
index 31dec0678..69488e6c7 100644
--- a/tests/refs/branches/create.c
+++ b/tests/refs/branches/create.c
@@ -65,10 +65,14 @@ void test_refs_branches_create__can_force_create_over_an_existing_branch(void)
cl_assert_equal_s("refs/heads/br2", git_reference_name(branch));
}
-void test_refs_branches_create__cannot_force_create_over_current_branch(void)
+void test_refs_branches_create__cannot_force_create_over_current_branch_in_nonbare_repo(void)
{
const git_oid *oid;
git_reference *branch2;
+
+ /* Default repo for these tests is a bare repo, but this test requires a non-bare one */
+ cl_git_sandbox_cleanup();
+ repo = cl_git_sandbox_init("testrepo");
retrieve_known_commit(&target, repo);
cl_git_pass(git_branch_lookup(&branch2, repo, "master", GIT_BRANCH_LOCAL));
@@ -84,6 +88,26 @@ void test_refs_branches_create__cannot_force_create_over_current_branch(void)
git_reference_free(branch2);
}
+void test_refs_branches_create__can_force_create_over_current_branch_in_bare_repo(void)
+{
+ const git_oid *oid;
+ git_reference *branch2;
+ retrieve_known_commit(&target, repo);
+
+ cl_git_pass(git_branch_lookup(&branch2, repo, "master", GIT_BRANCH_LOCAL));
+ cl_assert_equal_s("refs/heads/master", git_reference_name(branch2));
+ cl_assert_equal_i(true, git_branch_is_head(branch2));
+ oid = git_commit_id(target);
+
+ cl_git_pass(git_branch_create(&branch, repo, "master", target, 1));
+ git_reference_free(branch);
+ branch = NULL;
+ cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL));
+ cl_assert_equal_s("refs/heads/master", git_reference_name(branch));
+ cl_git_pass(git_oid_cmp(git_reference_target(branch), oid));
+ git_reference_free(branch2);
+}
+
void test_refs_branches_create__creating_a_branch_with_an_invalid_name_returns_EINVALIDSPEC(void)
{
retrieve_known_commit(&target, repo);
diff --git a/tests/refs/branches/upstream.c b/tests/refs/branches/upstream.c
index 8f2e7a2ca..82f5665d8 100644
--- a/tests/refs/branches/upstream.c
+++ b/tests/refs/branches/upstream.c
@@ -175,7 +175,7 @@ void test_refs_branches_upstream__no_fetch_refspec(void)
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/test"));
cl_git_pass(git_reference_create(&ref, repo, "refs/remotes/matching/master", git_reference_target(branch), 1, "fetch"));
cl_git_fail(git_branch_set_upstream(branch, "matching/master"));
- cl_assert_equal_s("Could not determine remote for 'refs/remotes/matching/master'",
+ cl_assert_equal_s("could not determine remote for 'refs/remotes/matching/master'",
giterr_last()->message);
/* we can't set it automatically, so let's test the user setting it by hand */
diff --git a/tests/refs/crashes.c b/tests/refs/crashes.c
index 7a10411c8..228f479a0 100644
--- a/tests/refs/crashes.c
+++ b/tests/refs/crashes.c
@@ -6,7 +6,7 @@ void test_refs_crashes__double_free(void)
git_reference *ref, *ref2;
const char *REFNAME = "refs/heads/xxx";
- cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
+ repo = cl_git_sandbox_init("testrepo.git");
cl_git_pass(git_reference_symbolic_create(&ref, repo, REFNAME, "refs/heads/master", 0, NULL));
cl_git_pass(git_reference_lookup(&ref2, repo, REFNAME));
cl_git_pass(git_reference_delete(ref));
@@ -16,5 +16,5 @@ void test_refs_crashes__double_free(void)
/* reference is gone from disk, so reloading it will fail */
cl_git_fail(git_reference_lookup(&ref2, repo, REFNAME));
- git_repository_free(repo);
+ cl_git_sandbox_cleanup();
}
diff --git a/tests/refs/create.c b/tests/refs/create.c
index 6d5a5f1f6..469cddd1e 100644
--- a/tests/refs/create.c
+++ b/tests/refs/create.c
@@ -12,19 +12,22 @@ static git_repository *g_repo;
void test_refs_create__initialize(void)
{
- g_repo = cl_git_sandbox_init("testrepo");
+ g_repo = cl_git_sandbox_init("testrepo");
+ p_fsync__cnt = 0;
}
void test_refs_create__cleanup(void)
{
- cl_git_sandbox_cleanup();
+ cl_git_sandbox_cleanup();
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 1));
+ cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, 1));
+ cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 0));
}
void test_refs_create__symbolic(void)
{
- // create a new symbolic reference
+ /* create a new symbolic reference */
git_reference *new_reference, *looked_up_ref, *resolved_ref;
git_repository *repo2;
git_oid id;
@@ -65,9 +68,57 @@ void test_refs_create__symbolic(void)
git_reference_free(resolved_ref);
}
+void test_refs_create__symbolic_with_arbitrary_content(void)
+{
+ git_reference *new_reference, *looked_up_ref;
+ git_repository *repo2;
+ git_oid id;
+
+ const char *new_head_tracker = "ANOTHER_HEAD_TRACKER";
+ const char *arbitrary_target = "ARBITRARY DATA";
+
+ git_oid_fromstr(&id, current_master_tip);
+
+ /* Attempt to create symbolic ref with arbitrary data in target
+ * fails by default
+ */
+ cl_git_fail(git_reference_symbolic_create(&new_reference, g_repo, new_head_tracker, arbitrary_target, 0, NULL));
+
+ git_libgit2_opts(GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, 0);
+
+ /* With strict target validation disabled, ref creation succeeds */
+ cl_git_pass(git_reference_symbolic_create(&new_reference, g_repo, new_head_tracker, arbitrary_target, 0, NULL));
+
+ /* Ensure the reference can be looked-up... */
+ cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, new_head_tracker));
+ cl_assert(git_reference_type(looked_up_ref) & GIT_REF_SYMBOLIC);
+ cl_assert(reference_is_packed(looked_up_ref) == 0);
+ cl_assert_equal_s(looked_up_ref->name, new_head_tracker);
+ git_reference_free(looked_up_ref);
+
+ /* Ensure the target is what we expect it to be */
+ cl_assert_equal_s(git_reference_symbolic_target(new_reference), arbitrary_target);
+
+ /* Similar test with a fresh new repository object */
+ cl_git_pass(git_repository_open(&repo2, "testrepo"));
+
+ /* Ensure the reference can be looked-up... */
+ cl_git_pass(git_reference_lookup(&looked_up_ref, repo2, new_head_tracker));
+ cl_assert(git_reference_type(looked_up_ref) & GIT_REF_SYMBOLIC);
+ cl_assert(reference_is_packed(looked_up_ref) == 0);
+ cl_assert_equal_s(looked_up_ref->name, new_head_tracker);
+
+ /* Ensure the target is what we expect it to be */
+ cl_assert_equal_s(git_reference_symbolic_target(new_reference), arbitrary_target);
+
+ git_repository_free(repo2);
+ git_reference_free(new_reference);
+ git_reference_free(looked_up_ref);
+}
+
void test_refs_create__deep_symbolic(void)
{
- // create a deep symbolic reference
+ /* create a deep symbolic reference */
git_reference *new_reference, *looked_up_ref, *resolved_ref;
git_oid id;
@@ -87,7 +138,7 @@ void test_refs_create__deep_symbolic(void)
void test_refs_create__oid(void)
{
- // create a new OID reference
+ /* create a new OID reference */
git_reference *new_reference, *looked_up_ref;
git_repository *repo2;
git_oid id;
@@ -248,3 +299,69 @@ void test_refs_create__creating_a_loose_ref_with_invalid_windows_name(void)
test_win32_name("refs/heads/com1");
}
+
+/* Creating a loose ref involves fsync'ing the reference, the
+ * reflog and (on non-Windows) the containing directories.
+ * Creating a packed ref involves fsync'ing the packed ref file
+ * and (on non-Windows) the containing directory.
+ */
+#ifdef GIT_WIN32
+static int expected_fsyncs_create = 2, expected_fsyncs_compress = 1;
+#else
+static int expected_fsyncs_create = 4, expected_fsyncs_compress = 2;
+#endif
+
+static void count_fsyncs(size_t *create_count, size_t *compress_count)
+{
+ git_reference *ref = NULL;
+ git_refdb *refdb;
+ git_oid id;
+
+ p_fsync__cnt = 0;
+
+ git_oid_fromstr(&id, current_master_tip);
+ cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/fsync_test", &id, 0, "log message"));
+ git_reference_free(ref);
+
+ *create_count = p_fsync__cnt;
+ p_fsync__cnt = 0;
+
+ cl_git_pass(git_repository_refdb(&refdb, g_repo));
+ cl_git_pass(git_refdb_compress(refdb));
+ git_refdb_free(refdb);
+
+ *compress_count = p_fsync__cnt;
+ p_fsync__cnt = 0;
+}
+
+void test_refs_create__does_not_fsync_by_default(void)
+{
+ size_t create_count, compress_count;
+ count_fsyncs(&create_count, &compress_count);
+
+ cl_assert_equal_i(0, create_count);
+ cl_assert_equal_i(0, compress_count);
+}
+
+void test_refs_create__fsyncs_when_global_opt_set(void)
+{
+ size_t create_count, compress_count;
+
+ cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 1));
+ count_fsyncs(&create_count, &compress_count);
+
+ cl_assert_equal_i(expected_fsyncs_create, create_count);
+ cl_assert_equal_i(expected_fsyncs_compress, compress_count);
+}
+
+void test_refs_create__fsyncs_when_repo_config_set(void)
+{
+ size_t create_count, compress_count;
+
+ cl_repo_set_bool(g_repo, "core.fsyncObjectFiles", true);
+
+ count_fsyncs(&create_count, &compress_count);
+
+ cl_assert_equal_i(expected_fsyncs_create, create_count);
+ cl_assert_equal_i(expected_fsyncs_compress, compress_count);
+}
diff --git a/tests/refs/list.c b/tests/refs/list.c
index 374943b05..f7ca3f707 100644
--- a/tests/refs/list.c
+++ b/tests/refs/list.c
@@ -36,7 +36,7 @@ void test_refs_list__all(void)
/* We have exactly 12 refs in total if we include the packed ones:
* there is a reference that exists both in the packfile and as
* loose, but we only list it once */
- cl_assert_equal_i((int)ref_list.count, 15);
+ cl_assert_equal_i((int)ref_list.count, 17);
git_strarray_free(&ref_list);
}
@@ -51,7 +51,7 @@ void test_refs_list__do_not_retrieve_references_which_name_end_with_a_lock_exten
"144344043ba4d4a405da03de3844aa829ae8be0e\n");
cl_git_pass(git_reference_list(&ref_list, g_repo));
- cl_assert_equal_i((int)ref_list.count, 15);
+ cl_assert_equal_i((int)ref_list.count, 17);
git_strarray_free(&ref_list);
}
diff --git a/tests/refs/namespaces.c b/tests/refs/namespaces.c
new file mode 100644
index 000000000..bb6bb1ce0
--- /dev/null
+++ b/tests/refs/namespaces.c
@@ -0,0 +1,36 @@
+#include "clar_libgit2.h"
+
+#include "repository.h"
+
+static git_repository *g_repo;
+
+void test_refs_namespaces__initialize(void)
+{
+ g_repo = cl_git_sandbox_init("testrepo");
+}
+
+void test_refs_namespaces__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+}
+
+void test_refs_namespaces__get_and_set(void)
+{
+ cl_assert_equal_s(NULL, git_repository_get_namespace(g_repo));
+
+ cl_git_pass(git_repository_set_namespace(g_repo, "namespace"));
+ cl_assert_equal_s("namespace", git_repository_get_namespace(g_repo));
+
+ cl_git_pass(git_repository_set_namespace(g_repo, NULL));
+ cl_assert_equal_s(NULL, git_repository_get_namespace(g_repo));
+}
+
+void test_refs_namespaces__namespace_doesnt_show_normal_refs(void)
+{
+ static git_strarray ref_list;
+
+ cl_git_pass(git_repository_set_namespace(g_repo, "namespace"));
+ cl_git_pass(git_reference_list(&ref_list, g_repo));
+ cl_assert_equal_i(0, ref_list.count);
+ git_strarray_free(&ref_list);
+}
diff --git a/tests/refs/reflog/reflog.c b/tests/refs/reflog/reflog.c
index fdb15502c..252242152 100644
--- a/tests/refs/reflog/reflog.c
+++ b/tests/refs/reflog/reflog.c
@@ -4,7 +4,7 @@
#include "git2/reflog.h"
#include "reflog.h"
-
+static const char *merge_reflog_message = "commit (merge): Merge commit";
static const char *new_ref = "refs/heads/test-reflog";
static const char *current_master_tip = "a65fedf39aefe402d3bb6e24df4d4f5fe4547750";
#define commit_msg "commit: bla bla"
@@ -261,7 +261,7 @@ void test_refs_reflog_reflog__reading_a_reflog_with_invalid_format_returns_error
error = giterr_last();
cl_assert(error != NULL);
- cl_assert_equal_s("Unable to parse OID - contains invalid characters", error->message);
+ cl_assert_equal_s("unable to parse OID - contains invalid characters", error->message);
git_reference_free(ref);
git_buf_free(&logpath);
@@ -448,3 +448,45 @@ void test_refs_reflog_reflog__logallrefupdates_nonbare_set_false(void)
assert_no_reflog_update();
}
+
+void test_refs_reflog_reflog__show_merge_for_merge_commits(void)
+{
+ git_oid b1_oid;
+ git_oid b2_oid;
+ git_oid merge_commit_oid;
+ git_commit *b1_commit;
+ git_commit *b2_commit;
+ git_signature *s;
+ git_commit *parent_commits[2];
+ git_tree *tree;
+ git_reflog *log;
+ const git_reflog_entry *entry;
+
+ cl_git_pass(git_signature_now(&s, "alice", "alice@example.com"));
+
+ cl_git_pass(git_reference_name_to_id(&b1_oid, g_repo, "HEAD"));
+ cl_git_pass(git_reference_name_to_id(&b2_oid, g_repo, "refs/heads/test"));
+
+ cl_git_pass(git_commit_lookup(&b1_commit, g_repo, &b1_oid));
+ cl_git_pass(git_commit_lookup(&b2_commit, g_repo, &b2_oid));
+
+ parent_commits[0] = b1_commit;
+ parent_commits[1] = b2_commit;
+
+ cl_git_pass(git_commit_tree(&tree, b1_commit));
+
+ cl_git_pass(git_commit_create(&merge_commit_oid,
+ g_repo, "HEAD", s, s, NULL,
+ "Merge commit", tree,
+ 2, (const struct git_commit **) parent_commits));
+
+ cl_git_pass(git_reflog_read(&log, g_repo, "HEAD"));
+ entry = git_reflog_entry_byindex(log, 0);
+ cl_assert_equal_s(merge_reflog_message, git_reflog_entry_message(entry));
+
+ git_reflog_free(log);
+ git_tree_free(tree);
+ git_commit_free(b1_commit);
+ git_commit_free(b2_commit);
+ git_signature_free(s);
+}
diff --git a/tests/refs/revparse.c b/tests/refs/revparse.c
index c22c30440..459188cf7 100644
--- a/tests/refs/revparse.c
+++ b/tests/refs/revparse.c
@@ -122,6 +122,14 @@ static void test_id(
test_id_inrepo(spec, expected_left, expected_right, expected_flags, g_repo);
}
+static void test_invalid_revspec(const char* invalid_spec)
+{
+ git_revspec revspec;
+
+ cl_assert_equal_i(
+ GIT_EINVALIDSPEC, git_revparse(&revspec, g_repo, invalid_spec));
+}
+
void test_refs_revparse__initialize(void)
{
cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git")));
@@ -749,6 +757,33 @@ void test_refs_revparse__parses_range_operator(void)
"4a202b346bb0fb0db7eff3cffeb3c70babbd2045",
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE);
+
+ test_id("HEAD~3..",
+ "4a202b346bb0fb0db7eff3cffeb3c70babbd2045",
+ "a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
+ GIT_REVPARSE_RANGE);
+
+ test_id("HEAD~3...",
+ "4a202b346bb0fb0db7eff3cffeb3c70babbd2045",
+ "a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
+ GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE);
+
+ test_id("..HEAD~3",
+ "a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
+ "4a202b346bb0fb0db7eff3cffeb3c70babbd2045",
+ GIT_REVPARSE_RANGE);
+
+ test_id("...HEAD~3",
+ "a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
+ "4a202b346bb0fb0db7eff3cffeb3c70babbd2045",
+ GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE);
+
+ test_id("...",
+ "a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
+ "a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
+ GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE);
+
+ test_invalid_revspec("..");
}
void test_refs_revparse__ext_retrieves_both_the_reference_and_its_target(void)
diff --git a/tests/repo/discover.c b/tests/repo/discover.c
index 358daee9f..eadd055e9 100644
--- a/tests/repo/discover.c
+++ b/tests/repo/discover.c
@@ -9,6 +9,7 @@
#define SUB_REPOSITORY_FOLDER_NAME "sub_repo"
#define SUB_REPOSITORY_FOLDER DISCOVER_FOLDER "/" SUB_REPOSITORY_FOLDER_NAME
+#define SUB_REPOSITORY_GITDIR SUB_REPOSITORY_FOLDER "/.git"
#define SUB_REPOSITORY_FOLDER_SUB SUB_REPOSITORY_FOLDER "/sub"
#define SUB_REPOSITORY_FOLDER_SUB_SUB SUB_REPOSITORY_FOLDER_SUB "/subsub"
#define SUB_REPOSITORY_FOLDER_SUB_SUB_SUB SUB_REPOSITORY_FOLDER_SUB_SUB "/subsubsub"
@@ -24,20 +25,26 @@
#define ALTERNATE_NOT_FOUND_FOLDER DISCOVER_FOLDER "/alternate_not_found_repo"
static void ensure_repository_discover(const char *start_path,
- const char *ceiling_dirs,
- git_buf *expected_path)
+ const char *ceiling_dirs,
+ const char *expected_path)
{
- git_buf found_path = GIT_BUF_INIT;
- cl_git_pass(git_repository_discover(&found_path, start_path, 0, ceiling_dirs));
- //across_fs is always 0 as we can't automate the filesystem change tests
- cl_assert_equal_s(found_path.ptr, expected_path->ptr);
+ git_buf found_path = GIT_BUF_INIT, resolved = GIT_BUF_INIT;
+
+ git_buf_attach(&resolved, p_realpath(expected_path, NULL), 0);
+ cl_assert(resolved.size > 0);
+ cl_git_pass(git_path_to_dir(&resolved));
+ cl_git_pass(git_repository_discover(&found_path, start_path, 1, ceiling_dirs));
+
+ cl_assert_equal_s(found_path.ptr, resolved.ptr);
+
+ git_buf_free(&resolved);
git_buf_free(&found_path);
}
static void write_file(const char *path, const char *content)
{
git_file file;
- int error;
+ int error;
if (git_path_exists(path)) {
cl_git_pass(p_unlink(path));
@@ -68,42 +75,30 @@ static void append_ceiling_dir(git_buf *ceiling_dirs, const char *path)
cl_assert(git_buf_oom(ceiling_dirs) == 0);
}
-void test_repo_discover__0(void)
+static git_buf discovered;
+static git_buf ceiling_dirs;
+
+void test_repo_discover__initialize(void)
{
- // test discover
git_repository *repo;
- git_buf ceiling_dirs_buf = GIT_BUF_INIT, repository_path = GIT_BUF_INIT,
- sub_repository_path = GIT_BUF_INIT, found_path = GIT_BUF_INIT;
- const char *ceiling_dirs;
const mode_t mode = 0777;
-
git_futils_mkdir_r(DISCOVER_FOLDER, mode);
- append_ceiling_dir(&ceiling_dirs_buf, TEMP_REPO_FOLDER);
- ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf);
- cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&repository_path, DISCOVER_FOLDER, 0, ceiling_dirs));
+ git_buf_init(&discovered, 0);
+ git_buf_init(&ceiling_dirs, 0);
+ append_ceiling_dir(&ceiling_dirs, TEMP_REPO_FOLDER);
cl_git_pass(git_repository_init(&repo, DISCOVER_FOLDER, 1));
- cl_git_pass(git_repository_discover(&repository_path, DISCOVER_FOLDER, 0, ceiling_dirs));
git_repository_free(repo);
cl_git_pass(git_repository_init(&repo, SUB_REPOSITORY_FOLDER, 0));
cl_git_pass(git_futils_mkdir_r(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, mode));
- cl_git_pass(git_repository_discover(&sub_repository_path, SUB_REPOSITORY_FOLDER, 0, ceiling_dirs));
-
cl_git_pass(git_futils_mkdir_r(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, mode));
- ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB, ceiling_dirs, &sub_repository_path);
- ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB, ceiling_dirs, &sub_repository_path);
- ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, ceiling_dirs, &sub_repository_path);
cl_git_pass(git_futils_mkdir_r(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, mode));
write_file(REPOSITORY_ALTERNATE_FOLDER "/" DOT_GIT, "gitdir: ../" SUB_REPOSITORY_FOLDER_NAME "/" DOT_GIT);
write_file(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB "/" DOT_GIT, "gitdir: ../../../" SUB_REPOSITORY_FOLDER_NAME "/" DOT_GIT);
write_file(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB "/" DOT_GIT, "gitdir: ../../../../");
- ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER, ceiling_dirs, &sub_repository_path);
- ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB, ceiling_dirs, &sub_repository_path);
- ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs, &sub_repository_path);
- ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs, &repository_path);
cl_git_pass(git_futils_mkdir_r(ALTERNATE_MALFORMED_FOLDER1, mode));
write_file(ALTERNATE_MALFORMED_FOLDER1 "/" DOT_GIT, "Anything but not gitdir:");
@@ -113,41 +108,103 @@ void test_repo_discover__0(void)
write_file(ALTERNATE_MALFORMED_FOLDER3 "/" DOT_GIT, "gitdir: \n\n\n");
cl_git_pass(git_futils_mkdir_r(ALTERNATE_NOT_FOUND_FOLDER, mode));
write_file(ALTERNATE_NOT_FOUND_FOLDER "/" DOT_GIT, "gitdir: a_repository_that_surely_does_not_exist");
- cl_git_fail(git_repository_discover(&found_path, ALTERNATE_MALFORMED_FOLDER1, 0, ceiling_dirs));
- cl_git_fail(git_repository_discover(&found_path, ALTERNATE_MALFORMED_FOLDER2, 0, ceiling_dirs));
- cl_git_fail(git_repository_discover(&found_path, ALTERNATE_MALFORMED_FOLDER3, 0, ceiling_dirs));
- cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, ALTERNATE_NOT_FOUND_FOLDER, 0, ceiling_dirs));
- append_ceiling_dir(&ceiling_dirs_buf, SUB_REPOSITORY_FOLDER_SUB);
- ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf);
+ git_repository_free(repo);
+}
+
+void test_repo_discover__cleanup(void)
+{
+ git_buf_free(&discovered);
+ git_buf_free(&ceiling_dirs);
+ cl_git_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, NULL, GIT_RMDIR_REMOVE_FILES));
+}
+
+void test_repo_discover__discovering_repo_with_exact_path_succeeds(void)
+{
+ cl_git_pass(git_repository_discover(&discovered, DISCOVER_FOLDER, 0, ceiling_dirs.ptr));
+ cl_git_pass(git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER, 0, ceiling_dirs.ptr));
+}
+
+void test_repo_discover__discovering_nonexistent_dir_fails(void)
+{
+ cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, DISCOVER_FOLDER "-nonexistent", 0, NULL));
+}
+
+void test_repo_discover__discovering_repo_with_subdirectory_succeeds(void)
+{
+ ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
+ ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
+ ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
+}
+
+void test_repo_discover__discovering_repository_with_alternative_gitdir_succeeds(void)
+{
+ ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
+ ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
+ ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
+ ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs.ptr, DISCOVER_FOLDER);
+}
+
+void test_repo_discover__discovering_repository_with_malformed_alternative_gitdir_fails(void)
+{
+ cl_git_fail(git_repository_discover(&discovered, ALTERNATE_MALFORMED_FOLDER1, 0, ceiling_dirs.ptr));
+ cl_git_fail(git_repository_discover(&discovered, ALTERNATE_MALFORMED_FOLDER2, 0, ceiling_dirs.ptr));
+ cl_git_fail(git_repository_discover(&discovered, ALTERNATE_MALFORMED_FOLDER3, 0, ceiling_dirs.ptr));
+ cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, ALTERNATE_NOT_FOUND_FOLDER, 0, ceiling_dirs.ptr));
+}
+
+void test_repo_discover__discovering_repository_with_ceiling(void)
+{
+ append_ceiling_dir(&ceiling_dirs, SUB_REPOSITORY_FOLDER_SUB);
/* this must pass as ceiling_directories cannot prevent the current
* working directory to be checked */
- ensure_repository_discover(SUB_REPOSITORY_FOLDER, ceiling_dirs, &sub_repository_path);
- ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB, ceiling_dirs, &sub_repository_path);
- cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs));
- cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs));
-
- append_ceiling_dir(&ceiling_dirs_buf, SUB_REPOSITORY_FOLDER);
- ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf);
-
- //this must pass as ceiling_directories cannot predent the current
- //working directory to be checked
- ensure_repository_discover(SUB_REPOSITORY_FOLDER, ceiling_dirs, &sub_repository_path);
- cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB, 0, ceiling_dirs));
- cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs));
- cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs));
-
- //.gitfile redirection should not be affected by ceiling directories
- ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER, ceiling_dirs, &sub_repository_path);
- ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB, ceiling_dirs, &sub_repository_path);
- ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs, &sub_repository_path);
- ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs, &repository_path);
+ ensure_repository_discover(SUB_REPOSITORY_FOLDER, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
- cl_git_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, NULL, GIT_RMDIR_REMOVE_FILES));
- git_repository_free(repo);
- git_buf_free(&ceiling_dirs_buf);
- git_buf_free(&repository_path);
- git_buf_free(&sub_repository_path);
+ ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
+ cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs.ptr));
+ cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs.ptr));
+}
+
+void test_repo_discover__other_ceiling(void)
+{
+ append_ceiling_dir(&ceiling_dirs, SUB_REPOSITORY_FOLDER);
+
+ /* this must pass as ceiling_directories cannot predent the current
+ * working directory to be checked */
+ ensure_repository_discover(SUB_REPOSITORY_FOLDER, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
+
+ cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER_SUB, 0, ceiling_dirs.ptr));
+ cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs.ptr));
+ cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs.ptr));
+}
+
+void test_repo_discover__ceiling_should_not_affect_gitdir_redirection(void)
+{
+ append_ceiling_dir(&ceiling_dirs, SUB_REPOSITORY_FOLDER);
+
+ /* gitfile redirection should not be affected by ceiling directories */
+ ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
+ ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
+ ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
+ ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs.ptr, DISCOVER_FOLDER);
+}
+
+void test_repo_discover__discovery_starting_at_file_succeeds(void)
+{
+ int fd;
+
+ cl_assert((fd = p_creat(SUB_REPOSITORY_FOLDER "/file", 0600)) >= 0);
+ cl_assert(p_close(fd) == 0);
+
+ ensure_repository_discover(SUB_REPOSITORY_FOLDER "/file", ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
}
+void test_repo_discover__discovery_starting_at_system_root_causes_no_hang(void)
+{
+#ifdef GIT_WIN32
+ git_buf out = GIT_BUF_INIT;
+ cl_git_fail(git_repository_discover(&out, "C:/", 0, NULL));
+ cl_git_fail(git_repository_discover(&out, "//localhost/", 0, NULL));
+#endif
+}
diff --git a/tests/repo/env.c b/tests/repo/env.c
index 5a89c0d49..6404f88e9 100644
--- a/tests/repo/env.c
+++ b/tests/repo/env.c
@@ -56,8 +56,8 @@ static int GIT_FORMAT_PRINTF(2, 3) cl_setenv_printf(const char *name, const char
static void env_pass_(const char *path, const char *file, int line)
{
git_repository *repo;
- cl_git_pass_(git_repository_open_ext(NULL, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), file, line);
- cl_git_pass_(git_repository_open_ext(&repo, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), file, line);
+ cl_git_expect(git_repository_open_ext(NULL, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), 0, file, line);
+ cl_git_expect(git_repository_open_ext(&repo, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), 0, file, line);
cl_assert_at_line(git__suffixcmp(git_repository_path(repo), "attr/.git/") == 0, file, line);
cl_assert_at_line(git__suffixcmp(git_repository_workdir(repo), "attr/") == 0, file, line);
cl_assert_at_line(!git_repository_is_bare(repo), file, line);
@@ -98,24 +98,24 @@ static void env_check_objects_(bool a, bool t, bool p, const char *file, int lin
cl_git_pass(git_oid_fromstr(&oid_a, "45141a79a77842c59a63229403220a4e4be74e3d"));
cl_git_pass(git_oid_fromstr(&oid_t, "1385f264afb75a56a5bec74243be9b367ba4ca08"));
cl_git_pass(git_oid_fromstr(&oid_p, "0df1a5865c8abfc09f1f2182e6a31be550e99f07"));
- cl_git_pass_(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL), file, line);
+ cl_git_expect(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL), 0, file, line);
if (a) {
- cl_git_pass_(git_object_lookup(&object, repo, &oid_a, GIT_OBJ_BLOB), file, line);
+ cl_git_expect(git_object_lookup(&object, repo, &oid_a, GIT_OBJ_BLOB), 0, file, line);
git_object_free(object);
} else {
cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_a, GIT_OBJ_BLOB), file, line);
}
if (t) {
- cl_git_pass_(git_object_lookup(&object, repo, &oid_t, GIT_OBJ_BLOB), file, line);
+ cl_git_expect(git_object_lookup(&object, repo, &oid_t, GIT_OBJ_BLOB), 0, file, line);
git_object_free(object);
} else {
cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_t, GIT_OBJ_BLOB), file, line);
}
if (p) {
- cl_git_pass_(git_object_lookup(&object, repo, &oid_p, GIT_OBJ_COMMIT), file, line);
+ cl_git_expect(git_object_lookup(&object, repo, &oid_p, GIT_OBJ_COMMIT), 0, file, line);
git_object_free(object);
} else {
cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_p, GIT_OBJ_COMMIT), file, line);
diff --git a/tests/repo/head.c b/tests/repo/head.c
index 31c228777..d02116087 100644
--- a/tests/repo/head.c
+++ b/tests/repo/head.c
@@ -261,15 +261,19 @@ void test_repo_head__setting_head_updates_reflog(void)
cl_git_pass(git_revparse_single(&tag, repo, "tags/test"));
cl_git_pass(git_repository_set_head_detached(repo, git_object_id(tag)));
cl_git_pass(git_repository_set_head(repo, "refs/heads/haacked"));
+ cl_git_pass(git_repository_set_head(repo, "refs/tags/test"));
+ cl_git_pass(git_repository_set_head(repo, "refs/remotes/test/master"));
- test_reflog(repo, 2, NULL, "refs/heads/haacked", "foo@example.com", "checkout: moving from master to haacked");
- test_reflog(repo, 1, NULL, "tags/test^{commit}", "foo@example.com", "checkout: moving from unborn to e90810b8df3e80c413d903f631643c716887138d");
- test_reflog(repo, 0, "tags/test^{commit}", "refs/heads/haacked", "foo@example.com", "checkout: moving from e90810b8df3e80c413d903f631643c716887138d to haacked");
+ test_reflog(repo, 4, NULL, "refs/heads/haacked", "foo@example.com", "checkout: moving from master to haacked");
+ test_reflog(repo, 3, NULL, "tags/test^{commit}", "foo@example.com", "checkout: moving from unborn to e90810b8df3e80c413d903f631643c716887138d");
+ test_reflog(repo, 2, "tags/test^{commit}", "refs/heads/haacked", "foo@example.com", "checkout: moving from e90810b8df3e80c413d903f631643c716887138d to haacked");
+ test_reflog(repo, 1, "refs/heads/haacked", "tags/test^{commit}", "foo@example.com", "checkout: moving from haacked to test");
+ test_reflog(repo, 0, "tags/test^{commit}", "refs/remotes/test/master", "foo@example.com", "checkout: moving from e90810b8df3e80c413d903f631643c716887138d to test/master");
cl_git_pass(git_annotated_commit_from_revspec(&annotated, repo, "haacked~0"));
cl_git_pass(git_repository_set_head_detached_from_annotated(repo, annotated));
- test_reflog(repo, 0, NULL, "refs/heads/haacked", "foo@example.com", "checkout: moving from haacked to haacked~0");
+ test_reflog(repo, 0, NULL, "refs/heads/haacked", "foo@example.com", "checkout: moving from be3563ae3f795b2b4353bcce3a527ad0a4f7f644 to haacked~0");
git_annotated_commit_free(annotated);
git_object_free(tag);
diff --git a/tests/repo/init.c b/tests/repo/init.c
index 04d4a5c5e..6a455bfa6 100644
--- a/tests/repo/init.c
+++ b/tests/repo/init.c
@@ -320,6 +320,17 @@ void test_repo_init__sets_logAllRefUpdates_according_to_type_of_repository(void)
assert_config_entry_on_init_bytype("core.logallrefupdates", true, false);
}
+void test_repo_init__empty_template_path(void)
+{
+ git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
+ opts.template_path = "";
+
+ cl_git_pass(git_futils_mkdir("foo", 0755, 0));
+ cl_git_pass(git_repository_init_ext(&_repo, "foo", &opts));
+
+ cleanup_repository("foo");
+}
+
void test_repo_init__extended_0(void)
{
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
diff --git a/tests/repo/open.c b/tests/repo/open.c
index 6114ad2e1..3239b6fec 100644
--- a/tests/repo/open.c
+++ b/tests/repo/open.c
@@ -398,7 +398,8 @@ void test_repo_open__force_bare(void)
cl_git_fail(git_repository_open_bare(&barerepo, "alternate/subdir/sub2"));
cl_git_pass(git_repository_open_ext(
- &barerepo, "alternate/subdir/sub2", GIT_REPOSITORY_OPEN_BARE, NULL));
+ &barerepo, "alternate/subdir/sub2",
+ GIT_REPOSITORY_OPEN_BARE|GIT_REPOSITORY_OPEN_CROSS_FS, NULL));
cl_assert(git_repository_is_bare(barerepo));
git_repository_free(barerepo);
}
diff --git a/tests/resources/diff_format_email/.gitted/index b/tests/resources/diff_format_email/.gitted/index
index d94f87de8..092a888e7 100644
--- a/tests/resources/diff_format_email/.gitted/index
+++ b/tests/resources/diff_format_email/.gitted/index
Binary files differ
diff --git a/tests/resources/diff_format_email/.gitted/objects/06/b7b69a62cbd1e53c6c4e0c3f16473dcfdb4af6 b/tests/resources/diff_format_email/.gitted/objects/06/b7b69a62cbd1e53c6c4e0c3f16473dcfdb4af6
new file mode 100644
index 000000000..37588f169
--- /dev/null
+++ b/tests/resources/diff_format_email/.gitted/objects/06/b7b69a62cbd1e53c6c4e0c3f16473dcfdb4af6
Binary files differ
diff --git a/tests/resources/diff_format_email/.gitted/objects/52/19b9784f9a92d7bd7cb567a6d6a21bfb86697e b/tests/resources/diff_format_email/.gitted/objects/52/19b9784f9a92d7bd7cb567a6d6a21bfb86697e
new file mode 100644
index 000000000..534e3b07d
--- /dev/null
+++ b/tests/resources/diff_format_email/.gitted/objects/52/19b9784f9a92d7bd7cb567a6d6a21bfb86697e
Binary files differ
diff --git a/tests/resources/diff_format_email/.gitted/objects/53/525d4cc3ef3ba4a5cbf69492fdffb4e4a74558 b/tests/resources/diff_format_email/.gitted/objects/53/525d4cc3ef3ba4a5cbf69492fdffb4e4a74558
new file mode 100644
index 000000000..b74d31f4f
--- /dev/null
+++ b/tests/resources/diff_format_email/.gitted/objects/53/525d4cc3ef3ba4a5cbf69492fdffb4e4a74558
Binary files differ
diff --git a/tests/resources/diff_format_email/.gitted/objects/a7/a65f98355b5a7567bcc395f6f7936c9252cf57 b/tests/resources/diff_format_email/.gitted/objects/a7/a65f98355b5a7567bcc395f6f7936c9252cf57
new file mode 100644
index 000000000..36a4b7be6
--- /dev/null
+++ b/tests/resources/diff_format_email/.gitted/objects/a7/a65f98355b5a7567bcc395f6f7936c9252cf57
Binary files differ
diff --git a/tests/resources/diff_format_email/.gitted/objects/c7/1a05d36025c806496a74d46d7d596eb23295c4 b/tests/resources/diff_format_email/.gitted/objects/c7/1a05d36025c806496a74d46d7d596eb23295c4
new file mode 100644
index 000000000..2822fe3e4
--- /dev/null
+++ b/tests/resources/diff_format_email/.gitted/objects/c7/1a05d36025c806496a74d46d7d596eb23295c4
Binary files differ
diff --git a/tests/resources/diff_format_email/.gitted/objects/d3/b6b38486f620b5b532a8cc6e0198ab7c3f52e4 b/tests/resources/diff_format_email/.gitted/objects/d3/b6b38486f620b5b532a8cc6e0198ab7c3f52e4
new file mode 100644
index 000000000..5b2e664f4
--- /dev/null
+++ b/tests/resources/diff_format_email/.gitted/objects/d3/b6b38486f620b5b532a8cc6e0198ab7c3f52e4
Binary files differ
diff --git a/tests/resources/diff_format_email/.gitted/refs/heads/master b/tests/resources/diff_format_email/.gitted/refs/heads/master
index 3bc734d47..4024b97cd 100644
--- a/tests/resources/diff_format_email/.gitted/refs/heads/master
+++ b/tests/resources/diff_format_email/.gitted/refs/heads/master
@@ -1 +1 @@
-627e7e12d87e07a83fad5b6bfa25e86ead4a5270
+5219b9784f9a92d7bd7cb567a6d6a21bfb86697e
diff --git a/tests/resources/diff_format_email/file3.txt b/tests/resources/diff_format_email/file3.txt
index 730965344..c71a05d36 100644
--- a/tests/resources/diff_format_email/file3.txt
+++ b/tests/resources/diff_format_email/file3.txt
@@ -4,3 +4,4 @@ file3
file3
file3
file3
+file3
diff --git a/tests/resources/indexv4/.gitted/HEAD b/tests/resources/indexv4/.gitted/HEAD
new file mode 100644
index 000000000..cb089cd89
--- /dev/null
+++ b/tests/resources/indexv4/.gitted/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests/resources/indexv4/.gitted/config b/tests/resources/indexv4/.gitted/config
new file mode 100644
index 000000000..515f48362
--- /dev/null
+++ b/tests/resources/indexv4/.gitted/config
@@ -0,0 +1,5 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
diff --git a/tests/resources/indexv4/.gitted/index b/tests/resources/indexv4/.gitted/index
new file mode 100644
index 000000000..e8fc61736
--- /dev/null
+++ b/tests/resources/indexv4/.gitted/index
Binary files differ
diff --git a/tests/resources/indexv4/.gitted/objects/4c/9109b3e671d851eec87e0e72f6305b582e7e99 b/tests/resources/indexv4/.gitted/objects/4c/9109b3e671d851eec87e0e72f6305b582e7e99
new file mode 100644
index 000000000..cedd594b0
--- /dev/null
+++ b/tests/resources/indexv4/.gitted/objects/4c/9109b3e671d851eec87e0e72f6305b582e7e99
Binary files differ
diff --git a/tests/resources/indexv4/.gitted/objects/b0/952dbb50bed5f01e03e31b296184cb183e54a7 b/tests/resources/indexv4/.gitted/objects/b0/952dbb50bed5f01e03e31b296184cb183e54a7
new file mode 100644
index 000000000..0ddc1d1a9
--- /dev/null
+++ b/tests/resources/indexv4/.gitted/objects/b0/952dbb50bed5f01e03e31b296184cb183e54a7
Binary files differ
diff --git a/tests/resources/indexv4/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 b/tests/resources/indexv4/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
new file mode 100644
index 000000000..711223894
--- /dev/null
+++ b/tests/resources/indexv4/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
Binary files differ
diff --git a/tests/resources/indexv4/.gitted/refs/heads/master b/tests/resources/indexv4/.gitted/refs/heads/master
new file mode 100644
index 000000000..f3e960eb3
--- /dev/null
+++ b/tests/resources/indexv4/.gitted/refs/heads/master
@@ -0,0 +1 @@
+b0952dbb50bed5f01e03e31b296184cb183e54a7
diff --git a/tests/resources/indexv4/file.tx b/tests/resources/indexv4/file.tx
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/resources/indexv4/file.tx
diff --git a/tests/resources/indexv4/file.txt b/tests/resources/indexv4/file.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/resources/indexv4/file.txt
diff --git a/tests/resources/indexv4/file.txz b/tests/resources/indexv4/file.txz
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/resources/indexv4/file.txz
diff --git a/tests/resources/indexv4/foo b/tests/resources/indexv4/foo
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/resources/indexv4/foo
diff --git a/tests/resources/indexv4/zzz b/tests/resources/indexv4/zzz
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/resources/indexv4/zzz
diff --git a/tests/resources/merge-resolve/.gitted/objects/2a/f2d9bcbc73723ac988bb202d4397f72a6ca7a0 b/tests/resources/merge-resolve/.gitted/objects/2a/f2d9bcbc73723ac988bb202d4397f72a6ca7a0
new file mode 100644
index 000000000..0d658237b
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/2a/f2d9bcbc73723ac988bb202d4397f72a6ca7a0
Binary files differ
diff --git a/tests/resources/merge-resolve/.gitted/objects/37/f53a5a14f64e91089a39ea58e71c87d81df765 b/tests/resources/merge-resolve/.gitted/objects/37/f53a5a14f64e91089a39ea58e71c87d81df765
new file mode 100644
index 000000000..95327ed64
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/37/f53a5a14f64e91089a39ea58e71c87d81df765
@@ -0,0 +1 @@
+xAjC1 D)ّe}%z^ߖ,wpr: tVԶ6RBBLh,9+%rǮh1%p"=Iue{ڶ߶Igrm-23/'|R~Uk{dJ \ No newline at end of file
diff --git a/tests/resources/merge-resolve/.gitted/objects/4d/d1ef7569b18d92d93c0a35bb6b93049137b355 b/tests/resources/merge-resolve/.gitted/objects/4d/d1ef7569b18d92d93c0a35bb6b93049137b355
new file mode 100644
index 000000000..86a21ad50
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/4d/d1ef7569b18d92d93c0a35bb6b93049137b355
Binary files differ
diff --git a/tests/resources/merge-resolve/.gitted/objects/63/ec604d491161ddafdae4179843c26d54bd999a b/tests/resources/merge-resolve/.gitted/objects/63/ec604d491161ddafdae4179843c26d54bd999a
new file mode 100644
index 000000000..bc74da5ba
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/63/ec604d491161ddafdae4179843c26d54bd999a
Binary files differ
diff --git a/tests/resources/merge-resolve/.gitted/objects/68/f7c02064019d89e40e51d7776b6f67914420a2 b/tests/resources/merge-resolve/.gitted/objects/68/f7c02064019d89e40e51d7776b6f67914420a2
new file mode 100644
index 000000000..809a5b38b
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/68/f7c02064019d89e40e51d7776b6f67914420a2
Binary files differ
diff --git a/tests/resources/merge-resolve/.gitted/objects/94/29c05dd6f6f39fc567b4ce923b16df5d3d7a7a b/tests/resources/merge-resolve/.gitted/objects/94/29c05dd6f6f39fc567b4ce923b16df5d3d7a7a
new file mode 100644
index 000000000..d4d93f508
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/94/29c05dd6f6f39fc567b4ce923b16df5d3d7a7a
Binary files differ
diff --git a/tests/resources/merge-resolve/.gitted/objects/a1/07e18a58f38c46086c8f8f1dcd54c40154eeb6 b/tests/resources/merge-resolve/.gitted/objects/a1/07e18a58f38c46086c8f8f1dcd54c40154eeb6
new file mode 100644
index 000000000..598c6a7a6
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/a1/07e18a58f38c46086c8f8f1dcd54c40154eeb6
@@ -0,0 +1,3 @@
+xK
+1]$|`7.{g@&7^Z=
+ja[J pFH ZQIg#P4} n-cy4o]ݟBlVp6 uja_ ?H \ No newline at end of file
diff --git a/tests/resources/merge-resolve/.gitted/objects/a2/d8d1824c68541cca94ffb90f79291eba495921 b/tests/resources/merge-resolve/.gitted/objects/a2/d8d1824c68541cca94ffb90f79291eba495921
new file mode 100644
index 000000000..2d3d94718
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/a2/d8d1824c68541cca94ffb90f79291eba495921
Binary files differ
diff --git a/tests/resources/merge-resolve/.gitted/objects/bc/85d1aad435ff3705a8c30ace85f7542c5736cb b/tests/resources/merge-resolve/.gitted/objects/bc/85d1aad435ff3705a8c30ace85f7542c5736cb
new file mode 100644
index 000000000..ae529fe87
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/bc/85d1aad435ff3705a8c30ace85f7542c5736cb
Binary files differ
diff --git a/tests/resources/merge-resolve/.gitted/objects/c8/26ef8b17b5cd2c4a0023f265f3a423b3aa0388 b/tests/resources/merge-resolve/.gitted/objects/c8/26ef8b17b5cd2c4a0023f265f3a423b3aa0388
new file mode 100644
index 000000000..b655d7c40
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/c8/26ef8b17b5cd2c4a0023f265f3a423b3aa0388
Binary files differ
diff --git a/tests/resources/merge-resolve/.gitted/objects/cd/3e8d4aa06bdc781f264171030bc28f2b370fee b/tests/resources/merge-resolve/.gitted/objects/cd/3e8d4aa06bdc781f264171030bc28f2b370fee
new file mode 100644
index 000000000..144225df1
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/cd/3e8d4aa06bdc781f264171030bc28f2b370fee
Binary files differ
diff --git a/tests/resources/merge-resolve/.gitted/objects/e2/6b8888956137218d8589368a3e606cf50fbb56 b/tests/resources/merge-resolve/.gitted/objects/e2/6b8888956137218d8589368a3e606cf50fbb56
new file mode 100644
index 000000000..d4ec2b972
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/e2/6b8888956137218d8589368a3e606cf50fbb56
Binary files differ
diff --git a/tests/resources/merge-resolve/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 b/tests/resources/merge-resolve/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
new file mode 100644
index 000000000..711223894
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
Binary files differ
diff --git a/tests/resources/merge-resolve/.gitted/objects/f9/7da95f156121bea8f978623628f4cbdbf30b36 b/tests/resources/merge-resolve/.gitted/objects/f9/7da95f156121bea8f978623628f4cbdbf30b36
new file mode 100644
index 000000000..d785511fb
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/f9/7da95f156121bea8f978623628f4cbdbf30b36
@@ -0,0 +1 @@
+x1!E9)0[^^u])zщ%A). dgDCtzSWdMXcb3g/ϵ[P1u/}at}.}Ӊzcơ>15x^iH \ No newline at end of file
diff --git a/tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename1 b/tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename1
new file mode 100644
index 000000000..0ed914fef
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename1
@@ -0,0 +1 @@
+f97da95f156121bea8f978623628f4cbdbf30b36
diff --git a/tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename2 b/tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename2
new file mode 100644
index 000000000..8e020ccfc
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename2
@@ -0,0 +1 @@
+37f53a5a14f64e91089a39ea58e71c87d81df765
diff --git a/tests/resources/rebase-submodule/.gitted/HEAD b/tests/resources/rebase-submodule/.gitted/HEAD
new file mode 100644
index 000000000..cb089cd89
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests/resources/rebase-submodule/.gitted/ORIG_HEAD b/tests/resources/rebase-submodule/.gitted/ORIG_HEAD
new file mode 100644
index 000000000..a1ccbb40d
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/ORIG_HEAD
@@ -0,0 +1 @@
+5fdf086684daae0a8bc61a81afe178edc1e556e7
diff --git a/tests/resources/rebase-submodule/.gitted/config b/tests/resources/rebase-submodule/.gitted/config
new file mode 100644
index 000000000..af2095f84
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/config
@@ -0,0 +1,9 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+[branch "asparagus"]
+ rebase = true
+[branch "master"]
+ rebase = true
diff --git a/tests/resources/rebase-submodule/.gitted/description b/tests/resources/rebase-submodule/.gitted/description
new file mode 100644
index 000000000..498b267a8
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests/resources/rebase-submodule/.gitted/index b/tests/resources/rebase-submodule/.gitted/index
new file mode 100644
index 000000000..b63efabdb
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/index
Binary files differ
diff --git a/tests/resources/rebase-submodule/.gitted/info/exclude b/tests/resources/rebase-submodule/.gitted/info/exclude
new file mode 100644
index 000000000..a5196d1be
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/tests/resources/rebase-submodule/.gitted/info/refs b/tests/resources/rebase-submodule/.gitted/info/refs
new file mode 100644
index 000000000..230a6494b
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/info/refs
@@ -0,0 +1,4 @@
+c64ea52df5b31efd7b73769418dc9e25b8803d25 refs/heads/asparagus
+c64ea52df5b31efd7b73769418dc9e25b8803d25 refs/remotes/origin/HEAD
+c64ea52df5b31efd7b73769418dc9e25b8803d25 refs/remotes/origin/asparagus
+02a35db3f24db554b757b3009bc782784267c743 refs/remotes/origin/master
diff --git a/tests/resources/rebase-submodule/.gitted/objects/01/971e2453a407e4b9f6c865e2c37f4db21da294 b/tests/resources/rebase-submodule/.gitted/objects/01/971e2453a407e4b9f6c865e2c37f4db21da294
new file mode 100644
index 000000000..308b38697
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/01/971e2453a407e4b9f6c865e2c37f4db21da294
@@ -0,0 +1 @@
+xUAj0Юu@Xfd%4Rj"t|>ZA[o)G2R1䠭 qbth&Bԗoi?M<"Z̨ELdY\cڒsu`dhO]K}_XO;E<[(U{R1J \ No newline at end of file
diff --git a/tests/resources/rebase-submodule/.gitted/objects/17/f8ae8ebdd08a4bb272f61b897b308ad42b1b12 b/tests/resources/rebase-submodule/.gitted/objects/17/f8ae8ebdd08a4bb272f61b897b308ad42b1b12
new file mode 100644
index 000000000..79e4c484f
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/17/f8ae8ebdd08a4bb272f61b897b308ad42b1b12
@@ -0,0 +1 @@
+x-Kn0 D)xMȢYv P'jqXt@=3p0qF eҤv&"[^;HHzb6Sq3*1zGmpK|=.yGw:Ǻ" *CNel:eO.Uϵ9mփ5De$+xo}RC \ No newline at end of file
diff --git a/tests/resources/rebase-submodule/.gitted/objects/42/cdad903aef3e7b614675e6584a8be417941911 b/tests/resources/rebase-submodule/.gitted/objects/42/cdad903aef3e7b614675e6584a8be417941911
new file mode 100644
index 000000000..99b5e6d2c
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/42/cdad903aef3e7b614675e6584a8be417941911
Binary files differ
diff --git a/tests/resources/rebase-submodule/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850a b/tests/resources/rebase-submodule/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850a
new file mode 100644
index 000000000..016398531
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850a
Binary files differ
diff --git a/tests/resources/rebase-submodule/.gitted/objects/5b/1e8bccf7787e942aecf61912f94a2c274f85a5 b/tests/resources/rebase-submodule/.gitted/objects/5b/1e8bccf7787e942aecf61912f94a2c274f85a5
new file mode 100644
index 000000000..d4776d883
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/5b/1e8bccf7787e942aecf61912f94a2c274f85a5
Binary files differ
diff --git a/tests/resources/rebase-submodule/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598 b/tests/resources/rebase-submodule/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598
new file mode 100644
index 000000000..6aaf79fcb
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598
Binary files differ
diff --git a/tests/resources/rebase-submodule/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096 b/tests/resources/rebase-submodule/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096
new file mode 100644
index 000000000..ed1de3ada
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096
Binary files differ
diff --git a/tests/resources/rebase-submodule/.gitted/objects/7c/71f7606bd3bfb25d063c970804e7fc00b9605b b/tests/resources/rebase-submodule/.gitted/objects/7c/71f7606bd3bfb25d063c970804e7fc00b9605b
new file mode 100644
index 000000000..ef923e714
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/7c/71f7606bd3bfb25d063c970804e7fc00b9605b
Binary files differ
diff --git a/tests/resources/rebase-submodule/.gitted/objects/7c/7bf85e978f1d18c0566f702d2cb7766b9c8d4f b/tests/resources/rebase-submodule/.gitted/objects/7c/7bf85e978f1d18c0566f702d2cb7766b9c8d4f
new file mode 100644
index 000000000..fe8b15777
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/7c/7bf85e978f1d18c0566f702d2cb7766b9c8d4f
@@ -0,0 +1 @@
+xN0Dd' \V\~/1rw5m|0 tntƺ%kcnu a:K,^W55<i:q^33qe\ ӝ KR &ڡȶJ,Nי#|VhNwDžԙԺ {Y}RYa) \ No newline at end of file
diff --git a/tests/resources/rebase-submodule/.gitted/objects/a7/b066537e6be7109abfe4ff97b675d4e077da20 b/tests/resources/rebase-submodule/.gitted/objects/a7/b066537e6be7109abfe4ff97b675d4e077da20
new file mode 100644
index 000000000..54f9b6617
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/a7/b066537e6be7109abfe4ff97b675d4e077da20
Binary files differ
diff --git a/tests/resources/rebase-submodule/.gitted/objects/ab/6cf22b4c67a274aa8d31b5877d92341e8c2a9c b/tests/resources/rebase-submodule/.gitted/objects/ab/6cf22b4c67a274aa8d31b5877d92341e8c2a9c
new file mode 100644
index 000000000..5acdf362e
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/ab/6cf22b4c67a274aa8d31b5877d92341e8c2a9c
Binary files differ
diff --git a/tests/resources/rebase-submodule/.gitted/objects/c4/e6cca3ec6ae0148ed231f97257df8c311e015f b/tests/resources/rebase-submodule/.gitted/objects/c4/e6cca3ec6ae0148ed231f97257df8c311e015f
new file mode 100644
index 000000000..2bbf28f57
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/c4/e6cca3ec6ae0148ed231f97257df8c311e015f
@@ -0,0 +1 @@
+x%P1n0 WCNEN7:*pԒ/WmI$=^^._?~|C6yTȄA(#1e鴓.(Hto@̸K-as1r6)&)8ŷTa<0ׇJ٢[K5IJcq͓쌫r_ۇ"u^@7~X)2 G,fR`B43vQH֩uab SwcJq)fƔOv; \ No newline at end of file
diff --git a/tests/resources/rebase-submodule/.gitted/objects/f3/6de77de6f53dddafeb024ecaf375e45c3d9ddd b/tests/resources/rebase-submodule/.gitted/objects/f3/6de77de6f53dddafeb024ecaf375e45c3d9ddd
new file mode 100644
index 000000000..cd330a71f
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/f3/6de77de6f53dddafeb024ecaf375e45c3d9ddd
Binary files differ
diff --git a/tests/resources/rebase-submodule/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807d b/tests/resources/rebase-submodule/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807d
new file mode 100644
index 000000000..f655d12ea
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807d
Binary files differ
diff --git a/tests/resources/rebase-submodule/.gitted/packed-refs b/tests/resources/rebase-submodule/.gitted/packed-refs
new file mode 100644
index 000000000..44ac842a1
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/packed-refs
@@ -0,0 +1,2 @@
+# pack-refs with: peeled fully-peeled
+c64ea52df5b31efd7b73769418dc9e25b8803d25 refs/heads/asparagus
diff --git a/tests/resources/rebase-submodule/.gitted/refs/heads/asparagus b/tests/resources/rebase-submodule/.gitted/refs/heads/asparagus
new file mode 100644
index 000000000..e6adde8e6
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/refs/heads/asparagus
@@ -0,0 +1 @@
+17f8ae8ebdd08a4bb272f61b897b308ad42b1b12
diff --git a/tests/resources/rebase-submodule/.gitted/refs/heads/master b/tests/resources/rebase-submodule/.gitted/refs/heads/master
new file mode 100644
index 000000000..2523d491d
--- /dev/null
+++ b/tests/resources/rebase-submodule/.gitted/refs/heads/master
@@ -0,0 +1 @@
+01971e2453a407e4b9f6c865e2c37f4db21da294
diff --git a/tests/resources/rebase-submodule/asparagus.txt b/tests/resources/rebase-submodule/asparagus.txt
new file mode 100644
index 000000000..ffb36e513
--- /dev/null
+++ b/tests/resources/rebase-submodule/asparagus.txt
@@ -0,0 +1,10 @@
+ASPARAGUS SOUP.
+
+Take four large bunches of asparagus, scrape it nicely, cut off one inch
+of the tops, and lay them in water, chop the stalks and put them on the
+fire with a piece of bacon, a large onion cut up, and pepper and salt;
+add two quarts of water, boil them till the stalks are quite soft, then
+pulp them through a sieve, and strain the water to it, which must be put
+back in the pot; put into it a chicken cut up, with the tops of
+asparagus which had been laid by, boil it until these last articles are
+sufficiently done, thicken with flour, butter and milk, and serve it up.
diff --git a/tests/resources/rebase-submodule/beef.txt b/tests/resources/rebase-submodule/beef.txt
new file mode 100644
index 000000000..68f6182f4
--- /dev/null
+++ b/tests/resources/rebase-submodule/beef.txt
@@ -0,0 +1,22 @@
+BEEF SOUP.
+
+Take the hind shin of beef, cut off all the flesh off the leg-bone,
+which must be taken away entirely, or the soup will be greasy. Wash the
+meat clean and lay it in a pot, sprinkle over it one small
+table-spoonful of pounded black pepper, and two of salt; three onions
+the size of a hen's egg, cut small, six small carrots scraped and cut
+up, two small turnips pared and cut into dice; pour on three quarts of
+water, cover the pot close, and keep it gently and steadily boiling five
+hours, which will leave about three pints of clear soup; do not let the
+pot boil over, but take off the scum carefully, as it rises. When it has
+boiled four hours, put in a small bundle of thyme and parsley, and a
+pint of celery cut small, or a tea-spoonful of celery seed pounded.
+These latter ingredients would lose their delicate flavour if boiled too
+much. Just before you take it up, brown it in the following manner: put
+a small table-spoonful of nice brown sugar into an iron skillet, set it
+on the fire and stir it till it melts and looks very dark, pour into it
+a ladle full of the soup, a little at a time; stirring it all the while.
+Strain this browning and mix it well with the soup; take out the bundle
+of thyme and parsley, put the nicest pieces of meat in your tureen, and
+pour on the soup and vegetables; put in some toasted bread cut in dice,
+and serve it up.
diff --git a/tests/resources/rebase-submodule/bouilli.txt b/tests/resources/rebase-submodule/bouilli.txt
new file mode 100644
index 000000000..4b7c56500
--- /dev/null
+++ b/tests/resources/rebase-submodule/bouilli.txt
@@ -0,0 +1,18 @@
+SOUP WITH BOUILLI.
+
+Take the nicest part of the thick brisket of beef, about eight pounds,
+put it into a pot with every thing directed for the other soup; make it
+exactly in the same way, only put it on an hour sooner, that you may
+have time to prepare the bouilli; after it has boiled five hours, take
+out the beef, cover up the soup and set it near the fire that it may
+keep hot. Take the skin off the beef, have the yelk of an egg well
+beaten, dip a feather in it and wash the top of your beef, sprinkle over
+it the crumb of stale bread finely grated, put it in a Dutch oven
+previously heated, put the top on with coals enough to brown, but not
+burn the beef; let it stand nearly an hour, and prepare your gravy
+thus:--Take a sufficient quantity of soup and the vegetables boiled in
+it; add to it a table-spoonful of red wine, and two of mushroom catsup,
+thicken with a little bit of butter and a little brown flour; make it
+very hot, pour it in your dish, and put the beef on it. Garnish it with
+green pickle, cut in thin slices, serve up the soup in a tureen with
+bits of toasted bread.
diff --git a/tests/resources/rebase-submodule/gitmodules b/tests/resources/rebase-submodule/gitmodules
new file mode 100644
index 000000000..f36de77de
--- /dev/null
+++ b/tests/resources/rebase-submodule/gitmodules
@@ -0,0 +1,3 @@
+[submodule "my-submodule"]
+ path = my-submodule
+ url = bogus
diff --git a/tests/resources/rebase-submodule/gravy.txt b/tests/resources/rebase-submodule/gravy.txt
new file mode 100644
index 000000000..c4e6cca3e
--- /dev/null
+++ b/tests/resources/rebase-submodule/gravy.txt
@@ -0,0 +1,8 @@
+GRAVY SOUP.
+
+Get eight pounds of coarse lean beef--wash it clean and lay it in your
+pot, put in the same ingredients as for the shin soup, with the same
+quantity of water, and follow the process directed for that. Strain the
+soup through a sieve, and serve it up clear, with nothing more than
+toasted bread in it; two table-spoonsful of mushroom catsup will add a
+fine flavour to the soup.
diff --git a/tests/resources/rebase-submodule/oyster.txt b/tests/resources/rebase-submodule/oyster.txt
new file mode 100644
index 000000000..68af1fc74
--- /dev/null
+++ b/tests/resources/rebase-submodule/oyster.txt
@@ -0,0 +1,13 @@
+OYSTER SOUP.
+
+Wash and drain two quarts of oysters, put them on with three quarts of
+water, three onions chopped up, two or three slices of lean ham, pepper
+and salt; boil it till reduced one-half, strain it through a sieve,
+return the liquid into the pot, put in one quart of fresh oysters, boil
+it till they are sufficiently done, and thicken the soup with four
+spoonsful of flour, two gills of rich cream, and the yelks of six new
+laid eggs beaten well; boil it a few minutes after the thickening is put
+in. Take care that it does not curdle, and that the flour is not in
+lumps; serve it up with the last oysters that were put in. If the
+flavour of thyme be agreeable, you may put in a little, but take care
+that it does not boil in it long enough to discolour the soup.
diff --git a/tests/resources/rebase-submodule/veal.txt b/tests/resources/rebase-submodule/veal.txt
new file mode 100644
index 000000000..a7b066537
--- /dev/null
+++ b/tests/resources/rebase-submodule/veal.txt
@@ -0,0 +1,18 @@
+VEAL SOUP.
+
+Put into a pot three quarts of water, three onions cut small, one
+spoonful of black pepper pounded, and two of salt, with two or three
+slices of lean ham; let it boil steadily two hours; skim it
+occasionally, then put into it a shin of veal, let it boil two hours
+longer; take out the slices of ham, and skim off the grease if any
+should rise, take a gill of good cream, mix with it two table-spoonsful
+of flour very nicely, and the yelks of two eggs beaten well, strain this
+mixture, and add some chopped parsley; pour some soup on by degrees,
+stir it well, and pour it into the pot, continuing to stir until it has
+boiled two or three minutes to take off the raw taste of the eggs. If
+the cream be not perfectly sweet, and the eggs quite new, the thickening
+will curdle in the soup. For a change you may put a dozen ripe tomatos
+in, first taking off their skins, by letting them stand a few minutes in
+hot water, when they may be easily peeled. When made in this way you
+must thicken it with the flour only. Any part of the veal may be used,
+but the shin or knuckle is the nicest.
diff --git a/tests/resources/sha1/hello_c b/tests/resources/sha1/hello_c
new file mode 100644
index 000000000..45950b2ad
--- /dev/null
+++ b/tests/resources/sha1/hello_c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ printf("Hello, %s\n", "world");
+}
diff --git a/tests/resources/sha1/shattered-1.pdf b/tests/resources/sha1/shattered-1.pdf
new file mode 100644
index 000000000..ba9aaa145
--- /dev/null
+++ b/tests/resources/sha1/shattered-1.pdf
Binary files differ
diff --git a/tests/resources/submodules-worktree-child/.gitted b/tests/resources/submodules-worktree-child/.gitted
new file mode 100644
index 000000000..03286f522
--- /dev/null
+++ b/tests/resources/submodules-worktree-child/.gitted
@@ -0,0 +1 @@
+gitdir: ../submodules/testrepo/.git/worktrees/submodules-worktree-child
diff --git a/tests/resources/submodules-worktree-child/README b/tests/resources/submodules-worktree-child/README
new file mode 100644
index 000000000..a8233120f
--- /dev/null
+++ b/tests/resources/submodules-worktree-child/README
@@ -0,0 +1 @@
+hey there
diff --git a/tests/resources/submodules-worktree-child/branch_file.txt b/tests/resources/submodules-worktree-child/branch_file.txt
new file mode 100644
index 000000000..3697d64be
--- /dev/null
+++ b/tests/resources/submodules-worktree-child/branch_file.txt
@@ -0,0 +1,2 @@
+hi
+bye!
diff --git a/tests/resources/submodules-worktree-child/new.txt b/tests/resources/submodules-worktree-child/new.txt
new file mode 100644
index 000000000..a71586c1d
--- /dev/null
+++ b/tests/resources/submodules-worktree-child/new.txt
@@ -0,0 +1 @@
+my new file
diff --git a/tests/resources/submodules-worktree-parent/.gitmodules b/tests/resources/submodules-worktree-parent/.gitmodules
new file mode 100644
index 000000000..78308c925
--- /dev/null
+++ b/tests/resources/submodules-worktree-parent/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "testrepo"]
+ path = testrepo
+ url = /Users/rb/src/libgit2/tests/resources/testrepo.git
diff --git a/tests/resources/submodules-worktree-parent/.gitted b/tests/resources/submodules-worktree-parent/.gitted
new file mode 100644
index 000000000..87bd9ae29
--- /dev/null
+++ b/tests/resources/submodules-worktree-parent/.gitted
@@ -0,0 +1 @@
+gitdir: ../submodules/.git/worktrees/submodules-worktree-parent
diff --git a/tests/resources/submodules-worktree-parent/deleted b/tests/resources/submodules-worktree-parent/deleted
new file mode 100644
index 000000000..092bfb9bd
--- /dev/null
+++ b/tests/resources/submodules-worktree-parent/deleted
@@ -0,0 +1 @@
+yo
diff --git a/tests/resources/submodules-worktree-parent/modified b/tests/resources/submodules-worktree-parent/modified
new file mode 100644
index 000000000..092bfb9bd
--- /dev/null
+++ b/tests/resources/submodules-worktree-parent/modified
@@ -0,0 +1 @@
+yo
diff --git a/tests/resources/submodules-worktree-parent/unmodified b/tests/resources/submodules-worktree-parent/unmodified
new file mode 100644
index 000000000..092bfb9bd
--- /dev/null
+++ b/tests/resources/submodules-worktree-parent/unmodified
@@ -0,0 +1 @@
+yo
diff --git a/tests/resources/submodules.git/HEAD b/tests/resources/submodules.git/HEAD
new file mode 100644
index 000000000..cb089cd89
--- /dev/null
+++ b/tests/resources/submodules.git/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests/resources/submodules.git/config b/tests/resources/submodules.git/config
new file mode 100644
index 000000000..07d359d07
--- /dev/null
+++ b/tests/resources/submodules.git/config
@@ -0,0 +1,4 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = true
diff --git a/tests/resources/submodules.git/objects/26/a3b32a9b7d97486c5557f5902e8ac94638145e b/tests/resources/submodules.git/objects/26/a3b32a9b7d97486c5557f5902e8ac94638145e
new file mode 100644
index 000000000..2c3c2cb61
--- /dev/null
+++ b/tests/resources/submodules.git/objects/26/a3b32a9b7d97486c5557f5902e8ac94638145e
@@ -0,0 +1,2 @@
+x%=
+0 F])0"I*|-t{?2ilV8$mvkk*F DA=(=|=6 DAv=A}&'O$= \ No newline at end of file
diff --git a/tests/resources/submodules.git/objects/78/308c9251cf4eee8b25a76c7d2790c73d797357 b/tests/resources/submodules.git/objects/78/308c9251cf4eee8b25a76c7d2790c73d797357
new file mode 100644
index 000000000..c85fb5512
--- /dev/null
+++ b/tests/resources/submodules.git/objects/78/308c9251cf4eee8b25a76c7d2790c73d797357
Binary files differ
diff --git a/tests/resources/submodules.git/objects/97/896810b3210244a62a82458b8e0819ecfc6850 b/tests/resources/submodules.git/objects/97/896810b3210244a62a82458b8e0819ecfc6850
new file mode 100644
index 000000000..1c8dbdf9f
--- /dev/null
+++ b/tests/resources/submodules.git/objects/97/896810b3210244a62a82458b8e0819ecfc6850
@@ -0,0 +1,3 @@
+x[
+0E*fʤS K4ݿwׅ9p2MCFP @u..p!OYdiYU'̕8XbPn6
+ħԞ1[q}0qc[W#1fR:SZ+Y+{tdlvOmu_}5i` K \ No newline at end of file
diff --git a/tests/resources/submodules.git/objects/b6/0fd986699ba4e9e68bea07cf8e793f323ef888 b/tests/resources/submodules.git/objects/b6/0fd986699ba4e9e68bea07cf8e793f323ef888
new file mode 100644
index 000000000..3d78bd6be
--- /dev/null
+++ b/tests/resources/submodules.git/objects/b6/0fd986699ba4e9e68bea07cf8e793f323ef888
Binary files differ
diff --git a/tests/resources/submodules.git/objects/d5/f7fc3f74f7dec08280f370a975b112e8f60818 b/tests/resources/submodules.git/objects/d5/f7fc3f74f7dec08280f370a975b112e8f60818
new file mode 100644
index 000000000..6e0b49e86
--- /dev/null
+++ b/tests/resources/submodules.git/objects/d5/f7fc3f74f7dec08280f370a975b112e8f60818
Binary files differ
diff --git a/tests/resources/submodules.git/objects/e3/50052cc767cd1fcb37e84e9a89e701925be4ae b/tests/resources/submodules.git/objects/e3/50052cc767cd1fcb37e84e9a89e701925be4ae
new file mode 100644
index 000000000..082a58941
--- /dev/null
+++ b/tests/resources/submodules.git/objects/e3/50052cc767cd1fcb37e84e9a89e701925be4ae
Binary files differ
diff --git a/tests/resources/submodules.git/objects/info/packs b/tests/resources/submodules.git/objects/info/packs
new file mode 100644
index 000000000..0785ef698
--- /dev/null
+++ b/tests/resources/submodules.git/objects/info/packs
@@ -0,0 +1,2 @@
+P pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.pack
+
diff --git a/tests/resources/submodules.git/objects/pack/pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.idx b/tests/resources/submodules.git/objects/pack/pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.idx
new file mode 100644
index 000000000..810fc3181
--- /dev/null
+++ b/tests/resources/submodules.git/objects/pack/pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.idx
Binary files differ
diff --git a/tests/resources/submodules.git/objects/pack/pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.pack b/tests/resources/submodules.git/objects/pack/pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.pack
new file mode 100644
index 000000000..c25c4a73f
--- /dev/null
+++ b/tests/resources/submodules.git/objects/pack/pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.pack
Binary files differ
diff --git a/tests/resources/submodules.git/refs/heads/master b/tests/resources/submodules.git/refs/heads/master
new file mode 100644
index 000000000..32b935853
--- /dev/null
+++ b/tests/resources/submodules.git/refs/heads/master
@@ -0,0 +1 @@
+97896810b3210244a62a82458b8e0819ecfc6850
diff --git a/tests/resources/submodules/.gitted/logs/refs/heads/submodules-worktree-parent b/tests/resources/submodules/.gitted/logs/refs/heads/submodules-worktree-parent
new file mode 100644
index 000000000..65e988535
--- /dev/null
+++ b/tests/resources/submodules/.gitted/logs/refs/heads/submodules-worktree-parent
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 97896810b3210244a62a82458b8e0819ecfc6850 Patrick Steinhardt <ps@pks.im> 1447084240 +0100 branch: Created from HEAD
diff --git a/tests/resources/submodules/.gitted/refs/heads/submodules-worktree-parent b/tests/resources/submodules/.gitted/refs/heads/submodules-worktree-parent
new file mode 100644
index 000000000..32b935853
--- /dev/null
+++ b/tests/resources/submodules/.gitted/refs/heads/submodules-worktree-parent
@@ -0,0 +1 @@
+97896810b3210244a62a82458b8e0819ecfc6850
diff --git a/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/HEAD b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/HEAD
new file mode 100644
index 000000000..a07134b85
--- /dev/null
+++ b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/submodules-worktree-parent
diff --git a/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/ORIG_HEAD b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/ORIG_HEAD
new file mode 100644
index 000000000..32b935853
--- /dev/null
+++ b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/ORIG_HEAD
@@ -0,0 +1 @@
+97896810b3210244a62a82458b8e0819ecfc6850
diff --git a/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/commondir b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/commondir
new file mode 100644
index 000000000..aab0408ce
--- /dev/null
+++ b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/commondir
@@ -0,0 +1 @@
+../..
diff --git a/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/gitdir b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/gitdir
new file mode 100644
index 000000000..eaaf13b95
--- /dev/null
+++ b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/gitdir
@@ -0,0 +1 @@
+../../../../submodules-worktree-parent/.git
diff --git a/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/index b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/index
new file mode 100644
index 000000000..5b68f18a4
--- /dev/null
+++ b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/index
Binary files differ
diff --git a/tests/resources/submodules/testrepo/.gitted/config b/tests/resources/submodules/testrepo/.gitted/config
index d6dcad12b..8e5571191 100644
--- a/tests/resources/submodules/testrepo/.gitted/config
+++ b/tests/resources/submodules/testrepo/.gitted/config
@@ -4,9 +4,6 @@
bare = false
logallrefupdates = true
ignorecase = true
-[remote "origin"]
- fetch = +refs/heads/*:refs/remotes/origin/*
- url = /Users/rb/src/libgit2/tests/resources/testrepo.git
[branch "master"]
remote = origin
merge = refs/heads/master
diff --git a/tests/resources/submodules/testrepo/.gitted/logs/refs/heads/submodules-worktree-child b/tests/resources/submodules/testrepo/.gitted/logs/refs/heads/submodules-worktree-child
new file mode 100644
index 000000000..dd4650ff8
--- /dev/null
+++ b/tests/resources/submodules/testrepo/.gitted/logs/refs/heads/submodules-worktree-child
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 a65fedf39aefe402d3bb6e24df4d4f5fe4547750 Patrick Steinhardt <ps@pks.im> 1447084252 +0100 branch: Created from HEAD
diff --git a/tests/resources/submodules/testrepo/.gitted/refs/heads/submodules-worktree-child b/tests/resources/submodules/testrepo/.gitted/refs/heads/submodules-worktree-child
new file mode 100644
index 000000000..3d8f0a402
--- /dev/null
+++ b/tests/resources/submodules/testrepo/.gitted/refs/heads/submodules-worktree-child
@@ -0,0 +1 @@
+a65fedf39aefe402d3bb6e24df4d4f5fe4547750
diff --git a/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/HEAD b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/HEAD
new file mode 100644
index 000000000..ef82bd4df
--- /dev/null
+++ b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/submodules-worktree-child
diff --git a/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/ORIG_HEAD b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/ORIG_HEAD
new file mode 100644
index 000000000..3d8f0a402
--- /dev/null
+++ b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/ORIG_HEAD
@@ -0,0 +1 @@
+a65fedf39aefe402d3bb6e24df4d4f5fe4547750
diff --git a/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/commondir b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/commondir
new file mode 100644
index 000000000..aab0408ce
--- /dev/null
+++ b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/commondir
@@ -0,0 +1 @@
+../..
diff --git a/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/gitdir b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/gitdir
new file mode 100644
index 000000000..b0ef96e11
--- /dev/null
+++ b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/gitdir
@@ -0,0 +1 @@
+../../../../../submodules-worktree-child/.git
diff --git a/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/index b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/index
new file mode 100644
index 000000000..52a42f966
--- /dev/null
+++ b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/index
Binary files differ
diff --git a/tests/resources/testrepo-worktree/.gitted b/tests/resources/testrepo-worktree/.gitted
new file mode 100644
index 000000000..fe4556a92
--- /dev/null
+++ b/tests/resources/testrepo-worktree/.gitted
@@ -0,0 +1 @@
+gitdir: ../testrepo/.git/worktrees/testrepo-worktree
diff --git a/tests/resources/testrepo-worktree/README b/tests/resources/testrepo-worktree/README
new file mode 100644
index 000000000..a8233120f
--- /dev/null
+++ b/tests/resources/testrepo-worktree/README
@@ -0,0 +1 @@
+hey there
diff --git a/tests/resources/testrepo-worktree/branch_file.txt b/tests/resources/testrepo-worktree/branch_file.txt
new file mode 100644
index 000000000..3697d64be
--- /dev/null
+++ b/tests/resources/testrepo-worktree/branch_file.txt
@@ -0,0 +1,2 @@
+hi
+bye!
diff --git a/tests/resources/testrepo-worktree/link_to_new.txt b/tests/resources/testrepo-worktree/link_to_new.txt
new file mode 120000
index 000000000..c0528fd6c
--- /dev/null
+++ b/tests/resources/testrepo-worktree/link_to_new.txt
@@ -0,0 +1 @@
+new.txt \ No newline at end of file
diff --git a/tests/resources/testrepo-worktree/new.txt b/tests/resources/testrepo-worktree/new.txt
new file mode 100644
index 000000000..a71586c1d
--- /dev/null
+++ b/tests/resources/testrepo-worktree/new.txt
@@ -0,0 +1 @@
+my new file
diff --git a/tests/resources/testrepo.git/objects/43/da5ec3274dd061df152ff5e69853d562b01842 b/tests/resources/testrepo.git/objects/43/da5ec3274dd061df152ff5e69853d562b01842
new file mode 100644
index 000000000..298feece4
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/43/da5ec3274dd061df152ff5e69853d562b01842
@@ -0,0 +1,2 @@
+x-]jC!F*f)]@
+ 8 Zۯiv>Os0B%s)fMlhV45 &4ѕ@:D)oIr`$LYws¥Fg`$bo; U|zOu}/._ׁ~J \ No newline at end of file
diff --git a/tests/resources/testrepo.git/objects/43/e968a905a821532069bb413801d35b200631cf b/tests/resources/testrepo.git/objects/43/e968a905a821532069bb413801d35b200631cf
new file mode 100644
index 000000000..ec04abf68
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/43/e968a905a821532069bb413801d35b200631cf
@@ -0,0 +1,4 @@
+xK
+1]}%N'7 8
+\u5zc 68b,D20'Qb㭃@ҩRQ[94)qsmp+
+纾gG=r]/3((tRa>E \ No newline at end of file
diff --git a/tests/resources/testrepo.git/objects/5d/0f8f7891e872d284beef38254882dc879b2602 b/tests/resources/testrepo.git/objects/5d/0f8f7891e872d284beef38254882dc879b2602
new file mode 100644
index 000000000..7a22451ed
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/5d/0f8f7891e872d284beef38254882dc879b2602
Binary files differ
diff --git a/tests/resources/testrepo.git/objects/5f/34cd6e3285089647165983482cf90873d50940 b/tests/resources/testrepo.git/objects/5f/34cd6e3285089647165983482cf90873d50940
new file mode 100644
index 000000000..b1df3bdd5
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/5f/34cd6e3285089647165983482cf90873d50940
Binary files differ
diff --git a/tests/resources/testrepo.git/objects/8e/73b769e97678d684b809b163bebdae2911720f b/tests/resources/testrepo.git/objects/8e/73b769e97678d684b809b163bebdae2911720f
new file mode 100644
index 000000000..d75977a25
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/8e/73b769e97678d684b809b163bebdae2911720f
@@ -0,0 +1,2 @@
+xj0S)*a㚔+l8[A 33yM$m* $qG?YA5< t8r57nD#.d)~N0˄)R,|,hjQ*tC~ |uzҧݗ>
+ƒd8\S]!7 s ,[P2fw^ \ No newline at end of file
diff --git a/tests/resources/testrepo.git/objects/b2/04707bbc546a1a770ef6ced37c7089cc3bfe6b b/tests/resources/testrepo.git/objects/b2/04707bbc546a1a770ef6ced37c7089cc3bfe6b
new file mode 100644
index 000000000..f9ec61c1e
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/b2/04707bbc546a1a770ef6ced37c7089cc3bfe6b
@@ -0,0 +1,2 @@
+x-]0 })t.Q J),{-7^\^ҷA7(FW"A%ɣygiTId?_#[(-D0wdpR*\Bi ~[;|madjRja
+kRstmG"7{~LD \ No newline at end of file
diff --git a/tests/resources/testrepo.git/objects/b2/35959d89084af8d3544fbdf675e47944f86524 b/tests/resources/testrepo.git/objects/b2/35959d89084af8d3544fbdf675e47944f86524
new file mode 100644
index 000000000..7d563dbd3
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/b2/35959d89084af8d3544fbdf675e47944f86524
Binary files differ
diff --git a/tests/resources/testrepo.git/objects/b9/1e763008b10db366442469339f90a2b8400d0a b/tests/resources/testrepo.git/objects/b9/1e763008b10db366442469339f90a2b8400d0a
new file mode 100644
index 000000000..7bab59be8
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/b9/1e763008b10db366442469339f90a2b8400d0a
Binary files differ
diff --git a/tests/resources/testrepo.git/objects/bd/758010071961f28336333bc41e9c64c9a64866 b/tests/resources/testrepo.git/objects/bd/758010071961f28336333bc41e9c64c9a64866
new file mode 100644
index 000000000..c5e3b87ad
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/bd/758010071961f28336333bc41e9c64c9a64866
Binary files differ
diff --git a/tests/resources/testrepo.git/objects/db/4df74a2fc340a0d0cb0cafc0db471fdfff1048 b/tests/resources/testrepo.git/objects/db/4df74a2fc340a0d0cb0cafc0db471fdfff1048
new file mode 100644
index 000000000..5f3d50efa
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/db/4df74a2fc340a0d0cb0cafc0db471fdfff1048
@@ -0,0 +1,2 @@
+x-QJ1PsIz2= @/tz7f",^߬WպpFWgkѭ`$8J0c5
+I҈J>!+NU(û1Di<_7.5O X[#fo; ]\e=[@t&xHhYJn \ No newline at end of file
diff --git a/tests/resources/testrepo.git/objects/db/793a00a5615eca1aac97e42b3a68b1acfa8bfd b/tests/resources/testrepo.git/objects/db/793a00a5615eca1aac97e42b3a68b1acfa8bfd
new file mode 100644
index 000000000..ae82880de
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/db/793a00a5615eca1aac97e42b3a68b1acfa8bfd
Binary files differ
diff --git a/tests/resources/testrepo.git/objects/db/c0be625bed24b5d8f5d9a927484f2065d321af b/tests/resources/testrepo.git/objects/db/c0be625bed24b5d8f5d9a927484f2065d321af
new file mode 100644
index 000000000..b966b0b2f
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/db/c0be625bed24b5d8f5d9a927484f2065d321af
Binary files differ
diff --git a/tests/resources/testrepo.git/objects/f0/a2a10243ca64f935dbe3dccb89ec8bf16bdace b/tests/resources/testrepo.git/objects/f0/a2a10243ca64f935dbe3dccb89ec8bf16bdace
new file mode 100644
index 000000000..1b299dc25
--- /dev/null
+++ b/tests/resources/testrepo.git/objects/f0/a2a10243ca64f935dbe3dccb89ec8bf16bdace
Binary files differ
diff --git a/tests/resources/testrepo/.gitted/logs/refs/heads/testrepo-worktree b/tests/resources/testrepo/.gitted/logs/refs/heads/testrepo-worktree
new file mode 100644
index 000000000..93ab5f06f
--- /dev/null
+++ b/tests/resources/testrepo/.gitted/logs/refs/heads/testrepo-worktree
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 099fabac3a9ea935598528c27f866e34089c2eff Patrick Steinhardt <ps@pks.im> 1442484463 +0200 branch: Created from HEAD
diff --git a/tests/resources/testrepo/.gitted/objects/9b/1719f5cf069568785080a0bbabbe7c377e22ae b/tests/resources/testrepo/.gitted/objects/9b/1719f5cf069568785080a0bbabbe7c377e22ae
new file mode 100644
index 000000000..13e3f581a
--- /dev/null
+++ b/tests/resources/testrepo/.gitted/objects/9b/1719f5cf069568785080a0bbabbe7c377e22ae
Binary files differ
diff --git a/tests/resources/testrepo/.gitted/objects/a3/8d028f71eaa590febb7d716b1ca32350cf70da b/tests/resources/testrepo/.gitted/objects/a3/8d028f71eaa590febb7d716b1ca32350cf70da
new file mode 100644
index 000000000..4df22ec17
--- /dev/null
+++ b/tests/resources/testrepo/.gitted/objects/a3/8d028f71eaa590febb7d716b1ca32350cf70da
Binary files differ
diff --git a/tests/resources/testrepo/.gitted/objects/ad/edac69457183c8265c8a9614c1c4fed31d1ff3 b/tests/resources/testrepo/.gitted/objects/ad/edac69457183c8265c8a9614c1c4fed31d1ff3
new file mode 100644
index 000000000..c054fc0c4
--- /dev/null
+++ b/tests/resources/testrepo/.gitted/objects/ad/edac69457183c8265c8a9614c1c4fed31d1ff3
Binary files differ
diff --git a/tests/resources/testrepo/.gitted/refs/heads/merge-conflict b/tests/resources/testrepo/.gitted/refs/heads/merge-conflict
new file mode 100644
index 000000000..3e24a24e0
--- /dev/null
+++ b/tests/resources/testrepo/.gitted/refs/heads/merge-conflict
@@ -0,0 +1 @@
+a38d028f71eaa590febb7d716b1ca32350cf70da
diff --git a/tests/resources/testrepo/.gitted/refs/heads/testrepo-worktree b/tests/resources/testrepo/.gitted/refs/heads/testrepo-worktree
new file mode 100644
index 000000000..f31fe781b
--- /dev/null
+++ b/tests/resources/testrepo/.gitted/refs/heads/testrepo-worktree
@@ -0,0 +1 @@
+099fabac3a9ea935598528c27f866e34089c2eff
diff --git a/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/HEAD b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/HEAD
new file mode 100644
index 000000000..1b8637e32
--- /dev/null
+++ b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/testrepo-worktree
diff --git a/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/commondir b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/commondir
new file mode 100644
index 000000000..aab0408ce
--- /dev/null
+++ b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/commondir
@@ -0,0 +1 @@
+../..
diff --git a/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/gitdir b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/gitdir
new file mode 100644
index 000000000..0d37a5792
--- /dev/null
+++ b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/gitdir
@@ -0,0 +1 @@
+../../../../testrepo-worktree/.git
diff --git a/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/index b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/index
new file mode 100644
index 000000000..41141906e
--- /dev/null
+++ b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/index
Binary files differ
diff --git a/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/logs/HEAD b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/logs/HEAD
new file mode 100644
index 000000000..3bede502e
--- /dev/null
+++ b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/logs/HEAD
@@ -0,0 +1 @@
+099fabac3a9ea935598528c27f866e34089c2eff 099fabac3a9ea935598528c27f866e34089c2eff Patrick Steinhardt <ps@pks.im> 1442484463 +0200 checkout: moving from 099fabac3a9ea935598528c27f866e34089c2eff to testrepo-worktree
diff --git a/tests/revwalk/basic.c b/tests/revwalk/basic.c
index 5ed7da4eb..547050c68 100644
--- a/tests/revwalk/basic.c
+++ b/tests/revwalk/basic.c
@@ -38,8 +38,9 @@ static const int commit_sorting_time_reverse[][6] = {
{4, 5, 2, 1, 3, 0}
};
+/* This is specified unsorted, so both combinations are possible */
static const int commit_sorting_segment[][6] = {
- {1, 2, -1, -1, -1, -1}
+ {1, 2, -1, -1, -1, -1}, {2, 1, -1, -1, -1, -1}
};
#define commit_count 6
@@ -155,9 +156,8 @@ void test_revwalk_basic__glob_heads(void)
cl_git_pass(git_revwalk_push_glob(_walk, "heads"));
- while (git_revwalk_next(&oid, _walk) == 0) {
+ while (git_revwalk_next(&oid, _walk) == 0)
i++;
- }
/* git log --branches --oneline | wc -l => 14 */
cl_assert_equal_i(i, 14);
@@ -177,7 +177,7 @@ void test_revwalk_basic__glob_heads_with_invalid(void)
/* walking */;
/* git log --branches --oneline | wc -l => 16 */
- cl_assert_equal_i(18, i);
+ cl_assert_equal_i(19, i);
}
void test_revwalk_basic__push_head(void)
@@ -331,6 +331,40 @@ void test_revwalk_basic__hide_then_push(void)
cl_assert_equal_i(i, 0);
}
+void test_revwalk_basic__topo_crash(void)
+{
+ git_oid oid;
+ git_oid_fromstr(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644");
+
+ revwalk_basic_setup_walk(NULL);
+ git_revwalk_sorting(_walk, GIT_SORT_TOPOLOGICAL);
+
+ cl_git_pass(git_revwalk_push(_walk, &oid));
+ cl_git_pass(git_revwalk_hide(_walk, &oid));
+
+ git_revwalk_next(&oid, _walk);
+}
+
+void test_revwalk_basic__from_new_to_old(void)
+{
+ git_oid from_oid, to_oid, oid;
+ int i = 0;
+
+ revwalk_basic_setup_walk(NULL);
+ git_revwalk_sorting(_walk, GIT_SORT_TIME);
+
+ cl_git_pass(git_oid_fromstr(&to_oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644"));
+ cl_git_pass(git_oid_fromstr(&from_oid, "a4a7dce85cf63874e984719f4fdd239f5145052f"));
+
+ cl_git_pass(git_revwalk_push(_walk, &to_oid));
+ cl_git_pass(git_revwalk_hide(_walk, &from_oid));
+
+ while (git_revwalk_next(&oid, _walk) == 0)
+ i++;
+
+ cl_assert_equal_i(i, 0);
+}
+
void test_revwalk_basic__push_range(void)
{
revwalk_basic_setup_walk(NULL);
@@ -338,7 +372,7 @@ void test_revwalk_basic__push_range(void)
git_revwalk_reset(_walk);
git_revwalk_sorting(_walk, 0);
cl_git_pass(git_revwalk_push_range(_walk, "9fd738e~2..9fd738e"));
- cl_git_pass(test_walk_only(_walk, commit_sorting_segment, 1));
+ cl_git_pass(test_walk_only(_walk, commit_sorting_segment, 2));
}
void test_revwalk_basic__push_mixed(void)
@@ -473,3 +507,51 @@ void test_revwalk_basic__big_timestamp(void)
git_signature_free(sig);
}
+
+/* Ensure that we correctly hide a commit that is (timewise) older
+ * than the commits that we are showing.
+ *
+ * % git rev-list 8e73b76..bd75801
+ * bd758010071961f28336333bc41e9c64c9a64866
+ */
+void test_revwalk_basic__old_hidden_commit_one(void)
+{
+ git_oid new_id, old_id, oid;
+
+ revwalk_basic_setup_walk("testrepo.git");
+
+ cl_git_pass(git_oid_fromstr(&new_id, "bd758010071961f28336333bc41e9c64c9a64866"));
+ cl_git_pass(git_revwalk_push(_walk, &new_id));
+
+ cl_git_pass(git_oid_fromstr(&old_id, "8e73b769e97678d684b809b163bebdae2911720f"));
+ cl_git_pass(git_revwalk_hide(_walk, &old_id));
+
+ cl_git_pass(git_revwalk_next(&oid, _walk));
+ cl_assert(!git_oid_streq(&oid, "bd758010071961f28336333bc41e9c64c9a64866"));
+
+ cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oid, _walk));
+}
+
+/* Ensure that we correctly hide a commit that is (timewise) older
+ * than the commits that we are showing.
+ *
+ * % git rev-list bd75801 ^b91e763
+ * bd758010071961f28336333bc41e9c64c9a64866
+ */
+void test_revwalk_basic__old_hidden_commit_two(void)
+{
+ git_oid new_id, old_id, oid;
+
+ revwalk_basic_setup_walk("testrepo.git");
+
+ cl_git_pass(git_oid_fromstr(&new_id, "bd758010071961f28336333bc41e9c64c9a64866"));
+ cl_git_pass(git_revwalk_push(_walk, &new_id));
+
+ cl_git_pass(git_oid_fromstr(&old_id, "b91e763008b10db366442469339f90a2b8400d0a"));
+ cl_git_pass(git_revwalk_hide(_walk, &old_id));
+
+ cl_git_pass(git_revwalk_next(&oid, _walk));
+ cl_assert(!git_oid_streq(&oid, "bd758010071961f28336333bc41e9c64c9a64866"));
+
+ cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oid, _walk));
+}
diff --git a/tests/revwalk/hidecb.c b/tests/revwalk/hidecb.c
index 14cf39afd..b274ed86a 100644
--- a/tests/revwalk/hidecb.c
+++ b/tests/revwalk/hidecb.c
@@ -158,6 +158,7 @@ void test_revwalk_hidecb__hide_some_commits(void)
cl_git_pass(git_revwalk_new(&walk, _repo));
cl_git_pass(git_revwalk_push(walk, &_head_id));
+ git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL);
/* Add hide callback */
cl_git_pass(git_revwalk_add_hide_cb(walk, hide_commit_cb, NULL));
@@ -182,6 +183,7 @@ void test_revwalk_hidecb__test_payload(void)
cl_git_pass(git_revwalk_new(&walk, _repo));
cl_git_pass(git_revwalk_push(walk, &_head_id));
+ git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL);
/* Add hide callback, pass id of parent of initial commit as payload data */
cl_git_pass(git_revwalk_add_hide_cb(walk, hide_commit_use_payload_cb, &commit_ids[5]));
diff --git a/tests/revwalk/simplify.c b/tests/revwalk/simplify.c
index f65ce6c59..6dd068a42 100644
--- a/tests/revwalk/simplify.c
+++ b/tests/revwalk/simplify.c
@@ -40,6 +40,7 @@ void test_revwalk_simplify__first_parent(void)
git_oid_fromstr(&id, commit_head);
cl_git_pass(git_revwalk_push(walk, &id));
+ git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL);
git_revwalk_simplify_first_parent(walk);
i = 0;
diff --git a/tests/status/ignore.c b/tests/status/ignore.c
index c4878b2dd..dc58e8b45 100644
--- a/tests/status/ignore.c
+++ b/tests/status/ignore.c
@@ -20,8 +20,8 @@ static void assert_ignored_(
bool expected, const char *filepath, const char *file, int line)
{
int is_ignored = 0;
- cl_git_pass_(
- git_status_should_ignore(&is_ignored, g_repo, filepath), file, line);
+ cl_git_expect(
+ git_status_should_ignore(&is_ignored, g_repo, filepath), 0, file, line);
clar__assert(
(expected != 0) == (is_ignored != 0),
file, line, "expected != is_ignored", filepath, 1);
@@ -1077,3 +1077,108 @@ void test_status_ignore__negate_starstar(void)
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "code/projects/foo/bar/packages/repositories.config"));
cl_assert_equal_i(0, ignored);
}
+
+void test_status_ignore__ignore_all_toplevel_dirs_include_files(void)
+{
+ static const char *test_files[] = {
+ "empty_standard_repo/README.md",
+ "empty_standard_repo/src/main.c",
+ "empty_standard_repo/src/foo/foo.c",
+ "empty_standard_repo/dist/foo.o",
+ "empty_standard_repo/dist/main.o",
+ NULL
+ };
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile(
+ "empty_standard_repo/.gitignore",
+ "/*/\n"
+ "!/src\n");
+
+ assert_is_ignored("dist/foo.o");
+ assert_is_ignored("dist/main.o");
+
+ refute_is_ignored("README.md");
+ refute_is_ignored("src/foo.c");
+ refute_is_ignored("src/foo/foo.c");
+}
+
+void test_status_ignore__subdir_ignore_all_toplevel_dirs_include_files(void)
+{
+ static const char *test_files[] = {
+ "empty_standard_repo/project/README.md",
+ "empty_standard_repo/project/src/main.c",
+ "empty_standard_repo/project/src/foo/foo.c",
+ "empty_standard_repo/project/dist/foo.o",
+ "empty_standard_repo/project/dist/main.o",
+ NULL
+ };
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile(
+ "empty_standard_repo/project/.gitignore",
+ "/*/\n"
+ "!/src\n");
+
+ assert_is_ignored("project/dist/foo.o");
+ assert_is_ignored("project/dist/main.o");
+
+ refute_is_ignored("project/src/foo.c");
+ refute_is_ignored("project/src/foo/foo.c");
+ refute_is_ignored("project/README.md");
+}
+
+void test_status_ignore__subdir_ignore_everything_except_certain_files(void)
+{
+ static const char *test_files[] = {
+ "empty_standard_repo/project/README.md",
+ "empty_standard_repo/project/some_file",
+ "empty_standard_repo/project/src/main.c",
+ "empty_standard_repo/project/src/foo/foo.c",
+ "empty_standard_repo/project/dist/foo.o",
+ "empty_standard_repo/project/dist/main.o",
+ NULL
+ };
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile(
+ "empty_standard_repo/project/.gitignore",
+ "/*\n"
+ "!/src\n"
+ "!README.md\n");
+
+ assert_is_ignored("project/some_file");
+ assert_is_ignored("project/dist/foo.o");
+ assert_is_ignored("project/dist/main.o");
+
+ refute_is_ignored("project/README.md");
+ refute_is_ignored("project/src/foo.c");
+ refute_is_ignored("project/src/foo/foo.c");
+}
+
+void test_status_ignore__deeper(void)
+{
+ int ignored;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+ cl_git_mkfile("empty_standard_repo/.gitignore",
+ "*.data\n"
+ "!dont_ignore/*.data\n");
+
+ cl_git_pass(p_mkdir("empty_standard_repo/dont_ignore", 0777));
+ cl_git_mkfile("empty_standard_repo/foo.data", "");
+ cl_git_mkfile("empty_standard_repo/bar.data", "");
+ cl_git_mkfile("empty_standard_repo/dont_ignore/foo.data", "");
+ cl_git_mkfile("empty_standard_repo/dont_ignore/bar.data", "");
+
+ cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "foo.data"));
+ cl_assert_equal_i(1, ignored);
+ cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "bar.data"));
+ cl_assert_equal_i(1, ignored);
+
+ cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "dont_ignore/foo.data"));
+ cl_assert_equal_i(0, ignored);
+ cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "dont_ignore/bar.data"));
+ cl_assert_equal_i(0, ignored);
+}
diff --git a/tests/submodule/lookup.c b/tests/submodule/lookup.c
index 148f9273e..f84f07c60 100644
--- a/tests/submodule/lookup.c
+++ b/tests/submodule/lookup.c
@@ -11,6 +11,11 @@ void test_submodule_lookup__initialize(void)
g_repo = setup_fixture_submod2();
}
+void test_submodule_lookup__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+}
+
void test_submodule_lookup__simple_lookup(void)
{
assert_submodule_exists(g_repo, "sm_unchanged");
@@ -388,3 +393,55 @@ void test_submodule_lookup__renamed(void)
cl_git_pass(git_submodule_foreach(g_repo, sm_lookup_cb, &data));
cl_assert_equal_i(8, data.count);
}
+
+void test_submodule_lookup__cached(void)
+{
+ git_submodule *sm;
+ git_submodule *sm2;
+ /* See that the simple tests still pass. */
+
+ git_repository_submodule_cache_all(g_repo);
+ test_submodule_lookup__simple_lookup();
+ git_repository_submodule_cache_clear(g_repo);
+ test_submodule_lookup__simple_lookup();
+
+ /* Check that subsequent calls return different objects when cached. */
+ git_repository_submodule_cache_all(g_repo);
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
+ cl_git_pass(git_submodule_lookup(&sm2, g_repo, "sm_unchanged"));
+ cl_assert_equal_p(sm, sm2);
+ git_submodule_free(sm2);
+
+ /* and that we get new objects again after clearing the cache. */
+ git_repository_submodule_cache_clear(g_repo);
+ cl_git_pass(git_submodule_lookup(&sm2, g_repo, "sm_unchanged"));
+ cl_assert(sm != sm2);
+ git_submodule_free(sm);
+ git_submodule_free(sm2);
+}
+
+void test_submodule_lookup__lookup_in_bare_repository_fails(void)
+{
+ git_submodule *sm;
+
+ cl_git_sandbox_cleanup();
+ g_repo = cl_git_sandbox_init("submodules.git");
+
+ cl_git_fail(git_submodule_lookup(&sm, g_repo, "nonexisting"));
+}
+
+static int foreach_cb(git_submodule *sm, const char *name, void *payload)
+{
+ GIT_UNUSED(sm);
+ GIT_UNUSED(name);
+ GIT_UNUSED(payload);
+ return 0;
+}
+
+void test_submodule_lookup__foreach_in_bare_repository_fails(void)
+{
+ cl_git_sandbox_cleanup();
+ g_repo = cl_git_sandbox_init("submodules.git");
+
+ cl_git_fail(git_submodule_foreach(g_repo, foreach_cb, NULL));
+}
diff --git a/tests/submodule/open.c b/tests/submodule/open.c
new file mode 100644
index 000000000..0ef01ec24
--- /dev/null
+++ b/tests/submodule/open.c
@@ -0,0 +1,90 @@
+#include "clar_libgit2.h"
+#include "submodule_helpers.h"
+#include "path.h"
+
+static git_repository *g_parent;
+static git_repository *g_child;
+static git_submodule *g_module;
+
+void test_submodule_open__initialize(void)
+{
+ g_parent = setup_fixture_submod2();
+}
+
+void test_submodule_open__cleanup(void)
+{
+ git_submodule_free(g_module);
+ git_repository_free(g_child);
+ cl_git_sandbox_cleanup();
+ g_parent = NULL;
+ g_child = NULL;
+ g_module = NULL;
+}
+
+static void assert_sm_valid(git_repository *parent, git_repository *child, const char *sm_name)
+{
+ git_buf expected = GIT_BUF_INIT, actual = GIT_BUF_INIT;
+
+ /* assert working directory */
+ cl_git_pass(git_buf_joinpath(&expected, git_repository_workdir(parent), sm_name));
+ cl_git_pass(git_path_prettify_dir(&expected, expected.ptr, NULL));
+ cl_git_pass(git_buf_sets(&actual, git_repository_workdir(child)));
+ cl_git_pass(git_path_prettify_dir(&actual, actual.ptr, NULL));
+ cl_assert_equal_s(expected.ptr, actual.ptr);
+
+ git_buf_clear(&expected);
+ git_buf_clear(&actual);
+
+ /* assert common directory */
+ cl_git_pass(git_buf_joinpath(&expected, git_repository_commondir(parent), "modules"));
+ cl_git_pass(git_buf_joinpath(&expected, expected.ptr, sm_name));
+ cl_git_pass(git_path_prettify_dir(&expected, expected.ptr, NULL));
+ cl_git_pass(git_buf_sets(&actual, git_repository_commondir(child)));
+ cl_git_pass(git_path_prettify_dir(&actual, actual.ptr, NULL));
+ cl_assert_equal_s(expected.ptr, actual.ptr);
+
+ /* assert git directory */
+ cl_git_pass(git_buf_sets(&actual, git_repository_path(child)));
+ cl_git_pass(git_path_prettify_dir(&actual, actual.ptr, NULL));
+ cl_assert_equal_s(expected.ptr, actual.ptr);
+
+ git_buf_free(&expected);
+ git_buf_free(&actual);
+}
+
+void test_submodule_open__opening_via_lookup_succeeds(void)
+{
+ cl_git_pass(git_submodule_lookup(&g_module, g_parent, "sm_unchanged"));
+ cl_git_pass(git_submodule_open(&g_child, g_module));
+ assert_sm_valid(g_parent, g_child, "sm_unchanged");
+}
+
+void test_submodule_open__direct_open_succeeds(void)
+{
+ git_buf path = GIT_BUF_INIT;
+
+ cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_parent), "sm_unchanged"));
+ cl_git_pass(git_repository_open(&g_child, path.ptr));
+ assert_sm_valid(g_parent, g_child, "sm_unchanged");
+
+ git_buf_free(&path);
+}
+
+void test_submodule_open__direct_open_succeeds_for_broken_sm_with_gitdir(void)
+{
+ git_buf path = GIT_BUF_INIT;
+
+ /*
+ * This is actually not a valid submodule, but we
+ * encountered at least one occasion where the gitdir
+ * file existed inside of a submodule's gitdir. As we are
+ * now able to open these submodules correctly, we still
+ * add a test for this.
+ */
+ cl_git_mkfile("submod2/.git/modules/sm_unchanged/gitdir", ".git");
+ cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_parent), "sm_unchanged"));
+ cl_git_pass(git_repository_open(&g_child, path.ptr));
+ assert_sm_valid(g_parent, g_child, "sm_unchanged");
+
+ git_buf_free(&path);
+}
diff --git a/tests/submodule/submodule_helpers.c b/tests/submodule/submodule_helpers.c
index 6c2b9cf78..cd541ea86 100644
--- a/tests/submodule/submodule_helpers.c
+++ b/tests/submodule/submodule_helpers.c
@@ -204,7 +204,7 @@ void assert__submodule_exists(
git_submodule *sm;
int error = git_submodule_lookup(&sm, repo, name);
if (error)
- cl_git_report_failure(error, file, line, msg);
+ cl_git_report_failure(error, 0, file, line, msg);
cl_assert_at_line(sm != NULL, file, line);
git_submodule_free(sm);
}
diff --git a/tests/threads/basic.c b/tests/threads/basic.c
index 9c342bc42..af6049090 100644
--- a/tests/threads/basic.c
+++ b/tests/threads/basic.c
@@ -48,3 +48,30 @@ void test_threads_basic__set_error(void)
{
run_in_parallel(1, 4, set_error, NULL, NULL);
}
+
+#ifdef GIT_THREADS
+static void *return_normally(void *param)
+{
+ return param;
+}
+#endif
+
+void test_threads_basic__exit(void)
+{
+#ifndef GIT_THREADS
+ clar__skip();
+#else
+ git_thread thread;
+ void *result;
+
+ /* Ensure that the return value of the threadproc is returned. */
+ cl_git_pass(git_thread_create(&thread, return_normally, (void *)424242));
+ cl_git_pass(git_thread_join(&thread, &result));
+ cl_assert_equal_sz(424242, (size_t)result);
+
+ /* Ensure that the return value of `git_thread_exit` is returned. */
+ cl_git_pass(git_thread_create(&thread, return_normally, (void *)232323));
+ cl_git_pass(git_thread_join(&thread, &result));
+ cl_assert_equal_sz(232323, (size_t)result);
+#endif
+}
diff --git a/tests/threads/diff.c b/tests/threads/diff.c
index c32811469..256040265 100644
--- a/tests/threads/diff.c
+++ b/tests/threads/diff.c
@@ -19,12 +19,27 @@ static git_repository *_repo;
static git_tree *_a, *_b;
static git_atomic _counts[4];
static int _check_counts;
+#ifdef GIT_WIN32
+static int _retries;
+#endif
#define THREADS 20
+void test_threads_diff__initialize(void)
+{
+#ifdef GIT_WIN32
+ _retries = git_win32__retries;
+ git_win32__retries = 1;
+#endif
+}
+
void test_threads_diff__cleanup(void)
{
cl_git_sandbox_cleanup();
+
+#ifdef GIT_WIN32
+ git_win32__retries = _retries;
+#endif
}
static void setup_trees(void)
diff --git a/tests/threads/refdb.c b/tests/threads/refdb.c
index f869bcb44..94c5f5057 100644
--- a/tests/threads/refdb.c
+++ b/tests/threads/refdb.c
@@ -5,6 +5,12 @@
static git_repository *g_repo;
static int g_expected = 0;
+#ifdef GIT_WIN32
+static bool concurrent_compress = false;
+#else
+static bool concurrent_compress = true;
+#endif
+
void test_threads_refdb__initialize(void)
{
g_repo = NULL;
@@ -18,14 +24,28 @@ void test_threads_refdb__cleanup(void)
#define REPEAT 20
#define THREADS 20
+/* Number of references to create or delete in each thread */
+#define NREFS 10
+
+struct th_data {
+ cl_git_thread_err error;
+ int id;
+ const char *path;
+};
static void *iterate_refs(void *arg)
{
+ struct th_data *data = (struct th_data *) arg;
git_reference_iterator *i;
git_reference *ref;
- int count = 0;
+ int count = 0, error;
+ git_repository *repo;
- cl_git_pass(git_reference_iterator_new(&i, g_repo));
+ cl_git_thread_pass(data, git_repository_open(&repo, data->path));
+ do {
+ error = git_reference_iterator_new(&i, repo);
+ } while (error == GIT_ELOCKED);
+ cl_git_thread_pass(data, error);
for (count = 0; !git_reference_next(&ref, i); ++count) {
cl_assert(ref != NULL);
@@ -37,112 +57,92 @@ static void *iterate_refs(void *arg)
git_reference_iterator_free(i);
+ git_repository_free(repo);
giterr_clear();
return arg;
}
-void test_threads_refdb__iterator(void)
-{
- int r, t;
- git_thread th[THREADS];
- int id[THREADS];
- git_oid head;
- git_reference *ref;
- char name[128];
- git_refdb *refdb;
-
- g_repo = cl_git_sandbox_init("testrepo2");
-
- cl_git_pass(git_reference_name_to_id(&head, g_repo, "HEAD"));
-
- /* make a bunch of references */
-
- for (r = 0; r < 200; ++r) {
- p_snprintf(name, sizeof(name), "refs/heads/direct-%03d", r);
- cl_git_pass(git_reference_create(&ref, g_repo, name, &head, 0, NULL));
- git_reference_free(ref);
- }
-
- cl_git_pass(git_repository_refdb(&refdb, g_repo));
- cl_git_pass(git_refdb_compress(refdb));
- git_refdb_free(refdb);
-
- g_expected = 206;
-
- for (r = 0; r < REPEAT; ++r) {
- g_repo = cl_git_sandbox_reopen(); /* reopen to flush caches */
-
- for (t = 0; t < THREADS; ++t) {
- id[t] = t;
-#ifdef GIT_THREADS
- cl_git_pass(git_thread_create(&th[t], iterate_refs, &id[t]));
-#else
- th[t] = t;
- iterate_refs(&id[t]);
-#endif
- }
-
-#ifdef GIT_THREADS
- for (t = 0; t < THREADS; ++t) {
- cl_git_pass(git_thread_join(&th[t], NULL));
- }
-#endif
-
- memset(th, 0, sizeof(th));
- }
-}
-
static void *create_refs(void *arg)
{
- int *id = arg, i;
+ int i, error;
+ struct th_data *data = (struct th_data *) arg;
git_oid head;
char name[128];
- git_reference *ref[10];
+ git_reference *ref[NREFS];
+ git_repository *repo;
- cl_git_pass(git_reference_name_to_id(&head, g_repo, "HEAD"));
+ cl_git_thread_pass(data, git_repository_open(&repo, data->path));
- for (i = 0; i < 10; ++i) {
- p_snprintf(name, sizeof(name), "refs/heads/thread-%03d-%02d", *id, i);
- cl_git_pass(git_reference_create(&ref[i], g_repo, name, &head, 0, NULL));
+ do {
+ error = git_reference_name_to_id(&head, repo, "HEAD");
+ } while (error == GIT_ELOCKED);
+ cl_git_thread_pass(data, error);
- if (i == 5) {
+ for (i = 0; i < NREFS; ++i) {
+ p_snprintf(name, sizeof(name), "refs/heads/thread-%03d-%02d", data->id, i);
+ do {
+ error = git_reference_create(&ref[i], repo, name, &head, 0, NULL);
+ } while (error == GIT_ELOCKED);
+ cl_git_thread_pass(data, error);
+
+ if (concurrent_compress && i == NREFS/2) {
git_refdb *refdb;
- cl_git_pass(git_repository_refdb(&refdb, g_repo));
- cl_git_pass(git_refdb_compress(refdb));
+ cl_git_thread_pass(data, git_repository_refdb(&refdb, repo));
+ do {
+ error = git_refdb_compress(refdb);
+ } while (error == GIT_ELOCKED);
+ cl_git_thread_pass(data, error);
git_refdb_free(refdb);
}
}
- for (i = 0; i < 10; ++i)
+ for (i = 0; i < NREFS; ++i)
git_reference_free(ref[i]);
+ git_repository_free(repo);
+
giterr_clear();
return arg;
}
static void *delete_refs(void *arg)
{
- int *id = arg, i;
+ int i, error;
+ struct th_data *data = (struct th_data *) arg;
git_reference *ref;
char name[128];
+ git_repository *repo;
- for (i = 0; i < 10; ++i) {
+ cl_git_thread_pass(data, git_repository_open(&repo, data->path));
+
+ for (i = 0; i < NREFS; ++i) {
p_snprintf(
- name, sizeof(name), "refs/heads/thread-%03d-%02d", (*id) & ~0x3, i);
+ name, sizeof(name), "refs/heads/thread-%03d-%02d", (data->id) & ~0x3, i);
+
+ if (!git_reference_lookup(&ref, repo, name)) {
+ do {
+ error = git_reference_delete(ref);
+ } while (error == GIT_ELOCKED);
+ /* Sometimes we race with other deleter threads */
+ if (error == GIT_ENOTFOUND)
+ error = 0;
- if (!git_reference_lookup(&ref, g_repo, name)) {
- cl_git_pass(git_reference_delete(ref));
+ cl_git_thread_pass(data, error);
git_reference_free(ref);
}
- if (i == 5) {
+ if (concurrent_compress && i == NREFS/2) {
git_refdb *refdb;
- cl_git_pass(git_repository_refdb(&refdb, g_repo));
- cl_git_pass(git_refdb_compress(refdb));
+ cl_git_thread_pass(data, git_repository_refdb(&refdb, repo));
+ do {
+ error = git_refdb_compress(refdb);
+ } while (error == GIT_ELOCKED);
+ cl_git_thread_pass(data, error);
git_refdb_free(refdb);
}
}
+ git_repository_free(repo);
giterr_clear();
return arg;
}
@@ -150,7 +150,7 @@ static void *delete_refs(void *arg)
void test_threads_refdb__edit_while_iterate(void)
{
int r, t;
- int id[THREADS];
+ struct th_data th_data[THREADS];
git_oid head;
git_reference *ref;
char name[128];
@@ -189,33 +189,32 @@ void test_threads_refdb__edit_while_iterate(void)
default: fn = iterate_refs; break;
}
- id[t] = t;
-
- /* It appears with all reflog writing changes, etc., that this
- * test has started to fail quite frequently, so let's disable it
- * for now by just running on a single thread...
- */
-/* #ifdef GIT_THREADS */
-/* cl_git_pass(git_thread_create(&th[t], fn, &id[t])); */
-/* #else */
- fn(&id[t]);
-/* #endif */
+ th_data[t].id = t;
+ th_data[t].path = git_repository_path(g_repo);
+
+#ifdef GIT_THREADS
+ cl_git_pass(git_thread_create(&th[t], fn, &th_data[t]));
+#else
+ fn(&th_data[t]);
+#endif
}
#ifdef GIT_THREADS
-/* for (t = 0; t < THREADS; ++t) { */
-/* cl_git_pass(git_thread_join(th[t], NULL)); */
-/* } */
+ for (t = 0; t < THREADS; ++t) {
+ cl_git_pass(git_thread_join(&th[t], NULL));
+ cl_git_thread_check(&th_data[t]);
+ }
memset(th, 0, sizeof(th));
for (t = 0; t < THREADS; ++t) {
- id[t] = t;
- cl_git_pass(git_thread_create(&th[t], iterate_refs, &id[t]));
+ th_data[t].id = t;
+ cl_git_pass(git_thread_create(&th[t], iterate_refs, &th_data[t]));
}
for (t = 0; t < THREADS; ++t) {
cl_git_pass(git_thread_join(&th[t], NULL));
+ cl_git_thread_check(&th_data[t]);
}
#endif
}
diff --git a/tests/worktree/config.c b/tests/worktree/config.c
new file mode 100644
index 000000000..3ab317bb5
--- /dev/null
+++ b/tests/worktree/config.c
@@ -0,0 +1,45 @@
+#include "clar_libgit2.h"
+#include "worktree_helpers.h"
+
+#define COMMON_REPO "testrepo"
+#define WORKTREE_REPO "testrepo-worktree"
+
+static worktree_fixture fixture =
+ WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO);
+
+void test_worktree_config__initialize(void)
+{
+ setup_fixture_worktree(&fixture);
+}
+
+void test_worktree_config__cleanup(void)
+{
+ cleanup_fixture_worktree(&fixture);
+}
+
+void test_worktree_config__open(void)
+{
+ git_config *cfg;
+
+ cl_git_pass(git_repository_config(&cfg, fixture.worktree));
+ cl_assert(cfg != NULL);
+
+ git_config_free(cfg);
+}
+
+void test_worktree_config__set(void)
+{
+ git_config *cfg;
+ int32_t val;
+
+ cl_git_pass(git_repository_config(&cfg, fixture.worktree));
+ cl_git_pass(git_config_set_int32(cfg, "core.dummy", 5));
+ git_config_free(cfg);
+
+ // reopen to verify configuration has been set in the
+ // common dir
+ cl_git_pass(git_repository_config(&cfg, fixture.repo));
+ cl_git_pass(git_config_get_int32(&val, cfg, "core.dummy"));
+ cl_assert_equal_i(val, 5);
+ git_config_free(cfg);
+}
diff --git a/tests/worktree/merge.c b/tests/worktree/merge.c
new file mode 100644
index 000000000..36cc2a6c1
--- /dev/null
+++ b/tests/worktree/merge.c
@@ -0,0 +1,121 @@
+#include "clar_libgit2.h"
+
+#include "worktree_helpers.h"
+#include "merge/merge_helpers.h"
+
+#define COMMON_REPO "testrepo"
+#define WORKTREE_REPO "testrepo-worktree"
+
+#define MASTER_BRANCH "refs/heads/master"
+#define CONFLICT_BRANCH "refs/heads/merge-conflict"
+
+#define CONFLICT_BRANCH_FILE_TXT \
+ "<<<<<<< HEAD\n" \
+ "hi\n" \
+ "bye!\n" \
+ "=======\n" \
+ "conflict\n" \
+ ">>>>>>> merge-conflict\n" \
+
+static worktree_fixture fixture =
+ WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO);
+
+static const char *merge_files[] = {
+ GIT_MERGE_HEAD_FILE,
+ GIT_ORIG_HEAD_FILE,
+ GIT_MERGE_MODE_FILE,
+ GIT_MERGE_MSG_FILE,
+};
+
+void test_worktree_merge__initialize(void)
+{
+ setup_fixture_worktree(&fixture);
+}
+
+void test_worktree_merge__cleanup(void)
+{
+ cleanup_fixture_worktree(&fixture);
+}
+
+void test_worktree_merge__merge_head(void)
+{
+ git_reference *theirs_ref, *ref;
+ git_annotated_commit *theirs;
+
+ cl_git_pass(git_reference_lookup(&theirs_ref, fixture.worktree, CONFLICT_BRANCH));
+ cl_git_pass(git_annotated_commit_from_ref(&theirs, fixture.worktree, theirs_ref));
+ cl_git_pass(git_merge(fixture.worktree, (const git_annotated_commit **)&theirs, 1, NULL, NULL));
+
+ cl_git_pass(git_reference_lookup(&ref, fixture.worktree, GIT_MERGE_HEAD_FILE));
+
+ git_reference_free(ref);
+ git_reference_free(theirs_ref);
+ git_annotated_commit_free(theirs);
+}
+
+void test_worktree_merge__merge_setup(void)
+{
+ git_reference *ours_ref, *theirs_ref;
+ git_annotated_commit *ours, *theirs;
+ git_buf path = GIT_BUF_INIT;
+ unsigned i;
+
+ cl_git_pass(git_reference_lookup(&ours_ref, fixture.worktree, MASTER_BRANCH));
+ cl_git_pass(git_annotated_commit_from_ref(&ours, fixture.worktree, ours_ref));
+
+ cl_git_pass(git_reference_lookup(&theirs_ref, fixture.worktree, CONFLICT_BRANCH));
+ cl_git_pass(git_annotated_commit_from_ref(&theirs, fixture.worktree, theirs_ref));
+
+ cl_git_pass(git_merge__setup(fixture.worktree,
+ ours, (const git_annotated_commit **)&theirs, 1));
+
+ for (i = 0; i < ARRAY_SIZE(merge_files); i++) {
+ git_buf_clear(&path);
+ cl_git_pass(git_buf_printf(&path, "%s/%s",
+ fixture.worktree->gitdir, merge_files[i]));
+ cl_assert(git_path_exists(path.ptr));
+ }
+
+ git_buf_free(&path);
+ git_reference_free(ours_ref);
+ git_reference_free(theirs_ref);
+ git_annotated_commit_free(ours);
+ git_annotated_commit_free(theirs);
+}
+
+void test_worktree_merge__merge_conflict(void)
+{
+ git_buf path = GIT_BUF_INIT, buf = GIT_BUF_INIT;
+ git_reference *theirs_ref;
+ git_annotated_commit *theirs;
+ git_index *index;
+ const git_index_entry *entry;
+ size_t i, conflicts = 0;
+
+ cl_git_pass(git_reference_lookup(&theirs_ref, fixture.worktree, CONFLICT_BRANCH));
+ cl_git_pass(git_annotated_commit_from_ref(&theirs, fixture.worktree, theirs_ref));
+
+ cl_git_pass(git_merge(fixture.worktree,
+ (const git_annotated_commit **)&theirs, 1, NULL, NULL));
+
+ cl_git_pass(git_repository_index(&index, fixture.worktree));
+ for (i = 0; i < git_index_entrycount(index); i++) {
+ cl_assert(entry = git_index_get_byindex(index, i));
+
+ if (git_index_entry_is_conflict(entry))
+ conflicts++;
+ }
+ cl_assert_equal_sz(conflicts, 3);
+
+ git_reference_free(theirs_ref);
+ git_annotated_commit_free(theirs);
+ git_index_free(index);
+
+ cl_git_pass(git_buf_joinpath(&path, fixture.worktree->workdir, "branch_file.txt"));
+ cl_git_pass(git_futils_readbuffer(&buf, path.ptr));
+ cl_assert_equal_s(buf.ptr, CONFLICT_BRANCH_FILE_TXT);
+
+ git_buf_free(&path);
+ git_buf_free(&buf);
+}
+
diff --git a/tests/worktree/open.c b/tests/worktree/open.c
new file mode 100644
index 000000000..74b9007d9
--- /dev/null
+++ b/tests/worktree/open.c
@@ -0,0 +1,143 @@
+#include "clar_libgit2.h"
+#include "repository.h"
+#include "worktree.h"
+#include "worktree_helpers.h"
+
+#define COMMON_REPO "testrepo"
+#define WORKTREE_REPO "testrepo-worktree"
+
+static worktree_fixture fixture =
+ WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO);
+
+static void assert_worktree_valid(git_repository *wt, const char *parentdir, const char *wtdir)
+{
+ git_buf path = GIT_BUF_INIT;
+
+ cl_assert(wt->is_worktree);
+
+ cl_git_pass(git_buf_joinpath(&path, clar_sandbox_path(), wtdir));
+ cl_git_pass(git_path_prettify(&path, path.ptr, NULL));
+ cl_git_pass(git_path_to_dir(&path));
+ cl_assert_equal_s(wt->workdir, path.ptr);
+
+ cl_git_pass(git_buf_joinpath(&path, path.ptr, ".git"));
+ cl_git_pass(git_path_prettify(&path, path.ptr, NULL));
+ cl_assert_equal_s(wt->gitlink, path.ptr);
+
+ cl_git_pass(git_buf_joinpath(&path, clar_sandbox_path(), parentdir));
+ cl_git_pass(git_buf_joinpath(&path, path.ptr, ".git"));
+ cl_git_pass(git_buf_joinpath(&path, path.ptr, "worktrees"));
+ cl_git_pass(git_buf_joinpath(&path, path.ptr, wtdir));
+ cl_git_pass(git_path_prettify(&path, path.ptr, NULL));
+ cl_git_pass(git_path_to_dir(&path));
+ cl_assert_equal_s(wt->gitdir, path.ptr);
+
+ git_buf_free(&path);
+}
+
+void test_worktree_open__initialize(void)
+{
+ setup_fixture_worktree(&fixture);
+}
+
+void test_worktree_open__cleanup(void)
+{
+ cleanup_fixture_worktree(&fixture);
+}
+
+void test_worktree_open__repository(void)
+{
+ assert_worktree_valid(fixture.worktree, COMMON_REPO, WORKTREE_REPO);
+}
+
+void test_worktree_open__repository_through_workdir(void)
+{
+ git_repository *wt;
+
+ cl_git_pass(git_repository_open(&wt, WORKTREE_REPO));
+ assert_worktree_valid(wt, COMMON_REPO, WORKTREE_REPO);
+
+ git_repository_free(wt);
+}
+
+void test_worktree_open__repository_through_gitlink(void)
+{
+ git_repository *wt;
+
+ cl_git_pass(git_repository_open(&wt, WORKTREE_REPO "/.git"));
+ assert_worktree_valid(wt, COMMON_REPO, WORKTREE_REPO);
+
+ git_repository_free(wt);
+}
+
+void test_worktree_open__repository_through_gitdir(void)
+{
+ git_buf gitdir_path = GIT_BUF_INIT;
+ git_repository *wt;
+
+ cl_git_pass(git_buf_joinpath(&gitdir_path, COMMON_REPO, ".git"));
+ cl_git_pass(git_buf_joinpath(&gitdir_path, gitdir_path.ptr, "worktrees"));
+ cl_git_pass(git_buf_joinpath(&gitdir_path, gitdir_path.ptr, "testrepo-worktree"));
+
+ cl_git_pass(git_repository_open(&wt, gitdir_path.ptr));
+ assert_worktree_valid(wt, COMMON_REPO, WORKTREE_REPO);
+
+ git_buf_free(&gitdir_path);
+ git_repository_free(wt);
+}
+
+void test_worktree_open__open_discovered_worktree(void)
+{
+ git_buf path = GIT_BUF_INIT;
+ git_repository *repo;
+
+ cl_git_pass(git_repository_discover(&path,
+ git_repository_workdir(fixture.worktree), false, NULL));
+ cl_git_pass(git_repository_open(&repo, path.ptr));
+ cl_assert_equal_s(git_repository_workdir(fixture.worktree),
+ git_repository_workdir(repo));
+
+ git_buf_free(&path);
+ git_repository_free(repo);
+}
+
+void test_worktree_open__repository_with_nonexistent_parent(void)
+{
+ git_repository *repo;
+
+ cleanup_fixture_worktree(&fixture);
+
+ cl_fixture_sandbox(WORKTREE_REPO);
+ cl_git_pass(p_chdir(WORKTREE_REPO));
+ cl_git_pass(cl_rename(".gitted", ".git"));
+ cl_git_pass(p_chdir(".."));
+
+ cl_git_fail(git_repository_open(&repo, WORKTREE_REPO));
+
+ cl_fixture_cleanup(WORKTREE_REPO);
+}
+
+void test_worktree_open__open_from_repository(void)
+{
+ git_worktree *opened, *lookedup;
+
+ cl_git_pass(git_worktree_open_from_repository(&opened, fixture.worktree));
+ cl_git_pass(git_worktree_lookup(&lookedup, fixture.repo, WORKTREE_REPO));
+
+ cl_assert_equal_s(opened->name, lookedup->name);
+ cl_assert_equal_s(opened->gitdir_path, lookedup->gitdir_path);
+ cl_assert_equal_s(opened->gitlink_path, lookedup->gitlink_path);
+ cl_assert_equal_s(opened->parent_path, lookedup->parent_path);
+ cl_assert_equal_s(opened->commondir_path, lookedup->commondir_path);
+ cl_assert_equal_i(opened->locked, lookedup->locked);
+
+ git_worktree_free(opened);
+ git_worktree_free(lookedup);
+}
+
+void test_worktree_open__open_from_nonworktree_fails(void)
+{
+ git_worktree *wt;
+
+ cl_git_fail(git_worktree_open_from_repository(&wt, fixture.repo));
+}
diff --git a/tests/worktree/reflog.c b/tests/worktree/reflog.c
new file mode 100644
index 000000000..6152eb385
--- /dev/null
+++ b/tests/worktree/reflog.c
@@ -0,0 +1,65 @@
+#include "clar_libgit2.h"
+#include "worktree_helpers.h"
+
+#include "reflog.h"
+
+#define COMMON_REPO "testrepo"
+#define WORKTREE_REPO "testrepo-worktree"
+
+#define REFLOG "refs/heads/testrepo-worktree"
+#define REFLOG_MESSAGE "reflog message"
+
+static worktree_fixture fixture =
+ WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO);
+
+void test_worktree_reflog__initialize(void)
+{
+ setup_fixture_worktree(&fixture);
+}
+
+void test_worktree_reflog__cleanup(void)
+{
+ cleanup_fixture_worktree(&fixture);
+}
+
+void test_worktree_reflog__read(void)
+{
+ git_reflog *reflog;
+ const git_reflog_entry *entry;
+
+ cl_git_pass(git_reflog_read(&reflog, fixture.worktree, REFLOG));
+ cl_assert_equal_i(git_reflog_entrycount(reflog), 1);
+
+ entry = git_reflog_entry_byindex(reflog, 0);
+ cl_assert(entry != NULL);
+ cl_assert_equal_s(git_reflog_entry_message(entry), "branch: Created from HEAD");
+
+ git_reflog_free(reflog);
+}
+
+void test_worktree_reflog__append_then_read(void)
+{
+ git_reflog *reflog, *parent_reflog;
+ const git_reflog_entry *entry;
+ git_reference *head;
+ git_signature *sig;
+ const git_oid *oid;
+
+ cl_git_pass(git_repository_head(&head, fixture.worktree));
+ cl_assert((oid = git_reference_target(head)) != NULL);
+ cl_git_pass(git_signature_now(&sig, "foo", "foo@bar"));
+
+ cl_git_pass(git_reflog_read(&reflog, fixture.worktree, REFLOG));
+ cl_git_pass(git_reflog_append(reflog, oid, sig, REFLOG_MESSAGE));
+ git_reflog_write(reflog);
+
+ cl_git_pass(git_reflog_read(&parent_reflog, fixture.repo, REFLOG));
+ entry = git_reflog_entry_byindex(parent_reflog, 0);
+ cl_assert(git_oid_cmp(oid, &entry->oid_old) == 0);
+ cl_assert(git_oid_cmp(oid, &entry->oid_cur) == 0);
+
+ git_reference_free(head);
+ git_signature_free(sig);
+ git_reflog_free(reflog);
+ git_reflog_free(parent_reflog);
+}
diff --git a/tests/worktree/refs.c b/tests/worktree/refs.c
new file mode 100644
index 000000000..a10f50a2c
--- /dev/null
+++ b/tests/worktree/refs.c
@@ -0,0 +1,173 @@
+#include "clar_libgit2.h"
+#include "path.h"
+#include "refs.h"
+#include "worktree.h"
+#include "worktree_helpers.h"
+
+#define COMMON_REPO "testrepo"
+#define WORKTREE_REPO "testrepo-worktree"
+
+static worktree_fixture fixture =
+ WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO);
+
+void test_worktree_refs__initialize(void)
+{
+ setup_fixture_worktree(&fixture);
+}
+
+void test_worktree_refs__cleanup(void)
+{
+ cleanup_fixture_worktree(&fixture);
+}
+
+void test_worktree_refs__list(void)
+{
+ git_strarray refs, wtrefs;
+ unsigned i, j;
+ int error = 0;
+
+ cl_git_pass(git_reference_list(&refs, fixture.repo));
+ cl_git_pass(git_reference_list(&wtrefs, fixture.worktree));
+
+ if (refs.count != wtrefs.count)
+ {
+ error = GIT_ERROR;
+ goto exit;
+ }
+
+ for (i = 0; i < refs.count; i++)
+ {
+ int found = 0;
+
+ for (j = 0; j < wtrefs.count; j++)
+ {
+ if (!strcmp(refs.strings[i], wtrefs.strings[j]))
+ {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ error = GIT_ERROR;
+ goto exit;
+ }
+ }
+
+exit:
+ git_strarray_free(&refs);
+ git_strarray_free(&wtrefs);
+ cl_git_pass(error);
+}
+
+void test_worktree_refs__read_head(void)
+{
+ git_reference *head;
+
+ cl_git_pass(git_repository_head(&head, fixture.worktree));
+
+ git_reference_free(head);
+}
+
+void test_worktree_refs__set_head_fails_when_worktree_wants_linked_repos_HEAD(void)
+{
+ git_reference *head;
+
+ cl_git_pass(git_repository_head(&head, fixture.repo));
+ cl_git_fail(git_repository_set_head(fixture.worktree, git_reference_name(head)));
+
+ git_reference_free(head);
+}
+
+void test_worktree_refs__set_head_fails_when_main_repo_wants_worktree_head(void)
+{
+ git_reference *head;
+
+ cl_git_pass(git_repository_head(&head, fixture.worktree));
+ cl_git_fail(git_repository_set_head(fixture.repo, git_reference_name(head)));
+
+ git_reference_free(head);
+}
+
+void test_worktree_refs__set_head_works_for_current_HEAD(void)
+{
+ git_reference *head;
+
+ cl_git_pass(git_repository_head(&head, fixture.repo));
+ cl_git_pass(git_repository_set_head(fixture.repo, git_reference_name(head)));
+
+ git_reference_free(head);
+}
+
+void test_worktree_refs__set_head_fails_when_already_checked_out(void)
+{
+ cl_git_fail(git_repository_set_head(fixture.repo, "refs/heads/testrepo-worktree"));
+}
+
+void test_worktree_refs__delete_fails_for_checked_out_branch(void)
+{
+ git_reference *branch;
+
+ cl_git_pass(git_branch_lookup(&branch, fixture.repo,
+ "testrepo-worktree", GIT_BRANCH_LOCAL));
+ cl_git_fail(git_branch_delete(branch));
+
+ git_reference_free(branch);
+}
+
+void test_worktree_refs__delete_succeeds_after_pruning_worktree(void)
+{
+ git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT;
+ git_reference *branch;
+ git_worktree *worktree;
+
+ opts.flags = GIT_WORKTREE_PRUNE_VALID;
+
+ cl_git_pass(git_worktree_lookup(&worktree, fixture.repo, fixture.worktreename));
+ cl_git_pass(git_worktree_prune(worktree, &opts));
+ git_worktree_free(worktree);
+
+ cl_git_pass(git_branch_lookup(&branch, fixture.repo,
+ "testrepo-worktree", GIT_BRANCH_LOCAL));
+ cl_git_pass(git_branch_delete(branch));
+ git_reference_free(branch);
+}
+
+void test_worktree_refs__renaming_reference_updates_worktree_heads(void)
+{
+ git_reference *head, *branch, *renamed;
+
+ cl_git_pass(git_branch_lookup(&branch, fixture.repo,
+ "testrepo-worktree", GIT_BRANCH_LOCAL));
+ cl_git_pass(git_reference_rename(&renamed, branch, "refs/heads/renamed", 0, NULL));
+ cl_git_pass(git_repository_head(&head, fixture.worktree));
+
+ git_reference_free(head);
+ git_reference_free(branch);
+ git_reference_free(renamed);
+}
+
+void test_worktree_refs__creating_refs_uses_commondir(void)
+{
+ git_reference *head, *branch, *lookup;
+ git_commit *commit;
+ git_buf refpath = GIT_BUF_INIT;
+
+ cl_git_pass(git_buf_joinpath(&refpath,
+ git_repository_commondir(fixture.worktree), "refs/heads/testbranch"));
+ cl_assert(!git_path_exists(refpath.ptr));
+
+ cl_git_pass(git_repository_head(&head, fixture.worktree));
+ cl_git_pass(git_commit_lookup(&commit, fixture.worktree, git_reference_target(head)));
+ cl_git_pass(git_branch_create(&branch, fixture.worktree, "testbranch", commit, 0));
+ cl_git_pass(git_branch_lookup(&lookup, fixture.worktree, "testbranch", GIT_BRANCH_LOCAL));
+ cl_assert(git_reference_cmp(branch, lookup) == 0);
+ cl_assert(git_path_exists(refpath.ptr));
+
+ git_reference_free(lookup);
+ git_reference_free(branch);
+ git_reference_free(head);
+ git_commit_free(commit);
+ git_buf_free(&refpath);
+}
diff --git a/tests/worktree/repository.c b/tests/worktree/repository.c
new file mode 100644
index 000000000..5c7595c64
--- /dev/null
+++ b/tests/worktree/repository.c
@@ -0,0 +1,63 @@
+#include "clar_libgit2.h"
+#include "worktree_helpers.h"
+#include "submodule/submodule_helpers.h"
+
+#include "repository.h"
+
+#define COMMON_REPO "testrepo"
+#define WORKTREE_REPO "testrepo-worktree"
+
+static worktree_fixture fixture =
+ WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO);
+
+void test_worktree_repository__initialize(void)
+{
+ setup_fixture_worktree(&fixture);
+}
+
+void test_worktree_repository__cleanup(void)
+{
+ cleanup_fixture_worktree(&fixture);
+}
+
+void test_worktree_repository__head(void)
+{
+ git_reference *ref, *head;
+
+ cl_git_pass(git_reference_lookup(&ref, fixture.repo, "refs/heads/testrepo-worktree"));
+ cl_git_pass(git_repository_head_for_worktree(&head, fixture.repo, "testrepo-worktree"));
+ cl_assert(git_reference_cmp(ref, head) == 0);
+
+ git_reference_free(ref);
+ git_reference_free(head);
+}
+
+void test_worktree_repository__head_fails_for_invalid_worktree(void)
+{
+ git_reference *head = NULL;
+
+ cl_git_fail(git_repository_head_for_worktree(&head, fixture.repo, "invalid"));
+ cl_assert(head == NULL);
+}
+
+void test_worktree_repository__head_detached(void)
+{
+ git_reference *ref, *head;
+
+ cl_git_pass(git_reference_lookup(&ref, fixture.repo, "refs/heads/testrepo-worktree"));
+ cl_git_pass(git_repository_set_head_detached(fixture.worktree, &ref->target.oid));
+
+ cl_assert(git_repository_head_detached(fixture.worktree));
+ cl_assert(git_repository_head_detached_for_worktree(fixture.repo, "testrepo-worktree"));
+ cl_git_fail(git_repository_head_for_worktree(&head, fixture.repo, "testrepo-worktree"));
+
+ git_reference_free(ref);
+}
+
+void test_worktree_repository__head_detached_fails_for_invalid_worktree(void)
+{
+ git_reference *head = NULL;
+
+ cl_git_fail(git_repository_head_detached_for_worktree(fixture.repo, "invalid"));
+ cl_assert(head == NULL);
+}
diff --git a/tests/worktree/submodule.c b/tests/worktree/submodule.c
new file mode 100644
index 000000000..294385226
--- /dev/null
+++ b/tests/worktree/submodule.c
@@ -0,0 +1,92 @@
+#include "clar_libgit2.h"
+#include "repository.h"
+#include "worktree.h"
+#include "worktree_helpers.h"
+
+#define WORKTREE_PARENT "submodules-worktree-parent"
+#define WORKTREE_CHILD "submodules-worktree-child"
+
+static worktree_fixture parent
+ = WORKTREE_FIXTURE_INIT("submodules", WORKTREE_PARENT);
+static worktree_fixture child
+ = WORKTREE_FIXTURE_INIT(NULL, WORKTREE_CHILD);
+
+void test_worktree_submodule__initialize(void)
+{
+ setup_fixture_worktree(&parent);
+
+ cl_git_pass(p_rename(
+ "submodules/testrepo/.gitted",
+ "submodules/testrepo/.git"));
+
+ setup_fixture_worktree(&child);
+}
+
+void test_worktree_submodule__cleanup(void)
+{
+ cleanup_fixture_worktree(&child);
+ cleanup_fixture_worktree(&parent);
+}
+
+void test_worktree_submodule__submodule_worktree_parent(void)
+{
+ cl_assert(git_repository_path(parent.worktree) != NULL);
+ cl_assert(git_repository_workdir(parent.worktree) != NULL);
+
+ cl_assert(!parent.repo->is_worktree);
+ cl_assert(parent.worktree->is_worktree);
+}
+
+void test_worktree_submodule__submodule_worktree_child(void)
+{
+ cl_assert(!parent.repo->is_worktree);
+ cl_assert(parent.worktree->is_worktree);
+ cl_assert(child.worktree->is_worktree);
+}
+
+void test_worktree_submodule__open_discovered_submodule_worktree(void)
+{
+ git_buf path = GIT_BUF_INIT;
+ git_repository *repo;
+
+ cl_git_pass(git_repository_discover(&path,
+ git_repository_workdir(child.worktree), false, NULL));
+ cl_git_pass(git_repository_open(&repo, path.ptr));
+ cl_assert_equal_s(git_repository_workdir(child.worktree),
+ git_repository_workdir(repo));
+
+ git_buf_free(&path);
+ git_repository_free(repo);
+}
+
+void test_worktree_submodule__resolve_relative_url(void)
+{
+ git_buf wt_path = GIT_BUF_INIT;
+ git_buf sm_relative_path = GIT_BUF_INIT, wt_relative_path = GIT_BUF_INIT;
+ git_repository *repo;
+ git_worktree *wt;
+
+ cl_git_pass(git_futils_mkdir("subdir", 0755, GIT_MKDIR_PATH));
+ cl_git_pass(git_path_prettify_dir(&wt_path, "subdir", NULL));
+ cl_git_pass(git_buf_joinpath(&wt_path, wt_path.ptr, "wt"));
+
+ /* Open child repository, which is a submodule */
+ cl_git_pass(git_repository_open(&child.repo, WORKTREE_CHILD));
+
+ /* Create worktree of submodule repository */
+ cl_git_pass(git_worktree_add(&wt, child.repo, "subdir", wt_path.ptr, NULL));
+ cl_git_pass(git_repository_open_from_worktree(&repo, wt));
+
+ cl_git_pass(git_submodule_resolve_url(&sm_relative_path, repo,
+ "../" WORKTREE_CHILD));
+ cl_git_pass(git_submodule_resolve_url(&wt_relative_path, child.repo,
+ "../" WORKTREE_CHILD));
+
+ cl_assert_equal_s(sm_relative_path.ptr, wt_relative_path.ptr);
+
+ git_worktree_free(wt);
+ git_repository_free(repo);
+ git_buf_free(&wt_path);
+ git_buf_free(&sm_relative_path);
+ git_buf_free(&wt_relative_path);
+}
diff --git a/tests/worktree/worktree.c b/tests/worktree/worktree.c
new file mode 100644
index 000000000..4ac3b8bba
--- /dev/null
+++ b/tests/worktree/worktree.c
@@ -0,0 +1,583 @@
+#include "clar_libgit2.h"
+#include "worktree_helpers.h"
+#include "submodule/submodule_helpers.h"
+
+#include "checkout.h"
+#include "repository.h"
+#include "worktree.h"
+
+#define COMMON_REPO "testrepo"
+#define WORKTREE_REPO "testrepo-worktree"
+
+static worktree_fixture fixture =
+ WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO);
+
+void test_worktree_worktree__initialize(void)
+{
+ setup_fixture_worktree(&fixture);
+}
+
+void test_worktree_worktree__cleanup(void)
+{
+ cleanup_fixture_worktree(&fixture);
+}
+
+void test_worktree_worktree__list(void)
+{
+ git_strarray wts;
+
+ cl_git_pass(git_worktree_list(&wts, fixture.repo));
+ cl_assert_equal_i(wts.count, 1);
+ cl_assert_equal_s(wts.strings[0], "testrepo-worktree");
+
+ git_strarray_free(&wts);
+}
+
+void test_worktree_worktree__list_with_invalid_worktree_dirs(void)
+{
+ const char *filesets[3][2] = {
+ { "gitdir", "commondir" },
+ { "gitdir", "HEAD" },
+ { "HEAD", "commondir" },
+ };
+ git_buf path = GIT_BUF_INIT;
+ git_strarray wts;
+ unsigned i, j, len;
+
+ cl_git_pass(git_buf_printf(&path, "%s/worktrees/invalid",
+ fixture.repo->commondir));
+ cl_git_pass(p_mkdir(path.ptr, 0755));
+
+ len = path.size;
+
+ for (i = 0; i < ARRAY_SIZE(filesets); i++) {
+
+ for (j = 0; j < ARRAY_SIZE(filesets[i]); j++) {
+ git_buf_truncate(&path, len);
+ cl_git_pass(git_buf_joinpath(&path, path.ptr, filesets[i][j]));
+ cl_git_pass(p_close(p_creat(path.ptr, 0644)));
+ }
+
+ cl_git_pass(git_worktree_list(&wts, fixture.worktree));
+ cl_assert_equal_i(wts.count, 1);
+ cl_assert_equal_s(wts.strings[0], "testrepo-worktree");
+ git_strarray_free(&wts);
+
+ for (j = 0; j < ARRAY_SIZE(filesets[i]); j++) {
+ git_buf_truncate(&path, len);
+ cl_git_pass(git_buf_joinpath(&path, path.ptr, filesets[i][j]));
+ p_unlink(path.ptr);
+ }
+ }
+
+ git_buf_free(&path);
+}
+
+void test_worktree_worktree__list_in_worktree_repo(void)
+{
+ git_strarray wts;
+
+ cl_git_pass(git_worktree_list(&wts, fixture.worktree));
+ cl_assert_equal_i(wts.count, 1);
+ cl_assert_equal_s(wts.strings[0], "testrepo-worktree");
+
+ git_strarray_free(&wts);
+}
+
+void test_worktree_worktree__list_bare(void)
+{
+ git_repository *repo;
+ git_strarray wts;
+
+ repo = cl_git_sandbox_init("testrepo.git");
+ cl_git_pass(git_worktree_list(&wts, repo));
+ cl_assert_equal_i(wts.count, 0);
+
+ git_repository_free(repo);
+}
+
+void test_worktree_worktree__list_without_worktrees(void)
+{
+ git_repository *repo;
+ git_strarray wts;
+
+ repo = cl_git_sandbox_init("testrepo2");
+ cl_git_pass(git_worktree_list(&wts, repo));
+ cl_assert_equal_i(wts.count, 0);
+
+ git_repository_free(repo);
+}
+
+void test_worktree_worktree__lookup(void)
+{
+ git_worktree *wt;
+ git_buf gitdir_path = GIT_BUF_INIT;
+
+ cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+
+ cl_git_pass(git_buf_joinpath(&gitdir_path, fixture.repo->commondir, "worktrees/testrepo-worktree/"));
+
+ cl_assert_equal_s(wt->gitdir_path, gitdir_path.ptr);
+ cl_assert_equal_s(wt->parent_path, fixture.repo->workdir);
+ cl_assert_equal_s(wt->gitlink_path, fixture.worktree->gitlink);
+ cl_assert_equal_s(wt->commondir_path, fixture.repo->gitdir);
+ cl_assert_equal_s(wt->commondir_path, fixture.repo->commondir);
+
+ git_buf_free(&gitdir_path);
+ git_worktree_free(wt);
+}
+
+void test_worktree_worktree__lookup_nonexistent_worktree(void)
+{
+ git_worktree *wt;
+
+ cl_git_fail(git_worktree_lookup(&wt, fixture.repo, "nonexistent"));
+ cl_assert_equal_p(wt, NULL);
+}
+
+void test_worktree_worktree__open(void)
+{
+ git_worktree *wt;
+ git_repository *repo;
+
+ cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+
+ cl_git_pass(git_repository_open_from_worktree(&repo, wt));
+ cl_assert_equal_s(git_repository_workdir(repo),
+ git_repository_workdir(fixture.worktree));
+
+ git_repository_free(repo);
+ git_worktree_free(wt);
+}
+
+void test_worktree_worktree__open_invalid_commondir(void)
+{
+ git_worktree *wt;
+ git_repository *repo;
+ git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT;
+
+ cl_git_pass(git_buf_sets(&buf, "/path/to/nonexistent/commondir"));
+ cl_git_pass(git_buf_printf(&path,
+ "%s/worktrees/testrepo-worktree/commondir",
+ fixture.repo->commondir));
+ cl_git_pass(git_futils_writebuffer(&buf, path.ptr, O_RDWR, 0644));
+
+ cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+ cl_git_fail(git_repository_open_from_worktree(&repo, wt));
+
+ git_buf_free(&buf);
+ git_buf_free(&path);
+ git_worktree_free(wt);
+}
+
+void test_worktree_worktree__open_invalid_gitdir(void)
+{
+ git_worktree *wt;
+ git_repository *repo;
+ git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT;
+
+ cl_git_pass(git_buf_sets(&buf, "/path/to/nonexistent/gitdir"));
+ cl_git_pass(git_buf_printf(&path,
+ "%s/worktrees/testrepo-worktree/gitdir",
+ fixture.repo->commondir));
+ cl_git_pass(git_futils_writebuffer(&buf, path.ptr, O_RDWR, 0644));
+
+ cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+ cl_git_fail(git_repository_open_from_worktree(&repo, wt));
+
+ git_buf_free(&buf);
+ git_buf_free(&path);
+ git_worktree_free(wt);
+}
+
+void test_worktree_worktree__open_invalid_parent(void)
+{
+ git_worktree *wt;
+ git_repository *repo;
+ git_buf buf = GIT_BUF_INIT;
+
+ cl_git_pass(git_buf_sets(&buf, "/path/to/nonexistent/gitdir"));
+ cl_git_pass(git_futils_writebuffer(&buf,
+ fixture.worktree->gitlink, O_RDWR, 0644));
+
+ cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+ cl_git_fail(git_repository_open_from_worktree(&repo, wt));
+
+ git_buf_free(&buf);
+ git_worktree_free(wt);
+}
+
+void test_worktree_worktree__init(void)
+{
+ git_worktree *wt;
+ git_repository *repo;
+ git_reference *branch;
+ git_buf path = GIT_BUF_INIT;
+
+ cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-new"));
+ cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-new", path.ptr, NULL));
+
+ /* Open and verify created repo */
+ cl_git_pass(git_repository_open(&repo, path.ptr));
+ cl_assert(git__suffixcmp(git_repository_workdir(repo), "worktree-new/") == 0);
+ cl_git_pass(git_branch_lookup(&branch, repo, "worktree-new", GIT_BRANCH_LOCAL));
+
+ git_buf_free(&path);
+ git_worktree_free(wt);
+ git_reference_free(branch);
+ git_repository_free(repo);
+}
+
+void test_worktree_worktree__add_locked(void)
+{
+ git_worktree *wt;
+ git_repository *repo;
+ git_reference *branch;
+ git_buf path = GIT_BUF_INIT;
+ git_worktree_add_options opts = GIT_WORKTREE_ADD_OPTIONS_INIT;
+
+ opts.lock = 1;
+
+ cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-locked"));
+ cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-locked", path.ptr, &opts));
+
+ /* Open and verify created repo */
+ cl_assert(git_worktree_is_locked(NULL, wt));
+ cl_git_pass(git_repository_open(&repo, path.ptr));
+ cl_assert(git__suffixcmp(git_repository_workdir(repo), "worktree-locked/") == 0);
+ cl_git_pass(git_branch_lookup(&branch, repo, "worktree-locked", GIT_BRANCH_LOCAL));
+
+ git_buf_free(&path);
+ git_worktree_free(wt);
+ git_reference_free(branch);
+ git_repository_free(repo);
+}
+
+void test_worktree_worktree__init_existing_branch(void)
+{
+ git_reference *head, *branch;
+ git_commit *commit;
+ git_worktree *wt;
+ git_buf path = GIT_BUF_INIT;
+
+ cl_git_pass(git_repository_head(&head, fixture.repo));
+ cl_git_pass(git_commit_lookup(&commit, fixture.repo, &head->target.oid));
+ cl_git_pass(git_branch_create(&branch, fixture.repo, "worktree-new", commit, false));
+
+ cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-new"));
+ cl_git_fail(git_worktree_add(&wt, fixture.repo, "worktree-new", path.ptr, NULL));
+
+ git_buf_free(&path);
+ git_commit_free(commit);
+ git_reference_free(head);
+ git_reference_free(branch);
+}
+
+void test_worktree_worktree__init_existing_worktree(void)
+{
+ git_worktree *wt;
+ git_buf path = GIT_BUF_INIT;
+
+ cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-new"));
+ cl_git_fail(git_worktree_add(&wt, fixture.repo, "testrepo-worktree", path.ptr, NULL));
+
+ cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+ cl_assert_equal_s(wt->gitlink_path, fixture.worktree->gitlink);
+
+ git_buf_free(&path);
+ git_worktree_free(wt);
+}
+
+void test_worktree_worktree__init_existing_path(void)
+{
+ const char *wtfiles[] = { "HEAD", "commondir", "gitdir", "index" };
+ git_worktree *wt;
+ git_buf path = GIT_BUF_INIT;
+ unsigned i;
+
+ /* Delete files to verify they have not been created by
+ * the init call */
+ for (i = 0; i < ARRAY_SIZE(wtfiles); i++) {
+ cl_git_pass(git_buf_joinpath(&path,
+ fixture.worktree->gitdir, wtfiles[i]));
+ cl_git_pass(p_unlink(path.ptr));
+ }
+
+ cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../testrepo-worktree"));
+ cl_git_fail(git_worktree_add(&wt, fixture.repo, "worktree-new", path.ptr, NULL));
+
+ /* Verify files have not been re-created */
+ for (i = 0; i < ARRAY_SIZE(wtfiles); i++) {
+ cl_git_pass(git_buf_joinpath(&path,
+ fixture.worktree->gitdir, wtfiles[i]));
+ cl_assert(!git_path_exists(path.ptr));
+ }
+
+ git_buf_free(&path);
+}
+
+void test_worktree_worktree__init_submodule(void)
+{
+ git_repository *repo, *sm, *wt;
+ git_worktree *worktree;
+ git_buf path = GIT_BUF_INIT;
+
+ cleanup_fixture_worktree(&fixture);
+ repo = setup_fixture_submod2();
+
+ cl_git_pass(git_buf_joinpath(&path, repo->workdir, "sm_unchanged"));
+ cl_git_pass(git_repository_open(&sm, path.ptr));
+ cl_git_pass(git_buf_joinpath(&path, repo->workdir, "../worktree/"));
+ cl_git_pass(git_worktree_add(&worktree, sm, "repo-worktree", path.ptr, NULL));
+ cl_git_pass(git_repository_open_from_worktree(&wt, worktree));
+
+ cl_git_pass(git_path_prettify_dir(&path, path.ptr, NULL));
+ cl_assert_equal_s(path.ptr, wt->workdir);
+ cl_git_pass(git_path_prettify_dir(&path, sm->commondir, NULL));
+ cl_assert_equal_s(sm->commondir, wt->commondir);
+
+ cl_git_pass(git_buf_joinpath(&path, sm->gitdir, "worktrees/repo-worktree/"));
+ cl_assert_equal_s(path.ptr, wt->gitdir);
+
+ git_buf_free(&path);
+ git_worktree_free(worktree);
+ git_repository_free(sm);
+ git_repository_free(wt);
+}
+
+void test_worktree_worktree__validate(void)
+{
+ git_worktree *wt;
+
+ cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+ cl_git_pass(git_worktree_validate(wt));
+
+ git_worktree_free(wt);
+}
+
+void test_worktree_worktree__validate_invalid_commondir(void)
+{
+ git_worktree *wt;
+
+ cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+ git__free(wt->commondir_path);
+ wt->commondir_path = "/path/to/invalid/commondir";
+
+ cl_git_fail(git_worktree_validate(wt));
+
+ wt->commondir_path = NULL;
+ git_worktree_free(wt);
+}
+
+void test_worktree_worktree__validate_invalid_gitdir(void)
+{
+ git_worktree *wt;
+
+ cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+ git__free(wt->gitdir_path);
+ wt->gitdir_path = "/path/to/invalid/gitdir";
+ cl_git_fail(git_worktree_validate(wt));
+
+ wt->gitdir_path = NULL;
+ git_worktree_free(wt);
+}
+
+void test_worktree_worktree__validate_invalid_parent(void)
+{
+ git_worktree *wt;
+
+ cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+ git__free(wt->parent_path);
+ wt->parent_path = "/path/to/invalid/parent";
+ cl_git_fail(git_worktree_validate(wt));
+
+ wt->parent_path = NULL;
+ git_worktree_free(wt);
+}
+
+void test_worktree_worktree__lock_with_reason(void)
+{
+ git_worktree *wt;
+ git_buf reason = GIT_BUF_INIT;
+
+ cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+
+ cl_assert(!git_worktree_is_locked(NULL, wt));
+ cl_git_pass(git_worktree_lock(wt, "because"));
+ cl_assert(git_worktree_is_locked(&reason, wt) > 0);
+ cl_assert_equal_s(reason.ptr, "because");
+ cl_assert(wt->locked);
+
+ git_buf_free(&reason);
+ git_worktree_free(wt);
+}
+
+void test_worktree_worktree__lock_without_reason(void)
+{
+ git_worktree *wt;
+ git_buf reason = GIT_BUF_INIT;
+
+ cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+
+ cl_assert(!git_worktree_is_locked(NULL, wt));
+ cl_git_pass(git_worktree_lock(wt, NULL));
+ cl_assert(git_worktree_is_locked(&reason, wt) > 0);
+ cl_assert_equal_i(reason.size, 0);
+ cl_assert(wt->locked);
+
+ git_buf_free(&reason);
+ git_worktree_free(wt);
+}
+
+void test_worktree_worktree__unlock_unlocked_worktree(void)
+{
+ git_worktree *wt;
+
+ cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+ cl_assert(!git_worktree_is_locked(NULL, wt));
+ cl_assert(git_worktree_unlock(wt) == 0);
+ cl_assert(!wt->locked);
+
+ git_worktree_free(wt);
+}
+
+void test_worktree_worktree__unlock_locked_worktree(void)
+{
+ git_worktree *wt;
+
+ cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+ cl_git_pass(git_worktree_lock(wt, NULL));
+ cl_assert(git_worktree_is_locked(NULL, wt));
+ cl_git_pass(git_worktree_unlock(wt));
+ cl_assert(!wt->locked);
+
+ git_worktree_free(wt);
+}
+
+void test_worktree_worktree__prune_without_opts_fails(void)
+{
+ git_worktree *wt;
+ git_repository *repo;
+
+ cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+ cl_git_fail(git_worktree_prune(wt, NULL));
+
+ /* Assert the repository is still valid */
+ cl_git_pass(git_repository_open_from_worktree(&repo, wt));
+
+ git_worktree_free(wt);
+ git_repository_free(repo);
+}
+
+void test_worktree_worktree__prune_valid(void)
+{
+ git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT;
+ git_worktree *wt;
+ git_repository *repo;
+
+ opts.flags = GIT_WORKTREE_PRUNE_VALID;
+
+ cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+ cl_git_pass(git_worktree_prune(wt, &opts));
+
+ /* Assert the repository is not valid anymore */
+ cl_git_fail(git_repository_open_from_worktree(&repo, wt));
+
+ git_worktree_free(wt);
+ git_repository_free(repo);
+}
+
+void test_worktree_worktree__prune_locked(void)
+{
+ git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT;
+ git_worktree *wt;
+ git_repository *repo;
+
+ cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+ cl_git_pass(git_worktree_lock(wt, NULL));
+
+ opts.flags = GIT_WORKTREE_PRUNE_VALID;
+ cl_git_fail(git_worktree_prune(wt, &opts));
+ /* Assert the repository is still valid */
+ cl_git_pass(git_repository_open_from_worktree(&repo, wt));
+
+ opts.flags = GIT_WORKTREE_PRUNE_VALID|GIT_WORKTREE_PRUNE_LOCKED;
+ cl_git_pass(git_worktree_prune(wt, &opts));
+
+ git_worktree_free(wt);
+ git_repository_free(repo);
+}
+
+void test_worktree_worktree__prune_gitdir_only(void)
+{
+ git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT;
+ git_worktree *wt;
+
+ opts.flags = GIT_WORKTREE_PRUNE_VALID;
+ cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+ cl_git_pass(git_worktree_prune(wt, &opts));
+
+ cl_assert(!git_path_exists(wt->gitdir_path));
+ cl_assert(git_path_exists(wt->gitlink_path));
+
+ git_worktree_free(wt);
+}
+
+void test_worktree_worktree__prune_worktree(void)
+{
+ git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT;
+ git_worktree *wt;
+
+ opts.flags = GIT_WORKTREE_PRUNE_VALID|GIT_WORKTREE_PRUNE_WORKING_TREE;
+
+ cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+ cl_git_pass(git_worktree_prune(wt, &opts));
+
+ cl_assert(!git_path_exists(wt->gitdir_path));
+ cl_assert(!git_path_exists(wt->gitlink_path));
+
+ git_worktree_free(wt);
+}
+
+static int read_head_ref(git_repository *repo, const char *path, void *payload)
+{
+ git_vector *refs = (git_vector *) payload;
+ git_reference *head;
+
+ GIT_UNUSED(repo);
+
+ cl_git_pass(git_reference__read_head(&head, repo, path));
+
+ git_vector_insert(refs, head);
+
+ return 0;
+}
+
+void test_worktree_worktree__foreach_head_gives_same_results_in_wt_and_repo(void)
+{
+ git_vector repo_refs = GIT_VECTOR_INIT, worktree_refs = GIT_VECTOR_INIT;
+ git_reference *heads[2];
+ size_t i;
+
+ cl_git_pass(git_reference_lookup(&heads[0], fixture.repo, GIT_HEAD_FILE));
+ cl_git_pass(git_reference_lookup(&heads[1], fixture.worktree, GIT_HEAD_FILE));
+
+ cl_git_pass(git_repository_foreach_head(fixture.repo, read_head_ref, &repo_refs));
+ cl_git_pass(git_repository_foreach_head(fixture.worktree, read_head_ref, &worktree_refs));
+
+ cl_assert_equal_i(repo_refs.length, ARRAY_SIZE(heads));
+ cl_assert_equal_i(worktree_refs.length, ARRAY_SIZE(heads));
+
+ for (i = 0; i < ARRAY_SIZE(heads); i++) {
+ cl_assert_equal_s(heads[i]->name, ((git_reference *) repo_refs.contents[i])->name);
+ cl_assert_equal_s(heads[i]->name, ((git_reference *) repo_refs.contents[i])->name);
+ cl_assert_equal_s(heads[i]->name, ((git_reference *) worktree_refs.contents[i])->name);
+
+ git_reference_free(heads[i]);
+ git_reference_free(repo_refs.contents[i]);
+ git_reference_free(worktree_refs.contents[i]);
+ }
+
+ git_vector_free(&repo_refs);
+ git_vector_free(&worktree_refs);
+}
diff --git a/tests/worktree/worktree_helpers.c b/tests/worktree/worktree_helpers.c
new file mode 100644
index 000000000..6d4cdbaeb
--- /dev/null
+++ b/tests/worktree/worktree_helpers.c
@@ -0,0 +1,30 @@
+#include "clar_libgit2.h"
+#include "worktree_helpers.h"
+
+void cleanup_fixture_worktree(worktree_fixture *fixture)
+{
+ if (!fixture)
+ return;
+
+ if (fixture->repo) {
+ git_repository_free(fixture->repo);
+ fixture->repo = NULL;
+ }
+ if (fixture->worktree) {
+ git_repository_free(fixture->worktree);
+ fixture->worktree = NULL;
+ }
+
+ if (fixture->reponame)
+ cl_fixture_cleanup(fixture->reponame);
+ if (fixture->worktreename)
+ cl_fixture_cleanup(fixture->worktreename);
+}
+
+void setup_fixture_worktree(worktree_fixture *fixture)
+{
+ if (fixture->reponame)
+ fixture->repo = cl_git_sandbox_init(fixture->reponame);
+ if (fixture->worktreename)
+ fixture->worktree = cl_git_sandbox_init(fixture->worktreename);
+}
diff --git a/tests/worktree/worktree_helpers.h b/tests/worktree/worktree_helpers.h
new file mode 100644
index 000000000..35ea9ed4c
--- /dev/null
+++ b/tests/worktree/worktree_helpers.h
@@ -0,0 +1,11 @@
+typedef struct {
+ const char *reponame;
+ const char *worktreename;
+ git_repository *repo;
+ git_repository *worktree;
+} worktree_fixture;
+
+#define WORKTREE_FIXTURE_INIT(repo, worktree) { (repo), (worktree), NULL, NULL }
+
+void cleanup_fixture_worktree(worktree_fixture *fixture);
+void setup_fixture_worktree(worktree_fixture *fixture);